Skip to content

Game.Simulation.WetnessSystem

Assembly:
(Assembly not specified — typically in the game's managed assembly, e.g. Assembly-CSharp)

Namespace: Game.Simulation

Type: class

Base: GameSystemBase

Summary:
WetnessSystem is an ECS system that updates per-entity Surface components to simulate wetness, snow accumulation and drying based on the current climate (precipitation and temperature). It schedules a parallel IJobChunk (WetnessJob) which computes target wetness/dry/wet speeds, applies randomized changes to the Surface byte fields (m_Wetness, m_SnowAmount, m_AccumulatedWetness, m_AccumulatedSnow) and, when necessary, emits SubObjectsUpdated event entities for prefabs that have subobjects dependent on snow/wetness changes. The system runs on an interval (GetUpdateInterval returns 256) and uses the EndFrameBarrier to produce event entities safely across jobs.


Fields

  • public const int SNOW_REQUIREMENT_LIMIT
    Constant (value 15) used as the threshold for determining whether a Surface's accumulated snow counts as "snow requirement" (used to mark ObjectRequirementFlags.Snow). {{ This constant controls when snow-dependent subobjects should be considered required. }}

  • private ClimateSystem m_ClimateSystem
    {{ Reference to the ClimateSystem used to read current precipitation and temperature (m_ClimateSystem.precipitation and m_ClimateSystem.temperature). }}

  • private EndFrameBarrier m_EndFrameBarrier
    {{ A barrier system used to create an EntityCommandBuffer for use from the scheduled WetnessJob; the job's producer job handle is added to this barrier so the command buffer is played back safely at end of frame. }}

  • private EntityQuery m_SurfaceQuery
    {{ Query matching entities that have a Surface component and are not Deleted, Overridden or Temp. This is the query used to schedule WetnessJob. }}

  • private EntityArchetype m_SubObjectEventArchetype
    {{ Archetype used to create event entities that carry SubObjectsUpdated components when a prefab's subobject requirement changes (so other systems can react to subobject updates). }}

  • private TypeHandle __TypeHandle
    {{ Internal type-handle container used by the system to cache EntityTypeHandle, ComponentTypeHandle, BufferTypeHandle and ComponentLookup handles for scheduling the job. Not intended for user modification. }}

  • Nested type: private struct WetnessJob : IJobChunk
    {{ The job that runs over the Surface query, performing per-chunk updates of Surface values. See Methods section for details. }}

  • Nested type: private struct TypeHandle
    {{ Helper structure that caches and assigns handles (EntityTypeHandle, ComponentTypeHandle, BufferTypeHandle, ComponentLookup) from a SystemState for use by the job. }}

Properties

  • (None)
    {{ WetnessSystem does not expose public properties. Internal state is stored in private fields and accessed during OnUpdate. }}

Constructors

  • public WetnessSystem()
    {{ Default constructor. The system initializes its state in OnCreate/OnCreateForCompiler rather than in the constructor. }}

Methods

  • public override int GetUpdateInterval(SystemUpdatePhase phase)
    {{ Returns 256. The system is configured to run at this interval (i.e., it updates less frequently than every frame). }}

  • [Preserve] protected override void OnCreate()
    {{ Called when the system is created. OnCreate does:

  • Locates the ClimateSystem and EndFrameBarrier via World.GetOrCreateSystemManaged.
  • Builds m_SurfaceQuery to select Surface components excluding Deleted/Overridden/Temp.
  • Creates m_SubObjectEventArchetype for event entities containing Event and SubObjectsUpdated.
  • Calls RequireForUpdate(m_SurfaceQuery) so the system only updates when there are matching entities. This method sets up the system for runtime use. }}

  • [Preserve] protected override void OnUpdate()
    {{ Called when the system updates (per GetUpdateInterval). Behavior:

  • Reads precipitation and temperature from m_ClimateSystem.
  • Constructs three float4 vectors (target wetness, wet speed, dry speed) based on precipitation and temperature. Different formulas are used depending on whether temperature > 0 or <= 0.
  • Schedules the WetnessJob as a parallel IJobChunk across m_SurfaceQuery, passing:
    • entity/component handles from __TypeHandle
    • a RandomSeed
    • computed m_TargetWetness, m_WetSpeed and m_DrySpeed (saturated and negated where appropriate)
    • the command buffer acquired from m_EndFrameBarrier (AsParallelWriter)
  • Adds the job handle to m_EndFrameBarrier via AddJobHandleForProducer and assigns the job handle to base.Dependency. This is the main runtime logic that computes the per-surface wetness/snow changes in parallel. }}

  • protected override void OnCreateForCompiler()
    {{ Internal initialization helper used by the compiled code: assigns queries and type handles by calling __AssignQueries and TypeHandle.__AssignHandles. Not typically called by modders. }}

  • [MethodImpl(MethodImplOptions.AggressiveInlining)] private void __AssignQueries(ref SystemState state)
    {{ Compiler-generated helper: sets up queries used by the system; here it contains a placeholder EntityQueryBuilder call. }}

  • private struct WetnessJob.Execute(...)
    {{ Detailed behavior of WetnessJob:

  • Iterates over chunk entities and their Surface components.
  • For each Surface:
    • Determine ObjectRequirementFlags.Snow if m_AccumulatedSnow >= SNOW_REQUIREMENT_LIMIT.
    • Construct an int4 from the four byte members (m_Wetness, m_SnowAmount, m_AccumulatedWetness, m_AccumulatedSnow).
    • Compute a float4 speed vector: math.clamp(m_TargetWetness - int4*0.003921569f, m_DrySpeed, m_WetSpeed).
    • Multiply speed by a random float4 in [0.8, 1.0] and add a randomized integer delta via MathUtils.RoundToIntRandom, clamped to [0,255].
    • Store updated byte values back into the Surface component.
    • If the chunk has SubObject buffer and the entity has no Owner, and the change in snow-requirement flags toggled, check the prefab's ObjectGeometryData m_SubObjectMask to see if any subobjects are affected.
    • If affected, create an event entity of m_SubObjectEventArchetype and set SubObjectsUpdated with the original entity.
  • Uses EntityCommandBuffer.ParallelWriter to create and set event entities safely from parallel job logic. This job performs the randomized per-frame wetness/snow accumulation logic and triggers subobject update events when thresholds flip. }}

Usage Example

// The system itself overrides OnCreate and OnUpdate as shown in the source.
// Example: reading current climate values in another system or debugging:
protected override void OnCreate()
{
    base.OnCreate();
    // Ensure the WetnessSystem runs only when surfaces are present.
    // (In actual modding, you typically don't call WetnessSystem.OnCreate directly;
    //  instead you can reference its behavior or configure climate values.)
}

// Example simplified sketch: how WetnessSystem schedules its job (conceptual):
var job = new WetnessJob {
    m_EntityTypeHandle = ...,
    m_OwnerType = ...,
    m_PrefabRefType = ...,
    m_SubObjectType = ...,
    m_ObjectSurfaceType = ...,
    m_PrefabObjectGeometryData = ...,
    m_SubObjectEventArchetype = subObjectArchetype,
    m_RandomSeed = RandomSeed.Next(),
    m_TargetWetness = math.saturate(targetWetness),
    m_WetSpeed = math.saturate(wetSpeed),
    m_DrySpeed = -math.saturate(drySpeed),
    m_CommandBuffer = endFrameBarrier.CreateCommandBuffer().AsParallelWriter()
};
JobHandle handle = JobChunkExtensions.ScheduleParallel(job, surfaceQuery, dependency);
endFrameBarrier.AddJobHandleForProducer(handle);
dependency = handle;

Additional notes: - The system uses byte fields on Surface and packs several values together (wetness, snow amount, accumulated wetness, accumulated snow) so values are clamped to [0,255]. - SNOW_REQUIREMENT_LIMIT (15) is used to decide when a Surface counts as having snow for the purpose of subobject requirements. - SubObjectsUpdated events are only created for entities that have subobject buffers and do not have an Owner component (likely world objects rather than owned subobjects). - Wetness changes include a random component (RandomSeed.Next().NextFloat4(0.8f, 1f) and MathUtils.RoundToIntRandom) so updates are not fully deterministic per-chunk. - The job writes commands through an EntityCommandBuffer.ParallelWriter and the system registers its job handle with EndFrameBarrier so commands are safe to play back at end of frame.

If you want, I can produce a short doc focused only on the WetnessJob internals or an explanation of how to react to SubObjectsUpdated events from a custom system.