Skip to content

Releases: SphereII/SphereII.Mods

2.6.10.1108

24 Mar 14:26

Choose a tag to compare

2.6.10.1108 Pre-release
Pre-release

Version: 2.6.10.1108 [ Experimental ]
[ NPCv4 / IEntityAliveSDX - V4 Entity Support ]
NPCv4 (EntityAliveSDXV4) is a ground-up rewrite of the NPC entity that extends EntityTrader
instead of EntityAlive, using a component-based architecture (NPCLeaderComponent,
NPCPatrolComponent, NPCCombatComponent, NPCEffectsComponent) to replace the monolithic
EntityAliveSDX class. The goal is cleaner separation of concerns, better compatibility with
vanilla trader systems, and a more maintainable foundation for future NPC features.
The IEntityAliveSDX interface bridges V3 and V4, allowing shared code (UAI tasks, dialog
scripts, utility methods) to work with either entity type without hard casts.

	- Updated EntityUtilities.ExecuteCMD to support EntityAliveSDXV4 via IEntityAliveSDX and
	  IEntityOrderReceiverSDX interfaces. V3-exclusive fields (bodyDamage) remain gated behind
	  a conditional EntityAliveSDX cast; all other operations now work for both V3 and V4.
	- Updated EntityUtilities.TeleportNow to use IEntityAliveSDX type guard instead of a hard
	  EntityAliveSDX cast, allowing V4 entities to be teleported.
	- Updated EntityUtilities.AddQuestToRadius to detect both EntityAliveSDX (V3) and
	  EntityAliveSDXV4 (V4) when adding quests to nearby NPCs.
	- Updated DialogActionAnimatorSet to cast via IEntityAliveSDX instead of EntityAliveSDX,
	  allowing V4 entities to receive animator commands from dialogs.
	- Updated DialogActionDisplayInfo to cast via IEntityAliveSDX, allowing V4 entities to
	  display info dialogs.
	- Updated DialogActionRemoveBuffNPCSDX to cast via IEntityAliveSDX, allowing V4 entities
	  to have buffs removed through dialogs.
	- Updated DialogActionSwapWeapon to cast via IEntityAliveSDX, using the interface's
	  UpdateWeapon() method so V4 entities can swap weapons through dialogs.
	- Updated DialogRequirementHasQuestSDX to cast via IEntityAliveSDX; NPCInfo accessed via
	  EntityTrader cast, supporting V4 quest requirements.
	- Updated DialogRequirementNPCHasItemSDX to cast via IEntityAliveSDX with null-safe loot
	  container checks, supporting V4 inventory requirements.
	- Updated DialogActionPickUpNPC to cast via EntityAlive + IEntityAliveSDX, enabling V4
	  entity pickup. EntitySyncUtils.GetNPCItemValue, SetNPCItemValue, Collect, and
	  CollectClient now accept EntityAlive and use IEntityAliveSDX for name, title, and
	  weapon access; V3-specific fields (belongsPlayerId, _currentWeapon) use conditional
	  casts. IEntityAliveSDX gains FirstName and Title members. EntityAliveSDXV4.Title.set
	  was fixed (previously threw NotImplementedException). All deploy/place net packages
	  and ItemActionDeployNPCSDX updated to cast via EntityAlive rather than EntityAliveSDX.

[ UAI Troubleshooting / Diagnostics ]
	- Added per-entity AIPackage diagnostics to EntityAliveSDXV4.PostInit via new
	  LogMissingAIPackages() method. On spawn, logs which packages were found vs. missing
	  from UAIBase.AIPackages, making load-order conflicts immediately visible in the log.
	- Added empty-AIPackages-list warning in UAIBase.chooseAction Prefix: if an entity has
	  no AI packages, a single warning is logged explaining what to check.
	- Added per-package missing-package warning in UAIBase.chooseAction Prefix using a
	  HashSet deduplication guard, preventing log spam while still surfacing undefined
	  package names on first encounter.

[ UAI Performance / Bug Fixes ]
	- Replaced triple dictionary lookup (ContainsKey + two indexed accesses) in
	  UAIBase.chooseAction with a single TryGetValue call, reducing redundant hash lookups
	  per AI evaluation cycle.
	- Removed dead-code sort in AddWaypointTargetsToConsider: the sort was applied to the
	  WaypointTargets list immediately after Clear(), so it operated on an empty list every
	  time and had no effect.
	- Fixed incorrect log-line order in AddWaypointTargetsToConsider: the count was logged
	  before waypoints were gathered, reporting 0 every time.

[ UAI Farming ]
	- Fixed two farmer NPCs targeting the same crop simultaneously. Added a shared static
	  HashSet<Vector3i> claim registry to UAITaskFarming and UAITaskFarmingV4. A plot is
	  claimed in Start() immediately after selection and released in Stop(), covering both
	  normal task completion and interruption. FindTargetFarmPlot() skips any plot already
	  in the registry, so each farmer always works a unique plot.
	- Fixed harvested items not being added to the NPC's inventory. Three silent failure
	  modes were patched in HandleHarvestingAndCleanup for both UAITaskFarming and
	  UAITaskFarmingV4:
	    * FastMax(0, minCount) could produce a 0-count ItemStack that AddItem silently rejects;
	      clamped to FastMax(1, minCount).
	    * item.prob was never checked; items now roll against their drop probability.
	    * ItemClass.GetItem result was not validated; unknown item names now log a warning
	      and are skipped instead of producing an invalid ItemValue.None stack.
	- Fixed NPC farmer not harvesting fully-grown crops whose block type does not extend
	  BlockPlant (e.g. BlockPickUpAndReplace-based final stages such as plantedCoffee3HarvestPlayer).
	  FarmPlotData.Manage() previously checked IsDeadPlant() before checking harvest drops,
	  so any non-BlockPlant block was cleared as a "dead plant" with no items returned.
	  The branch order is now: HasItemsToDropForEvent(Harvest) first (harvest), then
	  IsDeadPlant() (clear), then growing-plant skip, then empty-plot replant.
	- Fixed NPC farmer not replanting immediately after harvesting. Two causes:
	    * CanPlaceBlockAt was checked against the live world while the harvested block was
	      still present, always returning false. The check is removed; placement validity is
	      guaranteed by the block name resolving correctly.
	    * SetBlocksRPC was called with two entries at the same position (air then seed).
	      The intermediate air state triggered a physics/support check that caused the seed
	      to fall through the world before it could stabilise. Replaced with a single-entry
	      RPC that writes the seed directly over the harvested block.
	- Fixed malformed drop table entries (empty item name, zero maxCount) from block
	  itemsToDrop reaching the NPC inventory loop and producing unknown-item warnings.
	  FarmPlotData.Manage() now strips these entries during harvest-item processing.
	- Fixed FarmPlotData.Manage() mutating the block singleton's shared itemsToDrop lists.
	  TryGetValue returns a direct reference to the block class's internal List; RemoveAt
	  and AddRange on that reference permanently altered shared drop data for all future
	  harvests. Drops are now copied into a pre-allocated local list via AddRange.
	- Added Log.Out diagnostics throughout FarmPlotData.Manage() (block name, hasHarvestDrops,
	  raw drop list, seed extraction result, replant path taken) to aid future field diagnosis.
	- Fixed NPC farmer not watering corner (diagonally adjacent) farm plots.
	  WaterPipeManager.GetWaterForPosition() only checked the 6 orthogonal neighbors for
	  direct water adjacency, so plots diagonally adjacent to a water source returned no
	  water and were skipped by the NPC despite being plantable by players. Added the 4
	  horizontal diagonal neighbors to the scan so corner plots are correctly detected.

[ Fire Manager ]
	- Fixed fire particle left-behind after a burning block is destroyed by a player or
	  explosion. ChunkSetBlock Harmony Postfix previously skipped all non-POI-reset block
	  changes due to an inverted guard (if (!_fromReset) return). The fix restructures the
	  check: POI resets always clear fire unconditionally; for other block changes, the patch
	  now checks IsBurning() and immediately calls ClearFire() if the new block is air. This
	  prevents the particle from lingering until the next UpdateFires cycle (up to
	  CheckInterval seconds). IsBurning() is an O(1) dictionary lookup, so the overhead on
	  every block change is negligible.

[ Utility / Code Quality ]
	- Removed duplicate ItemStack.Empty guard in EntityUtilities.CheckItemStack(ItemStack, Type):
	  the same Equals(stack, ItemStack.Empty) check was being evaluated twice with only a null
	  check in between.

Version: 2.6.8.1428 [ Experimental ]
[ Fire Manager ]
- Fixed fire state (active fires and smoke) not properly restoring on load. The Read() method now
correctly rebuilds fire data, restarts particle/light effects, and re-raises smoke events.
- Fixed smoke timers using real time (Time.time) instead of world time, causing smoke to
expire immediately on relog.
- Fixed loaded fires not being synced to clients after a server load.
- Fixed FireDamage property not being read from blocks due to an empty string check bug.
- Added FirePersists config option (default: false). When true, active fires and extinguished
positions are saved and restored across server restarts.

[ Fire Manager - Performance ]
	- Cached flammable/inflammable FastTags as static fields in FireHandler; previously parsed
	  on every IsFlammable() call during fire spread.
	- Replaced O(n²) string concatenation in FireHandler.Write() with string.Join; large fires
	  caused severe save slowdowns.
	- Replaced the new Queue allocation in FireHandler.UpdateFires() with a clear-and-refill
	  on the existing queue to avoid per-cycle heap allocation.
	- Replaced LINQ allocations in SmokeHandler.CheckSmokePositions() and Clear() with manual
	  loops using a reusable buffer field.
	- Fixed dead loop in SmokeHandler.LoadState() that iterated the smoke timer dictionary
	  immediately after clearing it.
	- Replaced LINQ allocations in LightManager.RemoveInvalidLights() with a manual loop
	  using a reusable buffer field.
	- Replaced per-call new HashSet allocation in LightManager.UpdateFadingLights() with a
	  reusab...
Read more

2.6.8.837

22 Mar 11:56

Choose a tag to compare

2.6.8.837 Pre-release
Pre-release

Version: 2.6.8.837 [ Experimental ]
[ Farming ]
- Fixed water depletion not working: BlockLiquidv2 blocks are now drained via DoExchangeAction; A21+ voxel water is drained via chunk.GetWater/SetWater with chunk-local coordinates.
- Fixed pipe blocks being incorrectly identified as direct water sources (IsDirectWaterSource now excludes BlockWaterPipeSDX before checking world.IsWater).
- Fixed CropManager.IsNearWater ignoring the caller's waterRange parameter (was creating a temporary PlantData on an air block, falling back to default range of 5).
- Fixed NPC farming: seed loss and race condition on replant (now uses a single atomic SetBlocksRPC with [air, seed] entries).
- Fixed NPC farming: seed is now returned to harvest items or NPC inventory if CanPlaceBlockAt fails.
- Fixed NPC harvested items being silently lost when NPC inventory is full; items are now dropped on the ground instead.

[ Sprinklers ]
	- Fixed sprinklers auto-activating when placed without a connected water source (CheckWaterConnection now always verifies actual water).
	- Fixed RequirePipesForSprinklers config not being enforced: CanPlaceBlockAt now requires an adjacent pipe block when the setting is enabled.
	- Simplified pipe block invalidation logic to use RefreshAllSprinklers.

[ XUi ]
	- Moved the broadcast button position to prevent overlap.

   [ Drop Box ]
	- Fixed an issue with drop box without a sign

2.6.4.713

18 Mar 10:59

Choose a tag to compare

2.6.4.713 Pre-release
Pre-release

Version: 2.6.4.713 [ Experimental ]
[ Fire Manager ]
- Fixed an issue where fire wasn't restarted on relog when enabled.

[ Challenges ]
	- Removed an unneccesary safety check that was causing problems with null reference

[ Farming ]
	- Refactored the Manage method for planting crops, and added a catch if inventory is full

[ NPCs ]
	- Fixed an issue where NPCs could be duplicated when the player dies.

2.5.53.911

01 Feb 13:43

Choose a tag to compare

Version: 2.5.53.911
[ NPCs ]
- Fixed an issue where an NPC would get run over while you were driving, and you'd pay the price.

[ Drop Box ]
	- Refactored distribution code slightly to add guards against lost item stacks during distribution.

[ Challenges ]
	- Added a check in Sleeper Cleared to make sure that another player is within the same POI as the clearer.

2.5.48.914

27 Jan 13:17

Choose a tag to compare

Version: 2.5.48.914

[ NPCs ]
	- Added a patch by Gussak to fix NPCs getting stuck on corpses.
		- https://github.com/SphereII/SphereII.Mods/issues/133

[ Remote Repair ]
	- Added some fixes to prevent repairing from remote containers when enemies are around.

[ Quality ]
	- Fixed an issue where item values of quality in the xml will scale to the quality settings over all.
	- ie, if you have 1 to 600 quality levels, and your xml list only 6 possible values ( vanilla ), then the tier of the quality item will be used
	- as an index value, rather than throwing out of bounds.
	Example:
		<! quality 56 would use 02.  Quality 500 would use .1, etc -->
		<triggered_effect trigger="onSelfEquipUpdate" action="ModifyCVar" cvar="$treatedPreacher" operation="set" value=".02,.04,.06,.08,.1,.2">
		
[ UAI ]
	- Added a safety check for UAI Consideration Target Weapon Range

[ Quests ]
	- Integrated some patches by khzmusik.
	```
	This implements the feature request from ticket 127, but also fixes other bugs that were introduced by vanilla game updates.

	New feature for [Teleport Quests] Localization of Objective keyword in ObjectiveGotoPOISDX.cs and related Objective patches.  

	#127: Subtypes of ObjectiveRandomPOIGoto use their own localization keys for keywords (and not just "ObjectiveRallyPointHeadTo") - 
	by default their values match vanilla in Localization.txt
	
	Subtypes of ObjectiveRandomPOIGoto no longer need their own implementations of SetDistanceOffset (the base class method was made public in a recent game update)
	QuestUtils.ValidPrefabForQuest once again checks for quest tags (if it didn't, ObjectiveRandomTaggedPOIGotoSDX would not be compatible with vanilla quests)
	
	I don't know why the code was originally commented out, but I took a guess that POIs weren't matching if the XML property was empty, so I additionally added a check for questTag.IsEmpty to make sure empty quest tags aren't considered
	QuestUtils.GetRandomPOINearTrader code updated to have the same functionality as DynamicPrefabDecorator.GetRandomPOINearTrader (which was updated for 2.5)
	
	Adjusted min search distances to match current vanilla value ObjectiveRandomTaggedPOIGotoSDX.CopyValues copies the values which are copied in the base class Clone method (this method can't be called by subclasses)
	Minor fixes to ObjectiveRandomTaggedPOIGotoSDX (documentation, renamed inaccurately-named variable)
	```

2.5.39.1103

18 Jan 15:05

Choose a tag to compare

Version: 2.5.39.1103
[ Quality]
- Backed out a bad patch causing cvars and buffs not to apply correctly.

2.5.36.1511

15 Jan 19:17

Choose a tag to compare

Version: 2.5.36.1511
[ Quality ]
- Fixed an issue where Quality levels above 255 were being reset to lower values when crafting in closed workstation.
- The game code was casting ItemQuality to a byte (limit 255) during the UI synchronization process,
causing any quality higher than 255 (e.g., 600) to overflow and wrap around (e.g., 600 became 88).
- We implemented a "Bit-Packing" strategy where the UI patch hides the high-quality value inside the
unused bits of the StartingEntityId integer (which survives the byte cast), and a second patch in AddCraftComplete
unpacks that value to restore the correct quality just before the item is finalized.

2.5.35.841

14 Jan 14:36

Choose a tag to compare

Version: 2.5.35.841
[ Challenges ]
- Added missing requirement check on BlockDestroyedByFire

[ Fire Manager ]
	- Re-fixed(1)(2) fire extinguish being recursive.
	- Also may have fixed the challenge for extinguish.

2.5.30.1209

09 Jan 16:13

Choose a tag to compare

Version: 2.5.30.1209
[ Challenges ]
- Removed debug lines

[ Quality ]
	- Fixed an issue with ModifyCVar script not correctly calculating the quality tier levels.
	- Added logging for crafting recipes where they lose their reference when crafting with the workstation closed.

[ EntityNPCBandit ]
	- Removed some inappropriate checks, such as playerstat changed.

2.5.25.1105

04 Jan 15:11

Choose a tag to compare

Version: 2.5.25.1105
[ NPCs ]
- Fixed an issue where NPCs would duplicate on dedi, and respawn dupes when reloading the game.

[ UAI ]
	- Fixed a bug where an NPC would sort of slide towards you rather than actually start running with you.
	- Optimized the UAI Follow task to perform a bit better.

[ Challenges ]
	- Reworked requirements for Challenges to work more smoothly with the game.

	*** XML Change Required! ***

	- Effect groups are now required for requirements.

	BEFORE:
    <challenge name="burntSurvivalPlantTrees" title_key="challengeBurntPlantTrees" icon="ui_game_symbol_tree" group="ScoreTest"
               short_description_key="challengeBurntPlantTreesShort" description_key="challengeBurntPlantTreesDesc"
               reward_text_key="challenge_reward_1000xp" reward_event="challenge_reward_1000">
        <objective type="PlaceBlockByTagV2, SCore" count="25" description_key="xuiPlantTrees"/>
        <requirement name="InBiome" biome="9"/>
        <requirement name="BlockHasTags" tags="challenge_plant_trees"/>
    </challenge>

	AFTER:
    <challenge name="burntSurvivalPlantTrees2" title_key="challengeBurntPlantTrees2" icon="ui_game_symbol_tree" group="ScoreTest"
               short_description_key="challengeBurntPlantTreesShort" description_key="challengeBurntPlantTreesDesc"
               reward_text_key="challenge_reward_1000xp" reward_event="challenge_reward_1000">
        <objective type="PlaceBlockByTagV2, SCore" count="25" description_key="xuiPlantTrees"/>
        <effect_group name="Groups are required">
            <requirement name="InBiome" biome="9"/>
            <requirement name="BlockHasTags" tags="challenge_plant_trees"/>
        </effect_group>
    </challenge>