Compare commits
10 Commits
78d4489699
...
4fa2cb0de4
| Author | SHA1 | Date | |
|---|---|---|---|
| 4fa2cb0de4 | |||
| 210d307406 | |||
| 12d5b96b71 | |||
| c58439d33a | |||
| 77de740b63 | |||
| 4a8220ad3e | |||
| b34945c2d2 | |||
| 835dace213 | |||
| a0f6d4a5c4 | |||
| 511e78556b |
+60
-7384
File diff suppressed because it is too large
Load Diff
+40
-3873
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 1d4b5e92ac7b6ea4880d30545df94704
|
guid: 48885d98d8dbc3c47943402d0a455f21
|
||||||
DefaultImporter:
|
DefaultImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
userData:
|
userData:
|
||||||
|
|||||||
+38
-79157
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 48885d98d8dbc3c47943402d0a455f21
|
|
||||||
DefaultImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 99c9720ab356a0642a771bea13969a05
|
|
||||||
DefaultImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: c51a770922f68b046b12dc55a7f054c2
|
guid: 0ebe15ac3d1a57d45ac9492075ce1fdb
|
||||||
folderAsset: yes
|
folderAsset: yes
|
||||||
DefaultImporter:
|
DefaultImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 4eba886d11c07eb4d97ca0d821a1560f
|
guid: 853083b81213dfe438063c6d6d41e564
|
||||||
folderAsset: yes
|
folderAsset: yes
|
||||||
DefaultImporter:
|
DefaultImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 91f9551ef855b3b4f98bcfcb7bf747e2
|
guid: a56e554160baf224282f9467d6a5dfa0
|
||||||
PrefabImporter:
|
PrefabImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
userData:
|
userData:
|
||||||
@@ -1,147 +0,0 @@
|
|||||||
%YAML 1.1
|
|
||||||
%TAG !u! tag:unity3d.com,2011:
|
|
||||||
--- !u!1 &3885353946372160549
|
|
||||||
GameObject:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
serializedVersion: 6
|
|
||||||
m_Component:
|
|
||||||
- component: {fileID: 3572766465862231365}
|
|
||||||
- component: {fileID: 3909651526955663392}
|
|
||||||
- component: {fileID: 3320445911748035220}
|
|
||||||
- component: {fileID: 9053853372340598254}
|
|
||||||
- component: {fileID: 6834786618115927220}
|
|
||||||
- component: {fileID: 2432281660239002494}
|
|
||||||
m_Layer: 0
|
|
||||||
m_Name: Conveyor
|
|
||||||
m_TagString: Untagged
|
|
||||||
m_Icon: {fileID: 0}
|
|
||||||
m_NavMeshLayer: 0
|
|
||||||
m_StaticEditorFlags: 0
|
|
||||||
m_IsActive: 1
|
|
||||||
--- !u!4 &3572766465862231365
|
|
||||||
Transform:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3885353946372160549}
|
|
||||||
serializedVersion: 2
|
|
||||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
|
||||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
|
||||||
m_LocalScale: {x: 2.5, y: 2.5, z: 2.5}
|
|
||||||
m_ConstrainProportionsScale: 0
|
|
||||||
m_Children: []
|
|
||||||
m_Father: {fileID: 0}
|
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
|
||||||
--- !u!33 &3909651526955663392
|
|
||||||
MeshFilter:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3885353946372160549}
|
|
||||||
m_Mesh: {fileID: 4300000, guid: abc00000000010690097314383055197, type: 3}
|
|
||||||
--- !u!23 &3320445911748035220
|
|
||||||
MeshRenderer:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3885353946372160549}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_CastShadows: 1
|
|
||||||
m_ReceiveShadows: 1
|
|
||||||
m_DynamicOccludee: 1
|
|
||||||
m_StaticShadowCaster: 0
|
|
||||||
m_MotionVectors: 1
|
|
||||||
m_LightProbeUsage: 1
|
|
||||||
m_ReflectionProbeUsage: 1
|
|
||||||
m_RayTracingMode: 2
|
|
||||||
m_RayTraceProcedural: 0
|
|
||||||
m_RayTracingAccelStructBuildFlagsOverride: 0
|
|
||||||
m_RayTracingAccelStructBuildFlags: 1
|
|
||||||
m_SmallMeshCulling: 1
|
|
||||||
m_ForceMeshLod: -1
|
|
||||||
m_MeshLodSelectionBias: 0
|
|
||||||
m_RenderingLayerMask: 1
|
|
||||||
m_RendererPriority: 0
|
|
||||||
m_Materials:
|
|
||||||
- {fileID: 2100000, guid: c01dbe8a4e818c5469eceae8b286bf4d, type: 2}
|
|
||||||
m_StaticBatchInfo:
|
|
||||||
firstSubMesh: 0
|
|
||||||
subMeshCount: 0
|
|
||||||
m_StaticBatchRoot: {fileID: 0}
|
|
||||||
m_ProbeAnchor: {fileID: 0}
|
|
||||||
m_LightProbeVolumeOverride: {fileID: 0}
|
|
||||||
m_ScaleInLightmap: 1
|
|
||||||
m_ReceiveGI: 1
|
|
||||||
m_PreserveUVs: 1
|
|
||||||
m_IgnoreNormalsForChartDetection: 0
|
|
||||||
m_ImportantGI: 0
|
|
||||||
m_StitchLightmapSeams: 1
|
|
||||||
m_SelectedEditorRenderState: 3
|
|
||||||
m_MinimumChartSize: 4
|
|
||||||
m_AutoUVMaxDistance: 0.5
|
|
||||||
m_AutoUVMaxAngle: 89
|
|
||||||
m_LightmapParameters: {fileID: 0}
|
|
||||||
m_GlobalIlluminationMeshLod: 0
|
|
||||||
m_SortingLayerID: 0
|
|
||||||
m_SortingLayer: 0
|
|
||||||
m_SortingOrder: 0
|
|
||||||
m_MaskInteraction: 0
|
|
||||||
m_AdditionalVertexStreams: {fileID: 0}
|
|
||||||
--- !u!114 &9053853372340598254
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3885353946372160549}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: c16549610bfe4458aa9389201d072bb6, type: 3}
|
|
||||||
m_Name:
|
|
||||||
m_EditorClassIdentifier: Unity.Entities.Hybrid::Unity.Entities.Hybrid.Baking.LinkedEntityGroupAuthoring
|
|
||||||
--- !u!114 &6834786618115927220
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3885353946372160549}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: 7c79d771cedb4794bf100ce60df5f764, type: 3}
|
|
||||||
m_Name:
|
|
||||||
m_EditorClassIdentifier: Unity.NetCode.Authoring.Hybrid::Unity.NetCode.GhostAuthoringComponent
|
|
||||||
HasOwner: 0
|
|
||||||
SupportAutoCommandTarget: 1
|
|
||||||
TrackInterpolationDelay: 0
|
|
||||||
GhostGroup: 0
|
|
||||||
UsePreSerialization: 0
|
|
||||||
UseSingleBaseline: 0
|
|
||||||
RollbackPredictedSpawnedGhostState: 0
|
|
||||||
RollbackPredictionOnStructuralChanges: 1
|
|
||||||
DefaultGhostMode: 0
|
|
||||||
SupportedGhostModes: 3
|
|
||||||
OptimizationMode: 0
|
|
||||||
Importance: 1
|
|
||||||
MaxSendRate: 0
|
|
||||||
prefabId:
|
|
||||||
--- !u!114 &2432281660239002494
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3885353946372160549}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: 23131e6166dce204582bbedc8511658e, type: 3}
|
|
||||||
m_Name:
|
|
||||||
m_EditorClassIdentifier: ProjectM.Authoring::ProjectM.Authoring.ConveyorAuthoring
|
|
||||||
Direction: 0
|
|
||||||
PeriodTicks: 20
|
|
||||||
@@ -1,151 +0,0 @@
|
|||||||
%YAML 1.1
|
|
||||||
%TAG !u! tag:unity3d.com,2011:
|
|
||||||
--- !u!1 &3885353946372160549
|
|
||||||
GameObject:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
serializedVersion: 6
|
|
||||||
m_Component:
|
|
||||||
- component: {fileID: 3572766465862231365}
|
|
||||||
- component: {fileID: 3909651526955663392}
|
|
||||||
- component: {fileID: 3320445911748035220}
|
|
||||||
- component: {fileID: 9053853372340598254}
|
|
||||||
- component: {fileID: 6834786618115927220}
|
|
||||||
- component: {fileID: 2544095781123180609}
|
|
||||||
m_Layer: 0
|
|
||||||
m_Name: Enemy
|
|
||||||
m_TagString: Untagged
|
|
||||||
m_Icon: {fileID: 0}
|
|
||||||
m_NavMeshLayer: 0
|
|
||||||
m_StaticEditorFlags: 0
|
|
||||||
m_IsActive: 1
|
|
||||||
--- !u!4 &3572766465862231365
|
|
||||||
Transform:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3885353946372160549}
|
|
||||||
serializedVersion: 2
|
|
||||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
|
||||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
|
||||||
m_LocalScale: {x: 0.8, y: 0.8, z: 0.8}
|
|
||||||
m_ConstrainProportionsScale: 0
|
|
||||||
m_Children: []
|
|
||||||
m_Father: {fileID: 0}
|
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
|
||||||
--- !u!33 &3909651526955663392
|
|
||||||
MeshFilter:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3885353946372160549}
|
|
||||||
m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0}
|
|
||||||
--- !u!23 &3320445911748035220
|
|
||||||
MeshRenderer:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3885353946372160549}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_CastShadows: 1
|
|
||||||
m_ReceiveShadows: 1
|
|
||||||
m_DynamicOccludee: 1
|
|
||||||
m_StaticShadowCaster: 0
|
|
||||||
m_MotionVectors: 1
|
|
||||||
m_LightProbeUsage: 1
|
|
||||||
m_ReflectionProbeUsage: 1
|
|
||||||
m_RayTracingMode: 2
|
|
||||||
m_RayTraceProcedural: 0
|
|
||||||
m_RayTracingAccelStructBuildFlagsOverride: 0
|
|
||||||
m_RayTracingAccelStructBuildFlags: 1
|
|
||||||
m_SmallMeshCulling: 1
|
|
||||||
m_ForceMeshLod: -1
|
|
||||||
m_MeshLodSelectionBias: 0
|
|
||||||
m_RenderingLayerMask: 1
|
|
||||||
m_RendererPriority: 0
|
|
||||||
m_Materials:
|
|
||||||
- {fileID: 2100000, guid: fc4f991205d0aa347b65d89045f80c70, type: 2}
|
|
||||||
m_StaticBatchInfo:
|
|
||||||
firstSubMesh: 0
|
|
||||||
subMeshCount: 0
|
|
||||||
m_StaticBatchRoot: {fileID: 0}
|
|
||||||
m_ProbeAnchor: {fileID: 0}
|
|
||||||
m_LightProbeVolumeOverride: {fileID: 0}
|
|
||||||
m_ScaleInLightmap: 1
|
|
||||||
m_ReceiveGI: 1
|
|
||||||
m_PreserveUVs: 1
|
|
||||||
m_IgnoreNormalsForChartDetection: 0
|
|
||||||
m_ImportantGI: 0
|
|
||||||
m_StitchLightmapSeams: 1
|
|
||||||
m_SelectedEditorRenderState: 3
|
|
||||||
m_MinimumChartSize: 4
|
|
||||||
m_AutoUVMaxDistance: 0.5
|
|
||||||
m_AutoUVMaxAngle: 89
|
|
||||||
m_LightmapParameters: {fileID: 0}
|
|
||||||
m_GlobalIlluminationMeshLod: 0
|
|
||||||
m_SortingLayerID: 0
|
|
||||||
m_SortingLayer: 0
|
|
||||||
m_SortingOrder: 0
|
|
||||||
m_MaskInteraction: 0
|
|
||||||
m_AdditionalVertexStreams: {fileID: 0}
|
|
||||||
--- !u!114 &9053853372340598254
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3885353946372160549}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: c16549610bfe4458aa9389201d072bb6, type: 3}
|
|
||||||
m_Name:
|
|
||||||
m_EditorClassIdentifier: Unity.Entities.Hybrid::Unity.Entities.Hybrid.Baking.LinkedEntityGroupAuthoring
|
|
||||||
--- !u!114 &6834786618115927220
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3885353946372160549}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: 7c79d771cedb4794bf100ce60df5f764, type: 3}
|
|
||||||
m_Name:
|
|
||||||
m_EditorClassIdentifier: Unity.NetCode.Authoring.Hybrid::Unity.NetCode.GhostAuthoringComponent
|
|
||||||
HasOwner: 0
|
|
||||||
SupportAutoCommandTarget: 1
|
|
||||||
TrackInterpolationDelay: 0
|
|
||||||
GhostGroup: 0
|
|
||||||
UsePreSerialization: 0
|
|
||||||
UseSingleBaseline: 0
|
|
||||||
RollbackPredictedSpawnedGhostState: 0
|
|
||||||
RollbackPredictionOnStructuralChanges: 1
|
|
||||||
DefaultGhostMode: 0
|
|
||||||
SupportedGhostModes: 3
|
|
||||||
OptimizationMode: 0
|
|
||||||
Importance: 1
|
|
||||||
MaxSendRate: 0
|
|
||||||
prefabId:
|
|
||||||
--- !u!114 &2544095781123180609
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3885353946372160549}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: 6b014797e9092694b9568c5b66d34a55, type: 3}
|
|
||||||
m_Name:
|
|
||||||
m_EditorClassIdentifier: ProjectM.Authoring::ProjectM.Authoring.EnemyAuthoring
|
|
||||||
MaxHealth: 30
|
|
||||||
HitRadius: 0.7
|
|
||||||
MoveSpeed: 3
|
|
||||||
AttackRange: 1.6
|
|
||||||
AttackDamage: 5
|
|
||||||
AttackCooldownTicks: 48
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 84c92c40b6b720441ac3a78870c0bba4
|
|
||||||
PrefabImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,151 +0,0 @@
|
|||||||
%YAML 1.1
|
|
||||||
%TAG !u! tag:unity3d.com,2011:
|
|
||||||
--- !u!1 &3885353946372160549
|
|
||||||
GameObject:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
serializedVersion: 6
|
|
||||||
m_Component:
|
|
||||||
- component: {fileID: 3572766465862231365}
|
|
||||||
- component: {fileID: 3909651526955663392}
|
|
||||||
- component: {fileID: 3320445911748035220}
|
|
||||||
- component: {fileID: 9053853372340598254}
|
|
||||||
- component: {fileID: 6834786618115927220}
|
|
||||||
- component: {fileID: 2544095781123180609}
|
|
||||||
m_Layer: 0
|
|
||||||
m_Name: EnemyBrute
|
|
||||||
m_TagString: Untagged
|
|
||||||
m_Icon: {fileID: 0}
|
|
||||||
m_NavMeshLayer: 0
|
|
||||||
m_StaticEditorFlags: 0
|
|
||||||
m_IsActive: 1
|
|
||||||
--- !u!4 &3572766465862231365
|
|
||||||
Transform:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3885353946372160549}
|
|
||||||
serializedVersion: 2
|
|
||||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
|
||||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
|
||||||
m_LocalScale: {x: 1.3, y: 1.3, z: 1.3}
|
|
||||||
m_ConstrainProportionsScale: 0
|
|
||||||
m_Children: []
|
|
||||||
m_Father: {fileID: 0}
|
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
|
||||||
--- !u!33 &3909651526955663392
|
|
||||||
MeshFilter:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3885353946372160549}
|
|
||||||
m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0}
|
|
||||||
--- !u!23 &3320445911748035220
|
|
||||||
MeshRenderer:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3885353946372160549}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_CastShadows: 1
|
|
||||||
m_ReceiveShadows: 1
|
|
||||||
m_DynamicOccludee: 1
|
|
||||||
m_StaticShadowCaster: 0
|
|
||||||
m_MotionVectors: 1
|
|
||||||
m_LightProbeUsage: 1
|
|
||||||
m_ReflectionProbeUsage: 1
|
|
||||||
m_RayTracingMode: 2
|
|
||||||
m_RayTraceProcedural: 0
|
|
||||||
m_RayTracingAccelStructBuildFlagsOverride: 0
|
|
||||||
m_RayTracingAccelStructBuildFlags: 1
|
|
||||||
m_SmallMeshCulling: 1
|
|
||||||
m_ForceMeshLod: -1
|
|
||||||
m_MeshLodSelectionBias: 0
|
|
||||||
m_RenderingLayerMask: 1
|
|
||||||
m_RendererPriority: 0
|
|
||||||
m_Materials:
|
|
||||||
- {fileID: 2100000, guid: 9335a56cb714259428014ed979262af7, type: 2}
|
|
||||||
m_StaticBatchInfo:
|
|
||||||
firstSubMesh: 0
|
|
||||||
subMeshCount: 0
|
|
||||||
m_StaticBatchRoot: {fileID: 0}
|
|
||||||
m_ProbeAnchor: {fileID: 0}
|
|
||||||
m_LightProbeVolumeOverride: {fileID: 0}
|
|
||||||
m_ScaleInLightmap: 1
|
|
||||||
m_ReceiveGI: 1
|
|
||||||
m_PreserveUVs: 1
|
|
||||||
m_IgnoreNormalsForChartDetection: 0
|
|
||||||
m_ImportantGI: 0
|
|
||||||
m_StitchLightmapSeams: 1
|
|
||||||
m_SelectedEditorRenderState: 3
|
|
||||||
m_MinimumChartSize: 4
|
|
||||||
m_AutoUVMaxDistance: 0.5
|
|
||||||
m_AutoUVMaxAngle: 89
|
|
||||||
m_LightmapParameters: {fileID: 0}
|
|
||||||
m_GlobalIlluminationMeshLod: 0
|
|
||||||
m_SortingLayerID: 0
|
|
||||||
m_SortingLayer: 0
|
|
||||||
m_SortingOrder: 0
|
|
||||||
m_MaskInteraction: 0
|
|
||||||
m_AdditionalVertexStreams: {fileID: 0}
|
|
||||||
--- !u!114 &9053853372340598254
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3885353946372160549}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: c16549610bfe4458aa9389201d072bb6, type: 3}
|
|
||||||
m_Name:
|
|
||||||
m_EditorClassIdentifier: Unity.Entities.Hybrid::Unity.Entities.Hybrid.Baking.LinkedEntityGroupAuthoring
|
|
||||||
--- !u!114 &6834786618115927220
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3885353946372160549}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: 7c79d771cedb4794bf100ce60df5f764, type: 3}
|
|
||||||
m_Name:
|
|
||||||
m_EditorClassIdentifier: Unity.NetCode.Authoring.Hybrid::Unity.NetCode.GhostAuthoringComponent
|
|
||||||
HasOwner: 0
|
|
||||||
SupportAutoCommandTarget: 1
|
|
||||||
TrackInterpolationDelay: 0
|
|
||||||
GhostGroup: 0
|
|
||||||
UsePreSerialization: 0
|
|
||||||
UseSingleBaseline: 0
|
|
||||||
RollbackPredictedSpawnedGhostState: 0
|
|
||||||
RollbackPredictionOnStructuralChanges: 1
|
|
||||||
DefaultGhostMode: 0
|
|
||||||
SupportedGhostModes: 3
|
|
||||||
OptimizationMode: 0
|
|
||||||
Importance: 1
|
|
||||||
MaxSendRate: 0
|
|
||||||
prefabId:
|
|
||||||
--- !u!114 &2544095781123180609
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3885353946372160549}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: 6b014797e9092694b9568c5b66d34a55, type: 3}
|
|
||||||
m_Name:
|
|
||||||
m_EditorClassIdentifier: ProjectM.Authoring::ProjectM.Authoring.EnemyAuthoring
|
|
||||||
MaxHealth: 80
|
|
||||||
HitRadius: 1
|
|
||||||
MoveSpeed: 2
|
|
||||||
AttackRange: 2
|
|
||||||
AttackDamage: 12
|
|
||||||
AttackCooldownTicks: 70
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 1bc4c3736da534a42a7040fcbe9c92d5
|
|
||||||
PrefabImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,164 +0,0 @@
|
|||||||
%YAML 1.1
|
|
||||||
%TAG !u! tag:unity3d.com,2011:
|
|
||||||
--- !u!1 &3885353946372160549
|
|
||||||
GameObject:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
serializedVersion: 6
|
|
||||||
m_Component:
|
|
||||||
- component: {fileID: 3572766465862231365}
|
|
||||||
- component: {fileID: 3909651526955663392}
|
|
||||||
- component: {fileID: 3320445911748035220}
|
|
||||||
- component: {fileID: 9053853372340598254}
|
|
||||||
- component: {fileID: 6834786618115927220}
|
|
||||||
- component: {fileID: 2544095781123180609}
|
|
||||||
- component: {fileID: 5988865165041574521}
|
|
||||||
m_Layer: 0
|
|
||||||
m_Name: EnemyCharger
|
|
||||||
m_TagString: Untagged
|
|
||||||
m_Icon: {fileID: 0}
|
|
||||||
m_NavMeshLayer: 0
|
|
||||||
m_StaticEditorFlags: 0
|
|
||||||
m_IsActive: 1
|
|
||||||
--- !u!4 &3572766465862231365
|
|
||||||
Transform:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3885353946372160549}
|
|
||||||
serializedVersion: 2
|
|
||||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
|
||||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
|
||||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
|
||||||
m_ConstrainProportionsScale: 0
|
|
||||||
m_Children: []
|
|
||||||
m_Father: {fileID: 0}
|
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
|
||||||
--- !u!33 &3909651526955663392
|
|
||||||
MeshFilter:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3885353946372160549}
|
|
||||||
m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0}
|
|
||||||
--- !u!23 &3320445911748035220
|
|
||||||
MeshRenderer:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3885353946372160549}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_CastShadows: 1
|
|
||||||
m_ReceiveShadows: 1
|
|
||||||
m_DynamicOccludee: 1
|
|
||||||
m_StaticShadowCaster: 0
|
|
||||||
m_MotionVectors: 1
|
|
||||||
m_LightProbeUsage: 1
|
|
||||||
m_ReflectionProbeUsage: 1
|
|
||||||
m_RayTracingMode: 2
|
|
||||||
m_RayTraceProcedural: 0
|
|
||||||
m_RayTracingAccelStructBuildFlagsOverride: 0
|
|
||||||
m_RayTracingAccelStructBuildFlags: 1
|
|
||||||
m_SmallMeshCulling: 1
|
|
||||||
m_ForceMeshLod: -1
|
|
||||||
m_MeshLodSelectionBias: 0
|
|
||||||
m_RenderingLayerMask: 1
|
|
||||||
m_RendererPriority: 0
|
|
||||||
m_Materials:
|
|
||||||
- {fileID: 2100000, guid: fc4f991205d0aa347b65d89045f80c70, type: 2}
|
|
||||||
m_StaticBatchInfo:
|
|
||||||
firstSubMesh: 0
|
|
||||||
subMeshCount: 0
|
|
||||||
m_StaticBatchRoot: {fileID: 0}
|
|
||||||
m_ProbeAnchor: {fileID: 0}
|
|
||||||
m_LightProbeVolumeOverride: {fileID: 0}
|
|
||||||
m_ScaleInLightmap: 1
|
|
||||||
m_ReceiveGI: 1
|
|
||||||
m_PreserveUVs: 1
|
|
||||||
m_IgnoreNormalsForChartDetection: 0
|
|
||||||
m_ImportantGI: 0
|
|
||||||
m_StitchLightmapSeams: 1
|
|
||||||
m_SelectedEditorRenderState: 3
|
|
||||||
m_MinimumChartSize: 4
|
|
||||||
m_AutoUVMaxDistance: 0.5
|
|
||||||
m_AutoUVMaxAngle: 89
|
|
||||||
m_LightmapParameters: {fileID: 0}
|
|
||||||
m_GlobalIlluminationMeshLod: 0
|
|
||||||
m_SortingLayerID: 0
|
|
||||||
m_SortingLayer: 0
|
|
||||||
m_SortingOrder: 0
|
|
||||||
m_MaskInteraction: 0
|
|
||||||
m_AdditionalVertexStreams: {fileID: 0}
|
|
||||||
--- !u!114 &9053853372340598254
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3885353946372160549}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: c16549610bfe4458aa9389201d072bb6, type: 3}
|
|
||||||
m_Name:
|
|
||||||
m_EditorClassIdentifier: Unity.Entities.Hybrid::Unity.Entities.Hybrid.Baking.LinkedEntityGroupAuthoring
|
|
||||||
--- !u!114 &6834786618115927220
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3885353946372160549}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: 7c79d771cedb4794bf100ce60df5f764, type: 3}
|
|
||||||
m_Name:
|
|
||||||
m_EditorClassIdentifier: Unity.NetCode.Authoring.Hybrid::Unity.NetCode.GhostAuthoringComponent
|
|
||||||
HasOwner: 0
|
|
||||||
SupportAutoCommandTarget: 1
|
|
||||||
TrackInterpolationDelay: 0
|
|
||||||
GhostGroup: 0
|
|
||||||
UsePreSerialization: 0
|
|
||||||
UseSingleBaseline: 0
|
|
||||||
RollbackPredictedSpawnedGhostState: 0
|
|
||||||
RollbackPredictionOnStructuralChanges: 1
|
|
||||||
DefaultGhostMode: 0
|
|
||||||
SupportedGhostModes: 3
|
|
||||||
OptimizationMode: 0
|
|
||||||
Importance: 1
|
|
||||||
MaxSendRate: 0
|
|
||||||
prefabId:
|
|
||||||
--- !u!114 &2544095781123180609
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3885353946372160549}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: 6b014797e9092694b9568c5b66d34a55, type: 3}
|
|
||||||
m_Name:
|
|
||||||
m_EditorClassIdentifier: ProjectM.Authoring::ProjectM.Authoring.EnemyAuthoring
|
|
||||||
MaxHealth: 45
|
|
||||||
HitRadius: 0.8
|
|
||||||
MoveSpeed: 2.6
|
|
||||||
AttackRange: 1.7
|
|
||||||
AttackDamage: 14
|
|
||||||
AttackCooldownTicks: 48
|
|
||||||
--- !u!114 &5988865165041574521
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3885353946372160549}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: 9565191e0ea7fc94db934ae91a43a4cf, type: 3}
|
|
||||||
m_Name:
|
|
||||||
m_EditorClassIdentifier: ProjectM.Authoring::ProjectM.Authoring.ChargerAuthoring
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 6da6b938e0fd50f48a885f6f50ac9d61
|
|
||||||
PrefabImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 0d42b4a8ef76489458ee1ecf51b4dbca
|
|
||||||
PrefabImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 31d233e9e507acf45a411f8ab0997bed
|
|
||||||
PrefabImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: f29273bdfc85a8b49a4e16719e9a2568
|
|
||||||
PrefabImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,151 +0,0 @@
|
|||||||
%YAML 1.1
|
|
||||||
%TAG !u! tag:unity3d.com,2011:
|
|
||||||
--- !u!1 &3885353946372160549
|
|
||||||
GameObject:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
serializedVersion: 6
|
|
||||||
m_Component:
|
|
||||||
- component: {fileID: 3572766465862231365}
|
|
||||||
- component: {fileID: 3909651526955663392}
|
|
||||||
- component: {fileID: 3320445911748035220}
|
|
||||||
- component: {fileID: 9053853372340598254}
|
|
||||||
- component: {fileID: 6834786618115927220}
|
|
||||||
- component: {fileID: 2544095781123180609}
|
|
||||||
m_Layer: 0
|
|
||||||
m_Name: EnemySwarmer
|
|
||||||
m_TagString: Untagged
|
|
||||||
m_Icon: {fileID: 0}
|
|
||||||
m_NavMeshLayer: 0
|
|
||||||
m_StaticEditorFlags: 0
|
|
||||||
m_IsActive: 1
|
|
||||||
--- !u!4 &3572766465862231365
|
|
||||||
Transform:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3885353946372160549}
|
|
||||||
serializedVersion: 2
|
|
||||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
|
||||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
|
||||||
m_LocalScale: {x: 0.6, y: 0.6, z: 0.6}
|
|
||||||
m_ConstrainProportionsScale: 0
|
|
||||||
m_Children: []
|
|
||||||
m_Father: {fileID: 0}
|
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
|
||||||
--- !u!33 &3909651526955663392
|
|
||||||
MeshFilter:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3885353946372160549}
|
|
||||||
m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0}
|
|
||||||
--- !u!23 &3320445911748035220
|
|
||||||
MeshRenderer:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3885353946372160549}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_CastShadows: 1
|
|
||||||
m_ReceiveShadows: 1
|
|
||||||
m_DynamicOccludee: 1
|
|
||||||
m_StaticShadowCaster: 0
|
|
||||||
m_MotionVectors: 1
|
|
||||||
m_LightProbeUsage: 1
|
|
||||||
m_ReflectionProbeUsage: 1
|
|
||||||
m_RayTracingMode: 2
|
|
||||||
m_RayTraceProcedural: 0
|
|
||||||
m_RayTracingAccelStructBuildFlagsOverride: 0
|
|
||||||
m_RayTracingAccelStructBuildFlags: 1
|
|
||||||
m_SmallMeshCulling: 1
|
|
||||||
m_ForceMeshLod: -1
|
|
||||||
m_MeshLodSelectionBias: 0
|
|
||||||
m_RenderingLayerMask: 1
|
|
||||||
m_RendererPriority: 0
|
|
||||||
m_Materials:
|
|
||||||
- {fileID: 2100000, guid: 41d8ba155b460ab4eacca90ee2ad64cd, type: 2}
|
|
||||||
m_StaticBatchInfo:
|
|
||||||
firstSubMesh: 0
|
|
||||||
subMeshCount: 0
|
|
||||||
m_StaticBatchRoot: {fileID: 0}
|
|
||||||
m_ProbeAnchor: {fileID: 0}
|
|
||||||
m_LightProbeVolumeOverride: {fileID: 0}
|
|
||||||
m_ScaleInLightmap: 1
|
|
||||||
m_ReceiveGI: 1
|
|
||||||
m_PreserveUVs: 1
|
|
||||||
m_IgnoreNormalsForChartDetection: 0
|
|
||||||
m_ImportantGI: 0
|
|
||||||
m_StitchLightmapSeams: 1
|
|
||||||
m_SelectedEditorRenderState: 3
|
|
||||||
m_MinimumChartSize: 4
|
|
||||||
m_AutoUVMaxDistance: 0.5
|
|
||||||
m_AutoUVMaxAngle: 89
|
|
||||||
m_LightmapParameters: {fileID: 0}
|
|
||||||
m_GlobalIlluminationMeshLod: 0
|
|
||||||
m_SortingLayerID: 0
|
|
||||||
m_SortingLayer: 0
|
|
||||||
m_SortingOrder: 0
|
|
||||||
m_MaskInteraction: 0
|
|
||||||
m_AdditionalVertexStreams: {fileID: 0}
|
|
||||||
--- !u!114 &9053853372340598254
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3885353946372160549}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: c16549610bfe4458aa9389201d072bb6, type: 3}
|
|
||||||
m_Name:
|
|
||||||
m_EditorClassIdentifier: Unity.Entities.Hybrid::Unity.Entities.Hybrid.Baking.LinkedEntityGroupAuthoring
|
|
||||||
--- !u!114 &6834786618115927220
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3885353946372160549}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: 7c79d771cedb4794bf100ce60df5f764, type: 3}
|
|
||||||
m_Name:
|
|
||||||
m_EditorClassIdentifier: Unity.NetCode.Authoring.Hybrid::Unity.NetCode.GhostAuthoringComponent
|
|
||||||
HasOwner: 0
|
|
||||||
SupportAutoCommandTarget: 1
|
|
||||||
TrackInterpolationDelay: 0
|
|
||||||
GhostGroup: 0
|
|
||||||
UsePreSerialization: 0
|
|
||||||
UseSingleBaseline: 0
|
|
||||||
RollbackPredictedSpawnedGhostState: 0
|
|
||||||
RollbackPredictionOnStructuralChanges: 1
|
|
||||||
DefaultGhostMode: 0
|
|
||||||
SupportedGhostModes: 3
|
|
||||||
OptimizationMode: 0
|
|
||||||
Importance: 1
|
|
||||||
MaxSendRate: 0
|
|
||||||
prefabId:
|
|
||||||
--- !u!114 &2544095781123180609
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3885353946372160549}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: 6b014797e9092694b9568c5b66d34a55, type: 3}
|
|
||||||
m_Name:
|
|
||||||
m_EditorClassIdentifier: ProjectM.Authoring::ProjectM.Authoring.EnemyAuthoring
|
|
||||||
MaxHealth: 15
|
|
||||||
HitRadius: 0.5
|
|
||||||
MoveSpeed: 5
|
|
||||||
AttackRange: 1.4
|
|
||||||
AttackDamage: 3
|
|
||||||
AttackCooldownTicks: 40
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 9855c5a5d578bb74ba2fb0d41a73a3b9
|
|
||||||
PrefabImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: b0921d4cb0eedd349a257759a157653a
|
|
||||||
PrefabImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: a6c2004a3cc32cc44b1bb7a795f86519
|
|
||||||
PrefabImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: f77a36036567c814496e6c59c42b2082
|
|
||||||
PrefabImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,151 +0,0 @@
|
|||||||
%YAML 1.1
|
|
||||||
%TAG !u! tag:unity3d.com,2011:
|
|
||||||
--- !u!1 &3885353946372160549
|
|
||||||
GameObject:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
serializedVersion: 6
|
|
||||||
m_Component:
|
|
||||||
- component: {fileID: 3572766465862231365}
|
|
||||||
- component: {fileID: 3909651526955663392}
|
|
||||||
- component: {fileID: 3320445911748035220}
|
|
||||||
- component: {fileID: 9053853372340598254}
|
|
||||||
- component: {fileID: 6834786618115927220}
|
|
||||||
- component: {fileID: 320054987393778360}
|
|
||||||
m_Layer: 0
|
|
||||||
m_Name: Fabricator
|
|
||||||
m_TagString: Untagged
|
|
||||||
m_Icon: {fileID: 0}
|
|
||||||
m_NavMeshLayer: 0
|
|
||||||
m_StaticEditorFlags: 0
|
|
||||||
m_IsActive: 1
|
|
||||||
--- !u!4 &3572766465862231365
|
|
||||||
Transform:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3885353946372160549}
|
|
||||||
serializedVersion: 2
|
|
||||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
|
||||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
|
||||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
|
||||||
m_ConstrainProportionsScale: 0
|
|
||||||
m_Children: []
|
|
||||||
m_Father: {fileID: 0}
|
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
|
||||||
--- !u!33 &3909651526955663392
|
|
||||||
MeshFilter:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3885353946372160549}
|
|
||||||
m_Mesh: {fileID: -1810898345513765494, guid: c8c42eb35b8e2e649b185de6fd33e2e7, type: 3}
|
|
||||||
--- !u!23 &3320445911748035220
|
|
||||||
MeshRenderer:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3885353946372160549}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_CastShadows: 1
|
|
||||||
m_ReceiveShadows: 1
|
|
||||||
m_DynamicOccludee: 1
|
|
||||||
m_StaticShadowCaster: 0
|
|
||||||
m_MotionVectors: 1
|
|
||||||
m_LightProbeUsage: 1
|
|
||||||
m_ReflectionProbeUsage: 1
|
|
||||||
m_RayTracingMode: 2
|
|
||||||
m_RayTraceProcedural: 0
|
|
||||||
m_RayTracingAccelStructBuildFlagsOverride: 0
|
|
||||||
m_RayTracingAccelStructBuildFlags: 1
|
|
||||||
m_SmallMeshCulling: 1
|
|
||||||
m_ForceMeshLod: -1
|
|
||||||
m_MeshLodSelectionBias: 0
|
|
||||||
m_RenderingLayerMask: 1
|
|
||||||
m_RendererPriority: 0
|
|
||||||
m_Materials:
|
|
||||||
- {fileID: 2100000, guid: 4cee7a5983b187943adc589b9cb1f084, type: 2}
|
|
||||||
m_StaticBatchInfo:
|
|
||||||
firstSubMesh: 0
|
|
||||||
subMeshCount: 0
|
|
||||||
m_StaticBatchRoot: {fileID: 0}
|
|
||||||
m_ProbeAnchor: {fileID: 0}
|
|
||||||
m_LightProbeVolumeOverride: {fileID: 0}
|
|
||||||
m_ScaleInLightmap: 1
|
|
||||||
m_ReceiveGI: 1
|
|
||||||
m_PreserveUVs: 1
|
|
||||||
m_IgnoreNormalsForChartDetection: 0
|
|
||||||
m_ImportantGI: 0
|
|
||||||
m_StitchLightmapSeams: 1
|
|
||||||
m_SelectedEditorRenderState: 3
|
|
||||||
m_MinimumChartSize: 4
|
|
||||||
m_AutoUVMaxDistance: 0.5
|
|
||||||
m_AutoUVMaxAngle: 89
|
|
||||||
m_LightmapParameters: {fileID: 0}
|
|
||||||
m_GlobalIlluminationMeshLod: 0
|
|
||||||
m_SortingLayerID: 0
|
|
||||||
m_SortingLayer: 0
|
|
||||||
m_SortingOrder: 0
|
|
||||||
m_MaskInteraction: 0
|
|
||||||
m_AdditionalVertexStreams: {fileID: 0}
|
|
||||||
--- !u!114 &9053853372340598254
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3885353946372160549}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: c16549610bfe4458aa9389201d072bb6, type: 3}
|
|
||||||
m_Name:
|
|
||||||
m_EditorClassIdentifier: Unity.Entities.Hybrid::Unity.Entities.Hybrid.Baking.LinkedEntityGroupAuthoring
|
|
||||||
--- !u!114 &6834786618115927220
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3885353946372160549}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: 7c79d771cedb4794bf100ce60df5f764, type: 3}
|
|
||||||
m_Name:
|
|
||||||
m_EditorClassIdentifier: Unity.NetCode.Authoring.Hybrid::Unity.NetCode.GhostAuthoringComponent
|
|
||||||
HasOwner: 0
|
|
||||||
SupportAutoCommandTarget: 1
|
|
||||||
TrackInterpolationDelay: 0
|
|
||||||
GhostGroup: 0
|
|
||||||
UsePreSerialization: 0
|
|
||||||
UseSingleBaseline: 0
|
|
||||||
RollbackPredictedSpawnedGhostState: 0
|
|
||||||
RollbackPredictionOnStructuralChanges: 1
|
|
||||||
DefaultGhostMode: 0
|
|
||||||
SupportedGhostModes: 3
|
|
||||||
OptimizationMode: 0
|
|
||||||
Importance: 1
|
|
||||||
MaxSendRate: 0
|
|
||||||
prefabId:
|
|
||||||
--- !u!114 &320054987393778360
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3885353946372160549}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: 014833c467fb1d6499f437b7bf76db80, type: 3}
|
|
||||||
m_Name:
|
|
||||||
m_EditorClassIdentifier: ProjectM.Authoring::ProjectM.Authoring.FabricatorAuthoring
|
|
||||||
InResourceId: 2
|
|
||||||
InAmount: 1
|
|
||||||
OutResourceId: 4
|
|
||||||
OutAmount: 3
|
|
||||||
PeriodTicks: 30
|
|
||||||
InputFromLedger: 1
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 8dd9baab4cbf6c04f9320ed5ed764c65
|
|
||||||
PrefabImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,148 +0,0 @@
|
|||||||
%YAML 1.1
|
|
||||||
%TAG !u! tag:unity3d.com,2011:
|
|
||||||
--- !u!1 &3885353946372160549
|
|
||||||
GameObject:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
serializedVersion: 6
|
|
||||||
m_Component:
|
|
||||||
- component: {fileID: 3572766465862231365}
|
|
||||||
- component: {fileID: 3909651526955663392}
|
|
||||||
- component: {fileID: 3320445911748035220}
|
|
||||||
- component: {fileID: 9053853372340598254}
|
|
||||||
- component: {fileID: 6834786618115927220}
|
|
||||||
- component: {fileID: 1647940186412478499}
|
|
||||||
m_Layer: 0
|
|
||||||
m_Name: Harvester
|
|
||||||
m_TagString: Untagged
|
|
||||||
m_Icon: {fileID: 0}
|
|
||||||
m_NavMeshLayer: 0
|
|
||||||
m_StaticEditorFlags: 0
|
|
||||||
m_IsActive: 1
|
|
||||||
--- !u!4 &3572766465862231365
|
|
||||||
Transform:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3885353946372160549}
|
|
||||||
serializedVersion: 2
|
|
||||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
|
||||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
|
||||||
m_LocalScale: {x: 2.5, y: 2.5, z: 2.5}
|
|
||||||
m_ConstrainProportionsScale: 0
|
|
||||||
m_Children: []
|
|
||||||
m_Father: {fileID: 0}
|
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
|
||||||
--- !u!33 &3909651526955663392
|
|
||||||
MeshFilter:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3885353946372160549}
|
|
||||||
m_Mesh: {fileID: 4300000, guid: abc00000000010690097314383055197, type: 3}
|
|
||||||
--- !u!23 &3320445911748035220
|
|
||||||
MeshRenderer:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3885353946372160549}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_CastShadows: 1
|
|
||||||
m_ReceiveShadows: 1
|
|
||||||
m_DynamicOccludee: 1
|
|
||||||
m_StaticShadowCaster: 0
|
|
||||||
m_MotionVectors: 1
|
|
||||||
m_LightProbeUsage: 1
|
|
||||||
m_ReflectionProbeUsage: 1
|
|
||||||
m_RayTracingMode: 2
|
|
||||||
m_RayTraceProcedural: 0
|
|
||||||
m_RayTracingAccelStructBuildFlagsOverride: 0
|
|
||||||
m_RayTracingAccelStructBuildFlags: 1
|
|
||||||
m_SmallMeshCulling: 1
|
|
||||||
m_ForceMeshLod: -1
|
|
||||||
m_MeshLodSelectionBias: 0
|
|
||||||
m_RenderingLayerMask: 1
|
|
||||||
m_RendererPriority: 0
|
|
||||||
m_Materials:
|
|
||||||
- {fileID: 2100000, guid: c01dbe8a4e818c5469eceae8b286bf4d, type: 2}
|
|
||||||
m_StaticBatchInfo:
|
|
||||||
firstSubMesh: 0
|
|
||||||
subMeshCount: 0
|
|
||||||
m_StaticBatchRoot: {fileID: 0}
|
|
||||||
m_ProbeAnchor: {fileID: 0}
|
|
||||||
m_LightProbeVolumeOverride: {fileID: 0}
|
|
||||||
m_ScaleInLightmap: 1
|
|
||||||
m_ReceiveGI: 1
|
|
||||||
m_PreserveUVs: 1
|
|
||||||
m_IgnoreNormalsForChartDetection: 0
|
|
||||||
m_ImportantGI: 0
|
|
||||||
m_StitchLightmapSeams: 1
|
|
||||||
m_SelectedEditorRenderState: 3
|
|
||||||
m_MinimumChartSize: 4
|
|
||||||
m_AutoUVMaxDistance: 0.5
|
|
||||||
m_AutoUVMaxAngle: 89
|
|
||||||
m_LightmapParameters: {fileID: 0}
|
|
||||||
m_GlobalIlluminationMeshLod: 0
|
|
||||||
m_SortingLayerID: 0
|
|
||||||
m_SortingLayer: 0
|
|
||||||
m_SortingOrder: 0
|
|
||||||
m_MaskInteraction: 0
|
|
||||||
m_AdditionalVertexStreams: {fileID: 0}
|
|
||||||
--- !u!114 &9053853372340598254
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3885353946372160549}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: c16549610bfe4458aa9389201d072bb6, type: 3}
|
|
||||||
m_Name:
|
|
||||||
m_EditorClassIdentifier: Unity.Entities.Hybrid::Unity.Entities.Hybrid.Baking.LinkedEntityGroupAuthoring
|
|
||||||
--- !u!114 &6834786618115927220
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3885353946372160549}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: 7c79d771cedb4794bf100ce60df5f764, type: 3}
|
|
||||||
m_Name:
|
|
||||||
m_EditorClassIdentifier: Unity.NetCode.Authoring.Hybrid::Unity.NetCode.GhostAuthoringComponent
|
|
||||||
HasOwner: 0
|
|
||||||
SupportAutoCommandTarget: 1
|
|
||||||
TrackInterpolationDelay: 0
|
|
||||||
GhostGroup: 0
|
|
||||||
UsePreSerialization: 0
|
|
||||||
UseSingleBaseline: 0
|
|
||||||
RollbackPredictedSpawnedGhostState: 0
|
|
||||||
RollbackPredictionOnStructuralChanges: 1
|
|
||||||
DefaultGhostMode: 0
|
|
||||||
SupportedGhostModes: 3
|
|
||||||
OptimizationMode: 0
|
|
||||||
Importance: 1
|
|
||||||
MaxSendRate: 0
|
|
||||||
prefabId:
|
|
||||||
--- !u!114 &1647940186412478499
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3885353946372160549}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: d69d7296747332b4fbe7901ec5210149, type: 3}
|
|
||||||
m_Name:
|
|
||||||
m_EditorClassIdentifier: ProjectM.Authoring::ProjectM.Authoring.HarvesterAuthoring
|
|
||||||
OutputResourceId: 2
|
|
||||||
Yield: 1
|
|
||||||
PeriodTicks: 60
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 9e227d9b387139340933dcf55d1c3a87
|
|
||||||
PrefabImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
+2601
-2559
File diff suppressed because it is too large
Load Diff
@@ -1,204 +0,0 @@
|
|||||||
%YAML 1.1
|
|
||||||
%TAG !u! tag:unity3d.com,2011:
|
|
||||||
--- !u!1 &2057690259992313649
|
|
||||||
GameObject:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
serializedVersion: 6
|
|
||||||
m_Component:
|
|
||||||
- component: {fileID: 4449724123933675757}
|
|
||||||
- component: {fileID: 3818890329194429404}
|
|
||||||
- component: {fileID: 6553709043537316589}
|
|
||||||
m_Layer: 0
|
|
||||||
m_Name: Model
|
|
||||||
m_TagString: Untagged
|
|
||||||
m_Icon: {fileID: 0}
|
|
||||||
m_NavMeshLayer: 0
|
|
||||||
m_StaticEditorFlags: 0
|
|
||||||
m_IsActive: 1
|
|
||||||
--- !u!4 &4449724123933675757
|
|
||||||
Transform:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 2057690259992313649}
|
|
||||||
serializedVersion: 2
|
|
||||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
|
||||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
|
||||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
|
||||||
m_ConstrainProportionsScale: 0
|
|
||||||
m_Children: []
|
|
||||||
m_Father: {fileID: 3572766465862231365}
|
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
|
||||||
--- !u!33 &3818890329194429404
|
|
||||||
MeshFilter:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 2057690259992313649}
|
|
||||||
m_Mesh: {fileID: -8131118695690612189, guid: 472a8342ece31c14f9d53ff7119b7857, type: 3}
|
|
||||||
--- !u!23 &6553709043537316589
|
|
||||||
MeshRenderer:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 2057690259992313649}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_CastShadows: 1
|
|
||||||
m_ReceiveShadows: 1
|
|
||||||
m_DynamicOccludee: 1
|
|
||||||
m_StaticShadowCaster: 0
|
|
||||||
m_MotionVectors: 1
|
|
||||||
m_LightProbeUsage: 1
|
|
||||||
m_ReflectionProbeUsage: 1
|
|
||||||
m_RayTracingMode: 2
|
|
||||||
m_RayTraceProcedural: 0
|
|
||||||
m_RayTracingAccelStructBuildFlagsOverride: 0
|
|
||||||
m_RayTracingAccelStructBuildFlags: 1
|
|
||||||
m_SmallMeshCulling: 1
|
|
||||||
m_ForceMeshLod: -1
|
|
||||||
m_MeshLodSelectionBias: 0
|
|
||||||
m_RenderingLayerMask: 1
|
|
||||||
m_RendererPriority: 0
|
|
||||||
m_Materials:
|
|
||||||
- {fileID: 2100000, guid: 4cee7a5983b187943adc589b9cb1f084, type: 2}
|
|
||||||
- {fileID: 2100000, guid: e600b338198602a449203a6e59c0e794, type: 2}
|
|
||||||
m_StaticBatchInfo:
|
|
||||||
firstSubMesh: 0
|
|
||||||
subMeshCount: 0
|
|
||||||
m_StaticBatchRoot: {fileID: 0}
|
|
||||||
m_ProbeAnchor: {fileID: 0}
|
|
||||||
m_LightProbeVolumeOverride: {fileID: 0}
|
|
||||||
m_ScaleInLightmap: 1
|
|
||||||
m_ReceiveGI: 1
|
|
||||||
m_PreserveUVs: 0
|
|
||||||
m_IgnoreNormalsForChartDetection: 0
|
|
||||||
m_ImportantGI: 0
|
|
||||||
m_StitchLightmapSeams: 1
|
|
||||||
m_SelectedEditorRenderState: 3
|
|
||||||
m_MinimumChartSize: 4
|
|
||||||
m_AutoUVMaxDistance: 0.5
|
|
||||||
m_AutoUVMaxAngle: 89
|
|
||||||
m_LightmapParameters: {fileID: 0}
|
|
||||||
m_GlobalIlluminationMeshLod: 0
|
|
||||||
m_SortingLayerID: 0
|
|
||||||
m_SortingLayer: 0
|
|
||||||
m_SortingOrder: 0
|
|
||||||
m_MaskInteraction: 0
|
|
||||||
m_AdditionalVertexStreams: {fileID: 0}
|
|
||||||
--- !u!1 &3885353946372160549
|
|
||||||
GameObject:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
serializedVersion: 6
|
|
||||||
m_Component:
|
|
||||||
- component: {fileID: 3572766465862231365}
|
|
||||||
- component: {fileID: 9053853372340598254}
|
|
||||||
- component: {fileID: 6834786618115927220}
|
|
||||||
- component: {fileID: 1794795016809289889}
|
|
||||||
- component: {fileID: 9049467567705961987}
|
|
||||||
m_Layer: 9
|
|
||||||
m_Name: Turret
|
|
||||||
m_TagString: Untagged
|
|
||||||
m_Icon: {fileID: 0}
|
|
||||||
m_NavMeshLayer: 0
|
|
||||||
m_StaticEditorFlags: 0
|
|
||||||
m_IsActive: 1
|
|
||||||
--- !u!4 &3572766465862231365
|
|
||||||
Transform:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3885353946372160549}
|
|
||||||
serializedVersion: 2
|
|
||||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
|
||||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
|
||||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
|
||||||
m_ConstrainProportionsScale: 0
|
|
||||||
m_Children:
|
|
||||||
- {fileID: 4449724123933675757}
|
|
||||||
m_Father: {fileID: 0}
|
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
|
||||||
--- !u!114 &9053853372340598254
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3885353946372160549}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: c16549610bfe4458aa9389201d072bb6, type: 3}
|
|
||||||
m_Name:
|
|
||||||
m_EditorClassIdentifier: Unity.Entities.Hybrid::Unity.Entities.Hybrid.Baking.LinkedEntityGroupAuthoring
|
|
||||||
--- !u!114 &6834786618115927220
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3885353946372160549}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: 7c79d771cedb4794bf100ce60df5f764, type: 3}
|
|
||||||
m_Name:
|
|
||||||
m_EditorClassIdentifier: Unity.NetCode.Authoring.Hybrid::Unity.NetCode.GhostAuthoringComponent
|
|
||||||
HasOwner: 0
|
|
||||||
SupportAutoCommandTarget: 1
|
|
||||||
TrackInterpolationDelay: 0
|
|
||||||
GhostGroup: 0
|
|
||||||
UsePreSerialization: 0
|
|
||||||
UseSingleBaseline: 0
|
|
||||||
RollbackPredictedSpawnedGhostState: 0
|
|
||||||
RollbackPredictionOnStructuralChanges: 1
|
|
||||||
DefaultGhostMode: 0
|
|
||||||
SupportedGhostModes: 3
|
|
||||||
OptimizationMode: 0
|
|
||||||
Importance: 1
|
|
||||||
MaxSendRate: 0
|
|
||||||
prefabId:
|
|
||||||
--- !u!114 &1794795016809289889
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 3885353946372160549}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: dfb1e0820cbf41b4bbbe99066dfadd40, type: 3}
|
|
||||||
m_Name:
|
|
||||||
m_EditorClassIdentifier: ProjectM.Authoring::ProjectM.Authoring.TurretAuthoring
|
|
||||||
Range: 10
|
|
||||||
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: 0.8, y: 1.2, z: 0.8}
|
|
||||||
m_Center: {x: 0, y: 0.6, z: 0}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 5459c9edea89bd94fa6f5043ae00eb40
|
|
||||||
PrefabImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,200 +0,0 @@
|
|||||||
%YAML 1.1
|
|
||||||
%TAG !u! tag:unity3d.com,2011:
|
|
||||||
--- !u!114 &-4441572633185463556
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 1
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 0}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: 97c23e3b12dc18c42a140437e53d3951, type: 3}
|
|
||||||
m_Name: Tonemapping
|
|
||||||
m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.Tonemapping
|
|
||||||
active: 1
|
|
||||||
mode:
|
|
||||||
m_OverrideState: 1
|
|
||||||
m_Value: 1
|
|
||||||
neutralHDRRangeReductionMode:
|
|
||||||
m_OverrideState: 0
|
|
||||||
m_Value: 2
|
|
||||||
acesPreset:
|
|
||||||
m_OverrideState: 0
|
|
||||||
m_Value: 3
|
|
||||||
hueShiftAmount:
|
|
||||||
m_OverrideState: 0
|
|
||||||
m_Value: 0
|
|
||||||
detectPaperWhite:
|
|
||||||
m_OverrideState: 0
|
|
||||||
m_Value: 0
|
|
||||||
paperWhite:
|
|
||||||
m_OverrideState: 0
|
|
||||||
m_Value: 300
|
|
||||||
detectBrightnessLimits:
|
|
||||||
m_OverrideState: 0
|
|
||||||
m_Value: 1
|
|
||||||
minNits:
|
|
||||||
m_OverrideState: 0
|
|
||||||
m_Value: 0.005
|
|
||||||
maxNits:
|
|
||||||
m_OverrideState: 0
|
|
||||||
m_Value: 1000
|
|
||||||
--- !u!114 &-3245916173682126434
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 1
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 0}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: 0b2db86121404754db890f4c8dfe81b2, type: 3}
|
|
||||||
m_Name: Bloom
|
|
||||||
m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.Bloom
|
|
||||||
active: 1
|
|
||||||
skipIterations:
|
|
||||||
m_OverrideState: 0
|
|
||||||
m_Value: 1
|
|
||||||
threshold:
|
|
||||||
m_OverrideState: 1
|
|
||||||
m_Value: 1.2
|
|
||||||
intensity:
|
|
||||||
m_OverrideState: 1
|
|
||||||
m_Value: 0.5
|
|
||||||
scatter:
|
|
||||||
m_OverrideState: 1
|
|
||||||
m_Value: 0.65
|
|
||||||
clamp:
|
|
||||||
m_OverrideState: 1
|
|
||||||
m_Value: 10
|
|
||||||
tint:
|
|
||||||
m_OverrideState: 1
|
|
||||||
m_Value: {r: 0.85, g: 0.92, b: 1, a: 1}
|
|
||||||
highQualityFiltering:
|
|
||||||
m_OverrideState: 1
|
|
||||||
m_Value: 1
|
|
||||||
filter:
|
|
||||||
m_OverrideState: 0
|
|
||||||
m_Value: 0
|
|
||||||
downscale:
|
|
||||||
m_OverrideState: 0
|
|
||||||
m_Value: 0
|
|
||||||
maxIterations:
|
|
||||||
m_OverrideState: 0
|
|
||||||
m_Value: 6
|
|
||||||
dirtTexture:
|
|
||||||
m_OverrideState: 0
|
|
||||||
m_Value: {fileID: 0}
|
|
||||||
dimension: 1
|
|
||||||
dirtIntensity:
|
|
||||||
m_OverrideState: 0
|
|
||||||
m_Value: 0
|
|
||||||
--- !u!114 &-2801731409977683993
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 1
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 0}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: 899c54efeace73346a0a16faa3afe726, type: 3}
|
|
||||||
m_Name: Vignette
|
|
||||||
m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.Vignette
|
|
||||||
active: 1
|
|
||||||
color:
|
|
||||||
m_OverrideState: 1
|
|
||||||
m_Value: {r: 0, g: 0, b: 0, a: 1}
|
|
||||||
center:
|
|
||||||
m_OverrideState: 0
|
|
||||||
m_Value: {x: 0.5, y: 0.5}
|
|
||||||
intensity:
|
|
||||||
m_OverrideState: 1
|
|
||||||
m_Value: 0.2
|
|
||||||
smoothness:
|
|
||||||
m_OverrideState: 1
|
|
||||||
m_Value: 0.4
|
|
||||||
rounded:
|
|
||||||
m_OverrideState: 0
|
|
||||||
m_Value: 0
|
|
||||||
--- !u!114 &11400000
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 0}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: d7fd9488000d3734a9e00ee676215985, type: 3}
|
|
||||||
m_Name: PostFX_Daylight
|
|
||||||
m_EditorClassIdentifier: Unity.RenderPipelines.Core.Runtime::UnityEngine.Rendering.VolumeProfile
|
|
||||||
components:
|
|
||||||
- {fileID: -3245916173682126434}
|
|
||||||
- {fileID: -4441572633185463556}
|
|
||||||
- {fileID: 5577075502713826208}
|
|
||||||
- {fileID: -2801731409977683993}
|
|
||||||
- {fileID: 7928249266562162677}
|
|
||||||
--- !u!114 &5577075502713826208
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 1
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 0}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: 66f335fb1ffd8684294ad653bf1c7564, type: 3}
|
|
||||||
m_Name: ColorAdjustments
|
|
||||||
m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.ColorAdjustments
|
|
||||||
active: 1
|
|
||||||
postExposure:
|
|
||||||
m_OverrideState: 1
|
|
||||||
m_Value: 0.85
|
|
||||||
contrast:
|
|
||||||
m_OverrideState: 1
|
|
||||||
m_Value: 4
|
|
||||||
colorFilter:
|
|
||||||
m_OverrideState: 1
|
|
||||||
m_Value: {r: 0.93, g: 0.96, b: 1, a: 1}
|
|
||||||
hueShift:
|
|
||||||
m_OverrideState: 1
|
|
||||||
m_Value: 0
|
|
||||||
saturation:
|
|
||||||
m_OverrideState: 1
|
|
||||||
m_Value: 4
|
|
||||||
--- !u!114 &7928249266562162677
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 3
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 0}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: 558a8e2b6826cf840aae193990ba9f2e, type: 3}
|
|
||||||
m_Name: ShadowsMidtonesHighlights
|
|
||||||
m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.ShadowsMidtonesHighlights
|
|
||||||
active: 1
|
|
||||||
shadows:
|
|
||||||
m_OverrideState: 1
|
|
||||||
m_Value: {x: 0.92, y: 1, z: 1.05, w: -0.02}
|
|
||||||
midtones:
|
|
||||||
m_OverrideState: 1
|
|
||||||
m_Value: {x: 0.98, y: 1, z: 1.02, w: 0}
|
|
||||||
highlights:
|
|
||||||
m_OverrideState: 1
|
|
||||||
m_Value: {x: 1.06, y: 1, z: 0.92, w: 0}
|
|
||||||
shadowsStart:
|
|
||||||
m_OverrideState: 1
|
|
||||||
m_Value: 0
|
|
||||||
shadowsEnd:
|
|
||||||
m_OverrideState: 1
|
|
||||||
m_Value: 0.3
|
|
||||||
highlightsStart:
|
|
||||||
m_OverrideState: 1
|
|
||||||
m_Value: 0.55
|
|
||||||
highlightsEnd:
|
|
||||||
m_OverrideState: 1
|
|
||||||
m_Value: 1
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 09ca16b0a83161346aaa963465d1ec16
|
|
||||||
NativeFormatImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
mainObjectFileID: 11400000
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
+9
-9
@@ -61,7 +61,7 @@ MonoBehaviour:
|
|||||||
m_Value: 1
|
m_Value: 1
|
||||||
intensity:
|
intensity:
|
||||||
m_OverrideState: 1
|
m_OverrideState: 1
|
||||||
m_Value: 0.55
|
m_Value: 0.6
|
||||||
scatter:
|
scatter:
|
||||||
m_OverrideState: 1
|
m_OverrideState: 1
|
||||||
m_Value: 0.65
|
m_Value: 0.65
|
||||||
@@ -70,7 +70,7 @@ MonoBehaviour:
|
|||||||
m_Value: 65472
|
m_Value: 65472
|
||||||
tint:
|
tint:
|
||||||
m_OverrideState: 1
|
m_OverrideState: 1
|
||||||
m_Value: {r: 0.8, g: 0.9, b: 1, a: 1}
|
m_Value: {r: 0.75, g: 0.95, b: 1, a: 1}
|
||||||
highQualityFiltering:
|
highQualityFiltering:
|
||||||
m_OverrideState: 1
|
m_OverrideState: 1
|
||||||
m_Value: 1
|
m_Value: 1
|
||||||
@@ -105,13 +105,13 @@ MonoBehaviour:
|
|||||||
active: 1
|
active: 1
|
||||||
color:
|
color:
|
||||||
m_OverrideState: 1
|
m_OverrideState: 1
|
||||||
m_Value: {r: 0, g: 0, b: 0, a: 1}
|
m_Value: {r: 0, g: 0.02, b: 0.04, a: 1}
|
||||||
center:
|
center:
|
||||||
m_OverrideState: 0
|
m_OverrideState: 0
|
||||||
m_Value: {x: 0.5, y: 0.5}
|
m_Value: {x: 0.5, y: 0.5}
|
||||||
intensity:
|
intensity:
|
||||||
m_OverrideState: 1
|
m_OverrideState: 1
|
||||||
m_Value: 0.32
|
m_Value: 0.28
|
||||||
smoothness:
|
smoothness:
|
||||||
m_OverrideState: 1
|
m_OverrideState: 1
|
||||||
m_Value: 0.4
|
m_Value: 0.4
|
||||||
@@ -128,7 +128,7 @@ MonoBehaviour:
|
|||||||
m_Enabled: 1
|
m_Enabled: 1
|
||||||
m_EditorHideFlags: 0
|
m_EditorHideFlags: 0
|
||||||
m_Script: {fileID: 11500000, guid: d7fd9488000d3734a9e00ee676215985, type: 3}
|
m_Script: {fileID: 11500000, guid: d7fd9488000d3734a9e00ee676215985, type: 3}
|
||||||
m_Name: PostFX_DarkSciFi
|
m_Name: PostFX_Lantern
|
||||||
m_EditorClassIdentifier: Unity.RenderPipelines.Core.Runtime::UnityEngine.Rendering.VolumeProfile
|
m_EditorClassIdentifier: Unity.RenderPipelines.Core.Runtime::UnityEngine.Rendering.VolumeProfile
|
||||||
components:
|
components:
|
||||||
- {fileID: -3245916173682126434}
|
- {fileID: -3245916173682126434}
|
||||||
@@ -150,16 +150,16 @@ MonoBehaviour:
|
|||||||
active: 1
|
active: 1
|
||||||
postExposure:
|
postExposure:
|
||||||
m_OverrideState: 1
|
m_OverrideState: 1
|
||||||
m_Value: 0.25
|
m_Value: 0.35
|
||||||
contrast:
|
contrast:
|
||||||
m_OverrideState: 1
|
m_OverrideState: 1
|
||||||
m_Value: 12
|
m_Value: 10
|
||||||
colorFilter:
|
colorFilter:
|
||||||
m_OverrideState: 1
|
m_OverrideState: 1
|
||||||
m_Value: {r: 0.93, g: 0.96, b: 1, a: 1}
|
m_Value: {r: 0.88, g: 0.97, b: 1, a: 1}
|
||||||
hueShift:
|
hueShift:
|
||||||
m_OverrideState: 0
|
m_OverrideState: 0
|
||||||
m_Value: 0
|
m_Value: 0
|
||||||
saturation:
|
saturation:
|
||||||
m_OverrideState: 1
|
m_OverrideState: 1
|
||||||
m_Value: 8
|
m_Value: 6
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 669d41422347ed94785dd2515084828f
|
guid: 96601eff473f9834cb459b40d0bbae14
|
||||||
NativeFormatImporter:
|
NativeFormatImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
mainObjectFileID: 11400000
|
mainObjectFileID: 11400000
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
%YAML 1.1
|
|
||||||
%TAG !u! tag:unity3d.com,2011:
|
|
||||||
--- !u!21 &2100000
|
|
||||||
Material:
|
|
||||||
serializedVersion: 8
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_Name: Sky_DaytimeProcedural
|
|
||||||
m_Shader: {fileID: 106, guid: 0000000000000000f000000000000000, type: 0}
|
|
||||||
m_Parent: {fileID: 0}
|
|
||||||
m_ModifiedSerializedProperties: 0
|
|
||||||
m_ValidKeywords:
|
|
||||||
- _SUNDISK_HIGH_QUALITY
|
|
||||||
m_InvalidKeywords: []
|
|
||||||
m_LightmapFlags: 4
|
|
||||||
m_EnableInstancingVariants: 0
|
|
||||||
m_DoubleSidedGI: 0
|
|
||||||
m_CustomRenderQueue: -1
|
|
||||||
stringTagMap: {}
|
|
||||||
disabledShaderPasses: []
|
|
||||||
m_LockedProperties:
|
|
||||||
m_SavedProperties:
|
|
||||||
serializedVersion: 3
|
|
||||||
m_TexEnvs: []
|
|
||||||
m_Ints: []
|
|
||||||
m_Floats:
|
|
||||||
- _AtmosphereThickness: 1
|
|
||||||
- _Exposure: 1.1
|
|
||||||
- _SunDisk: 2
|
|
||||||
- _SunSize: 0.04
|
|
||||||
- _SunSizeConvergence: 5
|
|
||||||
m_Colors:
|
|
||||||
- _GroundColor: {r: 0.6039216, g: 0.54901963, b: 0.4392157, a: 1}
|
|
||||||
- _SkyTint: {r: 0.65882355, g: 0.78431374, b: 0.9098039, a: 1}
|
|
||||||
m_BuildTextureStacks: []
|
|
||||||
m_AllowLocking: 1
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: e1cd63d2feef80f45a168f477934722f
|
|
||||||
NativeFormatImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
mainObjectFileID: 2100000
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
using ProjectM.Simulation;
|
|
||||||
using Unity.Entities;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace ProjectM.Authoring
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Authoring for a Conveyor belt ghost prefab. Bakes <see cref="PlacedStructure"/>{Type=Conveyor} +
|
|
||||||
/// <see cref="Conveyor"/> (default facing; BuildPlaceSystem overrides Direction per placement from the RPC) +
|
|
||||||
/// a DISABLED <see cref="ConveyorItem"/> (an empty belt). BuildPlaceSystem stamps the Cell; the transport
|
|
||||||
/// system initializes the period gate on first encounter.
|
|
||||||
/// </summary>
|
|
||||||
public class ConveyorAuthoring : MonoBehaviour
|
|
||||||
{
|
|
||||||
[Tooltip("Default belt facing (0=+X, 1=-X, 2=+Z, 3=-Z); the build RPC overrides this per placement.")]
|
|
||||||
public byte Direction = 0;
|
|
||||||
[Min(1)] public int PeriodTicks = 20;
|
|
||||||
|
|
||||||
private class ConveyorBaker : Baker<ConveyorAuthoring>
|
|
||||||
{
|
|
||||||
public override void Bake(ConveyorAuthoring authoring)
|
|
||||||
{
|
|
||||||
var entity = GetEntity(authoring, TransformUsageFlags.Dynamic);
|
|
||||||
this.AddPlacedStructure(entity, StructureType.Conveyor);
|
|
||||||
AddComponent(entity, new Conveyor
|
|
||||||
{
|
|
||||||
Direction = authoring.Direction,
|
|
||||||
PeriodTicks = authoring.PeriodTicks,
|
|
||||||
});
|
|
||||||
AddComponent(entity, new ConveyorItem { ResourceId = 0, Count = 0 });
|
|
||||||
SetComponentEnabled<ConveyorItem>(entity, false); // baked empty (disabled)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 23131e6166dce204582bbedc8511658e
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
using ProjectM.Simulation;
|
|
||||||
using Unity.Entities;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace ProjectM.Authoring
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Authoring for a Fabricator machine ghost prefab. Bakes <see cref="PlacedStructure"/>{Type=Fabricator} +
|
|
||||||
/// <see cref="Fabricator"/> recipe + a (kept) empty <see cref="MachineInput"/> buffer — the production query
|
|
||||||
/// needs the buffer as a column, but a ledger-fed Fabricator ignores it. It deposits its output directly into
|
|
||||||
/// the GLOBAL ledger, so it needs no output buffer. Default recipe (EB-2): 1 Ore -> 3 Charge, ledger-fed
|
|
||||||
/// (<see cref="Fabricator.InputFromLedger"/> != 0) — mints the turret-ammo Charge that <c>TurretFireSystem</c>
|
|
||||||
/// spends per shot.
|
|
||||||
/// </summary>
|
|
||||||
public class FabricatorAuthoring : MonoBehaviour
|
|
||||||
{
|
|
||||||
[Tooltip("Input resource id consumed per run (1=Aether, 2=Ore, 3=Biomass).")]
|
|
||||||
public byte InResourceId = ResourceId.Ore;
|
|
||||||
[Min(1)] public int InAmount = 1;
|
|
||||||
[Tooltip("Output resource id deposited to the global ledger (4 = EB-2 Charge / turret ammo).")]
|
|
||||||
public byte OutResourceId = ResourceId.Charge;
|
|
||||||
[Min(1)] public int OutAmount = 3;
|
|
||||||
[Min(1)] public int PeriodTicks = 30;
|
|
||||||
[Tooltip("EB-2: 1 = ledger-fed (consume the input from the shared ledger; no conveyor). 0 = M7 MachineInput chain.")]
|
|
||||||
public byte InputFromLedger = 1;
|
|
||||||
[Min(1f)] public float MaxHp = 120f;
|
|
||||||
|
|
||||||
private class FabricatorBaker : Baker<FabricatorAuthoring>
|
|
||||||
{
|
|
||||||
public override void Bake(FabricatorAuthoring authoring)
|
|
||||||
{
|
|
||||||
var entity = GetEntity(authoring, TransformUsageFlags.Dynamic);
|
|
||||||
this.AddPlacedStructure(entity, StructureType.Fabricator);
|
|
||||||
AddComponent(entity, new Fabricator
|
|
||||||
{
|
|
||||||
InResourceId = authoring.InResourceId,
|
|
||||||
InAmount = authoring.InAmount,
|
|
||||||
OutResourceId = authoring.OutResourceId,
|
|
||||||
OutAmount = authoring.OutAmount,
|
|
||||||
PeriodTicks = authoring.PeriodTicks,
|
|
||||||
InputFromLedger = authoring.InputFromLedger,
|
|
||||||
});
|
|
||||||
AddBuffer<MachineInput>(entity);
|
|
||||||
// EB-1 parity (DR-032): machines can die. Without Health this baker left the Fabricator OUT of
|
|
||||||
// the EnemyAISystem fortress-aggro snapshot entirely (its query keys on Health) — an invulnerable
|
|
||||||
// machine, diverging from DR-032. Now that it IS targetable, the DamageEvent buffer must exist
|
|
||||||
// (an AI strike appends into it; absent = ECB-playback throw) + Destructible lets
|
|
||||||
// HealthApplyDamageSystem destroy it at 0 (occupancy auto-frees).
|
|
||||||
this.AddDamageable(entity, authoring.MaxHp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 014833c467fb1d6499f437b7bf76db80
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
using ProjectM.Simulation;
|
|
||||||
using Unity.Entities;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace ProjectM.Authoring
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Authoring for a Harvester machine ghost prefab (duplicate a structure ghost so the ownerless interpolated
|
|
||||||
/// GhostAuthoringComponent comes free). Bakes <see cref="PlacedStructure"/>{Type=Harvester} + <see cref="Harvester"/>
|
|
||||||
/// stats + an empty <see cref="MachineOutput"/> buffer. BuildPlaceSystem stamps the Cell at placement; the
|
|
||||||
/// production system initializes the tick baseline on first encounter (NextTick/LastProcessedTick baked 0).
|
|
||||||
/// </summary>
|
|
||||||
public class HarvesterAuthoring : MonoBehaviour
|
|
||||||
{
|
|
||||||
[Tooltip("Resource id this generator produces (1=Aether, 2=Ore, 3=Biomass).")]
|
|
||||||
public byte OutputResourceId = ResourceId.Ore;
|
|
||||||
[Min(1)] public int Yield = 1;
|
|
||||||
[Min(1)] public int PeriodTicks = 60;
|
|
||||||
|
|
||||||
private class HarvesterBaker : Baker<HarvesterAuthoring>
|
|
||||||
{
|
|
||||||
public override void Bake(HarvesterAuthoring authoring)
|
|
||||||
{
|
|
||||||
var entity = GetEntity(authoring, TransformUsageFlags.Dynamic);
|
|
||||||
this.AddPlacedStructure(entity, StructureType.Harvester);
|
|
||||||
AddComponent(entity, new Harvester
|
|
||||||
{
|
|
||||||
ResourceId = authoring.OutputResourceId,
|
|
||||||
Yield = authoring.Yield,
|
|
||||||
PeriodTicks = authoring.PeriodTicks,
|
|
||||||
});
|
|
||||||
AddBuffer<MachineOutput>(entity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: d69d7296747332b4fbe7901ec5210149
|
|
||||||
@@ -6,21 +6,13 @@ using UnityEngine.Serialization;
|
|||||||
namespace ProjectM.Authoring
|
namespace ProjectM.Authoring
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Authoring for the baked <see cref="StructureCatalog"/> singleton (the build cost/prefab table). For the
|
/// Authoring for the baked <see cref="StructureCatalog"/> singleton (the build cost/prefab table). Flat
|
||||||
/// M6 foundation there is one buildable type (Turret), so the entry is flat fields — only the prefab
|
/// prefab + cost fields per buildable type (the type + cost-resource are byte consts in the baker —
|
||||||
/// object-ref + cost amount need inspector wiring; the type + cost-resource are byte consts in the baker
|
/// enum-via-MCP is unreliable, and bytes dodge the cross-assembly enum-in-Burst hazard); the runtime
|
||||||
/// (enum-via-MCP is unreliable, and bytes dodge the cross-assembly enum-in-Burst hazard). M7 generalizes to
|
/// <see cref="StructureCatalogEntry"/> buffer is the data-driven shape. Place once in the gameplay subscene.
|
||||||
/// an array; the runtime <see cref="StructureCatalogEntry"/> buffer is already the data-driven shape. Place
|
|
||||||
/// once in the gameplay subscene.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class StructureCatalogAuthoring : MonoBehaviour
|
public class StructureCatalogAuthoring : MonoBehaviour
|
||||||
{
|
{
|
||||||
[Tooltip("Turret structure ghost prefab (TurretAuthoring + GhostAuthoring).")]
|
|
||||||
public GameObject TurretPrefab;
|
|
||||||
|
|
||||||
[Tooltip("Ore cost to build a turret.")]
|
|
||||||
[Min(0)] public int TurretCostOre = 40; // DR-042 combat pass: was 10 (~1/3 node) -> 40 (~1.3 nodes); a real investment
|
|
||||||
|
|
||||||
[Tooltip("Wall structure ghost prefab (StructureAuthoring{Wall} + GhostAuthoring).")]
|
[Tooltip("Wall structure ghost prefab (StructureAuthoring{Wall} + GhostAuthoring).")]
|
||||||
public GameObject WallPrefab;
|
public GameObject WallPrefab;
|
||||||
|
|
||||||
@@ -33,18 +25,6 @@ namespace ProjectM.Authoring
|
|||||||
[Tooltip("Ore cost to build a pylon.")]
|
[Tooltip("Ore cost to build a pylon.")]
|
||||||
[Min(0)] public int PylonCostOre = 2;
|
[Min(0)] public int PylonCostOre = 2;
|
||||||
|
|
||||||
[Tooltip("Harvester machine ghost prefab (HarvesterAuthoring + GhostAuthoring).")]
|
|
||||||
public GameObject HarvesterPrefab;
|
|
||||||
[Min(0)] public int HarvesterCostOre = 20;
|
|
||||||
|
|
||||||
[Tooltip("Fabricator machine ghost prefab (FabricatorAuthoring + GhostAuthoring).")]
|
|
||||||
public GameObject FabricatorPrefab;
|
|
||||||
[Min(0)] public int FabricatorCostOre = 30;
|
|
||||||
|
|
||||||
[Tooltip("Conveyor belt ghost prefab (ConveyorAuthoring + GhostAuthoring).")]
|
|
||||||
public GameObject ConveyorPrefab;
|
|
||||||
[Min(0)] public int ConveyorCostOre = 2;
|
|
||||||
|
|
||||||
private class StructureCatalogBaker : Baker<StructureCatalogAuthoring>
|
private class StructureCatalogBaker : Baker<StructureCatalogAuthoring>
|
||||||
{
|
{
|
||||||
public override void Bake(StructureCatalogAuthoring authoring)
|
public override void Bake(StructureCatalogAuthoring authoring)
|
||||||
@@ -53,16 +33,6 @@ namespace ProjectM.Authoring
|
|||||||
AddComponent<StructureCatalog>(entity);
|
AddComponent<StructureCatalog>(entity);
|
||||||
var buf = AddBuffer<StructureCatalogEntry>(entity);
|
var buf = AddBuffer<StructureCatalogEntry>(entity);
|
||||||
|
|
||||||
if (authoring.TurretPrefab != null)
|
|
||||||
{
|
|
||||||
buf.Add(new StructureCatalogEntry
|
|
||||||
{
|
|
||||||
Type = StructureType.Turret,
|
|
||||||
Prefab = GetEntity(authoring.TurretPrefab, TransformUsageFlags.Dynamic),
|
|
||||||
CostResourceId = ResourceId.Ore,
|
|
||||||
CostAmount = authoring.TurretCostOre,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (authoring.WallPrefab != null)
|
if (authoring.WallPrefab != null)
|
||||||
{
|
{
|
||||||
buf.Add(new StructureCatalogEntry
|
buf.Add(new StructureCatalogEntry
|
||||||
@@ -84,40 +54,6 @@ namespace ProjectM.Authoring
|
|||||||
CostAmount = authoring.PylonCostOre,
|
CostAmount = authoring.PylonCostOre,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (authoring.HarvesterPrefab != null)
|
|
||||||
{
|
|
||||||
buf.Add(new StructureCatalogEntry
|
|
||||||
{
|
|
||||||
Type = StructureType.Harvester,
|
|
||||||
Prefab = GetEntity(authoring.HarvesterPrefab, TransformUsageFlags.Dynamic),
|
|
||||||
CostResourceId = ResourceId.Ore,
|
|
||||||
CostAmount = authoring.HarvesterCostOre,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (authoring.FabricatorPrefab != null)
|
|
||||||
{
|
|
||||||
buf.Add(new StructureCatalogEntry
|
|
||||||
{
|
|
||||||
Type = StructureType.Fabricator,
|
|
||||||
Prefab = GetEntity(authoring.FabricatorPrefab, TransformUsageFlags.Dynamic),
|
|
||||||
CostResourceId = ResourceId.Ore,
|
|
||||||
CostAmount = authoring.FabricatorCostOre,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (authoring.ConveyorPrefab != null)
|
|
||||||
{
|
|
||||||
buf.Add(new StructureCatalogEntry
|
|
||||||
{
|
|
||||||
Type = StructureType.Conveyor,
|
|
||||||
Prefab = GetEntity(authoring.ConveyorPrefab, TransformUsageFlags.Dynamic),
|
|
||||||
CostResourceId = ResourceId.Ore,
|
|
||||||
CostAmount = authoring.ConveyorCostOre,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,39 +0,0 @@
|
|||||||
using ProjectM.Simulation;
|
|
||||||
using Unity.Entities;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace ProjectM.Authoring
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Authoring for the turret structure ghost prefab (duplicate UpgradePickup.prefab so the ownerless
|
|
||||||
/// interpolated GhostAuthoringComponent comes free). Bakes <see cref="PlacedStructure"/>{Type=Turret} +
|
|
||||||
/// <see cref="Turret"/> stats. BuildPlaceSystem stamps Cell + LastProcessedTick at placement.
|
|
||||||
/// </summary>
|
|
||||||
public class TurretAuthoring : MonoBehaviour
|
|
||||||
{
|
|
||||||
[Min(1f)] public float Range = 10f;
|
|
||||||
[Min(1)] public int CooldownTicks = 30;
|
|
||||||
[Min(1f)] public float Damage = 12f;
|
|
||||||
[Min(1f)] public float MaxHp = 120f;
|
|
||||||
|
|
||||||
private class TurretBaker : Baker<TurretAuthoring>
|
|
||||||
{
|
|
||||||
public override void Bake(TurretAuthoring authoring)
|
|
||||||
{
|
|
||||||
var entity = GetEntity(authoring, TransformUsageFlags.Dynamic);
|
|
||||||
this.AddPlacedStructure(entity, StructureType.Turret);
|
|
||||||
AddComponent(entity, new Turret
|
|
||||||
{
|
|
||||||
Range = authoring.Range,
|
|
||||||
CooldownTicks = authoring.CooldownTicks,
|
|
||||||
Damage = authoring.Damage,
|
|
||||||
});
|
|
||||||
// EB-1: structures are damageable + destructible (Husks push for them; HealthApplyDamageSystem
|
|
||||||
// destroys a Destructible at Health<=0). The DamageEvent buffer MUST exist on the archetype or an
|
|
||||||
// AI/turret strike crashes at ECB playback. NO HitRadius on purpose -> ProjectileDamageSystem (needs
|
|
||||||
// Health+HitRadius) ignores structures, so player shots never friendly-fire your own turret.
|
|
||||||
this.AddDamageable(entity, authoring.MaxHp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: dfb1e0820cbf41b4bbbe99066dfadd40
|
|
||||||
@@ -19,7 +19,7 @@ namespace ProjectM.Authoring
|
|||||||
[Tooltip("All ability definitions available in the game. Indexed at runtime by AbilityId.")]
|
[Tooltip("All ability definitions available in the game. Indexed at runtime by AbilityId.")]
|
||||||
public List<AbilityDefinition> Abilities = new List<AbilityDefinition>();
|
public List<AbilityDefinition> Abilities = new List<AbilityDefinition>();
|
||||||
|
|
||||||
[Tooltip("All character-stats definitions. Indexed at runtime by CharacterId.")]
|
[Tooltip("All character-stats definitions. Indexed at runtime by FrameKind.")]
|
||||||
public List<CharacterStatsDefinition> Characters = new List<CharacterStatsDefinition>();
|
public List<CharacterStatsDefinition> Characters = new List<CharacterStatsDefinition>();
|
||||||
|
|
||||||
private class DatabaseBaker : Baker<AbilityDatabaseAuthoring>
|
private class DatabaseBaker : Baker<AbilityDatabaseAuthoring>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ namespace ProjectM.Authoring
|
|||||||
[CreateAssetMenu(menuName = "Project M/Character Stats Definition", fileName = "Character_")]
|
[CreateAssetMenu(menuName = "Project M/Character Stats Definition", fileName = "Character_")]
|
||||||
public class CharacterStatsDefinition : ScriptableObject
|
public class CharacterStatsDefinition : ScriptableObject
|
||||||
{
|
{
|
||||||
public CharacterId Id = CharacterId.Default;
|
public FrameKind Id = FrameKind.Default;
|
||||||
public string DisplayName = "Character";
|
public string DisplayName = "Character";
|
||||||
|
|
||||||
[Min(0f)] public float MoveSpeed = 6f;
|
[Min(0f)] public float MoveSpeed = 6f;
|
||||||
|
|||||||
@@ -41,7 +41,6 @@ namespace ProjectM.Authoring
|
|||||||
Tier = def.Tier,
|
Tier = def.Tier,
|
||||||
StackMax = def.StackMax,
|
StackMax = def.StackMax,
|
||||||
EquipSlot = def.EquipSlot,
|
EquipSlot = def.EquipSlot,
|
||||||
GrantedAbilityId = def.GrantedAbilityId,
|
|
||||||
Mod0 = ModAt(def, 0),
|
Mod0 = ModAt(def, 0),
|
||||||
Mod1 = ModAt(def, 1),
|
Mod1 = ModAt(def, 1),
|
||||||
Mod2 = ModAt(def, 2),
|
Mod2 = ModAt(def, 2),
|
||||||
|
|||||||
@@ -33,9 +33,6 @@ namespace ProjectM.Authoring
|
|||||||
[Tooltip("EquipSlotId byte: 0=Weapon, 1=Armor, 2=Trinket, 3=Tool, 255=not equippable.")]
|
[Tooltip("EquipSlotId byte: 0=Weapon, 1=Armor, 2=Trinket, 3=Tool, 255=not equippable.")]
|
||||||
public byte EquipSlot = 255;
|
public byte EquipSlot = 255;
|
||||||
|
|
||||||
[Tooltip("AbilityId granted when equipped in the Weapon slot (0=none): 1=Primary, 2=FastLight, 3=SlowHeavy.")]
|
|
||||||
public byte GrantedAbilityId = 0;
|
|
||||||
|
|
||||||
[Tooltip("Stat modifiers granted while equipped (first 4 used).")]
|
[Tooltip("Stat modifiers granted while equipped (first 4 used).")]
|
||||||
public List<ItemModAuthoring> Mods = new List<ItemModAuthoring>();
|
public List<ItemModAuthoring> Mods = new List<ItemModAuthoring>();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,9 +19,6 @@ namespace ProjectM.Authoring
|
|||||||
[Tooltip("Character-stats definition (move speed, turn rate, max health). Single source of those values.")]
|
[Tooltip("Character-stats definition (move speed, turn rate, max health). Single source of those values.")]
|
||||||
public CharacterStatsDefinition Character;
|
public CharacterStatsDefinition Character;
|
||||||
|
|
||||||
[Tooltip("Ability definition occupying the player's primary slot.")]
|
|
||||||
public AbilityDefinition PrimaryAbility;
|
|
||||||
|
|
||||||
[Header("Fallbacks (used only if a definition above is unassigned)")]
|
[Header("Fallbacks (used only if a definition above is unassigned)")]
|
||||||
[Min(0f)] public float FallbackMaxHealth = 100f;
|
[Min(0f)] public float FallbackMaxHealth = 100f;
|
||||||
|
|
||||||
@@ -42,14 +39,11 @@ namespace ProjectM.Authoring
|
|||||||
{
|
{
|
||||||
var entity = GetEntity(authoring, TransformUsageFlags.Dynamic);
|
var entity = GetEntity(authoring, TransformUsageFlags.Dynamic);
|
||||||
|
|
||||||
// Re-bake when a referenced definition's serialized values change.
|
// Re-bake when the referenced definition's serialized values change.
|
||||||
if (authoring.Character != null) DependsOn(authoring.Character);
|
if (authoring.Character != null) DependsOn(authoring.Character);
|
||||||
if (authoring.PrimaryAbility != null) DependsOn(authoring.PrimaryAbility);
|
|
||||||
|
|
||||||
byte characterId = authoring.Character != null
|
byte characterId = authoring.Character != null
|
||||||
? (byte)authoring.Character.Id : (byte)CharacterId.Default;
|
? (byte)authoring.Character.Id : (byte)FrameKind.Default;
|
||||||
byte abilityId = authoring.PrimaryAbility != null
|
|
||||||
? (byte)authoring.PrimaryAbility.Id : (byte)AbilityId.Primary;
|
|
||||||
float maxHealth = authoring.Character != null
|
float maxHealth = authoring.Character != null
|
||||||
? authoring.Character.MaxHealth : authoring.FallbackMaxHealth;
|
? authoring.Character.MaxHealth : authoring.FallbackMaxHealth;
|
||||||
|
|
||||||
@@ -57,14 +51,11 @@ namespace ProjectM.Authoring
|
|||||||
AddComponent<PlayerFacing>(entity);
|
AddComponent<PlayerFacing>(entity);
|
||||||
AddComponent<PlayerInput>(entity);
|
AddComponent<PlayerInput>(entity);
|
||||||
|
|
||||||
// Data-driven stat refs (replace M2's inlined PlayerMoveStats / AbilityStats values).
|
// Data-driven stat ref (replaces M2's inlined PlayerMoveStats values); the ability model is the
|
||||||
|
// 4-socket kit below (the legacy AbilityRef/DefaultAbility/EffectiveAbilityStats bakes are deleted).
|
||||||
AddComponent(entity, new CharacterStatsRef { Id = characterId });
|
AddComponent(entity, new CharacterStatsRef { Id = characterId });
|
||||||
AddComponent(entity, new AbilityRef { Id = abilityId });
|
|
||||||
// Unarmed/base ability restored on weapon-unequip (AbilityRef.Id mutates when a weapon is equipped).
|
|
||||||
AddComponent(entity, new DefaultAbility { Id = abilityId });
|
|
||||||
|
|
||||||
// Effective stats: zeroed at bake, recomputed every predicted tick by StatRecomputeSystem.
|
// Effective stats: zeroed at bake, recomputed every predicted tick by StatRecomputeSystem.
|
||||||
AddComponent(entity, new EffectiveAbilityStats());
|
|
||||||
AddComponent(entity, new EffectiveCharacterStats());
|
AddComponent(entity, new EffectiveCharacterStats());
|
||||||
|
|
||||||
// Empty replicated modifier stack (grown by upgrades/pickups/debug hook, server-authoritative).
|
// Empty replicated modifier stack (grown by upgrades/pickups/debug hook, server-authoritative).
|
||||||
@@ -82,7 +73,6 @@ namespace ProjectM.Authoring
|
|||||||
// damageable hit radius, predicted cooldown state, and the per-tick damage inbox.
|
// damageable hit radius, predicted cooldown state, and the per-tick damage inbox.
|
||||||
AddComponent(entity, new Health { Current = maxHealth, Max = maxHealth });
|
AddComponent(entity, new Health { Current = maxHealth, Max = maxHealth });
|
||||||
AddComponent(entity, new HitRadius { Value = authoring.HitRadius });
|
AddComponent(entity, new HitRadius { Value = authoring.HitRadius });
|
||||||
AddComponent<AbilityCooldown>(entity);
|
|
||||||
AddBuffer<DamageEvent>(entity);
|
AddBuffer<DamageEvent>(entity);
|
||||||
// MC-1 dash: predicted dash window (derived from PlayerInput.Dash) + cooldown gate, baked idle/ready.
|
// MC-1 dash: predicted dash window (derived from PlayerInput.Dash) + cooldown gate, baked idle/ready.
|
||||||
AddComponent<DashState>(entity);
|
AddComponent<DashState>(entity);
|
||||||
@@ -110,17 +100,17 @@ namespace ProjectM.Authoring
|
|||||||
// the Returning edge) + the server-only Blade-Dash per-dash dedup accumulator (non-replicated).
|
// the Returning edge) + the server-only Blade-Dash per-dash dedup accumulator (non-replicated).
|
||||||
AddComponent<BoonEffects>(entity);
|
AddComponent<BoonEffects>(entity);
|
||||||
AddComponent<DashTrailState>(entity);
|
AddComponent<DashTrailState>(entity);
|
||||||
// LANTERN Phase 1 (Step 1): 4-socket kit data model - parallels AbilityRef/AbilityCooldown
|
// LANTERN Phase 1 (Step 1): 4-socket kit data model — THE ability model (the legacy single
|
||||||
// (both kept until the AbilityFireSystem migration in Step 2). AbilitySocket = cold per-socket
|
// AbilityRef/AbilityCooldown path is deleted). AbilitySocket = cold per-socket loadout
|
||||||
// loadout (EquipmentSlot-modelled, 4 empty rows); SocketCooldown = hot owner-predicted per-socket
|
// (EquipmentSlot-modelled, 4 empty rows; GoInGameServerSystem seeds the frame loadout at spawn);
|
||||||
// cooldown; FrameId = replicated frame/class signal (baked 0, written server-side at frame select).
|
// SocketCooldown = hot owner-predicted per-socket cooldown; FrameId = replicated frame/class signal
|
||||||
|
// (baked 0, written server-side at frame select).
|
||||||
var sockets = AddBuffer<AbilitySocket>(entity);
|
var sockets = AddBuffer<AbilitySocket>(entity);
|
||||||
for (int sk = 0; sk < SocketId.Count; sk++)
|
for (int sk = 0; sk < SocketId.Count; sk++)
|
||||||
sockets.Add(new AbilitySocket { SparkId = 0 });
|
sockets.Add(new AbilitySocket { SparkId = 0 });
|
||||||
AddComponent<SocketCooldown>(entity);
|
AddComponent<SocketCooldown>(entity);
|
||||||
AddComponent<FrameId>(entity);
|
AddComponent<FrameId>(entity);
|
||||||
// Step 1b: per-socket effective-stats buffer (4 rows), folded each predicted tick by
|
// Step 1b: per-socket effective-stats buffer (4 rows), folded each predicted tick by StatRecomputeSystem.
|
||||||
// StatRecomputeSystem (additive; the legacy single EffectiveAbilityStats stays until steps 2/2.5).
|
|
||||||
var effSockets = AddBuffer<EffectiveSocketStats>(entity);
|
var effSockets = AddBuffer<EffectiveSocketStats>(entity);
|
||||||
for (int sk2 = 0; sk2 < SocketId.Count; sk2++)
|
for (int sk2 = 0; sk2 < SocketId.Count; sk2++)
|
||||||
effSockets.Add(new EffectiveSocketStats());
|
effSockets.Add(new EffectiveSocketStats());
|
||||||
|
|||||||
@@ -5,99 +5,33 @@ using UnityEngine;
|
|||||||
namespace ProjectM.Authoring
|
namespace ProjectM.Authoring
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Authoring for the GLOBAL cycle-director ghost prefab: an ownerless INTERPOLATED ghost (the
|
/// Authoring for the GLOBAL director ghost prefab: an ownerless INTERPOLATED ghost (the
|
||||||
/// GhostAuthoringComponent is inherited when this prefab is duplicated from UpgradePickup.prefab) that
|
/// GhostAuthoringComponent is inherited when this prefab is duplicated from UpgradePickup.prefab) that
|
||||||
/// carries the replicated macro-loop state (<see cref="CycleState"/>) and the shared resource ledger
|
/// carries the shared resource ledger (a <see cref="StorageEntry"/> buffer marked by
|
||||||
/// (a <see cref="StorageEntry"/> buffer marked by <see cref="ResourceLedger"/>). It is GLOBAL — it must
|
/// <see cref="ResourceLedger"/>), the replicated run-lifecycle FSM (<see cref="RunInfo"/>), the
|
||||||
|
/// expedition-objective readout, and the per-class permanent-meta tier buffer. It is GLOBAL — it must
|
||||||
/// carry NO <see cref="RegionTag"/> so GhostRelevancy keeps it relevant to every connection regardless of
|
/// carry NO <see cref="RegionTag"/> so GhostRelevancy keeps it relevant to every connection regardless of
|
||||||
/// region. The server CycleDirectorSpawnSystem overrides the baked CycleState at spawn (real PhaseEndTick)
|
/// region. (The old cycle/siege/goal/core state is retired — LANTERN purge.)
|
||||||
/// and adds the server-only CycleRuntime.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class CycleDirectorAuthoring : MonoBehaviour
|
public class CycleDirectorAuthoring : MonoBehaviour
|
||||||
{
|
{
|
||||||
[Header("Threat — post-expedition retaliation")]
|
|
||||||
[Tooltip("A completed expedition (a player returning to base) can draw a retaliation siege.")]
|
|
||||||
public bool PostExpeditionEnabled = true;
|
|
||||||
|
|
||||||
[Tooltip("Telegraph/arming delay (server ticks @60) between the return and the siege spawning.")]
|
|
||||||
public uint PostExpeditionDelayTicks = 300;
|
|
||||||
|
|
||||||
[Tooltip("Siege size floor (Husk count) for a post-expedition retaliation.")]
|
|
||||||
[Min(0)] public int SiegeSizeBase = 5;
|
|
||||||
|
|
||||||
[Tooltip("Extra Husks per unit of resources hauled back this run (0 = flat SiegeSizeBase).")]
|
|
||||||
[Min(0)] public int SiegeSizePerResource = 0;
|
|
||||||
|
|
||||||
[Tooltip("Max server ticks a siege may run before it auto-collapses (no soft-lock). 0 = no cap.")]
|
|
||||||
public uint SiegeTimeoutTicks = 3600;
|
|
||||||
[Header("Threat — scheduled base sieges (DR-042: DISABLED — reserved/inert hook)")]
|
|
||||||
[Tooltip("DR-042: OFF. A blind timed cadence was the AFK win path (auto-armed sieges the SiegeTimeout auto-cleared). The win-driver is now expedition clears; base sieges are post-expedition retaliation only. Code path kept as a config-inert reserved hook.")]
|
|
||||||
public bool ScheduleEnabled = false;
|
|
||||||
|
|
||||||
[Tooltip("Server ticks (@60) between scheduled base sieges. First fire is one interval out (mine/build grace).")]
|
|
||||||
public uint ScheduleIntervalTicks = 2700;
|
|
||||||
|
|
||||||
[Tooltip("Extra Husks per surviving wave (siege size = SiegeSizeBase + this * WaveNumber). 0 = flat.")]
|
|
||||||
[Min(0)] public int ScheduleSizePerWave = 1;
|
|
||||||
|
|
||||||
[Header("Endgame — Engine Core (END-1)")]
|
|
||||||
[Tooltip("Baked integrity ceiling of the losable Engine Core. Current is born full (or the persisted wounded value on Continue).")]
|
|
||||||
[Min(1)] public int CoreIntegrityMax = 100;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private class CycleDirectorBaker : Baker<CycleDirectorAuthoring>
|
private class CycleDirectorBaker : Baker<CycleDirectorAuthoring>
|
||||||
{
|
{
|
||||||
public override void Bake(CycleDirectorAuthoring authoring)
|
public override void Bake(CycleDirectorAuthoring authoring)
|
||||||
{
|
{
|
||||||
var entity = GetEntity(authoring, TransformUsageFlags.Dynamic);
|
var entity = GetEntity(authoring, TransformUsageFlags.Dynamic);
|
||||||
AddComponent(entity, new CycleState
|
|
||||||
{
|
|
||||||
Phase = CyclePhase.Calm,
|
|
||||||
CycleNumber = 1,
|
|
||||||
PhaseEndTick = 0u,
|
|
||||||
});
|
|
||||||
AddComponent<ResourceLedger>(entity);
|
AddComponent<ResourceLedger>(entity);
|
||||||
AddBuffer<StorageEntry>(entity);
|
AddBuffer<StorageEntry>(entity);
|
||||||
AddComponent(entity, new GoalProgress { Charge = 0, Target = 2 }); // DR-044 demo pacing: 2 expedition clears -> the climactic final siege (~10-20 min hands-off run)
|
|
||||||
// END-1: the losable Engine Core rides this GLOBAL ghost (no new ghost / no relevancy). Born full;
|
|
||||||
// CycleDirectorSpawnSystem overrides Current with a persisted wounded value on Continue.
|
|
||||||
AddComponent(entity, new CoreIntegrity
|
|
||||||
{
|
|
||||||
Current = authoring.CoreIntegrityMax,
|
|
||||||
Max = authoring.CoreIntegrityMax,
|
|
||||||
OverrunTick = 0u,
|
|
||||||
});
|
|
||||||
// END-2: the terminal run outcome is REPLICATED ([GhostField]) so the client HUD shows the win/loss
|
|
||||||
// banner by observing it. Baked here -> part of the ghost serializer (one re-bake). Born InProgress;
|
|
||||||
// CycleDirectorSpawnSystem overrides it with a persisted Victory/Loss on Continue.
|
|
||||||
AddComponent(entity, new RunOutcome { Value = RunOutcomeId.InProgress });
|
|
||||||
|
|
||||||
// DR-042 C7b: replicated expedition-objective summary (the HUD 'enemies remaining / cleared' readout).
|
// DR-042 C7b: replicated expedition-objective summary (the HUD 'enemies remaining / cleared' readout).
|
||||||
// Born Idle; ZoneEnemyDirectorSystem is the sole writer. New [GhostField] component -> re-hashes the
|
// Born Idle; RoomEnemyDirectorSystem is the sole writer.
|
||||||
// runtime-spawned director ghost (server + client bake the same prefab -> hash matches), like CoreIntegrity.
|
|
||||||
AddComponent(entity, new ExpeditionObjective { State = ExpeditionObjectiveState.Idle, Remaining = 0 });
|
AddComponent(entity, new ExpeditionObjective { State = ExpeditionObjectiveState.Idle, Remaining = 0 });
|
||||||
|
|
||||||
// Expedition redesign: the replicated run-lifecycle FSM (RunInfo, 17 [GhostField]s) + the per-class
|
// Expedition redesign: the replicated run-lifecycle FSM (RunInfo) + the per-class permanent-meta
|
||||||
// permanent-meta tier buffer (MetaTierState) BOTH land in this ONE coordinated re-bake (front-loaded
|
// tier buffer (MetaTierState). Born Staging/empty; server RunDirectorSystem / MetaSpendSystem are
|
||||||
// ghost layout — the writer systems arrive across Steps 2–13 while the state sits inert/default).
|
// the sole writers.
|
||||||
// Born Staging/empty; server RunDirectorSystem / MetaSpendSystem are the sole writers.
|
|
||||||
AddComponent(entity, new RunInfo { Lifecycle = RunLifecycle.Staging });
|
AddComponent(entity, new RunInfo { Lifecycle = RunLifecycle.Staging });
|
||||||
AddBuffer<MetaTierState>(entity);
|
AddBuffer<MetaTierState>(entity);
|
||||||
|
|
||||||
|
|
||||||
AddComponent(entity, new ThreatConfig
|
|
||||||
{
|
|
||||||
PostExpeditionEnabled = (byte)(authoring.PostExpeditionEnabled ? 1 : 0),
|
|
||||||
PostExpeditionDelayTicks = authoring.PostExpeditionDelayTicks,
|
|
||||||
SizeBase = authoring.SiegeSizeBase,
|
|
||||||
SizePerExpeditionResource = authoring.SiegeSizePerResource,
|
|
||||||
StartCondition = ThreatStartCondition.Immediate,
|
|
||||||
SiegeTimeoutTicks = authoring.SiegeTimeoutTicks,
|
|
||||||
ScheduleEnabled = (byte)(authoring.ScheduleEnabled ? 1 : 0),
|
|
||||||
ScheduleIntervalTicks = authoring.ScheduleIntervalTicks,
|
|
||||||
ScheduleSizePerWave = authoring.ScheduleSizePerWave,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,11 +27,9 @@ namespace ProjectM.Client
|
|||||||
// Dev hotkey fallback: key -> buildable.
|
// Dev hotkey fallback: key -> buildable.
|
||||||
static readonly (UnityEngine.InputSystem.Key Key, byte Type)[] s_BuildHotkeys =
|
static readonly (UnityEngine.InputSystem.Key Key, byte Type)[] s_BuildHotkeys =
|
||||||
{
|
{
|
||||||
(UnityEngine.InputSystem.Key.B, StructureType.Turret),
|
|
||||||
(UnityEngine.InputSystem.Key.V, StructureType.Wall),
|
(UnityEngine.InputSystem.Key.V, StructureType.Wall),
|
||||||
(UnityEngine.InputSystem.Key.F, StructureType.Fabricator),
|
// LANTERN purge: the automation buildables (Fabricator/Harvester/Conveyor) are deleted; Pylon stays
|
||||||
// DR-042 C6d: Pylon/Harvester/Conveyor are dead (unwired automation) — dropped from the hotkey fallback
|
// hidden from the hotkey fallback to match the build palette. PlaceStructure execute_code statics remain.
|
||||||
// to match the hidden build palette; their PlaceStructure execute_code statics remain for dev.
|
|
||||||
};
|
};
|
||||||
|
|
||||||
UnityEngine.Camera _camera; // cursor -> ground re-raycast for click-to-place (resolved lazily)
|
UnityEngine.Camera _camera; // cursor -> ground re-raycast for click-to-place (resolved lazily)
|
||||||
@@ -55,15 +53,10 @@ namespace ProjectM.Client
|
|||||||
public static void PlaceStructure(byte type, int cellX, int cellZ, byte direction = 0) =>
|
public static void PlaceStructure(byte type, int cellX, int cellZ, byte direction = 0) =>
|
||||||
s_PendingBuild.Enqueue(new PendingBuild { Type = type, CellX = cellX, CellZ = cellZ, Direction = direction });
|
s_PendingBuild.Enqueue(new PendingBuild { Type = type, CellX = cellX, CellZ = cellZ, Direction = direction });
|
||||||
|
|
||||||
/// <summary>EDITOR / execute_code hook: queue a turret placement at a specific cell.</summary>
|
|
||||||
public static void PlaceTurret(int cellX, int cellZ) => PlaceStructure(StructureType.Turret, cellX, cellZ);
|
|
||||||
|
|
||||||
/// <summary>EDITOR / execute_code hook: queue a wall placement at a specific cell.</summary>
|
/// <summary>EDITOR / execute_code hook: queue a wall placement at a specific cell.</summary>
|
||||||
public static void PlaceWall(int cellX, int cellZ) => PlaceStructure(StructureType.Wall, cellX, cellZ);
|
public static void PlaceWall(int cellX, int cellZ) => PlaceStructure(StructureType.Wall, cellX, cellZ);
|
||||||
|
|
||||||
/// <summary>EDITOR / execute_code hook: queue a fabricator placement at a specific cell.</summary>
|
|
||||||
public static void PlaceFabricator(int cellX, int cellZ) => PlaceStructure(StructureType.Fabricator, cellX, cellZ);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
protected override void OnCreate()
|
protected override void OnCreate()
|
||||||
|
|||||||
@@ -26,21 +26,18 @@ namespace ProjectM.Client
|
|||||||
=> s_Pending.Add(new Pending { Op = op, ArgA = argA, ArgB = argB });
|
=> s_Pending.Add(new Pending { Op = op, ArgA = argA, ArgB = argB });
|
||||||
|
|
||||||
// Convenience wrappers (overlay buttons + execute_code).
|
// Convenience wrappers (overlay buttons + execute_code).
|
||||||
public static void SpawnWave(int size) => Send(DebugOp.SpawnWave, size);
|
public static void SpawnWave() => Send(DebugOp.SpawnWave); // re-meant: force the next wave now
|
||||||
public static void EndSiege() => Send(DebugOp.EndSiege);
|
public static void StopWaves() => Send(DebugOp.EndSiege); // re-meant: quiet the arena (cull + delay waves)
|
||||||
public static void ClearEnemies() => Send(DebugOp.ClearEnemies);
|
public static void ClearEnemies() => Send(DebugOp.ClearEnemies);
|
||||||
public static void SetCalm() => Send(DebugOp.SetCalm);
|
|
||||||
public static void GrantResource(byte itemId, int count) => Send(DebugOp.GrantResource, itemId, count);
|
public static void GrantResource(byte itemId, int count) => Send(DebugOp.GrantResource, itemId, count);
|
||||||
public static void GrantUpgrade() => Send(DebugOp.GrantUpgrade);
|
public static void GrantUpgrade() => Send(DebugOp.GrantUpgrade);
|
||||||
public static void Teleport(byte region) => Send(DebugOp.Teleport, region);
|
public static void Teleport(byte region) => Send(DebugOp.Teleport, region);
|
||||||
public static void ToggleGod() => Send(DebugOp.ToggleGod);
|
public static void ToggleGod() => Send(DebugOp.ToggleGod);
|
||||||
public static void Heal() => Send(DebugOp.Heal);
|
public static void Heal() => Send(DebugOp.Heal);
|
||||||
public static void Kill() => Send(DebugOp.KillPlayer);
|
public static void Kill() => Send(DebugOp.KillPlayer);
|
||||||
public static void AdvanceGoal(int by) => Send(DebugOp.AdvanceGoal, by);
|
|
||||||
public static void SetHeat(int heat) => Send(DebugOp.SetHeat, heat);
|
|
||||||
/// <summary>Set the <see cref="ProjectM.Simulation.TuningKnob"/> knob to value (server-applied, x1000 fixed-point; MC-0).</summary>
|
/// <summary>Set the <see cref="ProjectM.Simulation.TuningKnob"/> knob to value (server-applied, x1000 fixed-point; MC-0).</summary>
|
||||||
public static void SetTuning(byte knob, float value) => Send(DebugOp.SetTuning, knob, Mathf.RoundToInt(value * 1000f));
|
public static void SetTuning(byte knob, float value) => Send(DebugOp.SetTuning, knob, Mathf.RoundToInt(value * 1000f));
|
||||||
/// <summary>Swap the sender's class to <paramref name="classId"/> (a <see cref="ProjectM.Simulation.CharacterId"/> byte); server-authoritative (class-switch dev tool).</summary>
|
/// <summary>Swap the sender's class to <paramref name="classId"/> (a <see cref="ProjectM.Simulation.FrameKind"/> byte); server-authoritative (class-switch dev tool).</summary>
|
||||||
public static void SetClass(byte classId) => Send(DebugOp.SetClass, classId);
|
public static void SetClass(byte classId) => Send(DebugOp.SetClass, classId);
|
||||||
public static void SetWarrior() => SetClass(ClassTraits.WarriorClass);
|
public static void SetWarrior() => SetClass(ClassTraits.WarriorClass);
|
||||||
public static void SetRanger() => SetClass(ClassTraits.RangerClass);
|
public static void SetRanger() => SetClass(ClassTraits.RangerClass);
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ namespace ProjectM.Client
|
|||||||
public class DebugOverlay : MonoBehaviour
|
public class DebugOverlay : MonoBehaviour
|
||||||
{
|
{
|
||||||
bool _open = true;
|
bool _open = true;
|
||||||
int _siegeSize = 5;
|
|
||||||
int _grantAmount = 50;
|
int _grantAmount = 50;
|
||||||
bool _tuningOpen;
|
bool _tuningOpen;
|
||||||
Vector2 _scroll;
|
Vector2 _scroll;
|
||||||
@@ -37,12 +36,9 @@ namespace ProjectM.Client
|
|||||||
_scroll = GUILayout.BeginScrollView(_scroll);
|
_scroll = GUILayout.BeginScrollView(_scroll);
|
||||||
|
|
||||||
GUILayout.Label("- World -");
|
GUILayout.Label("- World -");
|
||||||
_siegeSize = IntField("Siege size", _siegeSize);
|
if (GUILayout.Button("Force Next Wave")) DebugCommandSendSystem.SpawnWave();
|
||||||
if (GUILayout.Button("Spawn Wave / Force Siege")) DebugCommandSendSystem.SpawnWave(_siegeSize);
|
if (GUILayout.Button("Stop Waves")) DebugCommandSendSystem.StopWaves();
|
||||||
if (GUILayout.Button("End Siege")) DebugCommandSendSystem.EndSiege();
|
|
||||||
if (GUILayout.Button("Clear Enemies")) DebugCommandSendSystem.ClearEnemies();
|
if (GUILayout.Button("Clear Enemies")) DebugCommandSendSystem.ClearEnemies();
|
||||||
if (GUILayout.Button("Force Calm")) DebugCommandSendSystem.SetCalm();
|
|
||||||
if (GUILayout.Button("Advance Goal +1")) DebugCommandSendSystem.AdvanceGoal(1);
|
|
||||||
|
|
||||||
GUILayout.Space(6);
|
GUILayout.Space(6);
|
||||||
GUILayout.Label("- Resources -");
|
GUILayout.Label("- Resources -");
|
||||||
@@ -112,9 +108,6 @@ namespace ProjectM.Client
|
|||||||
TuningRow("Melee combo len", TuningKnob.MeleeComboLength, 1f, "0");
|
TuningRow("Melee combo len", TuningKnob.MeleeComboLength, 1f, "0");
|
||||||
GUILayout.Space(4);
|
GUILayout.Space(4);
|
||||||
TuningRow("Struct aggro w", TuningKnob.StructureAggroWeight, 0.1f, "0.00"); // EB-1: <1 prefers structures
|
TuningRow("Struct aggro w", TuningKnob.StructureAggroWeight, 0.1f, "0.00"); // EB-1: <1 prefers structures
|
||||||
TuningRow("Core dmg/husk", TuningKnob.CoreDamagePerHusk, 1f, "0"); // END-1: integrity per breaching Husk
|
|
||||||
TuningRow("Core regen int", TuningKnob.CoreRegenIntervalTicks, 1f, "0"); // END-1: ticks between +1 in Calm
|
|
||||||
TuningRow("Core overrun %", TuningKnob.CoreOverrunDrainPct, 0.05f, "0.00"); // END-1: ledger fraction lost on breach
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 0861914135cacf948ae2adfd7f7d6870
|
|
||||||
folderAsset: yes
|
|
||||||
DefaultImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace ProjectM.Client
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Tiny static coordination bridge for the first-run onboarding overlay. <see cref="Active"/> is true while a
|
|
||||||
/// coach-mark step is on screen (set each frame by <see cref="OnboardingSystem"/>); <see cref="HudSystem"/>
|
|
||||||
/// reads it to suppress its own ad-hoc location/gate hint so the player ever sees a single prompt voice.
|
|
||||||
/// A presentation-layer static, so it is RESET on play-enter (the CLAUDE.md stale-static rule) to avoid a
|
|
||||||
/// stale flag surviving a fast-enter-playmode domain reload and leaving the HUD hint suppressed.
|
|
||||||
/// </summary>
|
|
||||||
public static class OnboardingState
|
|
||||||
{
|
|
||||||
/// <summary>True while the coach-mark sequence is the active prompt voice (a step is being shown).</summary>
|
|
||||||
public static bool Active;
|
|
||||||
|
|
||||||
/// <summary>True only while an EARLY base-framing step (Welcome/Move/Build/Fabricator/ReadyUp) is showing, so
|
|
||||||
/// HudSystem blanks its own location line for those (the coach-mark owns the voice) but LEAVES the room/siege/
|
|
||||||
/// out-of-ammo cues visible during the combat steps (D4). Set each frame by OnboardingSystem.</summary>
|
|
||||||
public static bool SuppressLocationLine;
|
|
||||||
|
|
||||||
|
|
||||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
|
||||||
static void ResetOnPlayEnter() { Active = false; SuppressLocationLine = false; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 4e9b3bb074eef1c40b90591e85b90e32
|
|
||||||
@@ -1,145 +0,0 @@
|
|||||||
using ProjectM.Simulation;
|
|
||||||
|
|
||||||
namespace ProjectM.Client
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Pure, engine-free logic for the first-run onboarding coach-mark sequence — the testable core of
|
|
||||||
/// <see cref="OnboardingSystem"/> (mirrors the project's <c>*Math</c> helper discipline; no UnityEngine /
|
|
||||||
/// Entities types so it unit-tests as plain C#). Defines the ordered step list, a <see cref="Snapshot"/> of the
|
|
||||||
/// observable client state each step reads, the deterministic per-step completion test, prompt copy, the
|
|
||||||
/// spatial-cue kind, and the persisted-mask helpers.
|
|
||||||
///
|
|
||||||
/// RE-AUTHORED for the expedition redesign (demo polish): base nodes are gone (mining happens IN the run),
|
|
||||||
/// so the old at-base Mine step is dead — the first lap is now Build (grubstake Ore) → Fabricator →
|
|
||||||
/// READY UP → fight rooms (mine in-run) → boon → boss/return → defend. Step BITS are re-meant, never
|
|
||||||
/// renamed-in-place semantics: a veteran's full mask stays dormant; a partial first-run mask at worst
|
|
||||||
/// replays one beat.
|
|
||||||
///
|
|
||||||
/// Pacing (operator-locked = soft-gated): a step shows until its action is performed (no per-step timeout),
|
|
||||||
/// EXCEPT two info beats — <see cref="Fabricator"/> and <see cref="Defend"/> — which also auto-advance, plus
|
|
||||||
/// the timed <see cref="Welcome"/> strip. Veteran / co-op auto-suppress falls out for free: the count-based
|
|
||||||
/// steps (<see cref="Build"/>, <see cref="Fabricator"/>) test an ABSOLUTE structure count, so a client joining
|
|
||||||
/// an already-built base satisfies them on entry and skips straight past.
|
|
||||||
/// </summary>
|
|
||||||
public static class OnboardingStepMath
|
|
||||||
{
|
|
||||||
// ---- ordered steps (byte ids; bit i of GameSettings.OnboardingMask = step i complete) ----
|
|
||||||
public const byte Welcome = 0; // tiny win-condition framing strip (timed)
|
|
||||||
public const byte Move = 1;
|
|
||||||
public const byte Build = 2; // open palette + place a Turret (the 50-Ore grubstake covers it)
|
|
||||||
public const byte Fabricator = 3; // Ore -> Charge (soft info beat)
|
|
||||||
public const byte ReadyUp = 4; // press T / click READY — the party launches together
|
|
||||||
public const byte Rooms = 5; // fight the rooms; attack crystal nodes to haul resources
|
|
||||||
public const byte Boon = 6; // clear a room -> pick 1 of 3 boons + choose the path
|
|
||||||
public const byte Return = 7; // fell the boss — the haul + the Engine charge come home
|
|
||||||
public const byte Defend = 8; // survive the retaliation siege (soft info beat)
|
|
||||||
public const byte Done = 9; // closing beat
|
|
||||||
public const byte StepCount = 10;
|
|
||||||
|
|
||||||
// ---- tunable thresholds (public so the EditMode tests pin the contract) ----
|
|
||||||
public const float WelcomeSeconds = 5f;
|
|
||||||
public const float MoveThreshold = 3f; // accumulated player movement (world units)
|
|
||||||
public const float FabricatorSoftSeconds = 14f; // soft beat auto-advance if no Fabricator built
|
|
||||||
public const float DefendNoSiegeSeconds = 20f; // advance if no siege ever materialises
|
|
||||||
public const float DoneSeconds = 6f; // closing beat lingers before going dormant
|
|
||||||
public const float RoomsSeconds = 7f; // D2: keep the mine-the-crystals prompt + node pointer up a beat AFTER teleport (past the ~3s launch countdown -> ~4s in the room)
|
|
||||||
public const float ReturnMaxSeconds = 75f; // D3: soft backstop so a missed homecoming signal can NEVER stall the sequence
|
|
||||||
|
|
||||||
// ---- spatial-cue kinds the System resolves to a live world target ----
|
|
||||||
public const byte PointerNone = 0;
|
|
||||||
public const byte PointerOreNode = 1;
|
|
||||||
public const byte PointerBaseGate = 2; // RETIRED target (walk-in gate died with the redesign); byte kept
|
|
||||||
public const byte PointerExpeditionGate = 3; // RETIRED target; byte kept for mask/step stability
|
|
||||||
|
|
||||||
/// <summary>Observable client state for one evaluation. Built by the System from ECS + input each frame.</summary>
|
|
||||||
public struct Snapshot
|
|
||||||
{
|
|
||||||
public float StepElapsed; // seconds the current step has been shown
|
|
||||||
public float MoveDistance; // accumulated player movement since the Move step began
|
|
||||||
public int TurretCount; // live Turret structures (absolute)
|
|
||||||
public int FabricatorCount; // live Fabricator structures (absolute)
|
|
||||||
public bool LocalReady; // the LOCAL player's replicated PlayerReady flag
|
|
||||||
public byte Lifecycle; // replicated RunInfo.Lifecycle (RunLifecycle.*)
|
|
||||||
public bool OnExpedition; // local player is in the expedition region
|
|
||||||
public byte ObjectiveState; // ExpeditionObjective.State (Idle/Active/Cleared)
|
|
||||||
public bool SawSiege; // a Siege phase was observed while the Defend step was showing
|
|
||||||
public bool WasOnExpedition;// D3: latched true once the player was seen on expedition during the Return step (so a start-at-base Return doesn't instantly satisfy)
|
|
||||||
|
|
||||||
public byte Phase; // CycleState.Phase (Calm/Siege)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>True when the step's taught action is complete (or its soft timeout has elapsed).</summary>
|
|
||||||
public static bool IsSatisfied(byte step, in Snapshot s)
|
|
||||||
{
|
|
||||||
switch (step)
|
|
||||||
{
|
|
||||||
case Welcome: return s.StepElapsed >= WelcomeSeconds;
|
|
||||||
case Move: return s.MoveDistance >= MoveThreshold;
|
|
||||||
case Build: return s.TurretCount >= 1;
|
|
||||||
case Fabricator: return s.FabricatorCount >= 1 || s.StepElapsed >= FabricatorSoftSeconds;
|
|
||||||
case ReadyUp: return s.LocalReady || s.Lifecycle != RunLifecycle.Staging;
|
|
||||||
case Rooms: return s.OnExpedition && s.StepElapsed >= RoomsSeconds; // D2: show the mine prompt + node pointer IN the room, not the instant we teleport
|
|
||||||
case Boon: return s.ObjectiveState == ExpeditionObjectiveState.Cleared
|
|
||||||
|| s.Lifecycle == RunLifecycle.RoomReward
|
|
||||||
|| s.Lifecycle == RunLifecycle.RouteSelect;
|
|
||||||
case Return: return (s.WasOnExpedition && !s.OnExpedition) || s.StepElapsed >= ReturnMaxSeconds; // D3: home AFTER being on expedition, else a soft timeout (never gate on the 1-tick Returning edge)
|
|
||||||
case Defend: return s.SawSiege ? s.Phase == CyclePhase.Calm : s.StepElapsed >= DefendNoSiegeSeconds;
|
|
||||||
case Done: return s.StepElapsed >= DoneSeconds;
|
|
||||||
default: return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Which world target (if any) the prompt should point at this step.</summary>
|
|
||||||
public static byte PointerKind(byte step)
|
|
||||||
{
|
|
||||||
switch (step)
|
|
||||||
{
|
|
||||||
case Rooms: return PointerOreNode; // in-run crystal nodes (base nodes no longer exist)
|
|
||||||
default: return PointerNone;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Ultra-short, verb-first prompt copy with the player's real input glyph (scheme-aware).</summary>
|
|
||||||
public static string Prompt(byte step, bool gamepad)
|
|
||||||
{
|
|
||||||
string move = gamepad ? "Left Stick" : "WASD";
|
|
||||||
string build = gamepad ? "Y" : "Tab"; // matches the existing HUD build-discovery chip glyph
|
|
||||||
switch (step)
|
|
||||||
{
|
|
||||||
case Welcome: return "CLEAR 2 EXPEDITIONS to charge the Engine, then survive the FINAL SIEGE. (Space to continue · Esc → How to Play)";
|
|
||||||
case Move: return move + " — Move " + (gamepad ? "B" : "LShift") + " — Dash (brief invulnerability)";
|
|
||||||
case Build: return build + " — open Build, place a Turret by your Core (your " + ProjectM.Simulation.Tuning.StartingOre + " starting Ore covers it)";
|
|
||||||
case Fabricator: return "Build a Fabricator — turrets need Charge (Ore → ammo)";
|
|
||||||
case ReadyUp: return "Press T (or click READY UP) — when everyone is ready, the party launches";
|
|
||||||
case Rooms: return (gamepad ? "X attack · LT class ability" : "LMB attack · RMB class ability") + " — clear the room; shoot the glowing crystals for your haul";
|
|
||||||
case Boon: return "Clear the room — pick 1 of 3 BOONS, then choose your path on the map";
|
|
||||||
case Return: return "Fell the ALPHA HUSK, then return home — your haul + the Engine charge (+1) come with you";
|
|
||||||
case Defend: return "Defend the Core! — a completed run provokes a retaliation siege";
|
|
||||||
case Done: return "You've got it — clear 2 expeditions to fill the Engine, then hold the final siege to win.";
|
|
||||||
default: return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---- persisted-mask helpers (GameSettings.OnboardingMask) ----
|
|
||||||
|
|
||||||
/// <summary>D4: the early BASE-framing steps (the coach-mark owns the prompt voice, so the HUD blanks its own
|
|
||||||
/// location line) vs the combat steps (the HUD MUST keep showing room/siege/out-of-ammo cues). Welcome..ReadyUp
|
|
||||||
/// are early. Read each frame by OnboardingSystem to set OnboardingState.SuppressLocationLine.</summary>
|
|
||||||
public static bool IsEarlyStep(byte step) => step <= ReadyUp;
|
|
||||||
|
|
||||||
/// <summary>All steps complete (the sequence is dormant).</summary>
|
|
||||||
public static bool AllComplete(int mask)
|
|
||||||
{
|
|
||||||
int all = (1 << StepCount) - 1;
|
|
||||||
return (mask & all) == all;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>The lowest not-yet-completed step (resume point); <see cref="Done"/> when all are complete.</summary>
|
|
||||||
public static byte FirstIncomplete(int mask)
|
|
||||||
{
|
|
||||||
for (byte i = 0; i < StepCount; i++)
|
|
||||||
if ((mask & (1 << i)) == 0) return i;
|
|
||||||
return Done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: c264496096436e74ebba163a7a5d2205
|
|
||||||
@@ -1,332 +0,0 @@
|
|||||||
using ProjectM.Simulation;
|
|
||||||
using Unity.Entities;
|
|
||||||
using Unity.Mathematics;
|
|
||||||
using Unity.NetCode;
|
|
||||||
using Unity.Transforms;
|
|
||||||
using UnityEngine;
|
|
||||||
using UnityEngine.UIElements;
|
|
||||||
|
|
||||||
namespace ProjectM.Client
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// First-run onboarding overlay — a CLIENT-ONLY, observe-only presentation <see cref="SystemBase"/> in
|
|
||||||
/// <see cref="PresentationSystemGroup"/> (same shape/constraints as <see cref="HudSystem"/>: never mutates the
|
|
||||||
/// sim, never destroys a ghost, reads already-replicated state once per frame). Owns its own runtime UIDocument
|
|
||||||
/// (sortingOrder 60 — above the HUD's 50, below the pause overlay's 100) showing a single bottom-center
|
|
||||||
/// coach-mark prompt plus a world-space directional pointer.
|
|
||||||
///
|
|
||||||
/// The sequence is PER-CLIENT and client-local: progress lives in <see cref="GameSettings.OnboardingMask"/>
|
|
||||||
/// (via <see cref="SettingsService"/>), keyed to THIS player's own first-encounter — so a veteran host sees
|
|
||||||
/// nothing, a brand-new join-client is still taught, and a save wipe never re-teaches the host (the mask is in
|
|
||||||
/// settings.json, not the host-only SaveData). Soft-gated pacing: a step shows until its action is done; the
|
|
||||||
/// pure rules + auto-suppress (absolute count checks) live in <see cref="OnboardingStepMath"/>.
|
|
||||||
/// </summary>
|
|
||||||
[WorldSystemFilter(WorldSystemFilterFlags.ClientSimulation)]
|
|
||||||
[UpdateInGroup(typeof(PresentationSystemGroup))]
|
|
||||||
public partial class OnboardingSystem : SystemBase
|
|
||||||
{
|
|
||||||
const float ExpeditionRegionXMin = RegionMath.RegionBoundaryX; // player x past this = the +1000 expedition region (mirrors HudSystem)
|
|
||||||
|
|
||||||
GameObject _go;
|
|
||||||
UIDocument _doc;
|
|
||||||
bool _built;
|
|
||||||
Label _prompt;
|
|
||||||
Label _pointer;
|
|
||||||
|
|
||||||
// step machine (in-memory; persisted to the mask on each completion)
|
|
||||||
bool _maskLoaded;
|
|
||||||
int _mask;
|
|
||||||
byte _step;
|
|
||||||
bool _stepInit;
|
|
||||||
float _stepElapsed;
|
|
||||||
float _moveAccum;
|
|
||||||
float3 _lastPos;
|
|
||||||
bool _sawSiege;
|
|
||||||
bool _wasOnExpedition; // D3: latched true once the player is seen on expedition during the Return step
|
|
||||||
|
|
||||||
|
|
||||||
protected override void OnStartRunning()
|
|
||||||
{
|
|
||||||
if (_go != null) return;
|
|
||||||
_go = new GameObject("~Onboarding");
|
|
||||||
_doc = _go.AddComponent<UIDocument>();
|
|
||||||
_doc.panelSettings = MenuUi.LoadPanelSettings();
|
|
||||||
_doc.sortingOrder = 60; // above HUD (50), below pause (100)
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnDestroy()
|
|
||||||
{
|
|
||||||
OnboardingState.Active = false; // never let the static outlive its owning system (HUD suppression)
|
|
||||||
if (_go != null) Object.Destroy(_go);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnUpdate()
|
|
||||||
{
|
|
||||||
if (_doc == null) return;
|
|
||||||
var root = _doc.rootVisualElement;
|
|
||||||
if (root == null) return;
|
|
||||||
if (!_built) { BuildTree(root); _built = true; }
|
|
||||||
OnboardingState.SuppressLocationLine = false; // D4: default off each frame; a shown step sets it per-step below
|
|
||||||
|
|
||||||
|
|
||||||
float dt = SystemAPI.Time.DeltaTime; // wall-frame delta — correct in a presentation system
|
|
||||||
|
|
||||||
// ---- local player presence + position ----
|
|
||||||
bool havePlayer = false; float3 playerPos = default;
|
|
||||||
foreach (var lt in SystemAPI.Query<RefRO<LocalTransform>>().WithAll<GhostOwnerIsLocal, PlayerTag>())
|
|
||||||
{ havePlayer = true; playerPos = lt.ValueRO.Position; break; }
|
|
||||||
|
|
||||||
var settings = SettingsService.Current;
|
|
||||||
if (!_maskLoaded)
|
|
||||||
{
|
|
||||||
_mask = settings.OnboardingMask;
|
|
||||||
_step = OnboardingStepMath.FirstIncomplete(_mask);
|
|
||||||
_stepInit = false;
|
|
||||||
_maskLoaded = true;
|
|
||||||
}
|
|
||||||
bool hintsOn = settings.TutorialHints != 0;
|
|
||||||
|
|
||||||
// Dormant (hints off / all steps done) or no local player yet → fully hidden, no voice.
|
|
||||||
if (!hintsOn || OnboardingStepMath.AllComplete(_mask) || !havePlayer)
|
|
||||||
{
|
|
||||||
OnboardingState.Active = false;
|
|
||||||
root.style.display = DisplayStyle.None;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---- remaining observable state ----
|
|
||||||
byte lifecycle = RunLifecycle.Staging;
|
|
||||||
if (SystemAPI.TryGetSingleton<RunInfo>(out var runInfo)) lifecycle = runInfo.Lifecycle;
|
|
||||||
bool localReady = false;
|
|
||||||
foreach (var pr in SystemAPI.Query<RefRO<PlayerReady>>().WithAll<GhostOwnerIsLocal, PlayerTag>())
|
|
||||||
{ localReady = pr.ValueRO.Value != 0; break; }
|
|
||||||
CountStructures(out int turrets, out int fabs);
|
|
||||||
byte phase = CyclePhase.Calm;
|
|
||||||
if (SystemAPI.TryGetSingleton<CycleState>(out var cyc)) phase = cyc.Phase;
|
|
||||||
byte objState = ExpeditionObjectiveState.Idle;
|
|
||||||
if (SystemAPI.TryGetSingleton<ExpeditionObjective>(out var obj)) objState = obj.State;
|
|
||||||
bool onExp = playerPos.x > ExpeditionRegionXMin;
|
|
||||||
|
|
||||||
// ---- per-step entry init (baselines) ----
|
|
||||||
if (!_stepInit)
|
|
||||||
{
|
|
||||||
_stepElapsed = 0f; _moveAccum = 0f; _sawSiege = false; _wasOnExpedition = false;
|
|
||||||
_lastPos = playerPos;
|
|
||||||
_stepInit = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---- advance (FROZEN while the pause overlay is open, so the timed beats — Welcome/Fabricator/
|
|
||||||
// Defend/Done — aren't silently lost behind the pause dim that sits above this overlay) ----
|
|
||||||
if (!PauseMenuController.Open)
|
|
||||||
{
|
|
||||||
_stepElapsed += dt;
|
|
||||||
if (_step == OnboardingStepMath.Move) _moveAccum += math.distance(playerPos, _lastPos);
|
|
||||||
if (_step == OnboardingStepMath.Defend && phase == CyclePhase.Siege) _sawSiege = true;
|
|
||||||
if (_step == OnboardingStepMath.Return && onExp) _wasOnExpedition = true; // D3: latch "was on expedition" so a start-at-base Return doesn't instantly satisfy
|
|
||||||
|
|
||||||
|
|
||||||
var snap = new OnboardingStepMath.Snapshot
|
|
||||||
{
|
|
||||||
StepElapsed = _stepElapsed,
|
|
||||||
MoveDistance = _moveAccum,
|
|
||||||
LocalReady = localReady,
|
|
||||||
Lifecycle = lifecycle,
|
|
||||||
TurretCount = turrets,
|
|
||||||
FabricatorCount = fabs,
|
|
||||||
OnExpedition = onExp,
|
|
||||||
ObjectiveState = objState,
|
|
||||||
SawSiege = _sawSiege,
|
|
||||||
WasOnExpedition = _wasOnExpedition,
|
|
||||||
Phase = phase,
|
|
||||||
};
|
|
||||||
|
|
||||||
// The two pure-message beats can be dismissed with any input EXCEPT Esc (Esc opens Pause; see
|
|
||||||
// AnyInputPressed) so following the "Esc → Pause → How to Play" hint doesn't self-skip the framing.
|
|
||||||
bool skip = (_step == OnboardingStepMath.Welcome && ConfirmPressed()) || (_step == OnboardingStepMath.Done && AnyInputPressed()); // D5: Welcome dismisses ONLY on an explicit confirm (not WASD) so the win-condition strip is actually read
|
|
||||||
if (skip || OnboardingStepMath.IsSatisfied(_step, snap))
|
|
||||||
{
|
|
||||||
_mask |= (1 << _step);
|
|
||||||
Persist(_mask);
|
|
||||||
_step = OnboardingStepMath.FirstIncomplete(_mask); // auto-suppressed steps cascade one/frame
|
|
||||||
_stepInit = false;
|
|
||||||
if (OnboardingStepMath.AllComplete(_mask))
|
|
||||||
{
|
|
||||||
OnboardingState.Active = false;
|
|
||||||
root.style.display = DisplayStyle.None;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_lastPos = playerPos;
|
|
||||||
|
|
||||||
// ---- show the current step ----
|
|
||||||
OnboardingState.Active = true;
|
|
||||||
OnboardingState.SuppressLocationLine = OnboardingStepMath.IsEarlyStep(_step); // D4: blank the HUD line only for the early base-framing steps
|
|
||||||
root.style.display = DisplayStyle.Flex;
|
|
||||||
bool gamepad = AimPresentation.Scheme == InputSchemeId.Gamepad;
|
|
||||||
_prompt.text = OnboardingStepMath.Prompt(_step, gamepad);
|
|
||||||
UpdatePointer(_step, playerPos);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---- state gathering helpers ----
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void CountStructures(out int turrets, out int fabs)
|
|
||||||
{
|
|
||||||
turrets = 0; fabs = 0;
|
|
||||||
foreach (var ps in SystemAPI.Query<RefRO<PlacedStructure>>())
|
|
||||||
{
|
|
||||||
byte t = ps.ValueRO.Type;
|
|
||||||
if (t == StructureType.Turret) turrets++;
|
|
||||||
else if (t == StructureType.Fabricator) fabs++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Persist(int mask)
|
|
||||||
{
|
|
||||||
var s = SettingsService.Current;
|
|
||||||
s.OnboardingMask = mask;
|
|
||||||
SettingsService.Save(s); // atomic write; ~once per completed step
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool AnyInputPressed()
|
|
||||||
{
|
|
||||||
var kb = UnityEngine.InputSystem.Keyboard.current;
|
|
||||||
// any key dismisses a message beat — EXCEPT Esc, which is the pause key (don't self-skip the framing).
|
|
||||||
if (kb != null && kb.anyKey.wasPressedThisFrame && !kb.escapeKey.wasPressedThisFrame) return true;
|
|
||||||
var ms = UnityEngine.InputSystem.Mouse.current;
|
|
||||||
if (ms != null && ms.leftButton.wasPressedThisFrame) return true;
|
|
||||||
var gp = UnityEngine.InputSystem.Gamepad.current;
|
|
||||||
if (gp != null && (gp.buttonSouth.wasPressedThisFrame || gp.startButton.wasPressedThisFrame)) return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// D5: an EXPLICIT confirm only (Space/Enter/click/South) — movement keys must NOT skip the Welcome strip.
|
|
||||||
static bool ConfirmPressed()
|
|
||||||
{
|
|
||||||
var kb = UnityEngine.InputSystem.Keyboard.current;
|
|
||||||
if (kb != null && (kb.spaceKey.wasPressedThisFrame || kb.enterKey.wasPressedThisFrame)) return true;
|
|
||||||
var ms = UnityEngine.InputSystem.Mouse.current;
|
|
||||||
if (ms != null && ms.leftButton.wasPressedThisFrame) return true;
|
|
||||||
var gp = UnityEngine.InputSystem.Gamepad.current;
|
|
||||||
if (gp != null && (gp.buttonSouth.wasPressedThisFrame || gp.startButton.wasPressedThisFrame)) return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ---- world-space pointer ----
|
|
||||||
|
|
||||||
bool ResolveTarget(byte kind, float3 playerPos, out float3 target)
|
|
||||||
{
|
|
||||||
target = default;
|
|
||||||
if (kind == OnboardingStepMath.PointerOreNode)
|
|
||||||
{
|
|
||||||
float best = float.MaxValue; bool found = false;
|
|
||||||
foreach (var lt in SystemAPI.Query<RefRO<LocalTransform>>().WithAll<ResourceNode>())
|
|
||||||
{
|
|
||||||
float d = math.distancesq(lt.ValueRO.Position, playerPos);
|
|
||||||
if (d < best) { best = d; target = lt.ValueRO.Position; found = true; }
|
|
||||||
}
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
// Step 11: the walk-in ExpeditionGate was RETIRED (the ready-check launches runs), so gate pointers
|
|
||||||
// have no world target — hide the arrow; the step text still teaches. Step 14's HUD pass re-points
|
|
||||||
// onboarding at the READY panel instead.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UpdatePointer(byte step, float3 playerPos)
|
|
||||||
{
|
|
||||||
byte kind = OnboardingStepMath.PointerKind(step);
|
|
||||||
var cam = Camera.main;
|
|
||||||
var root = _doc.rootVisualElement;
|
|
||||||
if (kind == OnboardingStepMath.PointerNone || cam == null || !ResolveTarget(kind, playerPos, out float3 target))
|
|
||||||
{ _pointer.style.display = DisplayStyle.None; return; }
|
|
||||||
|
|
||||||
float pw = root.layout.width, ph = root.layout.height;
|
|
||||||
if (pw <= 1f || ph <= 1f) { _pointer.style.display = DisplayStyle.None; return; }
|
|
||||||
|
|
||||||
Vector3 sp = cam.WorldToScreenPoint((Vector3)target);
|
|
||||||
bool behind = sp.z < 0f;
|
|
||||||
float px = (sp.x / Mathf.Max(1f, Screen.width)) * pw;
|
|
||||||
float py = (1f - sp.y / Mathf.Max(1f, Screen.height)) * ph;
|
|
||||||
if (behind) { px = pw - px; py = ph - py; }
|
|
||||||
|
|
||||||
const float margin = 64f;
|
|
||||||
bool off = behind || px < margin || px > pw - margin || py < margin || py > ph - margin;
|
|
||||||
|
|
||||||
float cx = pw * 0.5f, cy = ph * 0.5f;
|
|
||||||
float dx = px - cx, dy = py - cy;
|
|
||||||
float len = Mathf.Sqrt(dx * dx + dy * dy);
|
|
||||||
if (len < 0.001f) { dx = 1f; dy = 0f; len = 1f; }
|
|
||||||
float ndx = dx / len, ndy = dy / len;
|
|
||||||
|
|
||||||
float ax, ay;
|
|
||||||
if (off)
|
|
||||||
{
|
|
||||||
// intersect the center→target ray with the margin rectangle (edge arrow)
|
|
||||||
float tx = (ndx > 0 ? (pw - margin - cx) : (margin - cx)) / (Mathf.Abs(ndx) < 1e-4f ? (ndx < 0 ? -1e-4f : 1e-4f) : ndx);
|
|
||||||
float ty = (ndy > 0 ? (ph - margin - cy) : (margin - cy)) / (Mathf.Abs(ndy) < 1e-4f ? (ndy < 0 ? -1e-4f : 1e-4f) : ndy);
|
|
||||||
float tt = Mathf.Min(Mathf.Abs(tx), Mathf.Abs(ty));
|
|
||||||
ax = cx + ndx * tt; ay = cy + ndy * tt;
|
|
||||||
}
|
|
||||||
else { ax = px; ay = py - 44f; } // float just above the on-screen target
|
|
||||||
|
|
||||||
float angle = Mathf.Atan2(dy, dx) * Mathf.Rad2Deg; // "▶" art points +x at 0°
|
|
||||||
_pointer.style.left = ax - 15f;
|
|
||||||
_pointer.style.top = ay - 18f;
|
|
||||||
_pointer.style.rotate = new StyleRotate(new Rotate(new Angle(angle)));
|
|
||||||
_pointer.style.display = DisplayStyle.Flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---- UITK construction ----
|
|
||||||
|
|
||||||
void BuildTree(VisualElement root)
|
|
||||||
{
|
|
||||||
root.style.position = Position.Absolute;
|
|
||||||
root.style.left = 0; root.style.right = 0; root.style.top = 0; root.style.bottom = 0;
|
|
||||||
root.pickingMode = PickingMode.Ignore; // never eat world clicks
|
|
||||||
|
|
||||||
var panel = new VisualElement();
|
|
||||||
panel.style.position = Position.Absolute;
|
|
||||||
panel.style.bottom = 210; panel.style.left = 0; panel.style.right = 0;
|
|
||||||
panel.style.flexDirection = FlexDirection.Row;
|
|
||||||
panel.style.justifyContent = Justify.Center;
|
|
||||||
panel.style.alignItems = Align.Center;
|
|
||||||
panel.pickingMode = PickingMode.Ignore;
|
|
||||||
|
|
||||||
var chip = new VisualElement();
|
|
||||||
chip.style.backgroundColor = new Color(0.05f, 0.07f, 0.10f, 0.92f);
|
|
||||||
chip.style.paddingLeft = 22; chip.style.paddingRight = 22;
|
|
||||||
chip.style.paddingTop = 10; chip.style.paddingBottom = 10;
|
|
||||||
chip.style.maxWidth = 920;
|
|
||||||
chip.pickingMode = PickingMode.Ignore;
|
|
||||||
MenuUi.Round(chip, 8);
|
|
||||||
MenuUi.Border(chip, new Color(MenuUi.Accent.r, MenuUi.Accent.g, MenuUi.Accent.b, 0.55f), 1);
|
|
||||||
|
|
||||||
_prompt = new Label(string.Empty);
|
|
||||||
_prompt.style.color = MenuUi.TextCol;
|
|
||||||
_prompt.style.fontSize = 18;
|
|
||||||
_prompt.style.unityFontStyleAndWeight = FontStyle.Bold;
|
|
||||||
_prompt.style.unityTextAlign = TextAnchor.MiddleCenter;
|
|
||||||
_prompt.style.whiteSpace = WhiteSpace.Normal;
|
|
||||||
var theme = HudTheme.Get();
|
|
||||||
if (theme != null) theme.ApplyBody(_prompt.style);
|
|
||||||
chip.Add(_prompt);
|
|
||||||
panel.Add(chip);
|
|
||||||
root.Add(panel);
|
|
||||||
|
|
||||||
_pointer = new Label("▶"); // ▶ right-pointing triangle (rotated toward the target)
|
|
||||||
_pointer.style.position = Position.Absolute;
|
|
||||||
_pointer.style.fontSize = 30;
|
|
||||||
_pointer.style.color = MenuUi.Accent;
|
|
||||||
_pointer.style.unityFontStyleAndWeight = FontStyle.Bold;
|
|
||||||
_pointer.pickingMode = PickingMode.Ignore;
|
|
||||||
_pointer.style.display = DisplayStyle.None;
|
|
||||||
root.Add(_pointer);
|
|
||||||
|
|
||||||
root.style.display = DisplayStyle.None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: b4828f5a68386fa4da379dcddbf629de
|
|
||||||
@@ -144,10 +144,8 @@ namespace ProjectM.Client
|
|||||||
|
|
||||||
// Hide the OS cursor only while aiming AND focused; restore otherwise (focus loss / pre-spawn) so an
|
// Hide the OS cursor only while aiming AND focused; restore otherwise (focus loss / pre-spawn) so an
|
||||||
// unfocused editor or a windowed session is never stranded with an invisible pointer.
|
// unfocused editor or a windowed session is never stranded with an invisible pointer.
|
||||||
// END-2: while the run is over (terminal banner up) keep the cursor visible so the player can click the
|
// AimReticleSystem is the sole Cursor.visible writer.
|
||||||
// Play Again / Quit buttons, regardless of aim state. AimReticleSystem is the sole Cursor.visible writer.
|
bool wantHidden = haveTarget && Application.isFocused && !AimPresentation.ForceCursorVisible;
|
||||||
bool runOver = SystemAPI.TryGetSingleton<RunOutcome>(out var ro) && ro.Value != RunOutcomeId.InProgress;
|
|
||||||
bool wantHidden = haveTarget && Application.isFocused && !AimPresentation.ForceCursorVisible && !runOver;
|
|
||||||
if (wantHidden != _cursorHidden)
|
if (wantHidden != _cursorHidden)
|
||||||
{
|
{
|
||||||
if (wantHidden) Cursor.lockState = CursorLockMode.None;
|
if (wantHidden) Cursor.lockState = CursorLockMode.None;
|
||||||
|
|||||||
@@ -6,13 +6,12 @@ using UnityEngine;
|
|||||||
namespace ProjectM.Client
|
namespace ProjectM.Client
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Client-only AMBIENT audio + cycle-phase stingers. A managed presentation <see cref="SystemBase"/>
|
/// Client-only AMBIENT audio bed + run cues. A managed presentation <see cref="SystemBase"/>
|
||||||
/// (<see cref="PresentationSystemGroup"/>, main thread, no Burst) that OBSERVES the replicated
|
/// (<see cref="PresentationSystemGroup"/>, main thread, no Burst) that plays a low, seamless-looping
|
||||||
/// <see cref="CycleState"/> and never touches the simulation. On start it plays a low, seamless-looping
|
/// procedural drone (asset-free, <c>AudioClip.Create</c> like <c>CombatFeedbackSystem.MakeClip</c>) plus
|
||||||
/// procedural drone (asset-free, <c>AudioClip.Create</c> like <c>CombatFeedbackSystem.MakeClip</c>); each
|
/// launch-countdown beeps and the boss-arrival roar — replicated-state observations only. Lives only in the
|
||||||
/// time the cycle phase changes it plays a short procedural stinger and eases the drone's intensity by phase
|
/// client world, so the server never creates audio and nothing here affects determinism. Volumes are
|
||||||
/// (calmer at base, tenser during Defend / "wave incoming"). Lives only in the client world, so the server
|
/// deliberately conservative. (The cycle-phase stingers + Core alarm retired with the siege loop — LANTERN purge.)
|
||||||
/// never creates audio and nothing here affects determinism. Volumes are deliberately conservative + tunable.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[WorldSystemFilter(WorldSystemFilterFlags.ClientSimulation)]
|
[WorldSystemFilter(WorldSystemFilterFlags.ClientSimulation)]
|
||||||
[UpdateInGroup(typeof(PresentationSystemGroup))]
|
[UpdateInGroup(typeof(PresentationSystemGroup))]
|
||||||
@@ -20,29 +19,17 @@ namespace ProjectM.Client
|
|||||||
{
|
{
|
||||||
AudioSource _ambient;
|
AudioSource _ambient;
|
||||||
AudioClip _ambientClip;
|
AudioClip _ambientClip;
|
||||||
AudioClip _stingExpedition;
|
|
||||||
AudioClip _stingDefend;
|
|
||||||
AudioClip _stingBuild;
|
|
||||||
GameObject _root;
|
GameObject _root;
|
||||||
|
|
||||||
byte _lastPhase;
|
|
||||||
bool _phaseInit;
|
|
||||||
AudioClip _stingCoreHit;
|
|
||||||
int _lastCore = -1;
|
|
||||||
float _coreStingCooldown;
|
|
||||||
AudioClip _stingBeep, _stingRoar;
|
AudioClip _stingBeep, _stingRoar;
|
||||||
int _lastCountdownSec = -1;
|
int _lastCountdownSec = -1;
|
||||||
bool _bossRoared;
|
bool _bossRoared;
|
||||||
|
|
||||||
const float AmbientBaseVolume = 0.10f; // low bed; Defend eases up to ~1.7x
|
const float AmbientBaseVolume = 0.10f; // low ambient bed
|
||||||
|
|
||||||
protected override void OnCreate()
|
protected override void OnCreate()
|
||||||
{
|
{
|
||||||
_ambientClip = MakeDrone();
|
_ambientClip = MakeDrone();
|
||||||
_stingExpedition = MakeSting(520f, 880f, 0.45f, 0.30f); // airy rising "deploy"
|
|
||||||
_stingDefend = MakeSting(300f, 140f, 0.55f, 0.42f); // tense falling "wave incoming"
|
|
||||||
_stingBuild = MakeSting(440f, 660f, 0.40f, 0.26f); // soft confirm
|
|
||||||
_stingCoreHit = MakeSting(240f, 70f, 0.30f, 0.55f); // harsh falling "Core hit" alarm
|
|
||||||
_stingBeep = MakeSting(880f, 880f, 0.09f, 0.30f); // countdown tick
|
_stingBeep = MakeSting(880f, 880f, 0.09f, 0.30f); // countdown tick
|
||||||
_stingRoar = MakeSting(90f, 38f, 0.90f, 0.60f); // boss-arrival roar (low falling growl)
|
_stingRoar = MakeSting(90f, 38f, 0.90f, 0.60f); // boss-arrival roar (low falling growl)
|
||||||
}
|
}
|
||||||
@@ -68,36 +55,8 @@ namespace ProjectM.Client
|
|||||||
protected override void OnUpdate()
|
protected override void OnUpdate()
|
||||||
{
|
{
|
||||||
if (_ambient == null) return;
|
if (_ambient == null) return;
|
||||||
if (!SystemAPI.TryGetSingleton<CycleState>(out var cyc)) return;
|
|
||||||
|
|
||||||
byte phase = cyc.Phase;
|
_ambient.volume = Mathf.MoveTowards(_ambient.volume, AmbientBaseVolume * GameVolume.Music, SystemAPI.Time.DeltaTime * 0.25f);
|
||||||
if (!_phaseInit)
|
|
||||||
{
|
|
||||||
_lastPhase = phase; // adopt the current phase silently (no stinger on first observe)
|
|
||||||
_phaseInit = true;
|
|
||||||
}
|
|
||||||
else if (phase != _lastPhase)
|
|
||||||
{
|
|
||||||
PlaySting(phase);
|
|
||||||
_lastPhase = phase;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ease the drone intensity toward the phase target (tenser during Defend).
|
|
||||||
float target = phase == CyclePhase.Siege ? AmbientBaseVolume * 1.7f : AmbientBaseVolume;
|
|
||||||
_ambient.volume = Mathf.MoveTowards(_ambient.volume, target * GameVolume.Music, SystemAPI.Time.DeltaTime * 0.25f);
|
|
||||||
|
|
||||||
// Core-under-attack alarm: a falling sting on each CoreIntegrity drop (rate-limited) so a base
|
|
||||||
// breach is AUDIBLE even when the fight has the player's eyes elsewhere.
|
|
||||||
_coreStingCooldown -= SystemAPI.Time.DeltaTime;
|
|
||||||
if (SystemAPI.TryGetSingleton<CoreIntegrity>(out var core))
|
|
||||||
{
|
|
||||||
if (_lastCore >= 0 && core.Current < _lastCore && _coreStingCooldown <= 0f)
|
|
||||||
{
|
|
||||||
_ambient.PlayOneShot(_stingCoreHit, 0.8f * GameVolume.Sfx);
|
|
||||||
_coreStingCooldown = 0.7f;
|
|
||||||
}
|
|
||||||
_lastCore = core.Current;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Launch countdown beeps (3-2-1) + the boss-arrival roar — replicated-state observations only.
|
// Launch countdown beeps (3-2-1) + the boss-arrival roar — replicated-state observations only.
|
||||||
if (SystemAPI.TryGetSingleton<RunInfo>(out var runAudio))
|
if (SystemAPI.TryGetSingleton<RunInfo>(out var runAudio))
|
||||||
@@ -131,13 +90,6 @@ namespace ProjectM.Client
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlaySting(byte phase)
|
|
||||||
{
|
|
||||||
AudioClip clip = phase == CyclePhase.Siege ? _stingDefend : _stingBuild;
|
|
||||||
if (clip != null && _ambient != null)
|
|
||||||
_ambient.PlayOneShot(clip, 0.6f * GameVolume.Music);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---- Procedural audio (asset-free; mirrors CombatFeedbackSystem.MakeClip) ----
|
// ---- Procedural audio (asset-free; mirrors CombatFeedbackSystem.MakeClip) ----
|
||||||
|
|
||||||
// A low, seamless-looping pad: each partial completes an integer number of cycles over the buffer
|
// A low, seamless-looping pad: each partial completes an integer number of cycles over the buffer
|
||||||
@@ -176,6 +128,6 @@ namespace ProjectM.Client
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Short one-shot tone sweeping f0->f1 with an exponential decay envelope.
|
// Short one-shot tone sweeping f0->f1 with an exponential decay envelope.
|
||||||
static AudioClip MakeSting(float f0, float f1, float dur, float vol) => FeedbackFx.MakeClip("sting", f0, f1, dur, vol, decay: 3.5f);
|
static AudioClip MakeSting(float f0, float f1, float dur, float vol) => FeedbackFx.MakeClip("sting", f0, f1, dur, vol, decay: 3.5f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ namespace ProjectM.Client
|
|||||||
|
|
||||||
protected override void OnUpdate()
|
protected override void OnUpdate()
|
||||||
{
|
{
|
||||||
if (UnityEngine.SceneManagement.SceneManager.GetActiveScene().name != "Game") { Hide(); return; }
|
if (!ScenePolicy.IsGameplayScene()) { Hide(); return; }
|
||||||
if (_cam == null) _cam = Camera.main;
|
if (_cam == null) _cam = Camera.main;
|
||||||
if (_cam == null) return;
|
if (_cam == null) return;
|
||||||
if (!AmbientLifeConfig.Enabled) { Hide(); return; }
|
if (!AmbientLifeConfig.Enabled) { Hide(); return; }
|
||||||
|
|||||||
@@ -63,8 +63,6 @@ namespace ProjectM.Client
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool haveRun = SystemAPI.TryGetSingleton<RunInfo>(out var runInfo);
|
bool haveRun = SystemAPI.TryGetSingleton<RunInfo>(out var runInfo);
|
||||||
bool haveCycle = SystemAPI.TryGetSingleton<CycleState>(out var cyc);
|
|
||||||
bool siege = haveCycle && cyc.Phase == CyclePhase.Siege;
|
|
||||||
|
|
||||||
// Resources from the ledger (last entry per type wins, matching the core loop).
|
// Resources from the ledger (last entry per type wins, matching the core loop).
|
||||||
int aether = 0, ore = 0, bio = 0;
|
int aether = 0, ore = 0, bio = 0;
|
||||||
@@ -83,9 +81,9 @@ namespace ProjectM.Client
|
|||||||
// Local class from the replicated AbilityRef (tracks the dev class-switch; PlayerClass is server-only).
|
// Local class from the replicated AbilityRef (tracks the dev class-switch; PlayerClass is server-only).
|
||||||
byte localClass = ClassTraits.WarriorClass;
|
byte localClass = ClassTraits.WarriorClass;
|
||||||
bool haveLocalPlayer = false;
|
bool haveLocalPlayer = false;
|
||||||
foreach (var (fr, ar) in SystemAPI.Query<RefRO<FrameId>, RefRO<AbilityRef>>().WithAll<PlayerTag, GhostOwnerIsLocal>())
|
foreach (var fr in SystemAPI.Query<RefRO<FrameId>>().WithAll<PlayerTag, GhostOwnerIsLocal>())
|
||||||
{
|
{
|
||||||
localClass = fr.ValueRO.Value != 0 ? fr.ValueRO.Value : ClassTraits.ClassForAbility(ar.ValueRO.Id); // FrameId signal, AbilityRef fallback
|
localClass = ClassTraits.Normalize(fr.ValueRO.Value); // FrameId is the sole class signal (legacy AbilityRef deleted)
|
||||||
haveLocalPlayer = true;
|
haveLocalPlayer = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -93,7 +91,7 @@ namespace ProjectM.Client
|
|||||||
// Faithful reproduction of the original `metaShow` gate: class/prep were shown on the SAME condition as
|
// Faithful reproduction of the original `metaShow` gate: class/prep were shown on the SAME condition as
|
||||||
// the meta shop, which requires the meta catalog + tier buffer to exist.
|
// the meta shop, which requires the meta catalog + tier buffer to exist.
|
||||||
DynamicBuffer<MetaTierState> metaRecord = default;
|
DynamicBuffer<MetaTierState> metaRecord = default;
|
||||||
bool metaShow = haveRun && runInfo.Lifecycle == RunLifecycle.Staging && haveLocalPlayer && !siege
|
bool metaShow = haveRun && runInfo.Lifecycle == RunLifecycle.Staging && haveLocalPlayer
|
||||||
&& SystemAPI.TryGetSingleton<MetaUpgradeCatalog>(out var metaCat) && metaCat.Value.IsCreated
|
&& SystemAPI.TryGetSingleton<MetaUpgradeCatalog>(out var metaCat) && metaCat.Value.IsCreated
|
||||||
&& SystemAPI.TryGetSingletonBuffer<MetaTierState>(out metaRecord, true);
|
&& SystemAPI.TryGetSingletonBuffer<MetaTierState>(out metaRecord, true);
|
||||||
|
|
||||||
|
|||||||
@@ -1,91 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using ProjectM.Simulation;
|
|
||||||
using Unity.Entities;
|
|
||||||
using UnityEngine;
|
|
||||||
using UnityEngine.SceneManagement;
|
|
||||||
|
|
||||||
namespace ProjectM.Client
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The Engine Core's CRYSTAL answers its replicated <see cref="CoreIntegrity"/> (07-01 backlog: the mesh sat
|
|
||||||
/// static while draining). Client-only observe-only presentation: the cosmetic <c>CoreCrystals</c> /
|
|
||||||
/// <c>CoreMachine</c> GameObjects in Game.unity (classic URP renderers, not entities) are tinted via
|
|
||||||
/// MaterialPropertyBlock — darker + blood-shifted as integrity falls, a white-hot flash on each hit (pairs
|
|
||||||
/// with the AmbientAudioSystem alarm). Property-guarded per the shader-value rule (only materials exposing
|
|
||||||
/// _BaseColor are touched); per-renderer MPBs never mutate the shared material assets (no bleed).
|
|
||||||
/// </summary>
|
|
||||||
[WorldSystemFilter(WorldSystemFilterFlags.ClientSimulation)]
|
|
||||||
[UpdateInGroup(typeof(PresentationSystemGroup))]
|
|
||||||
public partial class CoreVisualFeedbackSystem : SystemBase
|
|
||||||
{
|
|
||||||
static readonly int BaseColorId = Shader.PropertyToID("_BaseColor");
|
|
||||||
static readonly string[] TargetNames = { "CoreCrystals", "CoreMachine" };
|
|
||||||
const float FlashSeconds = 0.35f;
|
|
||||||
|
|
||||||
readonly List<Renderer> _renderers = new();
|
|
||||||
readonly List<Color> _authoredColors = new();
|
|
||||||
MaterialPropertyBlock _mpb;
|
|
||||||
bool _resolved;
|
|
||||||
int _lastCore = -1;
|
|
||||||
float _flashLeft;
|
|
||||||
|
|
||||||
protected override void OnUpdate()
|
|
||||||
{
|
|
||||||
if (!SystemAPI.TryGetSingleton<CoreIntegrity>(out var core) || core.Max <= 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// One-time renderer resolve, deferred until Game.unity is actually the active scene (the frontend
|
|
||||||
// path creates this world a frame BEFORE the scene loads — latching early would find nothing).
|
|
||||||
if (!_resolved)
|
|
||||||
{
|
|
||||||
var scene = SceneManager.GetActiveScene();
|
|
||||||
if (!scene.isLoaded || scene.name != "Game") return;
|
|
||||||
Resolve();
|
|
||||||
}
|
|
||||||
if (_renderers.Count == 0) return;
|
|
||||||
|
|
||||||
if (_lastCore >= 0 && core.Current < _lastCore)
|
|
||||||
_flashLeft = FlashSeconds; // hit edge -> white-hot pop (the audio alarm fires beside it)
|
|
||||||
_lastCore = core.Current;
|
|
||||||
_flashLeft -= SystemAPI.Time.DeltaTime;
|
|
||||||
|
|
||||||
float frac = Mathf.Clamp01(core.Current / (float)core.Max);
|
|
||||||
float dim = Mathf.Lerp(0.35f, 1f, frac);
|
|
||||||
float flash = _flashLeft > 0f ? Mathf.Clamp01(_flashLeft / FlashSeconds) : 0f;
|
|
||||||
for (int i = 0; i < _renderers.Count; i++)
|
|
||||||
{
|
|
||||||
var r = _renderers[i];
|
|
||||||
if (r == null) continue;
|
|
||||||
var c0 = _authoredColors[i];
|
|
||||||
// Wounded shift: keep red-ish energy, drain green/blue with integrity (reads as bleeding light).
|
|
||||||
var wounded = new Color(
|
|
||||||
Mathf.Min(1f, c0.r * dim + (1f - frac) * 0.25f),
|
|
||||||
c0.g * dim * (0.45f + 0.55f * frac),
|
|
||||||
c0.b * dim * (0.45f + 0.55f * frac),
|
|
||||||
c0.a);
|
|
||||||
var col = flash > 0f ? Color.Lerp(wounded, Color.white, flash) : wounded;
|
|
||||||
r.GetPropertyBlock(_mpb);
|
|
||||||
_mpb.SetColor(BaseColorId, col);
|
|
||||||
r.SetPropertyBlock(_mpb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Resolve()
|
|
||||||
{
|
|
||||||
_resolved = true;
|
|
||||||
_mpb = new MaterialPropertyBlock();
|
|
||||||
foreach (var name in TargetNames)
|
|
||||||
{
|
|
||||||
var go = GameObject.Find(name);
|
|
||||||
if (go == null) continue;
|
|
||||||
foreach (var r in go.GetComponentsInChildren<Renderer>())
|
|
||||||
{
|
|
||||||
var m = r.sharedMaterial;
|
|
||||||
if (m == null || !m.HasProperty(BaseColorId)) continue;
|
|
||||||
_renderers.Add(r);
|
|
||||||
_authoredColors.Add(m.GetColor(BaseColorId));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 47b2a19145125ac4e98411cab7f9b569
|
|
||||||
@@ -69,7 +69,7 @@ namespace ProjectM.Client
|
|||||||
|
|
||||||
protected override void OnUpdate()
|
protected override void OnUpdate()
|
||||||
{
|
{
|
||||||
if (UnityEngine.SceneManagement.SceneManager.GetActiveScene().name != "Game") return;
|
if (!ScenePolicy.IsGameplayScene()) return;
|
||||||
if (!DecalConfig.Enabled) { if (_tracked.Count > 0) ClearAll(); return; }
|
if (!DecalConfig.Enabled) { if (_tracked.Count > 0) ClearAll(); return; }
|
||||||
|
|
||||||
EntityManager.CompleteDependencyBeforeRO<BlightClutter>();
|
EntityManager.CompleteDependencyBeforeRO<BlightClutter>();
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ namespace ProjectM.Client
|
|||||||
|
|
||||||
protected override void OnUpdate()
|
protected override void OnUpdate()
|
||||||
{
|
{
|
||||||
if (UnityEngine.SceneManagement.SceneManager.GetActiveScene().name != "Game") return;
|
if (!ScenePolicy.IsGameplayScene()) return;
|
||||||
var cfg = DynamicLightConfig.Instance;
|
var cfg = DynamicLightConfig.Instance;
|
||||||
bool enabled = cfg == null || cfg.Enabled;
|
bool enabled = cfg == null || cfg.Enabled;
|
||||||
if (!enabled)
|
if (!enabled)
|
||||||
|
|||||||
@@ -26,15 +26,12 @@ namespace ProjectM.Client
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[WorldSystemFilter(WorldSystemFilterFlags.ClientSimulation)]
|
[WorldSystemFilter(WorldSystemFilterFlags.ClientSimulation)]
|
||||||
[UpdateInGroup(typeof(PresentationSystemGroup))]
|
[UpdateInGroup(typeof(PresentationSystemGroup))]
|
||||||
[UpdateAfter(typeof(OnboardingSystem))] // read OnboardingState.Active same-frame (single prompt voice)
|
|
||||||
public partial class HudSystem : SystemBase
|
public partial class HudSystem : SystemBase
|
||||||
{
|
{
|
||||||
// ---- palette (Aether language; Synty white skins are tinted into these) ----
|
// ---- palette (Aether language; Synty white skins are tinted into these) ----
|
||||||
static readonly Color AetherCyan = new(0.30f, 0.85f, 1f);
|
static readonly Color AetherCyan = new(0.30f, 0.85f, 1f);
|
||||||
static readonly Color OreAmber = new(1f, 0.72f, 0.35f);
|
static readonly Color OreAmber = new(1f, 0.72f, 0.35f);
|
||||||
static readonly Color BioGreen = new(0.55f, 0.85f, 0.45f);
|
static readonly Color BioGreen = new(0.55f, 0.85f, 0.45f);
|
||||||
static readonly Color ChargeViolet = new(0.80f, 0.45f, 1f);
|
|
||||||
static readonly Color CoreRed = new(1f, 0.40f, 0.32f); // END-1 Engine Core integrity bar
|
|
||||||
|
|
||||||
static readonly Color PanelDark = new(0.08f, 0.11f, 0.15f, 0.90f);
|
static readonly Color PanelDark = new(0.08f, 0.11f, 0.15f, 0.90f);
|
||||||
static readonly Color PanelWarm = new(0.16f, 0.09f, 0.09f, 0.88f);
|
static readonly Color PanelWarm = new(0.16f, 0.09f, 0.09f, 0.88f);
|
||||||
@@ -44,7 +41,6 @@ namespace ProjectM.Client
|
|||||||
static readonly Color SlotIdleBg = new(0.09f, 0.11f, 0.15f, 0.92f);
|
static readonly Color SlotIdleBg = new(0.09f, 0.11f, 0.15f, 0.92f);
|
||||||
static readonly Color SlotSelBg = new(0.16f, 0.26f, 0.32f, 0.95f);
|
static readonly Color SlotSelBg = new(0.16f, 0.26f, 0.32f, 0.95f);
|
||||||
static readonly Color SlotIdleBorder = new(1f, 1f, 1f, 0.08f);
|
static readonly Color SlotIdleBorder = new(1f, 1f, 1f, 0.08f);
|
||||||
const int MaxPips = 12;
|
|
||||||
const float ExpeditionRegionXMin = RegionMath.RegionBoundaryX; // camera x past this = the +1000 expedition region (DR-013)
|
const float ExpeditionRegionXMin = RegionMath.RegionBoundaryX; // camera x past this = the +1000 expedition region (DR-013)
|
||||||
|
|
||||||
GameObject _hudGo;
|
GameObject _hudGo;
|
||||||
@@ -60,18 +56,9 @@ namespace ProjectM.Client
|
|||||||
VisualElement _threatPanel, _threatIcon;
|
VisualElement _threatPanel, _threatIcon;
|
||||||
Label _threatNum;
|
Label _threatNum;
|
||||||
|
|
||||||
// macro: banner + location + goal
|
// macro: banner + location line
|
||||||
VisualElement _banner, _goalContainer, _goalPipsRow, _goalBar, _goalFill;
|
VisualElement _banner;
|
||||||
Label _phaseText, _cycleText, _locationText, _goalText;
|
Label _phaseText, _locationText;
|
||||||
|
|
||||||
// END-1: Engine Core integrity (losable base-heart) + overrun flash edge-detector
|
|
||||||
VisualElement _coreContainer, _coreBar, _coreFill;
|
|
||||||
Label _coreText;
|
|
||||||
uint _lastOverrunTick;
|
|
||||||
float _overrunFlashLeft;
|
|
||||||
// END-2: terminal win/loss banner (observes the replicated RunOutcome; latched server-side).
|
|
||||||
VisualElement _runBanner;
|
|
||||||
Label _runBannerText, _runBannerSub;
|
|
||||||
// Demo polish: the clickable READY panel (Staging/Launching).
|
// Demo polish: the clickable READY panel (Staging/Launching).
|
||||||
VisualElement _readyPanel, _readyPipRow;
|
VisualElement _readyPanel, _readyPipRow;
|
||||||
Button _readyBtn;
|
Button _readyBtn;
|
||||||
@@ -85,19 +72,15 @@ namespace ProjectM.Client
|
|||||||
VisualElement _depthPanel;
|
VisualElement _depthPanel;
|
||||||
int _depthShownFor;
|
int _depthShownFor;
|
||||||
bool _depthBuilt;
|
bool _depthBuilt;
|
||||||
VisualElement _outcomeFlash; // one-shot gold/red full-screen flash when the outcome banner first lands
|
|
||||||
float _outcomeFlashLeft;
|
|
||||||
byte _outcomeFlashedFor;
|
|
||||||
|
|
||||||
|
|
||||||
readonly List<VisualElement> _pips = new();
|
|
||||||
|
|
||||||
// resources
|
// resources
|
||||||
Label _aetherNum, _oreNum, _bioNum, _chargeNum;
|
Label _aetherNum, _oreNum, _bioNum;
|
||||||
|
|
||||||
// build palette + hints
|
// build palette + hints
|
||||||
VisualElement _paletteRow, _hintBar, _facingArrow, _buildDiscoveryChip;
|
VisualElement _paletteRow, _hintBar, _buildDiscoveryChip;
|
||||||
bool _paletteBuilt, _hintBuilt, _hintConveyor;
|
bool _paletteBuilt, _hintBuilt;
|
||||||
byte _hintScheme = 255;
|
byte _hintScheme = 255;
|
||||||
readonly Dictionary<byte, PaletteItem> _palette = new();
|
readonly Dictionary<byte, PaletteItem> _palette = new();
|
||||||
|
|
||||||
@@ -151,92 +134,42 @@ namespace ProjectM.Client
|
|||||||
// stays correct the day a Health/stats writer is parallelised.
|
// stays correct the day a Health/stats writer is parallelised.
|
||||||
EntityManager.CompleteDependencyBeforeRO<Health>();
|
EntityManager.CompleteDependencyBeforeRO<Health>();
|
||||||
EntityManager.CompleteDependencyBeforeRO<EffectiveCharacterStats>();
|
EntityManager.CompleteDependencyBeforeRO<EffectiveCharacterStats>();
|
||||||
EntityManager.CompleteDependencyBeforeRO<EffectiveAbilityStats>();
|
EntityManager.CompleteDependencyBeforeRO<SocketCooldown>();
|
||||||
EntityManager.CompleteDependencyBeforeRO<AbilityCooldown>();
|
EntityManager.CompleteDependencyBeforeRO<EffectiveSocketStats>();
|
||||||
EntityManager.CompleteDependencyBeforeRO<RespawnInvuln>();
|
EntityManager.CompleteDependencyBeforeRO<RespawnInvuln>();
|
||||||
|
|
||||||
float dt = SystemAPI.Time.DeltaTime; // wall-frame delta — correct in a presentation system
|
float dt = SystemAPI.Time.DeltaTime; // wall-frame delta — correct in a presentation system
|
||||||
bool haveTick = SystemAPI.TryGetSingleton<NetworkTime>(out var nt);
|
bool haveTick = SystemAPI.TryGetSingleton<NetworkTime>(out var nt);
|
||||||
int huskCount = _huskQuery.CalculateEntityCount();
|
int huskCount = _huskQuery.CalculateEntityCount();
|
||||||
|
|
||||||
// ---- Macro: phase + cycle + countdown (center-top banner) ----
|
// ---- Macro banner: run-lifecycle header (the siege/cycle machinery is retired — LANTERN purge) ----
|
||||||
bool haveRun = SystemAPI.TryGetSingleton<RunInfo>(out var runInfo); // hoisted: the phase banner is lifecycle-aware (Phase 0 fix — it read "AT BASE" inside expedition rooms)
|
bool haveRun = SystemAPI.TryGetSingleton<RunInfo>(out var runInfo);
|
||||||
|
bool onRun = haveRun && runInfo.Lifecycle != RunLifecycle.Staging;
|
||||||
// B6: run-failed read (review-confirmed design: NEVER key on Returning — it is a 1-tick transient and
|
|
||||||
// the Charge bank lands a tick after it; detect the (in-run)->Staging edge with a launch-cached Charge.
|
|
||||||
// Lifecycle + Charge ride the SAME director ghost snapshot, so at the Staging edge the bank has arrived).
|
|
||||||
if (haveRun)
|
if (haveRun)
|
||||||
{
|
{
|
||||||
bool haveGoalNow = SystemAPI.TryGetSingleton<GoalProgress>(out var goalSnap);
|
var col = onRun ? new Color(1f, 0.8f, 0.4f) : new Color(0.45f, 0.9f, 0.7f);
|
||||||
byte lcNow = runInfo.Lifecycle;
|
_phaseText.text = onRun ? "ON EXPEDITION" : "AT BASE";
|
||||||
if (lcNow == RunLifecycle.Launching && _prevRunLifecycle == RunLifecycle.Staging)
|
|
||||||
{
|
|
||||||
_chargeAtLaunch = haveGoalNow ? goalSnap.Charge : 0;
|
|
||||||
_wentInRun = false;
|
|
||||||
}
|
|
||||||
if (lcNow == RunLifecycle.InRoom) _wentInRun = true;
|
|
||||||
if (lcNow == RunLifecycle.Staging && _prevRunLifecycle != RunLifecycle.Staging && _wentInRun)
|
|
||||||
{
|
|
||||||
if (haveGoalNow && goalSnap.Charge <= _chargeAtLaunch)
|
|
||||||
_runFailedUntil = (float)SystemAPI.Time.ElapsedTime + 6f; // wipe/abort: nothing banked
|
|
||||||
_wentInRun = false;
|
|
||||||
}
|
|
||||||
_prevRunLifecycle = lcNow;
|
|
||||||
}
|
|
||||||
bool haveCycle = SystemAPI.TryGetSingleton<CycleState>(out var cyc);
|
|
||||||
bool siege = haveCycle && cyc.Phase == CyclePhase.Siege;
|
|
||||||
bool goalFull = SystemAPI.TryGetSingleton<GoalProgress>(out var goalNow) && goalNow.Target > 0 && goalNow.Charge >= goalNow.Target;
|
|
||||||
bool finalSiege = siege && goalFull; // END-2: the climactic final siege (goal cap reached)
|
|
||||||
bool onRun = haveRun && !siege && runInfo.Lifecycle != RunLifecycle.Staging; // mid-run: the base's Calm label is wrong
|
|
||||||
if (haveCycle)
|
|
||||||
{
|
|
||||||
var endTick = new NetworkTick(cyc.PhaseEndTick);
|
|
||||||
bool arming = haveTick && cyc.PhaseEndTick != 0 && endTick.IsValid && endTick.IsNewerThan(nt.ServerTick);
|
|
||||||
bool finalArming = !siege && goalFull && arming; // the cap-reached arming window before the final wave
|
|
||||||
int secs = arming ? (endTick.TicksSince(nt.ServerTick) / 60 + 1) : 0;
|
|
||||||
string detail;
|
|
||||||
if (siege)
|
|
||||||
detail = (finalSiege ? "FINAL SIEGE" : "WAVE " + cyc.WaveNumber) + " - " + huskCount + " HUSKS";
|
|
||||||
else if (arming)
|
|
||||||
detail = (finalArming ? "FINAL SIEGE INCOMING" : "INCURSION") + " - " + secs + "s";
|
|
||||||
else
|
|
||||||
detail = "";
|
|
||||||
// END-2: the climax reads distinct (intense red), not a normal incursion/wave.
|
|
||||||
var col = finalSiege || finalArming ? new Color(1f, 0.28f, 0.22f) : PhaseColor(cyc.Phase);
|
|
||||||
_phaseText.text = (finalSiege ? "HOLD THE ENGINE" : onRun ? "ON EXPEDITION" : PhaseLabel(cyc.Phase)) + (detail.Length > 0 ? " - " + detail : "");
|
|
||||||
_phaseText.style.color = col;
|
_phaseText.style.color = col;
|
||||||
_cycleText.text = "CYCLE " + cyc.CycleNumber;
|
|
||||||
_banner.style.borderBottomColor = col;
|
_banner.style.borderBottomColor = col;
|
||||||
RetintPanel(_banner, siege ? PanelWarm : PanelDark);
|
RetintPanel(_banner, PanelDark);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_phaseText.text = "";
|
_phaseText.text = "";
|
||||||
_cycleText.text = "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- Location line (banner sub-line) — Step 14: driven by the replicated RunInfo lifecycle FSM ----
|
// ---- Location line (banner sub-line) — Step 14: driven by the replicated RunInfo lifecycle FSM ----
|
||||||
// (the old camera-X + walk-in-gate copy died with the gate; siege/final overrides below still win).
|
|
||||||
var cam = Camera.main; // camera-X region signal still feeds downstream panels (atmosphere/threat)
|
var cam = Camera.main; // camera-X region signal still feeds downstream panels (atmosphere/threat)
|
||||||
bool onExpedition = cam != null && cam.transform.position.x > ExpeditionRegionXMin;
|
bool onExpedition = cam != null && cam.transform.position.x > ExpeditionRegionXMin;
|
||||||
SystemAPI.TryGetSingleton<ExpeditionObjective>(out var obj);
|
SystemAPI.TryGetSingleton<ExpeditionObjective>(out var obj);
|
||||||
if (haveRun && !siege && !finalSiege)
|
if (haveRun)
|
||||||
{
|
{
|
||||||
switch (runInfo.Lifecycle)
|
switch (runInfo.Lifecycle)
|
||||||
{
|
{
|
||||||
case RunLifecycle.Staging:
|
case RunLifecycle.Staging:
|
||||||
// The READY panel (bottom-center) owns the action + N/M count; the top line frames intent.
|
// The READY panel (bottom-center) owns the action + N/M count; the top line frames intent.
|
||||||
if ((float)SystemAPI.Time.ElapsedTime < _runFailedUntil)
|
_locationText.text = "AT THE BASE - build defenses, buy upgrades, READY UP to launch";
|
||||||
{
|
_locationText.style.color = new Color(0.55f, 0.85f, 1f);
|
||||||
// B6: a silent wipe used to land players home with ZERO explanation.
|
|
||||||
_locationText.text = "EXPEDITION FAILED - the party fell; nothing was banked";
|
|
||||||
_locationText.style.color = new Color(1f, 0.35f, 0.3f);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_locationText.text = "AT THE BASE - build defenses, buy upgrades, READY UP to launch";
|
|
||||||
_locationText.style.color = new Color(0.55f, 0.85f, 1f);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case RunLifecycle.Launching:
|
case RunLifecycle.Launching:
|
||||||
{
|
{
|
||||||
@@ -281,33 +214,18 @@ namespace ProjectM.Client
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!haveRun)
|
|
||||||
{
|
|
||||||
_locationText.text = finalSiege
|
|
||||||
? "FINAL SIEGE - hold the Engine, this is the last stand"
|
|
||||||
: siege ? "DEFEND THE BASE - hold the line"
|
|
||||||
: "MINE THE CRYSTALS - any attack harvests Ore, then BUILD";
|
|
||||||
_locationText.style.color = finalSiege ? new Color(1f, 0.3f, 0.25f)
|
|
||||||
: siege ? new Color(1f, 0.55f, 0.4f) : new Color(0.6f, 0.95f, 0.7f);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_locationText.text = finalSiege
|
_locationText.text = "";
|
||||||
? "FINAL SIEGE - hold the Engine, this is the last stand"
|
|
||||||
: "DEFEND THE BASE - hold the line";
|
|
||||||
_locationText.style.color = finalSiege ? new Color(1f, 0.3f, 0.25f) : new Color(1f, 0.55f, 0.4f);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// The clickable READY panel (Staging/Launching, hidden once the outcome latched — the banner owns
|
// The clickable READY panel (Staging/Launching). Counts are the replicated send-to-all PlayerReady flags.
|
||||||
// the screen then). Counts are the replicated send-to-all PlayerReady flags.
|
|
||||||
int rTotal = 0, rReady = 0;
|
int rTotal = 0, rReady = 0;
|
||||||
bool localReady = false;
|
bool localReady = false;
|
||||||
int launchSecs = 0;
|
int launchSecs = 0;
|
||||||
bool terminal = SystemAPI.TryGetSingleton<RunOutcome>(out var readyOc)
|
bool readyShow = haveRun
|
||||||
&& readyOc.Value != RunOutcomeId.InProgress;
|
|
||||||
bool readyShow = haveRun && !terminal && !goalFull /* D6: goal full -> final defense armed, launching is refused server-side */
|
|
||||||
&& (runInfo.Lifecycle == RunLifecycle.Staging || runInfo.Lifecycle == RunLifecycle.Launching);
|
&& (runInfo.Lifecycle == RunLifecycle.Staging || runInfo.Lifecycle == RunLifecycle.Launching);
|
||||||
if (readyShow)
|
if (readyShow)
|
||||||
{
|
{
|
||||||
@@ -353,38 +271,9 @@ namespace ProjectM.Client
|
|||||||
// Run-depth dots — keeps the roguelite spine visible while fighting (the map only shows at gates).
|
// Run-depth dots — keeps the roguelite spine visible while fighting (the map only shows at gates).
|
||||||
UpdateRunDepth(haveRun ? runInfo : default, haveRun);
|
UpdateRunDepth(haveRun ? runInfo : default, haveRun);
|
||||||
|
|
||||||
// ---- Goal (hex-pip meter, or a continuous bar for large targets) ----
|
|
||||||
if (SystemAPI.TryGetSingleton<GoalProgress>(out var goal))
|
|
||||||
{
|
|
||||||
_goalContainer.style.display = DisplayStyle.Flex;
|
|
||||||
float gfrac = goal.Target > 0 ? Mathf.Clamp01(goal.Charge / (float)goal.Target) : 0f;
|
|
||||||
_goalText.text = "GOAL " + goal.Charge + " / " + goal.Target;
|
|
||||||
if (goal.Target >= 1 && goal.Target <= MaxPips)
|
|
||||||
{
|
|
||||||
_goalPipsRow.style.display = DisplayStyle.Flex;
|
|
||||||
_goalBar.style.display = DisplayStyle.None;
|
|
||||||
int active = Mathf.Min(goal.Charge, goal.Target); // Charge is the integer pip count; never over-fill
|
|
||||||
for (int i = 0; i < _pips.Count; i++)
|
|
||||||
{
|
|
||||||
bool show = i < goal.Target;
|
|
||||||
_pips[i].style.display = show ? DisplayStyle.Flex : DisplayStyle.None;
|
|
||||||
if (show) SetPip(_pips[i], i < active);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_goalPipsRow.style.display = DisplayStyle.None;
|
|
||||||
_goalBar.style.display = DisplayStyle.Flex;
|
|
||||||
HudUi.SetFill(_goalFill, gfrac);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_goalContainer.style.display = DisplayStyle.None;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---- Resources (feed palette affordability) ----
|
// ---- Resources (feed palette affordability) ----
|
||||||
int aether = 0, ore = 0, bio = 0, charge = 0;
|
int aether = 0, ore = 0, bio = 0;
|
||||||
if (SystemAPI.TryGetSingletonEntity<ResourceLedger>(out var ledgerE))
|
if (SystemAPI.TryGetSingletonEntity<ResourceLedger>(out var ledgerE))
|
||||||
{
|
{
|
||||||
var buf = SystemAPI.GetBuffer<StorageEntry>(ledgerE);
|
var buf = SystemAPI.GetBuffer<StorageEntry>(ledgerE);
|
||||||
@@ -394,123 +283,28 @@ namespace ProjectM.Client
|
|||||||
if (en.ItemId == ResourceId.Aether) aether = en.Count;
|
if (en.ItemId == ResourceId.Aether) aether = en.Count;
|
||||||
else if (en.ItemId == ResourceId.Ore) ore = en.Count;
|
else if (en.ItemId == ResourceId.Ore) ore = en.Count;
|
||||||
else if (en.ItemId == ResourceId.Biomass) bio = en.Count;
|
else if (en.ItemId == ResourceId.Biomass) bio = en.Count;
|
||||||
else if (en.ItemId == ResourceId.Charge) charge = en.Count;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_aetherNum.text = aether.ToString();
|
_aetherNum.text = aether.ToString();
|
||||||
_oreNum.text = ore.ToString();
|
_oreNum.text = ore.ToString();
|
||||||
_bioNum.text = bio.ToString();
|
_bioNum.text = bio.ToString();
|
||||||
_chargeNum.text = charge.ToString();
|
|
||||||
|
|
||||||
|
|
||||||
// DR-042 C6a: dim the Aether upgrade button when it isn't affordable (cost is a compile-time const).
|
|
||||||
// (Step 11: upgrade-button affordability tint retired with the button.)
|
|
||||||
// EB-2 quiet-turret cue (GLOBAL, not per-turret, so the deterministic Charge split never reads as one
|
|
||||||
// broken turret): a dry base during a siege tells the player to build a Fabricator.
|
|
||||||
if (siege && charge == 0 && !onExpedition)
|
|
||||||
{
|
|
||||||
_locationText.text = "TURRETS OUT OF AMMO - build a Fabricator (Ore -> ammo)";
|
|
||||||
_locationText.style.color = new Color(1f, 0.4f, 0.9f);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---- Engine Core integrity (END-1): a red base-heart bar; an overrun stamps a transient pulse we flash ----
|
|
||||||
if (SystemAPI.TryGetSingleton<CoreIntegrity>(out var core) && core.Max > 0)
|
|
||||||
{
|
|
||||||
_coreContainer.style.display = DisplayStyle.Flex;
|
|
||||||
float cfrac = Mathf.Clamp01(core.Current / (float)core.Max);
|
|
||||||
HudUi.SetFill(_coreFill, cfrac);
|
|
||||||
_coreText.text = "CORE " + core.Current + " / " + core.Max;
|
|
||||||
_coreText.style.color = Color.Lerp(BlightRed, CoreRed, cfrac); // shifts to danger as it drops
|
|
||||||
if (core.OverrunTick != 0 && core.OverrunTick != _lastOverrunTick)
|
|
||||||
{
|
|
||||||
_lastOverrunTick = core.OverrunTick; // edge-detect the replicated breach pulse
|
|
||||||
_overrunFlashLeft = 3.5f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_coreContainer.style.display = DisplayStyle.None;
|
|
||||||
}
|
|
||||||
// Overrun flash overrides the location line (runs AFTER the EB-2 cue so it wins; at a breach Phase is Calm).
|
|
||||||
if (_overrunFlashLeft > 0f)
|
|
||||||
{
|
|
||||||
_overrunFlashLeft -= dt;
|
|
||||||
_locationText.text = "BASE OVERRUN - resources lost; the Core will recover";
|
|
||||||
_locationText.style.color = new Color(1f, 0.3f, 0.25f);
|
|
||||||
}
|
|
||||||
// First-run onboarding owns the prompt voice: while a coach-mark step is showing, blank the HUD's own
|
|
||||||
// location/gate hint so the player sees a single prompt (OnboardingSystem drives its own overlay).
|
|
||||||
if (OnboardingState.SuppressLocationLine) _locationText.text = ""; // D4: blank only for the early base-framing steps; room/siege/charge cues survive
|
|
||||||
// D6: goal full but the final siege hasn't spawned yet (the arming gap) -> the READY panel is hidden; tell the
|
|
||||||
// player what's coming instead of a stale base line (goalFull is replicated; RunPhase is server-only).
|
|
||||||
if (haveRun && goalFull && !terminal && !siege && !finalSiege)
|
|
||||||
{
|
|
||||||
_locationText.text = "GOAL REACHED - FINAL DEFENSE INCOMING: hold the Engine!";
|
|
||||||
_locationText.style.color = new Color(1f, 0.35f, 0.28f);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---- END-2: terminal run banner (Victory / Loss), observed from the replicated RunOutcome ----
|
|
||||||
if (SystemAPI.TryGetSingleton<RunOutcome>(out var runOutcome) && runOutcome.Value != RunOutcomeId.InProgress)
|
|
||||||
{
|
|
||||||
bool win = runOutcome.Value == RunOutcomeId.Victory;
|
|
||||||
if (_outcomeFlashedFor != runOutcome.Value)
|
|
||||||
{
|
|
||||||
// One-shot landing flourish: full-screen color flash + camera kick — the beat gets a payoff.
|
|
||||||
_outcomeFlashedFor = runOutcome.Value;
|
|
||||||
_outcomeFlashLeft = win ? 0.9f : 0.7f;
|
|
||||||
PrototypeCameraRig.PunchFov(win ? 5f : 3f, win ? 420f : 260f);
|
|
||||||
PrototypeCameraRig.AddShake(win ? 0.25f : 0.5f);
|
|
||||||
}
|
|
||||||
_runBanner.style.display = DisplayStyle.Flex;
|
|
||||||
_runBannerText.text = win ? "THE ENGINE HOLDS" : "OVERRUN";
|
|
||||||
_runBannerText.style.color = win ? new Color(0.45f, 0.95f, 1f) : new Color(1f, 0.35f, 0.3f);
|
|
||||||
_runBannerSub.text = win ? "VICTORY - the final siege is broken" : "THE FINAL STAND FELL";
|
|
||||||
_runBannerSub.style.color = win ? new Color(0.7f, 0.95f, 1f) : new Color(1f, 0.6f, 0.5f);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_runBanner.style.display = DisplayStyle.None;
|
|
||||||
_outcomeFlashedFor = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Outcome flash decay (lazy element; the banner dim sits above it, the world below).
|
|
||||||
if (_outcomeFlashLeft > 0f)
|
|
||||||
{
|
|
||||||
if (_outcomeFlash == null && _doc != null && _doc.rootVisualElement != null)
|
|
||||||
{
|
|
||||||
_outcomeFlash = new VisualElement { pickingMode = PickingMode.Ignore };
|
|
||||||
_outcomeFlash.style.position = Position.Absolute;
|
|
||||||
_outcomeFlash.style.left = 0; _outcomeFlash.style.right = 0;
|
|
||||||
_outcomeFlash.style.top = 0; _outcomeFlash.style.bottom = 0;
|
|
||||||
_doc.rootVisualElement.Add(_outcomeFlash);
|
|
||||||
}
|
|
||||||
_outcomeFlashLeft -= dt;
|
|
||||||
if (_outcomeFlash != null)
|
|
||||||
{
|
|
||||||
bool winFlash = _outcomeFlashedFor == RunOutcomeId.Victory;
|
|
||||||
var fc = winFlash ? new Color(1f, 0.85f, 0.35f) : new Color(1f, 0.20f, 0.15f);
|
|
||||||
_outcomeFlash.style.backgroundColor = new Color(fc.r, fc.g, fc.b, Mathf.Clamp01(_outcomeFlashLeft) * 0.35f);
|
|
||||||
_outcomeFlash.style.display = DisplayStyle.Flex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (_outcomeFlash != null)
|
|
||||||
{
|
|
||||||
_outcomeFlash.style.display = DisplayStyle.None;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ---- Threat readout (top-right) — hidden entirely at base with zero husks; its reappearance is the cue ----
|
|
||||||
bool showThreat = siege || huskCount > 0;
|
|
||||||
|
|
||||||
|
// ---- Threat readout (top-right) — hidden entirely with zero husks; its reappearance is the cue ----
|
||||||
|
bool showThreat = huskCount > 0;
|
||||||
_threatPanel.style.display = showThreat ? DisplayStyle.Flex : DisplayStyle.None;
|
_threatPanel.style.display = showThreat ? DisplayStyle.Flex : DisplayStyle.None;
|
||||||
if (showThreat)
|
if (showThreat)
|
||||||
{
|
{
|
||||||
float intensity = Mathf.Clamp01(huskCount / 30f);
|
float intensity = Mathf.Clamp01(huskCount / 30f);
|
||||||
Color tc = siege ? Color.Lerp(ThreatWarm, BlightRed, intensity) : ThreatWarm;
|
Color tc = Color.Lerp(ThreatWarm, BlightRed, intensity);
|
||||||
_threatNum.text = huskCount.ToString();
|
_threatNum.text = huskCount.ToString();
|
||||||
_threatNum.style.color = tc;
|
_threatNum.style.color = tc;
|
||||||
_threatIcon.style.unityBackgroundImageTintColor = tc;
|
_threatIcon.style.unityBackgroundImageTintColor = tc;
|
||||||
RetintPanel(_threatPanel, siege ? PanelWarm : PanelDark);
|
RetintPanel(_threatPanel, PanelDark);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- Build palette + control hints (bottom-center) ----
|
// ---- Build palette + control hints (bottom-center) ----
|
||||||
@@ -520,10 +314,7 @@ namespace ProjectM.Client
|
|||||||
if (buildActive)
|
if (buildActive)
|
||||||
{
|
{
|
||||||
byte scheme = AimPresentation.Scheme;
|
byte scheme = AimPresentation.Scheme;
|
||||||
bool conv = BuildPaletteState.Selected == StructureType.Conveyor;
|
if (!_hintBuilt || _hintScheme != scheme) RebuildHints(scheme);
|
||||||
if (!_hintBuilt || _hintScheme != scheme || _hintConveyor != conv) RebuildHints(scheme, conv);
|
|
||||||
if (conv && _facingArrow != null)
|
|
||||||
_facingArrow.style.rotate = new StyleRotate(new Rotate(new Angle(FacingDegrees(BuildPaletteState.Direction))));
|
|
||||||
_hintBar.style.display = DisplayStyle.Flex;
|
_hintBar.style.display = DisplayStyle.Flex;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -539,9 +330,9 @@ namespace ProjectM.Client
|
|||||||
float hp = 0f, maxHp = 1f, cdFrac = 1f;
|
float hp = 0f, maxHp = 1f, cdFrac = 1f;
|
||||||
bool dead = false, shielded = false;
|
bool dead = false, shielded = false;
|
||||||
|
|
||||||
foreach (var (health, effChar, effAbility, cd, invuln, entity) in
|
foreach (var (health, effChar, cd, invuln, entity) in
|
||||||
SystemAPI.Query<RefRO<Health>, RefRO<EffectiveCharacterStats>, RefRO<EffectiveAbilityStats>,
|
SystemAPI.Query<RefRO<Health>, RefRO<EffectiveCharacterStats>,
|
||||||
RefRO<AbilityCooldown>, RefRO<RespawnInvuln>>()
|
RefRO<SocketCooldown>, RefRO<RespawnInvuln>>()
|
||||||
.WithAll<GhostOwnerIsLocal, PlayerTag>().WithEntityAccess())
|
.WithAll<GhostOwnerIsLocal, PlayerTag>().WithEntityAccess())
|
||||||
{
|
{
|
||||||
found = true;
|
found = true;
|
||||||
@@ -549,8 +340,15 @@ namespace ProjectM.Client
|
|||||||
maxHp = effChar.ValueRO.MaxHealth > 0f ? effChar.ValueRO.MaxHealth : health.ValueRO.Max;
|
maxHp = effChar.ValueRO.MaxHealth > 0f ? effChar.ValueRO.MaxHealth : health.ValueRO.Max;
|
||||||
dead = SystemAPI.IsComponentEnabled<Dead>(entity);
|
dead = SystemAPI.IsComponentEnabled<Dead>(entity);
|
||||||
|
|
||||||
uint nextFire = cd.ValueRO.NextFireTick;
|
// Cooldown bar = socket 0 (the primary Spark) of the 4-socket kit (the legacy single
|
||||||
int cdTicks = effAbility.ValueRO.CooldownTicks;
|
// AbilityCooldown died — LANTERN purge). EffectiveSocketStats row 0 supplies the duration.
|
||||||
|
uint nextFire = cd.ValueRO.Get(0);
|
||||||
|
int cdTicks = 0;
|
||||||
|
if (SystemAPI.HasBuffer<EffectiveSocketStats>(entity))
|
||||||
|
{
|
||||||
|
var effSockets = SystemAPI.GetBuffer<EffectiveSocketStats>(entity);
|
||||||
|
if (effSockets.Length > 0) cdTicks = effSockets[0].CooldownTicks;
|
||||||
|
}
|
||||||
var nextTick = new NetworkTick(nextFire);
|
var nextTick = new NetworkTick(nextFire);
|
||||||
cdFrac = (haveTick && nextFire != 0 && cdTicks > 0 && nextTick.IsValid && nextTick.IsNewerThan(nt.ServerTick))
|
cdFrac = (haveTick && nextFire != 0 && cdTicks > 0 && nextTick.IsValid && nextTick.IsNewerThan(nt.ServerTick))
|
||||||
? Mathf.Clamp01(1f - nextTick.TicksSince(nt.ServerTick) / (float)cdTicks)
|
? Mathf.Clamp01(1f - nextTick.TicksSince(nt.ServerTick) / (float)cdTicks)
|
||||||
@@ -562,7 +360,7 @@ namespace ProjectM.Client
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
_doc.rootVisualElement.style.display = (found || haveCycle) ? DisplayStyle.Flex : DisplayStyle.None;
|
_doc.rootVisualElement.style.display = (found || haveRun) ? DisplayStyle.Flex : DisplayStyle.None;
|
||||||
|
|
||||||
// ---- Low-health vignette + hurt flash (full-screen) ----
|
// ---- Low-health vignette + hurt flash (full-screen) ----
|
||||||
_flash = HudVisualMath.DecayFlash(_flash, dt);
|
_flash = HudVisualMath.DecayFlash(_flash, dt);
|
||||||
@@ -661,27 +459,10 @@ namespace ProjectM.Client
|
|||||||
else p.style.backgroundColor = c;
|
else p.style.backgroundColor = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetPip(VisualElement pip, bool active)
|
|
||||||
{
|
|
||||||
var theme = HudTheme.Get();
|
|
||||||
var spr = active ? theme?.PipActive : theme?.PipInactive;
|
|
||||||
if (spr != null)
|
|
||||||
{
|
|
||||||
pip.style.backgroundImage = new StyleBackground(Background.FromSprite(spr));
|
|
||||||
pip.style.unityBackgroundImageTintColor = active ? AetherCyan : PipDim;
|
|
||||||
pip.style.backgroundSize = new StyleBackgroundSize(new BackgroundSize(BackgroundSizeType.Contain));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pip.style.backgroundColor = active ? AetherCyan : PipDim;
|
|
||||||
MenuUi.Round(pip, 3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// DR-042 C6d: Harvester/Conveyor/Pylon are dead (unwired automation) -> hidden from the build palette
|
|
||||||
// (catalog + prefabs stay baked, code-intact per DR-020). Only Turret/Wall/Fabricator are buildable in the UI.
|
// LANTERN purge: the automation buildables are deleted; Pylon stays hidden from the build palette (cosmetic-only).
|
||||||
static bool IsPaletteType(byte type) =>
|
static bool IsPaletteType(byte type) => type != StructureType.Pylon;
|
||||||
type != StructureType.Pylon && type != StructureType.Harvester && type != StructureType.Conveyor;
|
|
||||||
|
|
||||||
void UpdatePalette(int aether, int ore, int bio, bool onExpedition)
|
void UpdatePalette(int aether, int ore, int bio, bool onExpedition)
|
||||||
{
|
{
|
||||||
@@ -769,30 +550,15 @@ namespace ProjectM.Client
|
|||||||
_palette[type] = new PaletteItem { Root = root, Cost = costLabel, CostAmount = cost, CostRes = costRes, Glow = glow, Icon = iconEl };
|
_palette[type] = new PaletteItem { Root = root, Cost = costLabel, CostAmount = cost, CostRes = costRes, Glow = glow, Icon = iconEl };
|
||||||
}
|
}
|
||||||
|
|
||||||
void RebuildHints(byte scheme, bool conveyor)
|
void RebuildHints(byte scheme)
|
||||||
{
|
{
|
||||||
_hintBar.Clear();
|
_hintBar.Clear();
|
||||||
_facingArrow = null;
|
|
||||||
var theme = HudTheme.Get();
|
var theme = HudTheme.Get();
|
||||||
bool pad = scheme == InputSchemeId.Gamepad;
|
bool pad = scheme == InputSchemeId.Gamepad;
|
||||||
AddHint(pad ? theme?.PadPlace : theme?.KbmPlace, pad ? "A" : "LMB", "PLACE");
|
AddHint(pad ? theme?.PadPlace : theme?.KbmPlace, pad ? "A" : "LMB", "PLACE");
|
||||||
AddHint(pad ? theme?.PadCancel : theme?.KbmCancel, pad ? "B" : "RMB", "CANCEL");
|
AddHint(pad ? theme?.PadCancel : theme?.KbmCancel, pad ? "B" : "RMB", "CANCEL");
|
||||||
if (conveyor)
|
|
||||||
{
|
|
||||||
// Rotate hint + a LIVE facing arrow (resolves the DR-021 conveyor-facing indicator). Only conveyors
|
|
||||||
// rotate, so this chip is gated to them — the other buildables don't show a meaningless ROTATE.
|
|
||||||
var chip = MakeChip();
|
|
||||||
chip.Add(HudUi.Glyph(pad ? theme?.PadRotate : null, pad ? "LB" : "R", 26));
|
|
||||||
var lbl = HudUi.Text("FACING", 12, MenuUi.SubCol, TextAnchor.MiddleLeft);
|
|
||||||
lbl.style.marginLeft = 5; lbl.style.marginRight = 6;
|
|
||||||
chip.Add(lbl);
|
|
||||||
_facingArrow = HudUi.Icon(theme != null ? theme.ConveyorIcon : null, 24, AetherCyan);
|
|
||||||
chip.Add(_facingArrow);
|
|
||||||
_hintBar.Add(chip);
|
|
||||||
}
|
|
||||||
AddHint(pad ? theme?.PadExit : null, pad ? "MENU" : "ESC", "EXIT");
|
AddHint(pad ? theme?.PadExit : null, pad ? "MENU" : "ESC", "EXIT");
|
||||||
_hintScheme = scheme;
|
_hintScheme = scheme;
|
||||||
_hintConveyor = conveyor;
|
|
||||||
_hintBuilt = true;
|
_hintBuilt = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -837,7 +603,6 @@ namespace ProjectM.Client
|
|||||||
BuildDiscoveryChip(root);
|
BuildDiscoveryChip(root);
|
||||||
BuildDowned(root);
|
BuildDowned(root);
|
||||||
BuildInventory(root);
|
BuildInventory(root);
|
||||||
BuildRunBanner(root);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BuildVignette(VisualElement root)
|
void BuildVignette(VisualElement root)
|
||||||
@@ -965,69 +730,13 @@ namespace ProjectM.Client
|
|||||||
_banner.Add(bIcon);
|
_banner.Add(bIcon);
|
||||||
_phaseText = HudUi.Display("", 30, AetherCyan, TextAnchor.MiddleCenter);
|
_phaseText = HudUi.Display("", 30, AetherCyan, TextAnchor.MiddleCenter);
|
||||||
_banner.Add(_phaseText);
|
_banner.Add(_phaseText);
|
||||||
_cycleText = HudUi.Text("", 14, MenuUi.SubCol, TextAnchor.MiddleCenter);
|
|
||||||
_cycleText.style.marginLeft = 14;
|
|
||||||
_banner.Add(_cycleText);
|
|
||||||
macro.Add(_banner);
|
macro.Add(_banner);
|
||||||
|
|
||||||
_locationText = HudUi.Text("", 15, new Color(0.6f, 0.85f, 1f), TextAnchor.MiddleCenter);
|
_locationText = HudUi.Text("", 15, new Color(0.6f, 0.85f, 1f), TextAnchor.MiddleCenter);
|
||||||
_locationText.style.marginTop = 5;
|
_locationText.style.marginTop = 5;
|
||||||
macro.Add(_locationText);
|
macro.Add(_locationText);
|
||||||
|
|
||||||
// goal: hex-pip meter (or fallback bar) + numeral
|
|
||||||
_goalContainer = HudUi.Group(Align.Center);
|
|
||||||
_goalContainer.style.marginTop = 8;
|
|
||||||
|
|
||||||
var goalLine = new VisualElement();
|
|
||||||
goalLine.style.flexDirection = FlexDirection.Row;
|
|
||||||
goalLine.style.alignItems = Align.Center;
|
|
||||||
goalLine.pickingMode = PickingMode.Ignore;
|
|
||||||
|
|
||||||
_goalPipsRow = new VisualElement();
|
|
||||||
_goalPipsRow.style.flexDirection = FlexDirection.Row;
|
|
||||||
_goalPipsRow.style.alignItems = Align.Center;
|
|
||||||
_goalPipsRow.pickingMode = PickingMode.Ignore;
|
|
||||||
for (int i = 0; i < MaxPips; i++)
|
|
||||||
{
|
|
||||||
var pip = new VisualElement();
|
|
||||||
pip.style.width = 22; pip.style.height = 22;
|
|
||||||
pip.style.marginLeft = 2; pip.style.marginRight = 2;
|
|
||||||
pip.style.flexShrink = 0;
|
|
||||||
pip.pickingMode = PickingMode.Ignore;
|
|
||||||
pip.style.display = DisplayStyle.None;
|
|
||||||
_pips.Add(pip);
|
|
||||||
_goalPipsRow.Add(pip);
|
|
||||||
}
|
|
||||||
goalLine.Add(_goalPipsRow);
|
|
||||||
|
|
||||||
_goalText = HudUi.Display("GOAL 0 / 10", 16, AetherCyan, TextAnchor.MiddleCenter);
|
|
||||||
_goalText.style.marginLeft = 10;
|
|
||||||
goalLine.Add(_goalText);
|
|
||||||
_goalContainer.Add(goalLine);
|
|
||||||
|
|
||||||
// fallback continuous bar (large targets)
|
|
||||||
_goalBar = HudUi.Bar(360, 16, new Color(0.8f, 0.6f, 1f), out _goalFill);
|
|
||||||
_goalBar.style.marginTop = 4;
|
|
||||||
_goalBar.style.display = DisplayStyle.None;
|
|
||||||
_goalContainer.Add(_goalBar);
|
|
||||||
|
|
||||||
macro.Add(_goalContainer);
|
|
||||||
|
|
||||||
// END-1: Engine Core integrity bar (red) — the losable base-heart meter.
|
|
||||||
_coreContainer = HudUi.Group(Align.Center);
|
|
||||||
_coreContainer.style.marginTop = 6;
|
|
||||||
var coreLine = new VisualElement();
|
|
||||||
coreLine.style.flexDirection = FlexDirection.Row;
|
|
||||||
coreLine.style.alignItems = Align.Center;
|
|
||||||
coreLine.pickingMode = PickingMode.Ignore;
|
|
||||||
_coreBar = HudUi.Bar(360, 14, CoreRed, out _coreFill);
|
|
||||||
coreLine.Add(_coreBar);
|
|
||||||
_coreText = HudUi.Text("CORE 100 / 100", 13, CoreRed, TextAnchor.MiddleLeft);
|
|
||||||
_coreText.style.marginLeft = 10;
|
|
||||||
coreLine.Add(_coreText);
|
|
||||||
_coreContainer.Add(coreLine);
|
|
||||||
_coreContainer.style.display = DisplayStyle.None;
|
|
||||||
macro.Add(_coreContainer);
|
|
||||||
|
|
||||||
root.Add(macro);
|
root.Add(macro);
|
||||||
}
|
}
|
||||||
@@ -1046,7 +755,6 @@ namespace ProjectM.Client
|
|||||||
strip.Add(ResourceChip(theme != null ? theme.AetherIcon : null, AetherCyan, "0", out _aetherNum, 26, 20));
|
strip.Add(ResourceChip(theme != null ? theme.AetherIcon : null, AetherCyan, "0", out _aetherNum, 26, 20));
|
||||||
strip.Add(ResourceChip(theme != null ? theme.OreIcon : null, OreAmber, "0", out _oreNum, 30, 22));
|
strip.Add(ResourceChip(theme != null ? theme.OreIcon : null, OreAmber, "0", out _oreNum, 30, 22));
|
||||||
strip.Add(ResourceChip(theme != null ? theme.BioIcon : null, BioGreen, "0", out _bioNum, 26, 20));
|
strip.Add(ResourceChip(theme != null ? theme.BioIcon : null, BioGreen, "0", out _bioNum, 26, 20));
|
||||||
strip.Add(ResourceChip(null, ChargeViolet, "0", out _chargeNum, 26, 20)); // EB-2 turret ammo (flat violet, no icon)
|
|
||||||
// DR-042 C6a: the only Aether sink (ability-damage upgrade) gets a visible, clickable button (was U-key
|
// DR-042 C6a: the only Aether sink (ability-damage upgrade) gets a visible, clickable button (was U-key
|
||||||
// only). The Button element handles its own picking even though the HUD root Ignores clicks.
|
// only). The Button element handles its own picking even though the HUD root Ignores clicks.
|
||||||
// (Step 11: the Aether UPGRADE-DMG button was RETIRED with AbilityUpgradeRequest — the choice-of-3
|
// (Step 11: the Aether UPGRADE-DMG button was RETIRED with AbilityUpgradeRequest — the choice-of-3
|
||||||
@@ -1142,53 +850,7 @@ namespace ProjectM.Client
|
|||||||
_downed.style.display = DisplayStyle.None;
|
_downed.style.display = DisplayStyle.None;
|
||||||
root.Add(_downed);
|
root.Add(_downed);
|
||||||
}
|
}
|
||||||
void BuildRunBanner(VisualElement root)
|
|
||||||
{
|
|
||||||
_runBanner = new VisualElement();
|
|
||||||
_runBanner.style.position = Position.Absolute;
|
|
||||||
_runBanner.style.left = 0; _runBanner.style.right = 0; _runBanner.style.top = 0; _runBanner.style.bottom = 0;
|
|
||||||
_runBanner.style.alignItems = Align.Center;
|
|
||||||
_runBanner.style.justifyContent = Justify.Center;
|
|
||||||
_runBanner.pickingMode = PickingMode.Ignore;
|
|
||||||
_runBanner.style.backgroundColor = new Color(0.02f, 0.03f, 0.05f, 0.55f);
|
|
||||||
var col = HudUi.Group(Align.Center);
|
|
||||||
_runBannerText = HudUi.Display("", 72, Color.white, TextAnchor.MiddleCenter);
|
|
||||||
col.Add(_runBannerText);
|
|
||||||
_runBannerSub = HudUi.Text("", 22, MenuUi.SubCol, TextAnchor.MiddleCenter);
|
|
||||||
_runBannerSub.style.marginTop = 8;
|
|
||||||
col.Add(_runBannerSub);
|
|
||||||
// END-2 (SL-5): the terminal banner offers a clear action so the player isn't hunting for Esc.
|
|
||||||
// SINGLE: PLAY AGAIN Continues as a fresh campaign (base+meta kept — the terminal save rolls
|
|
||||||
// forward on stage). CO-OP (operator-locked): the honest exit is a clean teardown for everyone —
|
|
||||||
// the host ends the session (each joiner's ConnectionWatchdog returns them to the menu with a
|
|
||||||
// reason), a joiner just leaves. All self-guard on WorldLauncher.Busy. The row picks (Position)
|
|
||||||
// even though the banner root Ignores.
|
|
||||||
var btnRow = new VisualElement();
|
|
||||||
btnRow.style.flexDirection = FlexDirection.Row;
|
|
||||||
btnRow.style.justifyContent = Justify.Center;
|
|
||||||
btnRow.style.marginTop = 28;
|
|
||||||
btnRow.pickingMode = PickingMode.Position;
|
|
||||||
switch (WorldLauncher.LastMode)
|
|
||||||
{
|
|
||||||
case SessionMode.Host:
|
|
||||||
btnRow.Add(MenuUi.Button("END SESSION — ALL TO MENU", WorldLauncher.TeardownToMenu));
|
|
||||||
break;
|
|
||||||
case SessionMode.Join:
|
|
||||||
btnRow.Add(MenuUi.Button("LEAVE TO MENU", WorldLauncher.TeardownToMenu));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
var again = MenuUi.Button("PLAY AGAIN",
|
|
||||||
() => WorldLauncher.StartSession(SessionMode.Single, null, SaveService.HasSave()));
|
|
||||||
again.style.marginRight = 12;
|
|
||||||
btnRow.Add(again);
|
|
||||||
btnRow.Add(MenuUi.Button("QUIT TO MENU", WorldLauncher.TeardownToMenu));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
col.Add(btnRow);
|
|
||||||
_runBanner.Add(col);
|
|
||||||
_runBanner.style.display = DisplayStyle.None;
|
|
||||||
root.Add(_runBanner);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void BuildInventory(VisualElement root)
|
void BuildInventory(VisualElement root)
|
||||||
@@ -1313,48 +975,17 @@ namespace ProjectM.Client
|
|||||||
return resId == ResourceId.Aether ? t.AetherIcon : resId == ResourceId.Biomass ? t.BioIcon : t.OreIcon;
|
return resId == ResourceId.Aether ? t.AetherIcon : resId == ResourceId.Biomass ? t.BioIcon : t.OreIcon;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Conveyor facing (BuildPaletteState.Direction 0=+X,1=-X,2=+Z,3=-Z) → arrow rotation; the arrow art points up (+Z).
|
|
||||||
static float FacingDegrees(byte dir)
|
|
||||||
{
|
|
||||||
switch (dir)
|
|
||||||
{
|
|
||||||
case 0: return 90f; // +X
|
|
||||||
case 1: return 270f; // -X
|
|
||||||
case 3: return 180f; // -Z
|
|
||||||
default: return 0f; // +Z
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static Color PhaseColor(byte phase)
|
|
||||||
{
|
|
||||||
switch (phase)
|
|
||||||
{
|
|
||||||
case CyclePhase.Calm: return new Color(0.45f, 0.9f, 0.7f);
|
|
||||||
case CyclePhase.Siege: return new Color(1f, 0.45f, 0.3f);
|
|
||||||
default: return Color.white;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static string PhaseLabel(byte phase)
|
|
||||||
{
|
|
||||||
switch (phase)
|
|
||||||
{
|
|
||||||
case CyclePhase.Calm: return "AT BASE";
|
|
||||||
case CyclePhase.Siege: return "UNDER SIEGE";
|
|
||||||
default: return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static string StructureName(byte type)
|
static string StructureName(byte type)
|
||||||
{
|
{
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case StructureType.Turret: return "Turret";
|
|
||||||
case StructureType.Wall: return "Wall";
|
case StructureType.Wall: return "Wall";
|
||||||
case StructureType.Pylon: return "Pylon";
|
case StructureType.Pylon: return "Pylon";
|
||||||
case StructureType.Harvester: return "Harvester";
|
|
||||||
case StructureType.Fabricator: return "Fabricator";
|
|
||||||
case StructureType.Conveyor: return "Conveyor";
|
|
||||||
default: return "?";
|
default: return "?";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1558,11 +1189,6 @@ namespace ProjectM.Client
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// B6 run-failed read (client-local edge state; see the tracker near the top of OnUpdate).
|
|
||||||
byte _prevRunLifecycle;
|
|
||||||
int _chargeAtLaunch;
|
|
||||||
bool _wentInRun;
|
|
||||||
float _runFailedUntil;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,8 +60,6 @@ namespace ProjectM.Client
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool haveRun = SystemAPI.TryGetSingleton<RunInfo>(out var runInfo);
|
bool haveRun = SystemAPI.TryGetSingleton<RunInfo>(out var runInfo);
|
||||||
bool haveCycle = SystemAPI.TryGetSingleton<CycleState>(out var cyc);
|
|
||||||
bool siege = haveCycle && cyc.Phase == CyclePhase.Siege;
|
|
||||||
|
|
||||||
// Aether from the ledger (the sole meta-shop currency; last entry wins, matching the core loop).
|
// Aether from the ledger (the sole meta-shop currency; last entry wins, matching the core loop).
|
||||||
int aether = 0;
|
int aether = 0;
|
||||||
@@ -76,9 +74,9 @@ namespace ProjectM.Client
|
|||||||
// server-only); tiers from the replicated MetaTierState record on the director ghost.
|
// server-only); tiers from the replicated MetaTierState record on the director ghost.
|
||||||
byte localClass = ClassTraits.WarriorClass;
|
byte localClass = ClassTraits.WarriorClass;
|
||||||
bool haveLocalPlayer = false;
|
bool haveLocalPlayer = false;
|
||||||
foreach (var (fr, ar) in SystemAPI.Query<RefRO<FrameId>, RefRO<AbilityRef>>().WithAll<PlayerTag, GhostOwnerIsLocal>())
|
foreach (var fr in SystemAPI.Query<RefRO<FrameId>>().WithAll<PlayerTag, GhostOwnerIsLocal>())
|
||||||
{
|
{
|
||||||
localClass = fr.ValueRO.Value != 0 ? fr.ValueRO.Value : ClassTraits.ClassForAbility(ar.ValueRO.Id); // FrameId signal, AbilityRef fallback
|
localClass = ClassTraits.Normalize(fr.ValueRO.Value); // FrameId is the sole class signal (legacy AbilityRef deleted)
|
||||||
haveLocalPlayer = true;
|
haveLocalPlayer = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -86,7 +84,7 @@ namespace ProjectM.Client
|
|||||||
bool metaShow = false;
|
bool metaShow = false;
|
||||||
BlobAssetReference<MetaUpgradeCatalogBlob> metaPool = default;
|
BlobAssetReference<MetaUpgradeCatalogBlob> metaPool = default;
|
||||||
DynamicBuffer<MetaTierState> metaRecord = default;
|
DynamicBuffer<MetaTierState> metaRecord = default;
|
||||||
if (haveRun && runInfo.Lifecycle == RunLifecycle.Staging && haveLocalPlayer && !siege
|
if (haveRun && runInfo.Lifecycle == RunLifecycle.Staging && haveLocalPlayer
|
||||||
&& SystemAPI.TryGetSingleton<MetaUpgradeCatalog>(out var metaCat) && metaCat.Value.IsCreated
|
&& SystemAPI.TryGetSingleton<MetaUpgradeCatalog>(out var metaCat) && metaCat.Value.IsCreated
|
||||||
&& SystemAPI.TryGetSingletonBuffer<MetaTierState>(out metaRecord, true))
|
&& SystemAPI.TryGetSingletonBuffer<MetaTierState>(out metaRecord, true))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -11,9 +11,8 @@ namespace ProjectM.Client
|
|||||||
/// every AudioSource starts the same frame with loop=true and identical clip length, and per-bar amplitude
|
/// every AudioSource starts the same frame with loop=true and identical clip length, and per-bar amplitude
|
||||||
/// envelopes reach ~zero at each bar boundary so both the chord changes and the loop point are click-free
|
/// envelopes reach ~zero at each bar boundary so both the chord changes and the loop point are click-free
|
||||||
/// (the <c>AmbientAudioSystem.Snap</c> trick generalized to enveloped segments). The MIX is the state
|
/// (the <c>AmbientAudioSystem.Snap</c> trick generalized to enveloped segments). The MIX is the state
|
||||||
/// machine: layer volumes ease toward targets chosen from replicated state only — <see cref="RunInfo"/>
|
/// machine: layer volumes ease toward targets chosen from replicated state only — the <see cref="RunInfo"/>
|
||||||
/// lifecycle (staging / combat / boss / reward lull), <see cref="CycleState"/> siege, and the terminal
|
/// lifecycle (staging / launch / combat / boss / reward lull / return). Observe-only presentation
|
||||||
/// <see cref="RunOutcome"/> (one-shot victory/defeat sting + aftermath bed). Observe-only presentation
|
|
||||||
/// system: no sim writes, no determinism surface; asset-free per the project convention. Sits under SFX at
|
/// system: no sim writes, no determinism surface; asset-free per the project convention. Sits under SFX at
|
||||||
/// <see cref="MasterVolume"/> × <see cref="GameVolume.Music"/>; the low <c>AmbientAudioSystem</c> drone
|
/// <see cref="MasterVolume"/> × <see cref="GameVolume.Music"/>; the low <c>AmbientAudioSystem</c> drone
|
||||||
/// (vol 0.10) remains as texture beneath it.
|
/// (vol 0.10) remains as texture beneath it.
|
||||||
@@ -43,7 +42,6 @@ namespace ProjectM.Client
|
|||||||
GameObject _root;
|
GameObject _root;
|
||||||
AudioSource _bass, _pad, _arp, _pulse;
|
AudioSource _bass, _pad, _arp, _pulse;
|
||||||
float _vBass, _vPad, _vArp, _vPulse; // current smoothed volumes (pre-master)
|
float _vBass, _vPad, _vArp, _vPulse; // current smoothed volumes (pre-master)
|
||||||
byte _outcomePlayed; // which terminal outcome's sting has fired (0 = none)
|
|
||||||
|
|
||||||
protected override void OnStartRunning()
|
protected override void OnStartRunning()
|
||||||
{
|
{
|
||||||
@@ -80,27 +78,7 @@ namespace ProjectM.Client
|
|||||||
// ---- pick the mix from replicated state (defaults = quiet staging bed) ----
|
// ---- pick the mix from replicated state (defaults = quiet staging bed) ----
|
||||||
float tBass = 0.50f, tPad = 0.55f, tArp = 0.12f, tPulse = 0f;
|
float tBass = 0.50f, tPad = 0.55f, tArp = 0.12f, tPulse = 0f;
|
||||||
|
|
||||||
bool haveRun = SystemAPI.TryGetSingleton<RunInfo>(out var run);
|
if (SystemAPI.TryGetSingleton<RunInfo>(out var run))
|
||||||
SystemAPI.TryGetSingleton<CycleState>(out var cyc);
|
|
||||||
bool siege = cyc.Phase == CyclePhase.Siege;
|
|
||||||
bool finalSiege = siege && SystemAPI.TryGetSingleton<GoalProgress>(out var goal)
|
|
||||||
&& goal.Target > 0 && goal.Charge >= goal.Target;
|
|
||||||
|
|
||||||
byte outcome = SystemAPI.TryGetSingleton<RunOutcome>(out var oc) ? oc.Value : RunOutcomeId.InProgress;
|
|
||||||
if (outcome != RunOutcomeId.InProgress)
|
|
||||||
{
|
|
||||||
if (_outcomePlayed != outcome)
|
|
||||||
{
|
|
||||||
_outcomePlayed = outcome;
|
|
||||||
PlayOutcomeSting(outcome == RunOutcomeId.Victory);
|
|
||||||
}
|
|
||||||
tBass = 0.20f; tPad = 0.45f; tArp = 0f; tPulse = 0f; // aftermath bed under the banner
|
|
||||||
}
|
|
||||||
else if (siege)
|
|
||||||
{
|
|
||||||
tBass = 0.70f; tPad = 0.40f; tArp = 0.60f; tPulse = finalSiege ? 0.90f : 0.65f;
|
|
||||||
}
|
|
||||||
else if (haveRun)
|
|
||||||
{
|
{
|
||||||
switch (run.Lifecycle)
|
switch (run.Lifecycle)
|
||||||
{
|
{
|
||||||
@@ -138,15 +116,7 @@ namespace ProjectM.Client
|
|||||||
_pulse.volume = _vPulse * master;
|
_pulse.volume = _vPulse * master;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayOutcomeSting(bool victory)
|
|
||||||
{
|
|
||||||
// Victory: rising A-minor->major-feel arpeggio; defeat: falling minor third crawl.
|
|
||||||
float[] notes = victory
|
|
||||||
? new[] { 220f, 277.18f, 329.63f, 440f } // A3 C#4 E4 A4 (picardy lift)
|
|
||||||
: new[] { 220f, 207.65f, 174.61f, 146.83f }; // A3 Ab3 F3 D3
|
|
||||||
var clip = BuildStingClip(notes, victory ? 0.16f : 0.28f, victory ? 0.45f : 0.40f);
|
|
||||||
if (_pad != null) _pad.PlayOneShot(clip, 0.9f * GameVolume.Music);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ================= clip builders (deterministic, asset-free) =================
|
// ================= clip builders (deterministic, asset-free) =================
|
||||||
|
|
||||||
@@ -263,23 +233,6 @@ namespace ProjectM.Client
|
|||||||
return clip;
|
return clip;
|
||||||
}
|
}
|
||||||
|
|
||||||
static AudioClip BuildStingClip(float[] notes, float noteLen, float vol)
|
|
||||||
{
|
|
||||||
int len = (int)(notes.Length * noteLen * SampleRate) + SampleRate / 2; // + half-second tail
|
|
||||||
var clip = AudioClip.Create("music_sting", len, 1, SampleRate, false);
|
|
||||||
var data = new float[len];
|
|
||||||
for (int n = 0; n < notes.Length; n++)
|
|
||||||
{
|
|
||||||
int start = (int)(n * noteLen * SampleRate);
|
|
||||||
int dur = (int)(SampleRate * (noteLen + (n == notes.Length - 1 ? 0.5f : 0.05f)));
|
|
||||||
for (int i = 0; i < dur && start + i < len; i++)
|
|
||||||
{
|
|
||||||
float tn = i / (float)SampleRate;
|
|
||||||
data[start + i] += Mathf.Sin(2f * Mathf.PI * notes[n] * tn) * Mathf.Exp(-4.5f * tn) * vol;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
clip.SetData(data, 0);
|
|
||||||
return clip;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ namespace ProjectM.Client
|
|||||||
|
|
||||||
protected override void OnUpdate()
|
protected override void OnUpdate()
|
||||||
{
|
{
|
||||||
if (UnityEngine.SceneManagement.SceneManager.GetActiveScene().name != "Game") return;
|
if (!ScenePolicy.IsGameplayScene()) return;
|
||||||
if (_root == null) return;
|
if (_root == null) return;
|
||||||
|
|
||||||
var cfg = RoomDressingConfig.Instance;
|
var cfg = RoomDressingConfig.Instance;
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
using UnityEngine.SceneManagement;
|
||||||
|
|
||||||
|
namespace ProjectM.Client
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The ONE place client presentation systems ask "is this a gameplay-look scene?" — replaces the old
|
||||||
|
/// scattered <c>scene.name == "Game"</c> string gates (LANTERN realignment: Game and DevSandbox share
|
||||||
|
/// the same look; MainMenu/ArtStaging stay untouched by the dynamic look systems).
|
||||||
|
/// </summary>
|
||||||
|
public static class ScenePolicy
|
||||||
|
{
|
||||||
|
/// <summary>True in the scenes that carry the LANTERN gameplay look (Game + DevSandbox).</summary>
|
||||||
|
public static bool IsGameplayScene()
|
||||||
|
{
|
||||||
|
var name = SceneManager.GetActiveScene().name;
|
||||||
|
return name == "Game" || name == "DevSandbox";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: f4e4ab296b48b204f866c561e9acd11d
|
||||||
@@ -62,7 +62,7 @@ namespace ProjectM.Client
|
|||||||
|
|
||||||
protected override void OnUpdate()
|
protected override void OnUpdate()
|
||||||
{
|
{
|
||||||
if (UnityEngine.SceneManagement.SceneManager.GetActiveScene().name != "Game") { Pending.Clear(); return; }
|
if (!ScenePolicy.IsGameplayScene()) { Pending.Clear(); return; }
|
||||||
if (!DecalConfig.Enabled)
|
if (!DecalConfig.Enabled)
|
||||||
{
|
{
|
||||||
Pending.Clear();
|
Pending.Clear();
|
||||||
|
|||||||
@@ -4,31 +4,26 @@ using UnityEngine;
|
|||||||
namespace ProjectM.Client
|
namespace ProjectM.Client
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Client-only ATMOSPHERE cross-fade for the two-region world. A managed presentation system
|
/// Client-only water-column ATMOSPHERE for the LANTERN seabed (deep-sea murk). A managed presentation
|
||||||
/// (SystemBase, main thread, NO Burst) in <see cref="PresentationSystemGroup"/> that OBSERVES the
|
/// system (SystemBase, main thread, NO Burst) in <see cref="PresentationSystemGroup"/> that OBSERVES the
|
||||||
/// follow-camera's world-space X and lerps <see cref="RenderSettings"/> fog + Trilight sky-ambient between
|
/// follow-camera's world-space X and lerps <see cref="RenderSettings"/> fog + flat ambient between the
|
||||||
/// the lush cyan meadow base (origin) and the hostile orange arid expedition (+1000 X) — mirroring
|
/// base-shelf murk (origin) and the deeper out-shelf murk (+1000 X) — mirroring HudSystem's region split
|
||||||
/// HudSystem's region split at camera X > 500. The directional light + skybox + post-FX volume stay
|
/// at camera X > 500. The skybox stays empty and the post-FX volume GLOBAL; only fog colour/density +
|
||||||
/// GLOBAL; only fog colour/density + ambient sky colour shift per region. Pure presentation: never mutates
|
/// ambient shift per region. Pure presentation: never mutates the simulation. Knobs live in
|
||||||
/// the simulation, no ECS query (camera + RenderSettings only). Knobs live in
|
/// <see cref="WorldAtmosphereConfig"/> (falls back to baked LANTERN-murk defaults when absent). Gated by
|
||||||
/// <see cref="WorldAtmosphereConfig"/> (falls back to baked defaults when absent). Guarded to the gameplay
|
/// <see cref="ScenePolicy.IsGameplayScene"/> so it never restyles the menu or ArtStaging. Per-room-biome
|
||||||
/// "Game" scene so it never restyles the menu. Fog enable/mode + equator/ground ambient are baked into the
|
/// murk variants key on the replicated RunInfo.CurrentBiome (re-meant to depth/water flavors — the old
|
||||||
/// scene; this only drives the per-region deltas. Phase 1.5b: also drives a per-room-biome tint on the
|
/// meadow/arid/blight palettes died in the LANTERN realignment).
|
||||||
/// expedition ground quads (MaterialPropertyBlock — the material asset is never touched).
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[WorldSystemFilter(WorldSystemFilterFlags.ClientSimulation)]
|
[WorldSystemFilter(WorldSystemFilterFlags.ClientSimulation)]
|
||||||
[UpdateInGroup(typeof(PresentationSystemGroup))]
|
[UpdateInGroup(typeof(PresentationSystemGroup))]
|
||||||
public partial class WorldAtmosphereSystem : SystemBase
|
public partial class WorldAtmosphereSystem : SystemBase
|
||||||
{
|
{
|
||||||
Camera _cam;
|
Camera _cam;
|
||||||
MeshRenderer[] _ground;
|
|
||||||
MaterialPropertyBlock _mpb;
|
|
||||||
Color _groundCur;
|
|
||||||
static readonly int BaseColorId = Shader.PropertyToID("_BaseColor");
|
|
||||||
|
|
||||||
protected override void OnUpdate()
|
protected override void OnUpdate()
|
||||||
{
|
{
|
||||||
if (UnityEngine.SceneManagement.SceneManager.GetActiveScene().name != "Game") return;
|
if (!ScenePolicy.IsGameplayScene()) return;
|
||||||
if (_cam == null) _cam = Camera.main;
|
if (_cam == null) _cam = Camera.main;
|
||||||
if (_cam == null) return;
|
if (_cam == null) return;
|
||||||
|
|
||||||
@@ -36,39 +31,34 @@ namespace ProjectM.Client
|
|||||||
float boundary = cfg != null ? cfg.BoundaryX : 500f;
|
float boundary = cfg != null ? cfg.BoundaryX : 500f;
|
||||||
float half = cfg != null ? Mathf.Max(1f, cfg.BlendHalfWidth) : 80f;
|
float half = cfg != null ? Mathf.Max(1f, cfg.BlendHalfWidth) : 80f;
|
||||||
|
|
||||||
Color baseFog = cfg != null ? cfg.BaseFogColor : new Color(0.09f, 0.13f, 0.14f, 1f);
|
// LANTERN murk defaults (match the ArtStaging source-of-truth hues; density is the play-readability knob).
|
||||||
float baseDen = cfg != null ? cfg.BaseFogDensity : 0.010f;
|
Color baseFog = cfg != null ? cfg.BaseFogColor : new Color(0.02f, 0.10f, 0.12f, 1f);
|
||||||
Color baseAmb = cfg != null ? cfg.BaseAmbientSky : new Color(0.32f, 0.38f, 0.48f, 1f);
|
float baseDen = cfg != null ? cfg.BaseFogDensity : 0.035f;
|
||||||
Color expFog = cfg != null ? cfg.ExpeditionFogColor : new Color(0.24f, 0.13f, 0.06f, 1f);
|
Color baseAmb = cfg != null ? cfg.BaseAmbientSky : new Color(0.03f, 0.055f, 0.08f, 1f);
|
||||||
float expDen = cfg != null ? cfg.ExpeditionFogDensity : 0.016f;
|
Color expFog = cfg != null ? cfg.ExpeditionFogColor : new Color(0.015f, 0.075f, 0.10f, 1f);
|
||||||
Color expAmb = cfg != null ? cfg.ExpeditionAmbientSky : new Color(0.45f, 0.31f, 0.20f, 1f);
|
float expDen = cfg != null ? cfg.ExpeditionFogDensity : 0.04f;
|
||||||
// Step 14 (expedition redesign): the EXPEDITION-side palette keys on the replicated per-room biome
|
Color expAmb = cfg != null ? cfg.ExpeditionAmbientSky : new Color(0.02f, 0.045f, 0.07f, 1f);
|
||||||
// (RunInfo.CurrentBiome) so every room re-themes — the camera-X blend still owns the base↔run fade.
|
|
||||||
// Palettes are code consts (cosmetic; per-biome config knobs can layer on later without churn).
|
// Per-room murk flavors (cosmetic code consts; all stay inside the deep-sea band — hue shifts are
|
||||||
// Phase 1.5: all palettes moved to the dark-ambient set (dynamic lights carry readability).
|
// subtle, value stays dark so dynamic lights keep carrying readability).
|
||||||
// Ground tints are ABSOLUTE _BaseColor values (the MPB replaces the authored arid sand tint).
|
|
||||||
Color groundTarget = new Color(0.60f, 0.56f, 0.50f, 1f); // authored arid sand (Mat_Ground_Arid_Dark)
|
|
||||||
bool haveRun = SystemAPI.TryGetSingleton<ProjectM.Simulation.RunInfo>(out var runInfo);
|
bool haveRun = SystemAPI.TryGetSingleton<ProjectM.Simulation.RunInfo>(out var runInfo);
|
||||||
if (haveRun && runInfo.Lifecycle != ProjectM.Simulation.RunLifecycle.Staging)
|
if (haveRun && runInfo.Lifecycle != ProjectM.Simulation.RunLifecycle.Staging)
|
||||||
{
|
{
|
||||||
switch (runInfo.CurrentBiome)
|
switch (runInfo.CurrentBiome)
|
||||||
{
|
{
|
||||||
case ProjectM.Simulation.RoomBiomeId.Meadow:
|
case ProjectM.Simulation.RoomBiomeId.Meadow: // kelp shallows: a touch greener
|
||||||
expFog = new Color(0.10f, 0.16f, 0.10f, 1f); expDen = 0.012f;
|
expFog = new Color(0.02f, 0.10f, 0.09f, 1f); expDen = 0.035f;
|
||||||
expAmb = new Color(0.30f, 0.42f, 0.32f, 1f);
|
expAmb = new Color(0.025f, 0.06f, 0.06f, 1f);
|
||||||
groundTarget = new Color(0.47f, 0.55f, 0.43f, 1f);
|
|
||||||
break;
|
break;
|
||||||
case ProjectM.Simulation.RoomBiomeId.Cavern:
|
case ProjectM.Simulation.RoomBiomeId.Cavern: // crush-dark trench: colder + denser
|
||||||
expFog = new Color(0.06f, 0.08f, 0.12f, 1f); expDen = 0.020f;
|
expFog = new Color(0.01f, 0.05f, 0.08f, 1f); expDen = 0.05f;
|
||||||
expAmb = new Color(0.24f, 0.28f, 0.38f, 1f);
|
expAmb = new Color(0.015f, 0.035f, 0.06f, 1f);
|
||||||
groundTarget = new Color(0.42f, 0.46f, 0.55f, 1f);
|
|
||||||
break;
|
break;
|
||||||
case ProjectM.Simulation.RoomBiomeId.Blight:
|
case ProjectM.Simulation.RoomBiomeId.Blight: // gloam bloom: a sick green-violet cast
|
||||||
expFog = new Color(0.13f, 0.07f, 0.15f, 1f); expDen = 0.022f;
|
expFog = new Color(0.045f, 0.075f, 0.09f, 1f); expDen = 0.045f;
|
||||||
expAmb = new Color(0.32f, 0.24f, 0.38f, 1f);
|
expAmb = new Color(0.045f, 0.05f, 0.075f, 1f);
|
||||||
groundTarget = new Color(0.52f, 0.42f, 0.58f, 1f);
|
|
||||||
break;
|
break;
|
||||||
// Arid keeps the config/default burnt-dusk orange + sand ground above.
|
// default keeps the config/fallback out-shelf murk above.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,27 +69,6 @@ namespace ProjectM.Client
|
|||||||
RenderSettings.fogColor = Color.Lerp(baseFog, expFog, t);
|
RenderSettings.fogColor = Color.Lerp(baseFog, expFog, t);
|
||||||
RenderSettings.fogDensity = Mathf.Lerp(baseDen, expDen, t);
|
RenderSettings.fogDensity = Mathf.Lerp(baseDen, expDen, t);
|
||||||
RenderSettings.ambientSkyColor = Color.Lerp(baseAmb, expAmb, t);
|
RenderSettings.ambientSkyColor = Color.Lerp(baseAmb, expAmb, t);
|
||||||
|
|
||||||
// Per-room-biome ground tint (expedition quads only; the meadow base keeps its authored material).
|
|
||||||
if (_ground == null)
|
|
||||||
{
|
|
||||||
var found = new System.Collections.Generic.List<MeshRenderer>();
|
|
||||||
foreach (var mr in Object.FindObjectsByType<MeshRenderer>(FindObjectsSortMode.None))
|
|
||||||
if (mr.gameObject.name == "Ground_Arid") found.Add(mr);
|
|
||||||
if (found.Count > 0)
|
|
||||||
{
|
|
||||||
_ground = found.ToArray();
|
|
||||||
_mpb = new MaterialPropertyBlock();
|
|
||||||
_groundCur = groundTarget; // snap on first sight — no lerp from black
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (_ground != null)
|
|
||||||
{
|
|
||||||
_groundCur = Color.Lerp(_groundCur, groundTarget, 1f - Mathf.Exp(-2.5f * UnityEngine.Time.deltaTime));
|
|
||||||
_mpb.SetColor(BaseColorId, _groundCur);
|
|
||||||
for (int i = 0; i < _ground.Length; i++)
|
|
||||||
if (_ground[i] != null) _ground[i].SetPropertyBlock(_mpb);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ namespace ProjectM.Client
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static class HowToPlayPanel
|
public static class HowToPlayPanel
|
||||||
{
|
{
|
||||||
static readonly string[] Tabs = { "Controls", "The Loop", "Build & Economy", "Threats", "Win / Lose" };
|
static readonly string[] Tabs = { "Controls", "The Loop", "Build & Economy", "Threats" };
|
||||||
|
|
||||||
public static VisualElement Build(Action onClose)
|
public static VisualElement Build(Action onClose)
|
||||||
{
|
{
|
||||||
@@ -68,7 +68,7 @@ namespace ProjectM.Client
|
|||||||
switch (idx)
|
switch (idx)
|
||||||
{
|
{
|
||||||
case 0: // Controls (chosen class)
|
case 0: // Controls (chosen class)
|
||||||
bool ranger = WorldLauncher.SelectedClass == (byte)CharacterId.Ranger;
|
bool ranger = WorldLauncher.SelectedClass == (byte)FrameKind.Ranger;
|
||||||
Head(c, ranger ? "CLASS: Ranger (ranged anchor)" : "CLASS: Warrior (melee anchor)");
|
Head(c, ranger ? "CLASS: Ranger (ranged anchor)" : "CLASS: Warrior (melee anchor)");
|
||||||
Body(c, "Move — WASD / Left Stick");
|
Body(c, "Move — WASD / Left Stick");
|
||||||
Body(c, "Aim — Mouse cursor / Right Stick");
|
Body(c, "Aim — Mouse cursor / Right Stick");
|
||||||
@@ -85,35 +85,24 @@ namespace ProjectM.Client
|
|||||||
Body(c, "Pause — Esc");
|
Body(c, "Pause — Esc");
|
||||||
break;
|
break;
|
||||||
case 1: // The Loop
|
case 1: // The Loop
|
||||||
Head(c, "THE LOOP — expedition RUNS are how you win");
|
Head(c, "THE LOOP — descend, fight, bank");
|
||||||
Body(c, "1. BASE — pick your CLASS + buy PREP buffs (this run only); build Turrets + a Fabricator; spend Aether on PERMANENT class upgrades.");
|
Body(c, "1. BASE — pick your suit-frame, buy PREP buffs (this run only), spend Aether on PERMANENT upgrades.");
|
||||||
Body(c, "2. READY UP [T] — when everyone is ready, the party launches into a multi-room run together.");
|
Body(c, "2. READY UP [T] — when everyone is ready, the party launches into a multi-room run together.");
|
||||||
Body(c, "3. RUN — clear each room, pick 1 of 3 BOONS (this run only), choose your path on the map, mine the crystals.");
|
Body(c, "3. RUN — clear each room, pick 1 of 3 BOONS (this run only), choose your path, mine the crystals.");
|
||||||
Body(c, "4. BOSS — fell it and the party returns with the haul: +1 on the Engine meter. A wipe banks nothing.");
|
Body(c, "4. BOSS — fell it and the party returns with the haul. A wipe banks nothing but the depth record.");
|
||||||
Body(c, "5. SIEGE — a completed run provokes retaliation at base. Defend the Core!");
|
|
||||||
Body(c, "6. WIN — fill the Engine meter, then hold the final siege.");
|
|
||||||
break;
|
break;
|
||||||
case 2: // Build & Economy
|
case 2: // Build & Economy
|
||||||
Head(c, "RESOURCES & BUILDING");
|
Head(c, "RESOURCES & BUILDING");
|
||||||
Body(c, "Ore — main currency. Attack the glowing crystals INSIDE runs and haul them home (they're scarce — spend well).");
|
Body(c, "Ore — main currency. Attack the glowing crystals INSIDE runs and haul them home (they're scarce — spend well).");
|
||||||
Body(c, "Turret (40 Ore) — auto-fires at enemies. Needs Charge as ammo.");
|
|
||||||
Body(c, "Fabricator (30 Ore) — converts Ore → Charge so turrets keep firing.");
|
|
||||||
Body(c, "Wall (Biomass) — a cheap barrier that blocks enemies.");
|
Body(c, "Wall (Biomass) — a cheap barrier that blocks enemies.");
|
||||||
Body(c, "Aether — rare; fuels PERMANENT class upgrades at the base between runs.");
|
Body(c, "Aether — rare; fuels PERMANENT upgrades at the base between runs.");
|
||||||
Body(c, "Open Build with Tab (Y), pick a piece, click a green tile to place it.");
|
Body(c, "Open Build with Tab (Y), pick a piece, click a green tile to place it.");
|
||||||
break;
|
break;
|
||||||
case 3: // Threats
|
default: // Threats
|
||||||
Head(c, "THREATS");
|
Head(c, "THREATS");
|
||||||
Body(c, "Husks assault the base during a Siege — keep them off the Engine Core.");
|
|
||||||
Body(c, "A Husk that reaches the Core drains it. Lose the Core in the final siege and the run ends.");
|
|
||||||
Body(c, "Runs escalate room by room — elites guard the deep paths, a boss guards the end.");
|
Body(c, "Runs escalate room by room — elites guard the deep paths, a boss guards the end.");
|
||||||
Body(c, "Enemy variety scales the deeper you push.");
|
Body(c, "Enemy variety scales the deeper you push.");
|
||||||
break;
|
Body(c, "What the light doesn't hold, the dark takes back.");
|
||||||
default: // Win / Lose
|
|
||||||
Head(c, "WIN / LOSE");
|
|
||||||
Body(c, "WIN — clear expeditions to fill the Engine meter, then hold the final siege.");
|
|
||||||
Body(c, "LOSE — the Engine Core falls during the final siege.");
|
|
||||||
Body(c, "A Core breach mid-run is only a setback: resources lost, the Core recovers in Calm.");
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,17 +48,11 @@ namespace ProjectM.Client
|
|||||||
public Sprite BioIcon;
|
public Sprite BioIcon;
|
||||||
|
|
||||||
[Header("Structure icons")]
|
[Header("Structure icons")]
|
||||||
public Sprite TurretIcon;
|
|
||||||
public Sprite WallIcon;
|
public Sprite WallIcon;
|
||||||
public Sprite PylonIcon;
|
public Sprite PylonIcon;
|
||||||
public Sprite HarvesterIcon;
|
|
||||||
public Sprite FabricatorIcon;
|
|
||||||
public Sprite ConveyorIcon;
|
|
||||||
|
|
||||||
[Header("Build-ghost preview meshes (authored real-size, ground pivot — BuildSendSystem)")]
|
[Header("Build-ghost preview meshes (authored real-size, ground pivot — BuildSendSystem)")]
|
||||||
public Mesh TurretGhostMesh;
|
|
||||||
public Mesh WallGhostMesh;
|
public Mesh WallGhostMesh;
|
||||||
public Mesh FabricatorGhostMesh;
|
|
||||||
|
|
||||||
[Header("Build-mode control glyphs")]
|
[Header("Build-mode control glyphs")]
|
||||||
public Sprite KbmPlace; // LMB
|
public Sprite KbmPlace; // LMB
|
||||||
@@ -86,12 +80,8 @@ namespace ProjectM.Client
|
|||||||
{
|
{
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case StructureType.Turret: return TurretIcon;
|
|
||||||
case StructureType.Wall: return WallIcon;
|
case StructureType.Wall: return WallIcon;
|
||||||
case StructureType.Pylon: return PylonIcon;
|
case StructureType.Pylon: return PylonIcon;
|
||||||
case StructureType.Harvester: return HarvesterIcon;
|
|
||||||
case StructureType.Fabricator: return FabricatorIcon;
|
|
||||||
case StructureType.Conveyor: return ConveyorIcon;
|
|
||||||
default: return null;
|
default: return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -101,9 +91,7 @@ namespace ProjectM.Client
|
|||||||
{
|
{
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case StructureType.Turret: return TurretGhostMesh;
|
|
||||||
case StructureType.Wall: return WallGhostMesh;
|
case StructureType.Wall: return WallGhostMesh;
|
||||||
case StructureType.Fabricator: return FabricatorGhostMesh;
|
|
||||||
default: return null;
|
default: return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -99,8 +99,8 @@ namespace ProjectM.Client
|
|||||||
var classRow = new VisualElement();
|
var classRow = new VisualElement();
|
||||||
classRow.style.flexDirection = FlexDirection.Row;
|
classRow.style.flexDirection = FlexDirection.Row;
|
||||||
classRow.style.justifyContent = Justify.Center;
|
classRow.style.justifyContent = Justify.Center;
|
||||||
classRow.Add(MenuUi.Button("Warrior", () => SelectClass((byte)CharacterId.Warrior)));
|
classRow.Add(MenuUi.Button("Warrior", () => SelectClass((byte)FrameKind.Warrior)));
|
||||||
classRow.Add(MenuUi.Button("Ranger", () => SelectClass((byte)CharacterId.Ranger)));
|
classRow.Add(MenuUi.Button("Ranger", () => SelectClass((byte)FrameKind.Ranger)));
|
||||||
card.Add(classRow);
|
card.Add(classRow);
|
||||||
|
|
||||||
card.Add(MenuUi.Button("Single Player", () => Launch(SessionMode.Single, false)));
|
card.Add(MenuUi.Button("Single Player", () => Launch(SessionMode.Single, false)));
|
||||||
@@ -149,7 +149,7 @@ namespace ProjectM.Client
|
|||||||
if (_classLabel != null) _classLabel.text = ClassName(classId);
|
if (_classLabel != null) _classLabel.text = ClassName(classId);
|
||||||
}
|
}
|
||||||
|
|
||||||
static string ClassName(byte classId) => classId == (byte)CharacterId.Ranger ? "CLASS: Ranger (ranged)" : "CLASS: Warrior (melee)";
|
static string ClassName(byte classId) => classId == (byte)FrameKind.Ranger ? "CLASS: Ranger (ranged)" : "CLASS: Warrior (melee)";
|
||||||
|
|
||||||
void ShowSettings()
|
void ShowSettings()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -28,8 +28,8 @@ namespace ProjectM.Client
|
|||||||
|
|
||||||
public static bool Busy { get; private set; }
|
public static bool Busy { get; private set; }
|
||||||
|
|
||||||
/// <summary>Slice 2: the class chosen in the menu (a CharacterId byte), seeded into the client world at session start.</summary>
|
/// <summary>Slice 2: the frame chosen in the menu (a FrameKind byte), seeded into the client world at session start.</summary>
|
||||||
public static byte SelectedClass = (byte)CharacterId.Warrior;
|
public static byte SelectedClass = (byte)FrameKind.Warrior;
|
||||||
|
|
||||||
/// <summary>The mode of the most recently started session — the HUD's outcome banner branches on it
|
/// <summary>The mode of the most recently started session — the HUD's outcome banner branches on it
|
||||||
/// (single: PLAY AGAIN restarts; co-op: the honest exit is a clean teardown for everyone).</summary>
|
/// (single: PLAY AGAIN restarts; co-op: the honest exit is a clean teardown for everyone).</summary>
|
||||||
@@ -129,17 +129,11 @@ namespace ProjectM.Client
|
|||||||
static void StagePendingSave(World server)
|
static void StagePendingSave(World server)
|
||||||
{
|
{
|
||||||
var data = SaveService.Load();
|
var data = SaveService.Load();
|
||||||
// A terminal (won/lost) save Continues as a FRESH campaign — base+meta kept, outcome/meter/core reset
|
|
||||||
// (else the dead outcome banner re-latches from the first snapshot).
|
|
||||||
SaveService.RollTerminalCampaignForward(data);
|
|
||||||
|
|
||||||
if (data == null) return;
|
if (data == null) return;
|
||||||
var em = server.EntityManager;
|
var em = server.EntityManager;
|
||||||
var e = em.CreateEntity();
|
var e = em.CreateEntity();
|
||||||
// v5->v6 migration (operator-approved): an old save's Charge counted boss-cleared runs (DR-042), so a
|
em.AddComponentData(e, new PendingSave { RunsCompleted = data.RunsCompleted, MaxDepthReached = data.MaxDepthReached, HasData = 1 });
|
||||||
// missing RunsCompleted floors to it — the HUD never shows "Charge 3/4" beside "Runs completed: 0".
|
|
||||||
int runsCompleted = data.RunsCompleted > data.GoalCharge ? data.RunsCompleted : data.GoalCharge;
|
|
||||||
em.AddComponentData(e, new PendingSave { GoalCharge = data.GoalCharge, GoalTarget = data.GoalTarget, CoreCurrent = data.CoreCurrent, RunOutcome = (byte)data.RunOutcome, RunsCompleted = runsCompleted, MaxDepthReached = data.MaxDepthReached, HasData = 1 });
|
|
||||||
// v6: stage the meta tiers UNCONDITIONALLY (empty OK — the Bursted spawn system GetBuffers it in the
|
// v6: stage the meta tiers UNCONDITIONALLY (empty OK — the Bursted spawn system GetBuffers it in the
|
||||||
// HasData block; a conditional buffer would throw on any v<=5 Continue). Rows verbatim, no clamping.
|
// HasData block; a conditional buffer would throw on any v<=5 Continue). Rows verbatim, no clamping.
|
||||||
var mbuf = em.AddBuffer<PendingMetaRow>(e);
|
var mbuf = em.AddBuffer<PendingMetaRow>(e);
|
||||||
@@ -159,10 +153,6 @@ namespace ProjectM.Client
|
|||||||
var sbuf = em.AddBuffer<PendingStructure>(se);
|
var sbuf = em.AddBuffer<PendingStructure>(se);
|
||||||
foreach (var s in data.Structures)
|
foreach (var s in data.Structures)
|
||||||
sbuf.Add(SaveApply.ToPending(s)); // EB-1: pure mapping (unit-tested, incl. the wounded HP)
|
sbuf.Add(SaveApply.ToPending(s)); // EB-1: pure mapping (unit-tested, incl. the wounded HP)
|
||||||
var iobuf = em.AddBuffer<PendingStructureIo>(se);
|
|
||||||
if (data.StructureIo != null)
|
|
||||||
foreach (var io in data.StructureIo)
|
|
||||||
iobuf.Add(new PendingStructureIo { StructureIndex = io.StructureIndex, Slot = io.Slot, ResourceId = io.ResourceId, Count = io.Count });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,9 +165,6 @@ namespace ProjectM.Client
|
|||||||
using var q = em.CreateEntityQuery(ComponentType.ReadOnly<ResourceLedger>());
|
using var q = em.CreateEntityQuery(ComponentType.ReadOnly<ResourceLedger>());
|
||||||
if (q.IsEmptyIgnoreFilter) return;
|
if (q.IsEmptyIgnoreFilter) return;
|
||||||
var dir = q.GetSingletonEntity();
|
var dir = q.GetSingletonEntity();
|
||||||
var goal = em.HasComponent<GoalProgress>(dir) ? em.GetComponentData<GoalProgress>(dir) : default;
|
|
||||||
var core = em.HasComponent<CoreIntegrity>(dir) ? em.GetComponentData<CoreIntegrity>(dir) : default; // END-1
|
|
||||||
var outcome = em.HasComponent<RunOutcome>(dir) ? em.GetComponentData<RunOutcome>(dir) : default; // END-2
|
|
||||||
|
|
||||||
var buffer = em.GetBuffer<StorageEntry>(dir, true);
|
var buffer = em.GetBuffer<StorageEntry>(dir, true);
|
||||||
var rows = new LedgerRow[buffer.Length];
|
var rows = new LedgerRow[buffer.Length];
|
||||||
@@ -195,21 +182,16 @@ namespace ProjectM.Client
|
|||||||
// v6: the permanent-meta slice via the ONE shared collector — omitting it HERE (the most common
|
// v6: the permanent-meta slice via the ONE shared collector — omitting it HERE (the most common
|
||||||
// exit path) would silently WIPE all meta progression on quit (the meta review's top blocker).
|
// exit path) would silently WIPE all meta progression on quit (the meta review's top blocker).
|
||||||
MetaSaveScan.Collect(em, dir, out var metaRows, out var runsCompleted, out var maxDepth);
|
MetaSaveScan.Collect(em, dir, out var metaRows, out var runsCompleted, out var maxDepth);
|
||||||
SaveStructureScan.Collect(em, nowTick, out var structures, out var structureIo);
|
SaveStructureScan.Collect(em, nowTick, out var structures);
|
||||||
|
|
||||||
SaveService.Save(new SaveData
|
SaveService.Save(new SaveData
|
||||||
{
|
{
|
||||||
GoalCharge = goal.Charge,
|
|
||||||
GoalTarget = goal.Target,
|
|
||||||
CoreCurrent = core.Current,
|
|
||||||
RunsCompleted = runsCompleted,
|
RunsCompleted = runsCompleted,
|
||||||
MaxDepthReached = maxDepth,
|
MaxDepthReached = maxDepth,
|
||||||
MetaUpgrades = metaRows,
|
MetaUpgrades = metaRows,
|
||||||
RunOutcome = outcome.Value,
|
|
||||||
|
|
||||||
Ledger = rows,
|
Ledger = rows,
|
||||||
Structures = structures,
|
Structures = structures,
|
||||||
StructureIo = structureIo,
|
|
||||||
SavedAtMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
|
SavedAtMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,6 +62,71 @@ namespace ProjectM.EditorTools
|
|||||||
Debug.Log("[PlayerRigTools] AC_PlayerTopDown: IsAttacking + idle-based MeleeSwing built (no un-keyed-bone collapse).");
|
Debug.Log("[PlayerRigTools] AC_PlayerTopDown: IsAttacking + idle-based MeleeSwing built (no un-keyed-bone collapse).");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>LANTERN P5 (realignment): swap the Bathynaut suit body onto Player.prefab IN PLACE (GUID
|
||||||
|
/// preserved — the subscene PlayerSpawner refs never break). Mirrors the proven EnemyRigTools.BuildOne
|
||||||
|
/// recipe: strip the old Synty-soldier skeleton + SMR children (every ROOT component — ghost/authoring/
|
||||||
|
/// CC/Animator/RigDefinitionAuthoring — stays), flatten the suit body's skeleton + SMRs under the player
|
||||||
|
/// root, keep the feet-on-ground Root offset, re-slot the deformation material, and adopt the clone's
|
||||||
|
/// avatar (same shared humanoid Characters avatar — AC_PlayerTopDown's muscle clips retarget). Both
|
||||||
|
/// frames share this visual until per-frame player models land. Idempotent / re-runnable.</summary>
|
||||||
|
[MenuItem("ProjectM/Animation/Player - Build Bathynaut Player (LANTERN)")]
|
||||||
|
public static void BuildBathynautPlayer()
|
||||||
|
{
|
||||||
|
const string synty = "Assets/Synty/PolygonSciFiSpace/Prefabs/Characters/SM_Chr_SpaceSoldier_HelmetArmor_Male_01.prefab";
|
||||||
|
const string matPath = "Assets/_Project/Materials/M_SuitFrame_Bathynaut_Animated.mat";
|
||||||
|
const string output = "Assets/_Project/Prefabs/Player.prefab";
|
||||||
|
const float rootY = -0.90f; // the player's existing feet-on-ground offset (entity origin = capsule center)
|
||||||
|
|
||||||
|
var syntyAsset = AssetDatabase.LoadAssetAtPath<GameObject>(synty);
|
||||||
|
var mat = AssetDatabase.LoadAssetAtPath<Material>(matPath);
|
||||||
|
if (syntyAsset == null) { Debug.LogError($"[PlayerRigTools] Suit body prefab missing: {synty}"); return; }
|
||||||
|
if (mat == null) { Debug.LogError($"[PlayerRigTools] Deformation material missing: {matPath}"); return; }
|
||||||
|
|
||||||
|
var root = PrefabUtility.LoadPrefabContents(output);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Strip ONLY the old visual (skeleton + SMR children); root components stay untouched.
|
||||||
|
var kids = new System.Collections.Generic.List<Transform>();
|
||||||
|
foreach (Transform c in root.transform) kids.Add(c);
|
||||||
|
foreach (var c in kids) Object.DestroyImmediate(c.gameObject);
|
||||||
|
|
||||||
|
// Clone the suit body (unlinked) and flatten its skeleton + SMRs under the player root.
|
||||||
|
var clone = (GameObject)Object.Instantiate(syntyAsset);
|
||||||
|
var srcAnimator = clone.GetComponentInChildren<Animator>();
|
||||||
|
var avatar = srcAnimator != null ? srcAnimator.avatar : null;
|
||||||
|
var children = new System.Collections.Generic.List<Transform>();
|
||||||
|
foreach (Transform c in clone.transform) children.Add(c);
|
||||||
|
foreach (var c in children) c.SetParent(root.transform, false); // keep local transforms
|
||||||
|
Object.DestroyImmediate(clone);
|
||||||
|
|
||||||
|
// Feet-on-ground: offset the un-keyed Root bone.
|
||||||
|
var rootBone = root.transform.Find("Root");
|
||||||
|
if (rootBone != null) { var lp = rootBone.localPosition; lp.y = rootY; rootBone.localPosition = lp; }
|
||||||
|
else Debug.LogWarning("[PlayerRigTools] No 'Root' bone after the swap; feet offset skipped.");
|
||||||
|
|
||||||
|
// Deformation material on every SMR slot (else unskinned-static under Entities Graphics).
|
||||||
|
foreach (var smr in root.GetComponentsInChildren<SkinnedMeshRenderer>(true))
|
||||||
|
{
|
||||||
|
var mats = smr.sharedMaterials;
|
||||||
|
for (int i = 0; i < mats.Length; i++) mats[i] = mat;
|
||||||
|
smr.sharedMaterials = mats;
|
||||||
|
}
|
||||||
|
|
||||||
|
var anim = root.GetComponent<Animator>();
|
||||||
|
if (anim != null && avatar != null) anim.avatar = avatar; // controller (AC_PlayerTopDown) stays
|
||||||
|
|
||||||
|
PrefabUtility.SaveAsPrefabAsset(root, output);
|
||||||
|
Debug.Log("[PlayerRigTools] Bathynaut suit body swapped onto Player.prefab (in place).");
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
PrefabUtility.UnloadPrefabContents(root);
|
||||||
|
}
|
||||||
|
AssetDatabase.SaveAssets();
|
||||||
|
AssetDatabase.Refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static AnimationClip FindIdleClip(AnimatorController ac)
|
static AnimationClip FindIdleClip(AnimatorController ac)
|
||||||
{
|
{
|
||||||
foreach (var c in ac.layers[0].stateMachine.states)
|
foreach (var c in ac.layers[0].stateMachine.states)
|
||||||
|
|||||||
@@ -10,13 +10,11 @@ namespace ProjectM.Server
|
|||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// One-shot server restore of player-built structures for a "Continue" session. The menu (WorldLauncher) stages a
|
/// One-shot server restore of player-built structures for a "Continue" session. The menu (WorldLauncher) stages a
|
||||||
/// <see cref="PendingStructure"/>/<see cref="PendingStructureIo"/> carrier in the fresh ServerWorld BEFORE the
|
/// <see cref="PendingStructure"/> carrier in the fresh ServerWorld BEFORE the gameplay subscene streams; this
|
||||||
/// gameplay subscene streams; this system waits (RequireForUpdate) for the streamed <see cref="StructureCatalog"/>
|
/// system waits (RequireForUpdate) for the streamed <see cref="StructureCatalog"/> + <see cref="BaseAnchor"/> +
|
||||||
/// + <see cref="BaseAnchor"/> + a valid NetworkTime, then replays each saved structure CHARGE-FREE: Instantiate the
|
/// a valid NetworkTime, then replays each saved structure CHARGE-FREE: Instantiate the catalog prefab at the
|
||||||
/// catalog prefab at the saved cell (preserving the baked Scale), re-stamp the rebased tick fields
|
/// saved cell (preserving the baked Scale), restore the wounded HP born-correct, re-tag RegionTag{Base} +
|
||||||
/// (<see cref="ProductionMath.RestoreNextTick"/>; LastProcessed = now so within-session catch-up resumes from now,
|
/// RuntimePlacedTag, then DESTROY the carrier so it never runs again. The ledger restores separately +
|
||||||
/// never a wall-clock mint), re-tag RegionTag{Base} + RuntimePlacedTag, refill the in-flight conveyor item + the
|
|
||||||
/// machine I/O buffers, then DESTROY the carrier so it never runs again. The ledger/goal restore separately +
|
|
||||||
/// absolutely via CycleDirectorSpawnSystem's born-correct load (no double-spend, no Withdraw here).
|
/// absolutely via CycleDirectorSpawnSystem's born-correct load (no double-spend, no Withdraw here).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[BurstCompile]
|
[BurstCompile]
|
||||||
@@ -24,14 +22,12 @@ namespace ProjectM.Server
|
|||||||
public partial struct BaseRestoreSystem : ISystem
|
public partial struct BaseRestoreSystem : ISystem
|
||||||
{
|
{
|
||||||
ComponentLookup<LocalTransform> m_TransformLookup;
|
ComponentLookup<LocalTransform> m_TransformLookup;
|
||||||
ComponentLookup<Conveyor> m_ConveyorLookup;
|
|
||||||
ComponentLookup<Health> m_HealthLookup;
|
ComponentLookup<Health> m_HealthLookup;
|
||||||
|
|
||||||
[BurstCompile]
|
[BurstCompile]
|
||||||
public void OnCreate(ref SystemState state)
|
public void OnCreate(ref SystemState state)
|
||||||
{
|
{
|
||||||
m_TransformLookup = state.GetComponentLookup<LocalTransform>(isReadOnly: true);
|
m_TransformLookup = state.GetComponentLookup<LocalTransform>(isReadOnly: true);
|
||||||
m_ConveyorLookup = state.GetComponentLookup<Conveyor>(isReadOnly: true);
|
|
||||||
m_HealthLookup = state.GetComponentLookup<Health>(isReadOnly: true);
|
m_HealthLookup = state.GetComponentLookup<Health>(isReadOnly: true);
|
||||||
state.RequireForUpdate<StructureCatalog>();
|
state.RequireForUpdate<StructureCatalog>();
|
||||||
state.RequireForUpdate<BaseAnchor>();
|
state.RequireForUpdate<BaseAnchor>();
|
||||||
@@ -48,7 +44,6 @@ namespace ProjectM.Server
|
|||||||
uint now = serverTick.TickIndexForValidTick;
|
uint now = serverTick.TickIndexForValidTick;
|
||||||
|
|
||||||
m_TransformLookup.Update(ref state);
|
m_TransformLookup.Update(ref state);
|
||||||
m_ConveyorLookup.Update(ref state);
|
|
||||||
m_HealthLookup.Update(ref state);
|
m_HealthLookup.Update(ref state);
|
||||||
|
|
||||||
var anchor = SystemAPI.GetSingleton<BaseAnchor>();
|
var anchor = SystemAPI.GetSingleton<BaseAnchor>();
|
||||||
@@ -56,8 +51,8 @@ namespace ProjectM.Server
|
|||||||
|
|
||||||
var ecb = new EntityCommandBuffer(Allocator.Temp);
|
var ecb = new EntityCommandBuffer(Allocator.Temp);
|
||||||
|
|
||||||
foreach (var (pending, ioBuf, carrier) in
|
foreach (var (pending, carrier) in
|
||||||
SystemAPI.Query<DynamicBuffer<PendingStructure>, DynamicBuffer<PendingStructureIo>>().WithEntityAccess())
|
SystemAPI.Query<DynamicBuffer<PendingStructure>>().WithEntityAccess())
|
||||||
{
|
{
|
||||||
for (int s = 0; s < pending.Length; s++)
|
for (int s = 0; s < pending.Length; s++)
|
||||||
{
|
{
|
||||||
@@ -81,12 +76,12 @@ namespace ProjectM.Server
|
|||||||
{
|
{
|
||||||
Type = p.Type,
|
Type = p.Type,
|
||||||
Cell = cell,
|
Cell = cell,
|
||||||
NextTick = ProductionMath.RestoreNextTick(now, p.RemainingTicks),
|
NextTick = 0u, // cooldown restore retired with the automation chain (LANTERN purge)
|
||||||
LastProcessedTick = TickUtil.NonZero(now),
|
LastProcessedTick = TickUtil.NonZero(now),
|
||||||
});
|
});
|
||||||
// EB-1: restore the wounded HP born-correct in the SAME ecb as Instantiate (Health.Current is a
|
// EB-1: restore the wounded HP born-correct in the SAME ecb as Instantiate (Health.Current is a
|
||||||
// [GhostField]; a deferred set would leak baked Max to clients for one snapshot). Max + the
|
// [GhostField]; a deferred set would leak baked Max to clients for one snapshot). Max + the
|
||||||
// 0->full fallback come from the BAKED prefab, never the save. Automation machines lack Health.
|
// 0->full fallback come from the BAKED prefab, never the save.
|
||||||
if (m_HealthLookup.HasComponent(prefab))
|
if (m_HealthLookup.HasComponent(prefab))
|
||||||
{
|
{
|
||||||
var hm = m_HealthLookup[prefab];
|
var hm = m_HealthLookup[prefab];
|
||||||
@@ -94,35 +89,6 @@ namespace ProjectM.Server
|
|||||||
}
|
}
|
||||||
ecb.AddComponent(structure, new RegionTag { Region = RegionId.Base });
|
ecb.AddComponent(structure, new RegionTag { Region = RegionId.Base });
|
||||||
ecb.AddComponent<RuntimePlacedTag>(structure);
|
ecb.AddComponent<RuntimePlacedTag>(structure);
|
||||||
|
|
||||||
if (p.Type == StructureType.Conveyor && m_ConveyorLookup.HasComponent(prefab))
|
|
||||||
{
|
|
||||||
var conv = m_ConveyorLookup[prefab];
|
|
||||||
conv.Direction = p.Direction;
|
|
||||||
ecb.SetComponent(structure, conv);
|
|
||||||
ecb.SetComponent(structure, new ConveyorItem { ResourceId = p.ConveyorResId, Count = p.ConveyorCount });
|
|
||||||
ecb.SetComponentEnabled<ConveyorItem>(structure, p.ConveyorCount > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Refill machine I/O buffers from the flat io table (only slots with saved rows -> the prefab has them).
|
|
||||||
bool inInit = false, outInit = false;
|
|
||||||
DynamicBuffer<MachineInput> inBuf = default;
|
|
||||||
DynamicBuffer<MachineOutput> outBuf = default;
|
|
||||||
for (int r = 0; r < ioBuf.Length; r++)
|
|
||||||
{
|
|
||||||
if (ioBuf[r].StructureIndex != s)
|
|
||||||
continue;
|
|
||||||
if (ioBuf[r].Slot == 0)
|
|
||||||
{
|
|
||||||
if (!inInit) { inBuf = ecb.SetBuffer<MachineInput>(structure); inInit = true; }
|
|
||||||
inBuf.Add(new MachineInput { ResourceId = ioBuf[r].ResourceId, Count = ioBuf[r].Count });
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!outInit) { outBuf = ecb.SetBuffer<MachineOutput>(structure); outInit = true; }
|
|
||||||
outBuf.Add(new MachineOutput { ResourceId = ioBuf[r].ResourceId, Count = ioBuf[r].Count });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ecb.DestroyEntity(carrier);
|
ecb.DestroyEntity(carrier);
|
||||||
|
|||||||
@@ -1,276 +0,0 @@
|
|||||||
using ProjectM.Simulation;
|
|
||||||
using Unity.Burst;
|
|
||||||
using Unity.Collections;
|
|
||||||
using Unity.Entities;
|
|
||||||
using Unity.Mathematics;
|
|
||||||
using Unity.NetCode;
|
|
||||||
|
|
||||||
namespace ProjectM.Server
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Server-only, deterministic conveyor transport — the MIDDLE of the M7 auto-gather chain
|
|
||||||
/// (Harvester → Conveyor → Fabricator). Unlike the per-machine catch-up production systems, a conveyor is a
|
|
||||||
/// single TRANSPORT STEP: each period-due, empty <see cref="Conveyor"/> first PULLS one item off an adjacent
|
|
||||||
/// upstream <see cref="MachineOutput"/> (the cell at <c>myCell − DirOffset(dir)</c> — i.e. the machine feeding
|
|
||||||
/// INTO this belt) onto its own <see cref="ConveyorItem"/>; then every loaded conveyor advances its item
|
|
||||||
/// EXACTLY one cell toward <c>myCell + DirOffset(dir)</c>. The move resolution is delegated to the pure,
|
|
||||||
/// unit-tested <see cref="ConveyorMath.ResolveMoves"/> so determinism is provable WITHOUT a world: sources are
|
|
||||||
/// processed sorted by <see cref="ConveyorMath.CellKey"/> (NOT hashmap order), occupancy is read from a
|
|
||||||
/// pre-move double-buffer snapshot, a destination conveyor cell accepts at most one item (only if it was empty
|
|
||||||
/// in the snapshot; ties → lowest CellKey wins, losers stall with no silent loss), and machine-input sink
|
|
||||||
/// cells always accept (deposit). Sinks are a separate set so an item leaving the belt into a fabricator's
|
|
||||||
/// <see cref="MachineInput"/> never collides with belt occupancy.
|
|
||||||
/// <para>
|
|
||||||
/// Mirrors <c>TurretFireSystem</c>'s now-extraction (<c>NetworkTime.ServerTick.TickIndexForValidTick</c>) +
|
|
||||||
/// <see cref="PlacedStructure.NextTick"/> cooldown idiom (each conveyor is period-gated the same way), and
|
|
||||||
/// <c>ResourceHarvestSystem</c>'s Temp-collection foreach idiom. Runs in the plain server
|
|
||||||
/// <c>SimulationSystemGroup</c> <c>[UpdateAfter(HarvesterProductionSystem)]</c> (after harvesters deposit, so
|
|
||||||
/// fresh output is pull-eligible this tick; before the fabricator consumes). All buffer/enableable mutation is
|
|
||||||
/// in place (toggling an enableable bit is NOT a structural change) → no ECB.
|
|
||||||
/// </para>
|
|
||||||
/// </summary>
|
|
||||||
[BurstCompile]
|
|
||||||
[WorldSystemFilter(WorldSystemFilterFlags.ServerSimulation)]
|
|
||||||
[UpdateInGroup(typeof(SimulationSystemGroup))]
|
|
||||||
[UpdateAfter(typeof(HarvesterProductionSystem))]
|
|
||||||
public partial struct ConveyorTransportSystem : ISystem
|
|
||||||
{
|
|
||||||
[BurstCompile]
|
|
||||||
public void OnCreate(ref SystemState state)
|
|
||||||
{
|
|
||||||
state.RequireForUpdate<NetworkTime>();
|
|
||||||
state.RequireForUpdate(state.GetEntityQuery(ComponentType.ReadOnly<Conveyor>()));
|
|
||||||
}
|
|
||||||
|
|
||||||
[BurstCompile]
|
|
||||||
public void OnUpdate(ref SystemState state)
|
|
||||||
{
|
|
||||||
var serverTick = SystemAPI.GetSingleton<NetworkTime>().ServerTick;
|
|
||||||
if (!serverTick.IsValid)
|
|
||||||
return;
|
|
||||||
uint now = serverTick.TickIndexForValidTick;
|
|
||||||
|
|
||||||
// ---- Snapshot every conveyor once (entity, cell, direction, item, period-due) ----
|
|
||||||
var convEntity = new NativeList<Entity>(Allocator.Temp);
|
|
||||||
var convCell = new NativeList<int2>(Allocator.Temp);
|
|
||||||
var convDir = new NativeList<byte>(Allocator.Temp);
|
|
||||||
var convItemRes = new NativeList<int>(Allocator.Temp); // 0 = empty
|
|
||||||
var convItemCnt = new NativeList<int>(Allocator.Temp); // 0 = empty
|
|
||||||
var convDue = new NativeList<bool>(Allocator.Temp); // period-gate satisfied this tick
|
|
||||||
|
|
||||||
foreach (var (ps, conveyor, e) in
|
|
||||||
SystemAPI.Query<RefRW<PlacedStructure>, RefRO<Conveyor>>().WithEntityAccess())
|
|
||||||
{
|
|
||||||
int period = math.max(1, conveyor.ValueRO.PeriodTicks);
|
|
||||||
|
|
||||||
// Period-gate each conveyor through NextTick exactly like the production systems. A never-processed
|
|
||||||
// belt initialises its baseline this tick and is NOT due (mirrors NeedsInit on the machines).
|
|
||||||
bool due;
|
|
||||||
if (ProductionMath.NeedsInit(ps.ValueRO.LastProcessedTick))
|
|
||||||
{
|
|
||||||
ps.ValueRW.LastProcessedTick = TickUtil.NonZero(now);
|
|
||||||
ps.ValueRW.NextTick = TickUtil.NonZero(now + (uint)period);
|
|
||||||
due = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int cycles = ProductionMath.CyclesDue(
|
|
||||||
serverTick, ps.ValueRO.NextTick, ps.ValueRO.LastProcessedTick, period, Tuning.MaxProductionCatchup);
|
|
||||||
due = cycles > 0;
|
|
||||||
if (due)
|
|
||||||
{
|
|
||||||
// A belt moves at most one cell per period; collapse any catch-up to a single step but keep
|
|
||||||
// the baseline advancing so it re-evaluates next period.
|
|
||||||
ps.ValueRW.LastProcessedTick = TickUtil.NonZero(now);
|
|
||||||
ps.ValueRW.NextTick = TickUtil.NonZero(now + (uint)period);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int res = 0, cnt = 0;
|
|
||||||
if (SystemAPI.IsComponentEnabled<ConveyorItem>(e))
|
|
||||||
{
|
|
||||||
var item = SystemAPI.GetComponent<ConveyorItem>(e);
|
|
||||||
if (item.Count > 0)
|
|
||||||
{
|
|
||||||
res = item.ResourceId;
|
|
||||||
cnt = item.Count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
convEntity.Add(e);
|
|
||||||
convCell.Add(ps.ValueRO.Cell);
|
|
||||||
convDir.Add(conveyor.ValueRO.Direction);
|
|
||||||
convItemRes.Add(res);
|
|
||||||
convItemCnt.Add(cnt);
|
|
||||||
convDue.Add(due);
|
|
||||||
}
|
|
||||||
|
|
||||||
int n = convEntity.Length;
|
|
||||||
|
|
||||||
// Cell → conveyor snapshot index (belt occupancy map for ResolveMoves + the pull lookup).
|
|
||||||
var cellToIndex = new NativeHashMap<int2, int>(n, Allocator.Temp);
|
|
||||||
for (int i = 0; i < n; i++)
|
|
||||||
cellToIndex.TryAdd(convCell[i], i); // duplicate cells can't occur (one structure per cell)
|
|
||||||
|
|
||||||
// Sink cells = cells hosting a machine-input buffer (fabricators); these always accept a deposit. Map
|
|
||||||
// each sink cell to its owning entity so an arriving item can be deposited into its MachineInput.
|
|
||||||
var sinkCells = new NativeHashSet<int2>(8, Allocator.Temp);
|
|
||||||
var sinkCellToEntity = new NativeHashMap<int2, Entity>(8, Allocator.Temp);
|
|
||||||
foreach (var (ps, _, e) in
|
|
||||||
SystemAPI.Query<RefRO<PlacedStructure>, DynamicBuffer<MachineInput>>().WithEntityAccess())
|
|
||||||
{
|
|
||||||
sinkCells.Add(ps.ValueRO.Cell);
|
|
||||||
sinkCellToEntity.TryAdd(ps.ValueRO.Cell, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Source cells = cells hosting a machine-OUTPUT buffer (harvesters/fabricators) a belt can pull from.
|
|
||||||
// Built once so the pull phase is a single hash lookup per belt (no nested per-belt query).
|
|
||||||
var outputCellToEntity = new NativeHashMap<int2, Entity>(8, Allocator.Temp);
|
|
||||||
foreach (var (ps, _, e) in
|
|
||||||
SystemAPI.Query<RefRO<PlacedStructure>, DynamicBuffer<MachineOutput>>().WithEntityAccess())
|
|
||||||
{
|
|
||||||
outputCellToEntity.TryAdd(ps.ValueRO.Cell, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---- PULL: each empty, due belt draws one item off an adjacent UPSTREAM MachineOutput ----
|
|
||||||
// Upstream cell = myCell − DirOffset(dir): the machine feeding INTO this belt sits there. We pull a
|
|
||||||
// single unit so a harvester's buffered output flows onto the belt one item per period.
|
|
||||||
for (int i = 0; i < n; i++)
|
|
||||||
{
|
|
||||||
if (!convDue[i] || convItemCnt[i] > 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
int2 srcCell = convCell[i] - ConveyorMath.DirOffset(convDir[i]);
|
|
||||||
|
|
||||||
// The feeder must be a machine with a MachineOutput buffer (harvester or fabricator), NOT another
|
|
||||||
// conveyor (belts hand off in the move phase, not via pull). Single hash lookup on the prebuilt map.
|
|
||||||
if (!outputCellToEntity.TryGetValue(srcCell, out var feeder))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var output = SystemAPI.GetBuffer<MachineOutput>(feeder);
|
|
||||||
// Pull the first available resource row off the feeder (deterministic: first non-empty row order).
|
|
||||||
byte pulledId = 0;
|
|
||||||
for (int r = 0; r < output.Length; r++)
|
|
||||||
{
|
|
||||||
if (output[r].ResourceId != 0 && output[r].Count > 0)
|
|
||||||
{
|
|
||||||
pulledId = output[r].ResourceId;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (pulledId == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
int taken = MachineSlotMath.Withdraw(output, pulledId, 1);
|
|
||||||
if (taken <= 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Load the belt in the snapshot so it participates in THIS tick's move resolution.
|
|
||||||
convItemRes[i] = pulledId;
|
|
||||||
convItemCnt[i] = taken;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---- MOVE: resolve all belt advances from the pre-move (post-pull) snapshot, then apply ----
|
|
||||||
var srcCells = new NativeArray<int2>(n, Allocator.Temp);
|
|
||||||
var dirs = new NativeArray<byte>(n, Allocator.Temp);
|
|
||||||
var itemRes = new NativeArray<int>(n, Allocator.Temp);
|
|
||||||
var itemCnt = new NativeArray<int>(n, Allocator.Temp);
|
|
||||||
for (int i = 0; i < n; i++)
|
|
||||||
{
|
|
||||||
srcCells[i] = convCell[i];
|
|
||||||
dirs[i] = convDir[i];
|
|
||||||
// Pass the FULL post-pull occupancy (due AND non-due) so the resolver blocks a due belt from moving
|
|
||||||
// INTO an occupied non-due cell. Non-due belts must still not ADVANCE themselves — that is enforced
|
|
||||||
// after resolution by skipping any returned move whose source belt is not due this tick.
|
|
||||||
itemRes[i] = convItemRes[i];
|
|
||||||
itemCnt[i] = convItemCnt[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
var outMoveDst = new NativeArray<int2>(n, Allocator.Temp);
|
|
||||||
var outMoveSrcIdx = new NativeArray<int>(n, Allocator.Temp);
|
|
||||||
ConveyorMath.ResolveMoves(
|
|
||||||
srcCells, dirs, itemRes, itemCnt,
|
|
||||||
cellToIndex, sinkCells,
|
|
||||||
outMoveDst, outMoveSrcIdx, out int moveCount);
|
|
||||||
|
|
||||||
// Track which belts END this tick holding an item so we can settle enableable bits exactly once.
|
|
||||||
var endRes = new NativeArray<int>(n, Allocator.Temp);
|
|
||||||
var endCnt = new NativeArray<int>(n, Allocator.Temp);
|
|
||||||
for (int i = 0; i < n; i++)
|
|
||||||
{
|
|
||||||
// Default: every snapshot item stays put (stalls / non-due / no valid move). Moves below override.
|
|
||||||
endRes[i] = convItemRes[i];
|
|
||||||
endCnt[i] = convItemCnt[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int m = 0; m < moveCount; m++)
|
|
||||||
{
|
|
||||||
int srcIdx = outMoveSrcIdx[m];
|
|
||||||
|
|
||||||
// A non-due belt contributes its occupancy to the snapshot (so due belts can't overrun it) but must
|
|
||||||
// NOT advance its own item — skip its move and leave its item parked (the endRes/endCnt defaults).
|
|
||||||
if (!convDue[srcIdx])
|
|
||||||
continue;
|
|
||||||
|
|
||||||
int2 dst = outMoveDst[m];
|
|
||||||
int movRes = convItemRes[srcIdx];
|
|
||||||
int movCnt = convItemCnt[srcIdx];
|
|
||||||
|
|
||||||
// The source belt empties (its item left this cell).
|
|
||||||
endRes[srcIdx] = 0;
|
|
||||||
endCnt[srcIdx] = 0;
|
|
||||||
|
|
||||||
if (sinkCells.Contains(dst))
|
|
||||||
{
|
|
||||||
// Item leaves the belt network into a machine input slot.
|
|
||||||
if (sinkCellToEntity.TryGetValue(dst, out var sinkEntity))
|
|
||||||
{
|
|
||||||
var input = SystemAPI.GetBuffer<MachineInput>(sinkEntity);
|
|
||||||
MachineSlotMath.Deposit(input, (byte)movRes, movCnt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (cellToIndex.TryGetValue(dst, out int dstIdx))
|
|
||||||
{
|
|
||||||
// Item advances onto the next belt cell (resolver guaranteed it was empty in the snapshot).
|
|
||||||
endRes[dstIdx] = movRes;
|
|
||||||
endCnt[dstIdx] = movCnt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---- Settle each conveyor's ConveyorItem to its end-of-tick state (single write per belt) ----
|
|
||||||
for (int i = 0; i < n; i++)
|
|
||||||
{
|
|
||||||
var e = convEntity[i];
|
|
||||||
if (endCnt[i] > 0)
|
|
||||||
{
|
|
||||||
SystemAPI.SetComponent(e, new ConveyorItem { ResourceId = (byte)endRes[i], Count = endCnt[i] });
|
|
||||||
SystemAPI.SetComponentEnabled<ConveyorItem>(e, true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SystemAPI.SetComponent(e, new ConveyorItem { ResourceId = 0, Count = 0 });
|
|
||||||
SystemAPI.SetComponentEnabled<ConveyorItem>(e, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
convEntity.Dispose();
|
|
||||||
convCell.Dispose();
|
|
||||||
convDir.Dispose();
|
|
||||||
convItemRes.Dispose();
|
|
||||||
convItemCnt.Dispose();
|
|
||||||
convDue.Dispose();
|
|
||||||
cellToIndex.Dispose();
|
|
||||||
sinkCells.Dispose();
|
|
||||||
sinkCellToEntity.Dispose();
|
|
||||||
outputCellToEntity.Dispose();
|
|
||||||
srcCells.Dispose();
|
|
||||||
dirs.Dispose();
|
|
||||||
itemRes.Dispose();
|
|
||||||
itemCnt.Dispose();
|
|
||||||
outMoveDst.Dispose();
|
|
||||||
outMoveSrcIdx.Dispose();
|
|
||||||
endRes.Dispose();
|
|
||||||
endCnt.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 002c28988137cb945b9ffaccbb6d645f
|
|
||||||
@@ -1,104 +0,0 @@
|
|||||||
using ProjectM.Simulation;
|
|
||||||
using Unity.Burst;
|
|
||||||
using Unity.Entities;
|
|
||||||
using Unity.Mathematics;
|
|
||||||
using Unity.NetCode;
|
|
||||||
|
|
||||||
namespace ProjectM.Server
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Server-only, deterministic fabricator production — the BACK of the M7 auto-gather chain
|
|
||||||
/// (Harvester → Conveyor → Fabricator). Each <see cref="Fabricator"/> consumes
|
|
||||||
/// <see cref="Fabricator.InAmount"/> of its (byte) input resource from its OWN server-only
|
|
||||||
/// <see cref="MachineInput"/> buffer (filled by an upstream conveyor) and, on a
|
|
||||||
/// <see cref="Fabricator.PeriodTicks"/> cadence, deposits <see cref="Fabricator.OutAmount"/> of its output
|
|
||||||
/// resource into the GLOBAL ledger — so a self-running base compounds its stockpile. Resolves the ledger via
|
|
||||||
/// <c>GetSingletonEntity<ResourceLedger>()</c> → <c>GetBuffer<StorageEntry>()</c> (NEVER
|
|
||||||
/// <c>GetSingleton<StorageEntry></c> — a second StorageEntry buffer exists on the base container).
|
|
||||||
/// Mirrors <c>TurretFireSystem</c>'s now-extraction + cooldown idiom and <c>ResourceHarvestSystem</c>'s ledger
|
|
||||||
/// resolve; runs in the plain server <c>SimulationSystemGroup</c>
|
|
||||||
/// <c>[UpdateAfter(ConveyorTransportSystem)]</c> (which itself is after the harvester + the predicted group),
|
|
||||||
/// so a single tick can harvest → transport → fabricate in chain order. In-place buffer/ledger mutation
|
|
||||||
/// (not structural) → no ECB.
|
|
||||||
/// <para>
|
|
||||||
/// SINGLE GATED CATCH-UP PATH, INPUT-LIMITED (no mint-from-nothing): when due, the awarded
|
|
||||||
/// <see cref="ProductionMath.CyclesDue"/> cycles are further clamped to what the buffered input can afford
|
|
||||||
/// (<c>floor(TotalOf(input,InResourceId)/InAmount)</c>). The tick fields are re-stamped EVERY due period
|
|
||||||
/// regardless of <c>runs</c> (even a starved fabricator advances its baseline so it re-evaluates next period,
|
|
||||||
/// not on the next tick — preventing a busy retry storm). Offline catch-up is within-session tick math; never
|
|
||||||
/// wall-clock.
|
|
||||||
/// </para>
|
|
||||||
/// </summary>
|
|
||||||
[BurstCompile]
|
|
||||||
[WorldSystemFilter(WorldSystemFilterFlags.ServerSimulation)]
|
|
||||||
[UpdateInGroup(typeof(SimulationSystemGroup))]
|
|
||||||
[UpdateAfter(typeof(ConveyorTransportSystem))]
|
|
||||||
public partial struct FabricatorProductionSystem : ISystem
|
|
||||||
{
|
|
||||||
[BurstCompile]
|
|
||||||
public void OnCreate(ref SystemState state)
|
|
||||||
{
|
|
||||||
state.RequireForUpdate<NetworkTime>();
|
|
||||||
state.RequireForUpdate<ResourceLedger>();
|
|
||||||
state.RequireForUpdate(state.GetEntityQuery(ComponentType.ReadOnly<Fabricator>()));
|
|
||||||
}
|
|
||||||
|
|
||||||
[BurstCompile]
|
|
||||||
public void OnUpdate(ref SystemState state)
|
|
||||||
{
|
|
||||||
var serverTick = SystemAPI.GetSingleton<NetworkTime>().ServerTick;
|
|
||||||
if (!serverTick.IsValid)
|
|
||||||
return;
|
|
||||||
uint now = serverTick.TickIndexForValidTick;
|
|
||||||
|
|
||||||
var ledgerEntity = SystemAPI.GetSingletonEntity<ResourceLedger>();
|
|
||||||
var ledger = SystemAPI.GetBuffer<StorageEntry>(ledgerEntity);
|
|
||||||
|
|
||||||
foreach (var (ps, fab, input) in
|
|
||||||
SystemAPI.Query<RefRW<PlacedStructure>, RefRO<Fabricator>, DynamicBuffer<MachineInput>>())
|
|
||||||
{
|
|
||||||
int period = fab.ValueRO.PeriodTicks; // CyclesDue clamps to max(1, period)
|
|
||||||
|
|
||||||
// Never-processed (baked/just-placed) machine: initialise the catch-up baseline, produce nothing.
|
|
||||||
if (ProductionMath.NeedsInit(ps.ValueRO.LastProcessedTick))
|
|
||||||
{
|
|
||||||
ps.ValueRW.LastProcessedTick = TickUtil.NonZero(now);
|
|
||||||
ps.ValueRW.NextTick = TickUtil.NonZero(now + (uint)System.Math.Max(1, period));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cycles = ProductionMath.CyclesDue(
|
|
||||||
serverTick, ps.ValueRO.NextTick, ps.ValueRO.LastProcessedTick, period, Tuning.MaxProductionCatchup);
|
|
||||||
if (cycles <= 0)
|
|
||||||
continue; // still cooling down / nothing due
|
|
||||||
|
|
||||||
byte inId = fab.ValueRO.InResourceId;
|
|
||||||
int inAmount = fab.ValueRO.InAmount;
|
|
||||||
|
|
||||||
// Input-limited: never produce more than the available input affords (no mint-from-nothing). EB-2:
|
|
||||||
// a ledger-fed Fabricator (InputFromLedger != 0) sources its input from the SHARED ledger (read LIVE
|
|
||||||
// here so a 2nd ledger-fed Fabricator sees the 1st's same-tick withdrawal) instead of MachineInput;
|
|
||||||
// both modes deposit the output to the ledger. A zero/negative input amount is unsatisfiable.
|
|
||||||
bool fromLedger = fab.ValueRO.InputFromLedger != 0;
|
|
||||||
int available = fromLedger ? StorageMath.TotalOf(ledger, inId) : MachineSlotMath.TotalOf(input, inId);
|
|
||||||
int affordable = inAmount > 0 ? available / inAmount : 0;
|
|
||||||
int runs = math.min(cycles, affordable);
|
|
||||||
|
|
||||||
if (runs > 0)
|
|
||||||
{
|
|
||||||
if (fromLedger)
|
|
||||||
StorageMath.Withdraw(ledger, inId, inAmount * runs);
|
|
||||||
else
|
|
||||||
MachineSlotMath.Withdraw(input, inId, inAmount * runs);
|
|
||||||
StorageMath.Deposit(ledger, (ushort)fab.ValueRO.OutResourceId, fab.ValueRO.OutAmount * runs);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Re-stamp every due period regardless of runs (starved fabricators re-evaluate next period, not
|
|
||||||
// every tick) so the catch-up baseline never silently rewinds.
|
|
||||||
uint p = (uint)System.Math.Max(1, period);
|
|
||||||
ps.ValueRW.LastProcessedTick = TickUtil.NonZero(now);
|
|
||||||
ps.ValueRW.NextTick = TickUtil.NonZero(now + p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 1d8dbf02b41c9a94ea57fd7ca00f266d
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
using ProjectM.Simulation;
|
|
||||||
using Unity.Burst;
|
|
||||||
using Unity.Entities;
|
|
||||||
using Unity.NetCode;
|
|
||||||
|
|
||||||
namespace ProjectM.Server
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Server-only, deterministic harvester production — the FRONT of the M7 auto-gather chain
|
|
||||||
/// (Harvester → Conveyor → Fabricator). Each <see cref="Harvester"/> machine is a fixed-yield generator:
|
|
||||||
/// every <see cref="Harvester.PeriodTicks"/> server ticks it deposits <see cref="Harvester.Yield"/> of its
|
|
||||||
/// configured (byte) resource into its OWN server-only <see cref="MachineOutput"/> buffer (NOT the global
|
|
||||||
/// ledger — a conveyor pulls it onward, or it sits buffered). Mirrors <c>TurretFireSystem</c>'s exact
|
|
||||||
/// now-extraction (<c>NetworkTime.ServerTick.TickIndexForValidTick</c>) + <see cref="PlacedStructure.NextTick"/>
|
|
||||||
/// cooldown idiom, and runs in the plain server <c>SimulationSystemGroup</c>
|
|
||||||
/// <c>[UpdateAfter(PredictedSimulationSystemGroup)]</c> (the predicted group is OrderFirst → UpdateBefore is
|
|
||||||
/// ignored). Production mutates a DynamicBuffer in place (not a structural change) → no ECB needed.
|
|
||||||
/// <para>
|
|
||||||
/// SINGLE GATED CATCH-UP PATH (offline-quit safe, NO wall-clock minting): a never-processed machine
|
|
||||||
/// (LastProcessedTick==0) is initialised this tick and produces nothing; otherwise
|
|
||||||
/// <see cref="ProductionMath.CyclesDue"/> awards <c>floor((now-LastProcessedTick)/period)</c> cycles, clamped
|
|
||||||
/// to <see cref="Tuning.MaxProductionCatchup"/>, and the tick fields are re-stamped. All catch-up is
|
|
||||||
/// WITHIN-SESSION tick math; the stockpile is preserved across quit by the persistence layer, never re-minted
|
|
||||||
/// from a saved wall-clock.
|
|
||||||
/// </para>
|
|
||||||
/// </summary>
|
|
||||||
[BurstCompile]
|
|
||||||
[WorldSystemFilter(WorldSystemFilterFlags.ServerSimulation)]
|
|
||||||
[UpdateInGroup(typeof(SimulationSystemGroup))]
|
|
||||||
[UpdateAfter(typeof(PredictedSimulationSystemGroup))]
|
|
||||||
public partial struct HarvesterProductionSystem : ISystem
|
|
||||||
{
|
|
||||||
[BurstCompile]
|
|
||||||
public void OnCreate(ref SystemState state)
|
|
||||||
{
|
|
||||||
state.RequireForUpdate<NetworkTime>();
|
|
||||||
state.RequireForUpdate(state.GetEntityQuery(ComponentType.ReadOnly<Harvester>()));
|
|
||||||
}
|
|
||||||
|
|
||||||
[BurstCompile]
|
|
||||||
public void OnUpdate(ref SystemState state)
|
|
||||||
{
|
|
||||||
var serverTick = SystemAPI.GetSingleton<NetworkTime>().ServerTick;
|
|
||||||
if (!serverTick.IsValid)
|
|
||||||
return;
|
|
||||||
uint now = serverTick.TickIndexForValidTick;
|
|
||||||
|
|
||||||
foreach (var (ps, harvester, output) in
|
|
||||||
SystemAPI.Query<RefRW<PlacedStructure>, RefRO<Harvester>, DynamicBuffer<MachineOutput>>())
|
|
||||||
{
|
|
||||||
int period = harvester.ValueRO.PeriodTicks; // CyclesDue clamps to max(1, period)
|
|
||||||
|
|
||||||
// Never-processed (baked/just-placed) machine: initialise the catch-up baseline, produce nothing.
|
|
||||||
if (ProductionMath.NeedsInit(ps.ValueRO.LastProcessedTick))
|
|
||||||
{
|
|
||||||
ps.ValueRW.LastProcessedTick = TickUtil.NonZero(now);
|
|
||||||
ps.ValueRW.NextTick = TickUtil.NonZero(now + (uint)System.Math.Max(1, period));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cycles = ProductionMath.CyclesDue(
|
|
||||||
serverTick, ps.ValueRO.NextTick, ps.ValueRO.LastProcessedTick, period, Tuning.MaxProductionCatchup);
|
|
||||||
if (cycles <= 0)
|
|
||||||
continue; // still cooling down / nothing due
|
|
||||||
|
|
||||||
// Fixed-yield generation into the machine's own output slot (byte id; ledger conversion happens
|
|
||||||
// only at the global-ledger boundary, which this machine never crosses directly).
|
|
||||||
MachineSlotMath.Deposit(output, harvester.ValueRO.ResourceId, harvester.ValueRO.Yield * cycles);
|
|
||||||
|
|
||||||
uint p = (uint)System.Math.Max(1, period);
|
|
||||||
ps.ValueRW.LastProcessedTick = TickUtil.NonZero(now);
|
|
||||||
ps.ValueRW.NextTick = TickUtil.NonZero(now + p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: c484cb2331137134888f10eed7689140
|
|
||||||
@@ -23,13 +23,11 @@ namespace ProjectM.Server
|
|||||||
public partial struct BuildPlaceSystem : ISystem
|
public partial struct BuildPlaceSystem : ISystem
|
||||||
{
|
{
|
||||||
ComponentLookup<LocalTransform> m_TransformLookup;
|
ComponentLookup<LocalTransform> m_TransformLookup;
|
||||||
ComponentLookup<Conveyor> m_ConveyorLookup;
|
|
||||||
|
|
||||||
[BurstCompile]
|
[BurstCompile]
|
||||||
public void OnCreate(ref SystemState state)
|
public void OnCreate(ref SystemState state)
|
||||||
{
|
{
|
||||||
m_TransformLookup = state.GetComponentLookup<LocalTransform>(isReadOnly: true);
|
m_TransformLookup = state.GetComponentLookup<LocalTransform>(isReadOnly: true);
|
||||||
m_ConveyorLookup = state.GetComponentLookup<Conveyor>(isReadOnly: true);
|
|
||||||
state.RequireForUpdate<StructureCatalog>();
|
state.RequireForUpdate<StructureCatalog>();
|
||||||
state.RequireForUpdate<BaseAnchor>();
|
state.RequireForUpdate<BaseAnchor>();
|
||||||
state.RequireForUpdate<ResourceLedger>();
|
state.RequireForUpdate<ResourceLedger>();
|
||||||
@@ -43,21 +41,16 @@ namespace ProjectM.Server
|
|||||||
public void OnUpdate(ref SystemState state)
|
public void OnUpdate(ref SystemState state)
|
||||||
{
|
{
|
||||||
m_TransformLookup.Update(ref state);
|
m_TransformLookup.Update(ref state);
|
||||||
m_ConveyorLookup.Update(ref state);
|
|
||||||
uint now = SystemAPI.GetSingleton<NetworkTime>().ServerTick.TickIndexForValidTick;
|
uint now = SystemAPI.GetSingleton<NetworkTime>().ServerTick.TickIndexForValidTick;
|
||||||
var anchor = SystemAPI.GetSingleton<BaseAnchor>();
|
var anchor = SystemAPI.GetSingleton<BaseAnchor>();
|
||||||
|
|
||||||
var catalog = SystemAPI.GetBuffer<StructureCatalogEntry>(SystemAPI.GetSingletonEntity<StructureCatalog>());
|
var catalog = SystemAPI.GetBuffer<StructureCatalogEntry>(SystemAPI.GetSingletonEntity<StructureCatalog>());
|
||||||
var ledger = SystemAPI.GetBuffer<StorageEntry>(SystemAPI.GetSingletonEntity<ResourceLedger>());
|
var ledger = SystemAPI.GetBuffer<StorageEntry>(SystemAPI.GetSingletonEntity<ResourceLedger>());
|
||||||
|
|
||||||
// Derive occupancy from the live structure set (authoritative); also count turrets for the per-base cap.
|
// Derive occupancy from the live structure set (authoritative).
|
||||||
var occupied = new NativeHashSet<int2>(64, Allocator.Temp);
|
var occupied = new NativeHashSet<int2>(64, Allocator.Temp);
|
||||||
int turretCount = 0;
|
|
||||||
foreach (var ps in SystemAPI.Query<RefRO<PlacedStructure>>())
|
foreach (var ps in SystemAPI.Query<RefRO<PlacedStructure>>())
|
||||||
{
|
|
||||||
occupied.Add(ps.ValueRO.Cell);
|
occupied.Add(ps.ValueRO.Cell);
|
||||||
if (ps.ValueRO.Type == StructureType.Turret) turretCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
var ecb = new EntityCommandBuffer(Allocator.Temp);
|
var ecb = new EntityCommandBuffer(Allocator.Temp);
|
||||||
|
|
||||||
@@ -71,9 +64,7 @@ namespace ProjectM.Server
|
|||||||
for (int i = 0; i < catalog.Length; i++)
|
for (int i = 0; i < catalog.Length; i++)
|
||||||
if (catalog[i].Type == req.StructureType) { entryIdx = i; break; }
|
if (catalog[i].Type == req.StructureType) { entryIdx = i; break; }
|
||||||
|
|
||||||
// DR-042 combat pass: cap turrets per base (server-authoritative) so they can't be spammed.
|
if (entryIdx >= 0 && catalog[entryIdx].Prefab != Entity.Null
|
||||||
bool turretCapOk = req.StructureType != StructureType.Turret || turretCount < Tuning.TurretCap;
|
|
||||||
if (entryIdx >= 0 && catalog[entryIdx].Prefab != Entity.Null && turretCapOk
|
|
||||||
&& BuildPlacementMath.CanPlace(anchor, occupied, cell))
|
&& BuildPlacementMath.CanPlace(anchor, occupied, cell))
|
||||||
{
|
{
|
||||||
var entry = catalog[entryIdx];
|
var entry = catalog[entryIdx];
|
||||||
@@ -87,7 +78,6 @@ namespace ProjectM.Server
|
|||||||
// Commit IN-PLACE so a second same-tick request sees the spend + reservation.
|
// Commit IN-PLACE so a second same-tick request sees the spend + reservation.
|
||||||
StorageMath.Withdraw(ledger, entry.CostResourceId, entry.CostAmount);
|
StorageMath.Withdraw(ledger, entry.CostResourceId, entry.CostAmount);
|
||||||
occupied.Add(cell);
|
occupied.Add(cell);
|
||||||
if (req.StructureType == StructureType.Turret) turretCount++; // keep same-tick turret requests under the cap
|
|
||||||
|
|
||||||
var structure = ecb.Instantiate(entry.Prefab);
|
var structure = ecb.Instantiate(entry.Prefab);
|
||||||
var xform = m_TransformLookup[entry.Prefab];
|
var xform = m_TransformLookup[entry.Prefab];
|
||||||
@@ -102,12 +92,6 @@ namespace ProjectM.Server
|
|||||||
});
|
});
|
||||||
ecb.AddComponent(structure, new RegionTag { Region = RegionId.Base });
|
ecb.AddComponent(structure, new RegionTag { Region = RegionId.Base });
|
||||||
ecb.AddComponent<RuntimePlacedTag>(structure); // player-built -> persisted by SaveStructureScan
|
ecb.AddComponent<RuntimePlacedTag>(structure); // player-built -> persisted by SaveStructureScan
|
||||||
if (req.StructureType == StructureType.Conveyor && m_ConveyorLookup.HasComponent(entry.Prefab))
|
|
||||||
{
|
|
||||||
var conv = m_ConveyorLookup[entry.Prefab];
|
|
||||||
conv.Direction = req.Direction;
|
|
||||||
ecb.SetComponent(structure, conv);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user