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.