From bd8458853bc6058949c026747c36916a13b6a530 Mon Sep 17 00:00:00 2001 From: Luis Gonzalez Date: Thu, 25 Jun 2026 21:26:56 -0700 Subject: [PATCH] =?UTF-8?q?DR-042=20Phase=20C=20(legibility,=20part=202):?= =?UTF-8?q?=20walls=20block=20enemies=20(C5)=20=E2=80=94=20restore=20the?= =?UTF-8?q?=20fortress=20fantasy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Player-built structures now physically block enemies (husks walked straight through walls before). Dedicated "Structure" physics layer (slot 9) so the player passes its own walls while enemies are stopped: - New WorldCollisionConfig.StructureMask, baked from the "Structure" layer in WorldCollisionAuthoring (mirrors EnvironmentMask). EnemyAISystem ORs it into the movement sweep filter (CollidesWith = envMask | structMask) — no new system, same 1-2 SphereCasts per enemy. - Wall/Turret/Pylon prefabs get a cell-sized BoxCollider on the Structure layer (Wall's existing one relayered). - Physics matrix: Default x Structure unchecked, so the kinematic player CC (Default) passes its own walls while the enemy's explicit cast still hits them. Despawn frees collision for free (collider dies with the entity). Play-verified baked filters: StructMask=512; structure colliders BelongsTo=512, CollidesWith=0xFFFFFFFE (includes Environment for the enemy cast, EXCLUDES bit 0 so the player passes). 389/389 EditMode, no exceptions. Server-only/static colliders -> deterministic, no client divergence. SaveData stays v5. Phase C complete (C5-C7). A visual fun-gate (husk stops at wall, player walks through) is the operator's eyes. Co-Authored-By: Claude Opus 4.8 --- Assets/_Project/Prefabs/Pylon.prefab | 24 ++++++++++++++++++- Assets/_Project/Prefabs/Turret.prefab | 24 ++++++++++++++++++- Assets/_Project/Prefabs/Wall.prefab | 2 +- .../World/WorldCollisionAuthoring.cs | 7 +++++- .../Scripts/Server/Combat/EnemyAISystem.cs | 5 ++-- .../World/WorldCollisionComponents.cs | 7 ++++++ ProjectSettings/DynamicsManager.asset | 19 +++++++++++---- ProjectSettings/TagManager.asset | 2 +- 8 files changed, 78 insertions(+), 12 deletions(-) diff --git a/Assets/_Project/Prefabs/Pylon.prefab b/Assets/_Project/Prefabs/Pylon.prefab index f168f6ea6..17a6d0d49 100644 --- a/Assets/_Project/Prefabs/Pylon.prefab +++ b/Assets/_Project/Prefabs/Pylon.prefab @@ -102,7 +102,8 @@ GameObject: - component: {fileID: 9053853372340598254} - component: {fileID: 6834786618115927220} - component: {fileID: 7685488391646220227} - m_Layer: 0 + - component: {fileID: 1225369404710843925} + m_Layer: 9 m_Name: Pylon m_TagString: Untagged m_Icon: {fileID: 0} @@ -177,3 +178,24 @@ MonoBehaviour: m_EditorClassIdentifier: ProjectM.Authoring::ProjectM.Authoring.StructureAuthoring Kind: 6 MaxHp: 150 +--- !u!65 &1225369404710843925 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3885353946372160549} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Size: {x: 1.6, y: 2, z: 1.6} + m_Center: {x: 0, y: 1, z: 0} diff --git a/Assets/_Project/Prefabs/Turret.prefab b/Assets/_Project/Prefabs/Turret.prefab index 169a6728e..0dbcf9c32 100644 --- a/Assets/_Project/Prefabs/Turret.prefab +++ b/Assets/_Project/Prefabs/Turret.prefab @@ -378,7 +378,8 @@ GameObject: - component: {fileID: 9053853372340598254} - component: {fileID: 6834786618115927220} - component: {fileID: 1794795016809289889} - m_Layer: 0 + - component: {fileID: 9049467567705961987} + m_Layer: 9 m_Name: Turret m_TagString: Untagged m_Icon: {fileID: 0} @@ -455,6 +456,27 @@ MonoBehaviour: CooldownTicks: 30 Damage: 12 MaxHp: 120 +--- !u!65 &9049467567705961987 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3885353946372160549} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Size: {x: 1.6, y: 2, z: 1.6} + m_Center: {x: 0, y: 1, z: 0} --- !u!1 &4051895978514069616 GameObject: m_ObjectHideFlags: 0 diff --git a/Assets/_Project/Prefabs/Wall.prefab b/Assets/_Project/Prefabs/Wall.prefab index 5805637c7..fae933c61 100644 --- a/Assets/_Project/Prefabs/Wall.prefab +++ b/Assets/_Project/Prefabs/Wall.prefab @@ -103,7 +103,7 @@ GameObject: - component: {fileID: 6834786618115927220} - component: {fileID: 8793146551006314905} - component: {fileID: 7779358222264100756} - m_Layer: 0 + m_Layer: 9 m_Name: Wall m_TagString: Untagged m_Icon: {fileID: 0} diff --git a/Assets/_Project/Scripts/Authoring/World/WorldCollisionAuthoring.cs b/Assets/_Project/Scripts/Authoring/World/WorldCollisionAuthoring.cs index a5a7e174f..f3c0cc036 100644 --- a/Assets/_Project/Scripts/Authoring/World/WorldCollisionAuthoring.cs +++ b/Assets/_Project/Scripts/Authoring/World/WorldCollisionAuthoring.cs @@ -15,6 +15,9 @@ namespace ProjectM.Authoring { [Tooltip("Name of the Unity layer carrying the static world colliders (boundary ring + landmarks).")] public string EnvironmentLayerName = "Environment"; + [Tooltip("DR-042 C5: Unity layer carrying player-built structure colliders (Wall/Turret/Pylon) that block enemies.")] + public string StructureLayerName = "Structure"; + private class WorldCollisionBaker : Baker { @@ -23,7 +26,9 @@ namespace ProjectM.Authoring int layer = LayerMask.NameToLayer(authoring.EnvironmentLayerName); uint mask = layer >= 0 ? 1u << layer : 0u; var entity = GetEntity(TransformUsageFlags.None); - AddComponent(entity, new WorldCollisionConfig { EnvironmentMask = mask }); + int structLayer = LayerMask.NameToLayer(authoring.StructureLayerName); + uint structMask = structLayer >= 0 ? 1u << structLayer : 0u; + AddComponent(entity, new WorldCollisionConfig { EnvironmentMask = mask, StructureMask = structMask }); } } } diff --git a/Assets/_Project/Scripts/Server/Combat/EnemyAISystem.cs b/Assets/_Project/Scripts/Server/Combat/EnemyAISystem.cs index cc07c1e68..4c1c29656 100644 --- a/Assets/_Project/Scripts/Server/Combat/EnemyAISystem.cs +++ b/Assets/_Project/Scripts/Server/Combat/EnemyAISystem.cs @@ -100,8 +100,9 @@ namespace ProjectM.Server var ecb = new EntityCommandBuffer(Allocator.Temp); bool havePhysics = SystemAPI.TryGetSingleton(out var physics); uint envMask = SystemAPI.TryGetSingleton(out var worldCol) ? worldCol.EnvironmentMask : 0u; - var envFilter = new CollisionFilter { BelongsTo = ~0u, CollidesWith = envMask, GroupIndex = 0 }; - bool sweep = havePhysics && envMask != 0u; + uint sweepMask = envMask | worldCol.StructureMask; // DR-042 C5: also collide enemies against player-built walls + var envFilter = new CollisionFilter { BelongsTo = ~0u, CollidesWith = sweepMask, GroupIndex = 0 }; + bool sweep = havePhysics && sweepMask != 0u; const float SweepRadius = 0.5f; // collide-and-slide sphere radius for Husk movement foreach (var (xform, stats, cooldown, knockback, windup, region) in diff --git a/Assets/_Project/Scripts/Simulation/World/WorldCollisionComponents.cs b/Assets/_Project/Scripts/Simulation/World/WorldCollisionComponents.cs index e2fc32f97..8e5fefd46 100644 --- a/Assets/_Project/Scripts/Simulation/World/WorldCollisionComponents.cs +++ b/Assets/_Project/Scripts/Simulation/World/WorldCollisionComponents.cs @@ -11,7 +11,14 @@ namespace ProjectM.Simulation /// public struct WorldCollisionConfig : IComponentData { + /// BelongsTo bitmask of the Environment physics layer (1u << layerIndex). /// BelongsTo bitmask of the Environment physics layer (1u << layerIndex). public uint EnvironmentMask; + + /// DR-042 C5: BelongsTo bitmask of the "Structure" physics layer (player-built Wall/Turret/Pylon + /// colliders). OR'd into the enemy-movement sweep filter so husks collide-and-slide against walls. 0 if the + /// layer is absent (feature inert). The layer matrix excludes Structure×the player layer so the player CC + /// passes through its own walls. + public uint StructureMask; } } diff --git a/ProjectSettings/DynamicsManager.asset b/ProjectSettings/DynamicsManager.asset index fc90ab958..cf70fabbf 100644 --- a/ProjectSettings/DynamicsManager.asset +++ b/ProjectSettings/DynamicsManager.asset @@ -3,10 +3,11 @@ --- !u!55 &1 PhysicsManager: m_ObjectHideFlags: 0 - serializedVersion: 13 + serializedVersion: 23 m_Gravity: {x: 0, y: -9.81, z: 0} m_DefaultMaterial: {fileID: 0} m_BounceThreshold: 2 + m_DefaultMaxDepenetrationVelocity: 10 m_SleepThreshold: 0.005 m_DefaultContactOffset: 0.01 m_DefaultSolverIterations: 6 @@ -16,11 +17,11 @@ PhysicsManager: m_EnableAdaptiveForce: 0 m_ClothInterCollisionDistance: 0.1 m_ClothInterCollisionStiffness: 0.2 - m_ContactsGeneration: 1 - m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff - m_AutoSimulation: 1 + m_LayerCollisionMatrix: fffdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + m_SimulationMode: 0 m_AutoSyncTransforms: 0 m_ReuseCollisionCallbacks: 1 + m_InvokeCollisionCallbacks: 1 m_ClothInterCollisionSettingsToggle: 0 m_ClothGravity: {x: 0, y: -9.81, z: 0} m_ContactPairsMode: 0 @@ -31,6 +32,14 @@ PhysicsManager: m_WorldSubdivisions: 8 m_FrictionType: 0 m_EnableEnhancedDeterminism: 0 - m_EnableUnifiedHeightmaps: 1 + m_ImprovedPatchFriction: 0 + m_GenerateOnTriggerStayEvents: 1 m_SolverType: 0 m_DefaultMaxAngularSpeed: 50 + m_ScratchBufferChunkCount: 4 + m_CurrentBackendId: 4072204805 + m_FastMotionThreshold: 3.4028235e+38 + m_SceneBuffersReleaseInterval: 0 + m_ReleaseSceneBuffers: 0 + m_LogVerbosity: 3 + m_IncrementalStaticBroadphase: 1 diff --git a/ProjectSettings/TagManager.asset b/ProjectSettings/TagManager.asset index 0420de827..2d2a62b86 100644 --- a/ProjectSettings/TagManager.asset +++ b/ProjectSettings/TagManager.asset @@ -14,7 +14,7 @@ TagManager: - - - Environment - - + - Structure - - -