diff --git a/Assets/Scripts/External/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.sln.meta b/Assets/Art/Sound/Furniture.meta similarity index 67% rename from Assets/Scripts/External/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.sln.meta rename to Assets/Art/Sound/Furniture.meta index aa8a077601..511cd19676 100644 --- a/Assets/Scripts/External/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.sln.meta +++ b/Assets/Art/Sound/Furniture.meta @@ -1,5 +1,6 @@ fileFormatVersion: 2 -guid: 246f31a0e00fea74a93125fec6d80da8 +guid: d3991349b86bf2e4ea189af086fe12f7 +folderAsset: yes DefaultImporter: externalObjects: {} userData: diff --git a/Assets/Scripts/External/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/LiteNetLib.csproj.meta b/Assets/Art/Sound/Furniture/Machines.meta similarity index 67% rename from Assets/Scripts/External/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/LiteNetLib.csproj.meta rename to Assets/Art/Sound/Furniture/Machines.meta index f9c48e96e4..3772a6e748 100644 --- a/Assets/Scripts/External/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/LiteNetLib.csproj.meta +++ b/Assets/Art/Sound/Furniture/Machines.meta @@ -1,5 +1,6 @@ fileFormatVersion: 2 -guid: 2ad85b0f43f25f1499c27a4dca23ddd8 +guid: 1bc617755cd95694faa82b41d950685d +folderAsset: yes DefaultImporter: externalObjects: {} userData: diff --git a/Assets/Art/Sound/Furniture/Machines/Engineering.meta b/Assets/Art/Sound/Furniture/Machines/Engineering.meta new file mode 100644 index 0000000000..81c62c47e1 --- /dev/null +++ b/Assets/Art/Sound/Furniture/Machines/Engineering.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0b44802d0b77bea40acb901ac5feeed9 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Art/Sound/Furniture/Machines/Engineering/FuelPowerGenerator.ogg b/Assets/Art/Sound/Furniture/Machines/Engineering/FuelPowerGenerator.ogg new file mode 100644 index 0000000000..0c128e4392 Binary files /dev/null and b/Assets/Art/Sound/Furniture/Machines/Engineering/FuelPowerGenerator.ogg differ diff --git a/Assets/Art/Sound/Furniture/Machines/Engineering/FuelPowerGenerator.ogg.meta b/Assets/Art/Sound/Furniture/Machines/Engineering/FuelPowerGenerator.ogg.meta new file mode 100644 index 0000000000..2338eb19d7 --- /dev/null +++ b/Assets/Art/Sound/Furniture/Machines/Engineering/FuelPowerGenerator.ogg.meta @@ -0,0 +1,22 @@ +fileFormatVersion: 2 +guid: 59b65ecaf8dffbf49876ab2768490b59 +AudioImporter: + externalObjects: {} + serializedVersion: 6 + defaultSettings: + loadType: 0 + sampleRateSetting: 0 + sampleRateOverride: 44100 + compressionFormat: 1 + quality: 1 + conversionMode: 0 + platformSettingOverrides: {} + forceToMono: 0 + normalize: 1 + preloadAudioData: 1 + loadInBackground: 0 + ambisonic: 0 + 3D: 1 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Content/Addressables/AssetGroups/Sounds.asset b/Assets/Content/Addressables/AssetGroups/Sounds.asset index 1b0c88437c..2bcbe96b50 100644 --- a/Assets/Content/Addressables/AssetGroups/Sounds.asset +++ b/Assets/Content/Addressables/AssetGroups/Sounds.asset @@ -57,6 +57,10 @@ MonoBehaviour: m_Address: Assets/Art/Sound/World/Airlocks/AirlockOpen.ogg m_ReadOnly: 0 m_SerializedLabels: [] + - m_GUID: 59b65ecaf8dffbf49876ab2768490b59 + m_Address: Assets/Art/Sound/Furniture/Machines/Engineering/FuelPowerGenerator.ogg + m_ReadOnly: 0 + m_SerializedLabels: [] m_ReadOnly: 0 m_Settings: {fileID: 11400000, guid: ddc57d0f5f9fb874e8a26db0c5b215e0, type: 2} m_SchemaSet: diff --git a/Assets/Content/Data/Databases/Sounds.asset b/Assets/Content/Data/Databases/Sounds.asset index dbb671b685..0a1a8ed441 100644 --- a/Assets/Content/Data/Databases/Sounds.asset +++ b/Assets/Content/Data/Databases/Sounds.asset @@ -36,4 +36,6 @@ MonoBehaviour: _value: {fileID: 8300000, guid: fc2485e75c5d3ab4e86e814043c9e9cb, type: 3} - _key: AirlockOpen _value: {fileID: 8300000, guid: 34297ba204a9f3944872f100baaa2369, type: 3} + - _key: FuelPowerGenerator + _value: {fileID: 8300000, guid: 59b65ecaf8dffbf49876ab2768490b59, type: 3} _new: diff --git a/Assets/Content/Data/TileMap/Resources/Furniture/Machines/Engineering/SolarPanel.asset b/Assets/Content/Data/TileMap/Resources/Furniture/Machines/Engineering/SolarPanel.asset index 2f57094b58..504bfe3455 100644 --- a/Assets/Content/Data/TileMap/Resources/Furniture/Machines/Engineering/SolarPanel.asset +++ b/Assets/Content/Data/TileMap/Resources/Furniture/Machines/Engineering/SolarPanel.asset @@ -12,8 +12,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 4584c35d672b8a74797cc5efa123ce16, type: 3} m_Name: SolarPanel m_EditorClassIdentifier: - nameString: SolarPanel - prefab: {fileID: 6286745912349171764, guid: f0eca2b8867709749bc10f61917c4bdf, type: 3} + prefab: {fileID: 941367499997148975, guid: f0eca2b8867709749bc10f61917c4bdf, type: 3} icon: {fileID: 0} layer: 7 genericType: 0 diff --git a/Assets/Content/Scenes/Game.unity b/Assets/Content/Scenes/Game.unity index e556aa7d12..18b21567df 100644 --- a/Assets/Content/Scenes/Game.unity +++ b/Assets/Content/Scenes/Game.unity @@ -445,6 +445,54 @@ MonoBehaviour: _scenePathHash: 2499635508 k__BackingField: 10735852762014670918 k__BackingField: 0 +--- !u!1 &478499394 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 478499395} + - component: {fileID: 478499396} + m_Layer: 0 + m_Name: ElectricitySystem + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &478499395 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 478499394} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -700.46924, y: -415.26047, z: 42.020546} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1506918115} + m_RootOrder: 17 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &478499396 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 478499394} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: cec52cc8cb291414f83ee8b575949b02, type: 3} + m_Name: + m_EditorClassIdentifier: + _componentIndexCache: 7 + _addedNetworkObject: {fileID: 1506918116} + _networkObjectCache: {fileID: 1506918116} + _tickRate: 0.2 --- !u!1 &516802433 GameObject: m_ObjectHideFlags: 0 @@ -1155,8 +1203,8 @@ MonoBehaviour: k__BackingField: [] SerializedTransformProperties: Position: {x: 0, y: 0, z: 0} - Rotation: {x: 0, y: 0, z: 0, w: 0} - LocalScale: {x: 0, y: 0, z: 0} + Rotation: {x: 0, y: 0, z: 0, w: 1} + LocalScale: {x: 1, y: 1, z: 1} _isNetworked: 1 _isGlobal: 0 _initializeOrder: 0 @@ -1232,9 +1280,9 @@ MonoBehaviour: k__BackingField: - {fileID: 913757968} SerializedTransformProperties: - Position: {x: 0, y: 0, z: 0} - Rotation: {x: 0, y: 0, z: 0, w: 0} - LocalScale: {x: 0, y: 0, z: 0} + Position: {x: -1.510847, y: -0.9550402, z: -2.0797422} + Rotation: {x: 0, y: 0, z: 0, w: 1} + LocalScale: {x: 1, y: 1, z: 1} _isNetworked: 1 _isGlobal: 0 _initializeOrder: 0 @@ -1439,7 +1487,7 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 4468402021075485018, guid: cc5383d385556f443b2a7d3202f2b2c1, type: 3} propertyPath: m_AnchoredPosition.y - value: -230.00006 + value: -229.99997 objectReference: {fileID: 0} - target: {fileID: 4468402021449001342, guid: cc5383d385556f443b2a7d3202f2b2c1, type: 3} propertyPath: m_AnchoredPosition.x @@ -1967,6 +2015,7 @@ Transform: - {fileID: 1121348073} - {fileID: 606666309} - {fileID: 274660131} + - {fileID: 478499395} m_Father: {fileID: 0} m_RootOrder: 3 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} @@ -1993,6 +2042,7 @@ MonoBehaviour: - {fileID: 1121348074} - {fileID: 606666310} - {fileID: 274660132} + - {fileID: 478499396} k__BackingField: {fileID: 0} k__BackingField: - {fileID: 516802435} diff --git a/Assets/Content/WorldObjects/Furniture/Machines/Engineering/PacManGenerator.prefab b/Assets/Content/WorldObjects/Furniture/Machines/Engineering/PacManGenerator.prefab index d8bb3b4af9..cebf7a618c 100644 --- a/Assets/Content/WorldObjects/Furniture/Machines/Engineering/PacManGenerator.prefab +++ b/Assets/Content/WorldObjects/Furniture/Machines/Engineering/PacManGenerator.prefab @@ -12,6 +12,11 @@ GameObject: - component: {fileID: -5414623717715724467} - component: {fileID: 1498482382929386799} - component: {fileID: -2628458568064459714} + - component: {fileID: 219113547575591534} + - component: {fileID: 2550114539843098724} + - component: {fileID: -2157900375506616301} + - component: {fileID: 7239473696267242548} + - component: {fileID: 4189468537532167386} m_Layer: 0 m_Name: PacManGenerator m_TagString: Untagged @@ -51,19 +56,21 @@ MonoBehaviour: k__BackingField: 0 k__BackingField: 0 k__BackingField: {fileID: 0} - _networkBehaviours: [] + _networkBehaviours: + - {fileID: 219113547575591534} + - {fileID: -2157900375506616301} k__BackingField: {fileID: 0} k__BackingField: [] SerializedTransformProperties: Position: {x: 0, y: 0, z: 0} - Rotation: {x: 0, y: 0, z: 0, w: 0} - LocalScale: {x: 0, y: 0, z: 0} + Rotation: {x: 0, y: 0, z: 0, w: 1} + LocalScale: {x: 1, y: 1, z: 1} _isNetworked: 1 _isGlobal: 0 _initializeOrder: 0 _defaultDespawnType: 0 NetworkObserver: {fileID: 0} - k__BackingField: 0 + k__BackingField: 157 k__BackingField: 0 _scenePathHash: 0 k__BackingField: 0 @@ -93,6 +100,82 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: key: {fileID: 11400000, guid: 59526bd88a8f878449573560e06a54f9, type: 2} +--- !u!114 &219113547575591534 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1918783493706165866} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 328b489d4f8c1f04983e195ee8635c19, type: 3} + m_Name: + m_EditorClassIdentifier: + _componentIndexCache: 0 + _addedNetworkObject: {fileID: -5414623717715724467} + _networkObjectCache: {fileID: -5414623717715724467} + _powerProduction: 10 + _skinnedMeshRenderer: {fileID: 1698900335226549537} + _enabled: 0 +--- !u!114 &2550114539843098724 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1918783493706165866} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: c7a41c77d19af89459c70cd823369e19, type: 3} + m_Name: + m_EditorClassIdentifier: + _amplitude: 1 + _frequency: 35 +--- !u!114 &-2157900375506616301 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1918783493706165866} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1bbc87ddd49b01f4098910ffdf858004, type: 3} + m_Name: + m_EditorClassIdentifier: + _componentIndexCache: 1 + _addedNetworkObject: {fileID: -5414623717715724467} + _networkObjectCache: {fileID: -5414623717715724467} +--- !u!65 &7239473696267242548 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1918783493706165866} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 0.9038, y: 0.9088632, z: 0.8278526} + m_Center: {x: -0.012657881, y: 0.42530543, z: 0.015189469} +--- !u!114 &4189468537532167386 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1918783493706165866} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: b621d3404247f2e4da4ab459ad43eec7, type: 3} + m_Name: + m_EditorClassIdentifier: + _componentIndexCache: 255 + _addedNetworkObject: {fileID: -5414623717715724467} + _networkObjectCache: {fileID: 0} + _on: 0 --- !u!1 &4271595947011161493 GameObject: m_ObjectHideFlags: 0 @@ -186,7 +269,6 @@ GameObject: m_Component: - component: {fileID: 608453462504062702} - component: {fileID: 1698900335226549537} - - component: {fileID: 5323246766978482323} m_Layer: 0 m_Name: Body m_TagString: Untagged @@ -266,16 +348,3 @@ SkinnedMeshRenderer: m_Center: {x: -0.007445082, y: 0.4215365, z: -0.0044316053} m_Extent: {x: 0.41407037, y: 0.42270422, z: 0.41059247} m_DirtyAABB: 0 ---- !u!65 &5323246766978482323 -BoxCollider: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 4379219507269237858} - m_Material: {fileID: 0} - m_IsTrigger: 0 - m_Enabled: 1 - serializedVersion: 2 - m_Size: {x: 0.83231133, y: 0.8492101, z: 0.78938055} - m_Center: {x: -0.009774417, y: 0.42334524, z: 0.013316378} diff --git a/Assets/Content/WorldObjects/Furniture/Machines/Engineering/SMES.prefab b/Assets/Content/WorldObjects/Furniture/Machines/Engineering/SMES.prefab index 88f708ea4a..2c9728b4c4 100644 --- a/Assets/Content/WorldObjects/Furniture/Machines/Engineering/SMES.prefab +++ b/Assets/Content/WorldObjects/Furniture/Machines/Engineering/SMES.prefab @@ -12,6 +12,10 @@ GameObject: - component: {fileID: -5414623717715724467} - component: {fileID: -4242734897733728731} - component: {fileID: 7561631995620174181} + - component: {fileID: 6345351447614513914} + - component: {fileID: -7870356800615129184} + - component: {fileID: 4840393447774820463} + - component: {fileID: 8399519541836331320} m_Layer: 0 m_Name: SMES m_TagString: Untagged @@ -50,19 +54,21 @@ MonoBehaviour: k__BackingField: 0 k__BackingField: 0 k__BackingField: {fileID: 0} - _networkBehaviours: [] + _networkBehaviours: + - {fileID: 6345351447614513914} + - {fileID: -7870356800615129184} k__BackingField: {fileID: 0} k__BackingField: [] SerializedTransformProperties: Position: {x: 0, y: 0, z: 0} - Rotation: {x: 0, y: 0, z: 0, w: 0} - LocalScale: {x: 0, y: 0, z: 0} + Rotation: {x: 0, y: 0, z: 0, w: 1} + LocalScale: {x: 1, y: 1, z: 1} _isNetworked: 1 _isGlobal: 0 _initializeOrder: 0 _defaultDespawnType: 0 NetworkObserver: {fileID: 0} - k__BackingField: 0 + k__BackingField: 154 k__BackingField: 0 _scenePathHash: 0 k__BackingField: 0 @@ -92,6 +98,71 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: key: {fileID: 11400000, guid: 4e5b5032bc8027c4485bde316ce4057f, type: 2} +--- !u!114 &6345351447614513914 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1918783493706165866} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3f1cd0d7880cd9c4f98489ed5f9413ad, type: 3} + m_Name: + m_EditorClassIdentifier: + _componentIndexCache: 0 + _addedNetworkObject: {fileID: -5414623717715724467} + _networkObjectCache: {fileID: -5414623717715724467} + _maxCapacity: 1000 + _storedPower: 0 + _maxPowerRate: 5 + _isOn: 0 + _smesSkinnedMesh: {fileID: 755838239801065349} + _updateLightPeriod: 3 +--- !u!114 &-7870356800615129184 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1918783493706165866} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1bbc87ddd49b01f4098910ffdf858004, type: 3} + m_Name: + m_EditorClassIdentifier: + _componentIndexCache: 1 + _addedNetworkObject: {fileID: -5414623717715724467} + _networkObjectCache: {fileID: -5414623717715724467} +--- !u!65 &4840393447774820463 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1918783493706165866} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 0.8063088, y: 0.96126163, z: 0.85666853} + m_Center: {x: -0.011621445, y: 0.4648589, z: 0.0058107674} +--- !u!114 &8399519541836331320 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1918783493706165866} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: b621d3404247f2e4da4ab459ad43eec7, type: 3} + m_Name: + m_EditorClassIdentifier: + _componentIndexCache: 255 + _addedNetworkObject: {fileID: -5414623717715724467} + _networkObjectCache: {fileID: 0} + _on: 0 --- !u!1 &4379219507269237858 GameObject: m_ObjectHideFlags: 0 @@ -102,7 +173,6 @@ GameObject: m_Component: - component: {fileID: 608453462504062702} - component: {fileID: 755838239801065349} - - component: {fileID: 5323246766978482323} m_Layer: 0 m_Name: Body m_TagString: Untagged @@ -193,16 +263,3 @@ SkinnedMeshRenderer: m_Center: {x: -0.000000014901161, y: 0.48807514, z: 0.025044113} m_Extent: {x: 0.41364294, y: 0.48807514, z: 0.43868694} m_DirtyAABB: 0 ---- !u!65 &5323246766978482323 -BoxCollider: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 4379219507269237858} - m_Material: {fileID: 0} - m_IsTrigger: 0 - m_Enabled: 1 - serializedVersion: 2 - m_Size: {x: 0.83687043, y: 0.9540701, z: 0.8874018} - m_Center: {x: -0.012053996, y: 0.47577524, z: -0.003780365} diff --git a/Assets/Content/WorldObjects/Furniture/Machines/Engineering/SolarPanel.prefab b/Assets/Content/WorldObjects/Furniture/Machines/Engineering/SolarPanel.prefab index 2796829d31..3717402e09 100644 --- a/Assets/Content/WorldObjects/Furniture/Machines/Engineering/SolarPanel.prefab +++ b/Assets/Content/WorldObjects/Furniture/Machines/Engineering/SolarPanel.prefab @@ -1,8 +1,142 @@ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: ---- !u!1001 &6628854211070860645 -PrefabInstance: +--- !u!1 &24529576505488954 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5368364659833148326} + m_Layer: 0 + m_Name: Arm1 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &5368364659833148326 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 24529576505488954} + m_LocalRotation: {x: 0.7070975, y: -0.0035744, z: -0.003574408, w: 0.7070981} + m_LocalPosition: {x: -0.0000004766922, y: -0.000000010916779, z: -0.10818495} + m_LocalScale: {x: 0.9999998, y: 1.0000002, z: 0.99999994} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 2871253202867177793} + m_Father: {fileID: 1913738544526821531} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &541240759913317633 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7821888204805368556} + m_Layer: 0 + m_Name: Arm3 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &7821888204805368556 +Transform: m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 541240759913317633} + m_LocalRotation: {x: 0.72863936, y: -0.000000033950975, z: 0.0000006372906, w: 0.68489754} + m_LocalPosition: {x: -0.000000034815837, y: 0.40060344, z: 0.00000032600656} + m_LocalScale: {x: 1, y: 1.0000007, z: 1.0000002} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1400036219440598499} + m_Father: {fileID: 2871253202867177793} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &941367499997148975 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2110600898598905970} + - component: {fileID: 9182045811198193135} + m_Layer: 0 + m_Name: SolarPanelArm1 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2110600898598905970 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 941367499997148975} + m_LocalRotation: {x: 0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 3.1974423e-14, y: 0.000000007450479, z: -7.682743e-14} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 5630858412342417153} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!137 &9182045811198193135 +SkinnedMeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 941367499997148975} + 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: 3 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 695c4de41b9578049a93f19b1eef7213, 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_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 serializedVersion: 2 m_Modification: m_TransformParent: {fileID: 0} diff --git a/Assets/Content/WorldObjects/Structures/WallMounts/Lights/LightBulbFixture.prefab b/Assets/Content/WorldObjects/Structures/WallMounts/Lights/LightBulbFixture.prefab index 86fbd54eb6..dabfa9010d 100644 --- a/Assets/Content/WorldObjects/Structures/WallMounts/Lights/LightBulbFixture.prefab +++ b/Assets/Content/WorldObjects/Structures/WallMounts/Lights/LightBulbFixture.prefab @@ -187,8 +187,9 @@ GameObject: m_Component: - component: {fileID: 5737010110918057389} - component: {fileID: -7828078595381397262} - - component: {fileID: 6000490057296868418} - - component: {fileID: -4897036947527457848} + - component: {fileID: 5299084947188572917} + - component: {fileID: 8301714305325130111} + - component: {fileID: -7419120924986984554} m_Layer: 0 m_Name: LightBulbFixture m_TagString: Untagged @@ -228,24 +229,25 @@ MonoBehaviour: k__BackingField: 0 k__BackingField: 0 k__BackingField: {fileID: 0} - _networkBehaviours: [] + _networkBehaviours: + - {fileID: 8301714305325130111} k__BackingField: {fileID: 0} k__BackingField: [] SerializedTransformProperties: Position: {x: 0, y: 0, z: 0} - Rotation: {x: 0, y: 0, z: 0, w: 0} - LocalScale: {x: 0, y: 0, z: 0} + Rotation: {x: 0, y: 0, z: 0, w: 1} + LocalScale: {x: 1, y: 1, z: 1} _isNetworked: 1 _isGlobal: 0 _initializeOrder: 0 _defaultDespawnType: 0 NetworkObserver: {fileID: 0} - k__BackingField: 129 + k__BackingField: 130 k__BackingField: 0 _scenePathHash: 0 k__BackingField: 0 k__BackingField: 14169919452126136878 ---- !u!114 &6000490057296868418 +--- !u!114 &5299084947188572917 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -254,10 +256,12 @@ MonoBehaviour: m_GameObject: {fileID: 4866668043303595546} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: e00534faac6488c47893490f2bf4c5a2, type: 3} + m_Script: {fileID: 11500000, guid: b693691ec1592874896bee261d991d69, type: 3} m_Name: m_EditorClassIdentifier: ---- !u!114 &-4897036947527457848 + _consumer: {fileID: 8301714305325130111} + _light: {fileID: 2502875599337934467} +--- !u!114 &8301714305325130111 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -266,10 +270,29 @@ MonoBehaviour: m_GameObject: {fileID: 4866668043303595546} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 38640bf88ae0c29409092a258bd36878, type: 3} + m_Script: {fileID: 11500000, guid: b5dc697195ff36649947ce641b391e16, type: 3} m_Name: m_EditorClassIdentifier: - key: {fileID: 11400000, guid: 8702ef6979ffa88448c42ae7f62c602f, type: 2} + _componentIndexCache: 0 + _addedNetworkObject: {fileID: -7828078595381397262} + _networkObjectCache: {fileID: -7828078595381397262} + _powerConsumption: 5 + _powerStatus: 0 +--- !u!114 &-7419120924986984554 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4866668043303595546} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1bbc87ddd49b01f4098910ffdf858004, type: 3} + m_Name: + m_EditorClassIdentifier: + _componentIndexCache: 255 + _addedNetworkObject: {fileID: -7828078595381397262} + _networkObjectCache: {fileID: 0} --- !u!1 &6499595157872319857 GameObject: m_ObjectHideFlags: 0 diff --git a/Assets/Content/WorldObjects/Structures/WallMounts/Lights/LightTubeFixture.prefab b/Assets/Content/WorldObjects/Structures/WallMounts/Lights/LightTubeFixture.prefab index 83277dfc9a..70ed5d3bd8 100644 --- a/Assets/Content/WorldObjects/Structures/WallMounts/Lights/LightTubeFixture.prefab +++ b/Assets/Content/WorldObjects/Structures/WallMounts/Lights/LightTubeFixture.prefab @@ -104,8 +104,9 @@ GameObject: m_Component: - component: {fileID: 5737010110918057389} - component: {fileID: -7828078595381397262} - - component: {fileID: -4128736270194153783} - - component: {fileID: 54129137136314259} + - component: {fileID: 7100984474705242033} + - component: {fileID: 2988001657466237878} + - component: {fileID: -4164530281317530928} m_Layer: 0 m_Name: LightTubeFixture m_TagString: Untagged @@ -145,7 +146,8 @@ MonoBehaviour: k__BackingField: 0 k__BackingField: 0 k__BackingField: {fileID: 0} - _networkBehaviours: [] + _networkBehaviours: + - {fileID: 2988001657466237878} k__BackingField: {fileID: 0} k__BackingField: [] SerializedTransformProperties: @@ -157,12 +159,12 @@ MonoBehaviour: _initializeOrder: 0 _defaultDespawnType: 0 NetworkObserver: {fileID: 0} - k__BackingField: 108 + k__BackingField: 106 k__BackingField: 0 _scenePathHash: 0 k__BackingField: 0 k__BackingField: 10677383693949395304 ---- !u!114 &-4128736270194153783 +--- !u!114 &7100984474705242033 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -171,10 +173,12 @@ MonoBehaviour: m_GameObject: {fileID: 4866668043303595546} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: e00534faac6488c47893490f2bf4c5a2, type: 3} + m_Script: {fileID: 11500000, guid: b693691ec1592874896bee261d991d69, type: 3} m_Name: m_EditorClassIdentifier: ---- !u!114 &54129137136314259 + _consumer: {fileID: 2988001657466237878} + _light: {fileID: 2502875599337934467} +--- !u!114 &2988001657466237878 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -183,10 +187,29 @@ MonoBehaviour: m_GameObject: {fileID: 4866668043303595546} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 38640bf88ae0c29409092a258bd36878, type: 3} + m_Script: {fileID: 11500000, guid: b5dc697195ff36649947ce641b391e16, type: 3} m_Name: m_EditorClassIdentifier: - key: {fileID: 11400000, guid: 0c4f0a70b798e824c9bedd2c6fe407b3, type: 2} + _componentIndexCache: 0 + _addedNetworkObject: {fileID: -7828078595381397262} + _networkObjectCache: {fileID: -7828078595381397262} + _powerConsumption: 3 + _powerStatus: 0 +--- !u!114 &-4164530281317530928 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4866668043303595546} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1bbc87ddd49b01f4098910ffdf858004, type: 3} + m_Name: + m_EditorClassIdentifier: + _componentIndexCache: 255 + _addedNetworkObject: {fileID: -7828078595381397262} + _networkObjectCache: {fileID: 0} --- !u!1 &6499595157872319857 GameObject: m_ObjectHideFlags: 0 diff --git a/Assets/Content/WorldObjects/Structures/Wires/Cables.prefab b/Assets/Content/WorldObjects/Structures/Wires/Cables.prefab index 6dad69d7bc..0d3ff89023 100644 --- a/Assets/Content/WorldObjects/Structures/Wires/Cables.prefab +++ b/Assets/Content/WorldObjects/Structures/Wires/Cables.prefab @@ -12,10 +12,11 @@ GameObject: - component: {fileID: -7727686409064562107} - component: {fileID: -1074477776341974781} - component: {fileID: -4998431523760016775} - - component: {fileID: 687402633161505411} - component: {fileID: -64606549772055205} - component: {fileID: -8163292182942848012} - component: {fileID: -2606982493560320358} + - component: {fileID: 7106158604225815104} + - component: {fileID: 7926021692819508852} m_Layer: 0 m_Name: Cables m_TagString: Untagged @@ -54,7 +55,7 @@ MonoBehaviour: k__BackingField: 0 k__BackingField: {fileID: 0} _networkBehaviours: - - {fileID: 687402633161505411} + - {fileID: 7106158604225815104} k__BackingField: {fileID: 0} k__BackingField: [] SerializedTransformProperties: @@ -66,7 +67,7 @@ MonoBehaviour: _initializeOrder: 0 _defaultDespawnType: 0 NetworkObserver: {fileID: 0} - k__BackingField: 174 + k__BackingField: 176 k__BackingField: 0 _scenePathHash: 0 k__BackingField: 0 @@ -121,7 +122,7 @@ MeshRenderer: m_SortingLayer: 0 m_SortingOrder: 0 m_AdditionalVertexStreams: {fileID: 0} ---- !u!114 &687402633161505411 +--- !u!114 &-64606549772055205 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -130,21 +131,12 @@ MonoBehaviour: m_GameObject: {fileID: 2802364579275783218} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: bc6615260753fbd48af09343d5d55332, type: 3} + m_Script: {fileID: 11500000, guid: 92b450066fe390440b608959b8cb5e28, type: 3} m_Name: m_EditorClassIdentifier: - _componentIndexCache: 0 - _addedNetworkObject: {fileID: -7727686409064562107} - _networkObjectCache: {fileID: -7727686409064562107} - _syncedConnections: 0 - simpleAdjacency: - o: {fileID: -8711453034529356013, guid: 3e69413026bf051418bf84fec0ce5919, type: 3} - u: {fileID: -1590738978952025886, guid: 3e69413026bf051418bf84fec0ce5919, type: 3} - i: {fileID: -2043613833257120371, guid: 3e69413026bf051418bf84fec0ce5919, type: 3} - l: {fileID: -9081922812702010850, guid: 3e69413026bf051418bf84fec0ce5919, type: 3} - t: {fileID: -5358326586770029455, guid: 3e69413026bf051418bf84fec0ce5919, type: 3} - x: {fileID: -8228826546953468662, guid: 3e69413026bf051418bf84fec0ce5919, type: 3} ---- !u!114 &-64606549772055205 + _defaultDirection: 0 + _allowedDirections: 00000000 +--- !u!114 &-8163292182942848012 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -153,12 +145,10 @@ MonoBehaviour: m_GameObject: {fileID: 2802364579275783218} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 92b450066fe390440b608959b8cb5e28, type: 3} + m_Script: {fileID: 11500000, guid: e00534faac6488c47893490f2bf4c5a2, type: 3} m_Name: m_EditorClassIdentifier: - _defaultDirection: 0 - _allowedDirections: 00000000 ---- !u!114 &-8163292182942848012 +--- !u!114 &-2606982493560320358 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -167,10 +157,11 @@ MonoBehaviour: m_GameObject: {fileID: 2802364579275783218} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: e00534faac6488c47893490f2bf4c5a2, type: 3} + m_Script: {fileID: 11500000, guid: 38640bf88ae0c29409092a258bd36878, type: 3} m_Name: m_EditorClassIdentifier: ---- !u!114 &-2606982493560320358 + key: {fileID: 11400000, guid: 8e4acb94055727a408482366bdcd9691, type: 2} +--- !u!114 &7106158604225815104 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -179,7 +170,32 @@ MonoBehaviour: m_GameObject: {fileID: 2802364579275783218} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 38640bf88ae0c29409092a258bd36878, type: 3} + m_Script: {fileID: 11500000, guid: 87c77df6883c7c646b5ebc4c27bff005, type: 3} m_Name: m_EditorClassIdentifier: - key: {fileID: 11400000, guid: 8e4acb94055727a408482366bdcd9691, type: 2} + _componentIndexCache: 0 + _addedNetworkObject: {fileID: -7727686409064562107} + _networkObjectCache: {fileID: -7727686409064562107} + _adjacencyResolver: + o: {fileID: -8711453034529356013, guid: 3e69413026bf051418bf84fec0ce5919, type: 3} + u: {fileID: -1590738978952025886, guid: 3e69413026bf051418bf84fec0ce5919, type: 3} + i: {fileID: -2043613833257120371, guid: 3e69413026bf051418bf84fec0ce5919, type: 3} + l: {fileID: -9081922812702010850, guid: 3e69413026bf051418bf84fec0ce5919, type: 3} + t: {fileID: -5358326586770029455, guid: 3e69413026bf051418bf84fec0ce5919, type: 3} + x: {fileID: -8228826546953468662, guid: 3e69413026bf051418bf84fec0ce5919, type: 3} + _syncedConnections: 0 +--- !u!114 &7926021692819508852 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2802364579275783218} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d30cec7c035cc5649812af01ad936d85, type: 3} + m_Name: + m_EditorClassIdentifier: + _componentIndexCache: 255 + _addedNetworkObject: {fileID: -7727686409064562107} + _networkObjectCache: {fileID: 0} diff --git a/Assets/Scripts/External/QuickGraph.meta b/Assets/Scripts/External/QuickGraph.meta new file mode 100644 index 0000000000..d6bc6ae67e --- /dev/null +++ b/Assets/Scripts/External/QuickGraph.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1c9645dd020187d498b6940b92436a09 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/External/QuickGraph/QuickGraph.asmdef b/Assets/Scripts/External/QuickGraph/QuickGraph.asmdef new file mode 100644 index 0000000000..bd31fababa --- /dev/null +++ b/Assets/Scripts/External/QuickGraph/QuickGraph.asmdef @@ -0,0 +1,3 @@ +{ + "name": "QuickGraph" +} diff --git a/Assets/Scripts/External/QuickGraph/QuickGraph.asmdef.meta b/Assets/Scripts/External/QuickGraph/QuickGraph.asmdef.meta new file mode 100644 index 0000000000..170a53a25a --- /dev/null +++ b/Assets/Scripts/External/QuickGraph/QuickGraph.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: cb1568c00c2cb384889306082481b4dc +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/External/QuickGraph/QuikGraph.dll b/Assets/Scripts/External/QuickGraph/QuikGraph.dll new file mode 100644 index 0000000000..d676d9c1c7 Binary files /dev/null and b/Assets/Scripts/External/QuickGraph/QuikGraph.dll differ diff --git a/Assets/Scripts/External/QuickGraph/QuikGraph.dll.meta b/Assets/Scripts/External/QuickGraph/QuikGraph.dll.meta new file mode 100644 index 0000000000..c284270638 --- /dev/null +++ b/Assets/Scripts/External/QuickGraph/QuikGraph.dll.meta @@ -0,0 +1,33 @@ +fileFormatVersion: 2 +guid: bfb95a4ff8e4d6342a6082333328a7c8 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Any: + second: + enabled: 1 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + Windows Store Apps: WindowsStoreApps + second: + enabled: 0 + settings: + CPU: AnyCPU + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/SS3D/Core/Behaviours/Actor.cs b/Assets/Scripts/SS3D/Core/Behaviours/Actor.cs index c9e0545320..bea9222c2d 100644 --- a/Assets/Scripts/SS3D/Core/Behaviours/Actor.cs +++ b/Assets/Scripts/SS3D/Core/Behaviours/Actor.cs @@ -192,7 +192,6 @@ protected void Start() protected void OnDestroy() { RemoveEventListeners(); - OnDestroyed(); } diff --git a/Assets/Scripts/SS3D/Core/Behaviours/NetworkActor.cs b/Assets/Scripts/SS3D/Core/Behaviours/NetworkActor.cs index 7d1f9aeafd..9b021333a3 100644 --- a/Assets/Scripts/SS3D/Core/Behaviours/NetworkActor.cs +++ b/Assets/Scripts/SS3D/Core/Behaviours/NetworkActor.cs @@ -193,7 +193,6 @@ protected void Start() protected void OnDestroy() { RemoveEventListeners(); - OnDestroyed(); } diff --git a/Assets/Scripts/SS3D/Data/Generated/Sounds.cs b/Assets/Scripts/SS3D/Data/Generated/Sounds.cs index c2a1e4cf1b..df768b20f8 100644 --- a/Assets/Scripts/SS3D/Data/Generated/Sounds.cs +++ b/Assets/Scripts/SS3D/Data/Generated/Sounds.cs @@ -15,6 +15,7 @@ public static class Sounds public static DatabaseAsset Can4 = new DatabaseAsset("Can4", "Sounds"); public static DatabaseAsset AirlockClose = new DatabaseAsset("AirlockClose", "Sounds"); public static DatabaseAsset AirlockOpen = new DatabaseAsset("AirlockOpen", "Sounds"); + public static DatabaseAsset FuelPowerGenerator = new DatabaseAsset("FuelPowerGenerator", "Sounds"); } } diff --git a/Assets/Scripts/SS3D/Interactions/GenericToggleInteractionTarget.cs b/Assets/Scripts/SS3D/Interactions/GenericToggleInteractionTarget.cs new file mode 100644 index 0000000000..df7f540458 --- /dev/null +++ b/Assets/Scripts/SS3D/Interactions/GenericToggleInteractionTarget.cs @@ -0,0 +1,39 @@ +using FishNet.Object.Synchronizing; +using SS3D.Interactions.Interfaces; +using System; +using System.Collections.Generic; + +namespace SS3D.Interactions +{ + /// + /// Small script to make a game object toggleable. All it does is send an OnToggle event when its state changes. + /// + public class GenericToggleInteractionTarget : InteractionTargetNetworkBehaviour, IToggleable + { + [SyncVar] + private bool _on; + public Action OnToggle; + + public override IInteraction[] CreateTargetInteractions(InteractionEvent interactionEvent) + { + List interactions = new(1) + { + new ToggleInteraction() + }; + + return interactions.ToArray(); + } + + public bool GetState() + { + return _on; + } + + public void Toggle() + { + _on = !_on; + + OnToggle?.Invoke(_on); + } + } +} diff --git a/Assets/Scripts/SS3D/Interactions/GenericToggleInteractionTarget.cs.meta b/Assets/Scripts/SS3D/Interactions/GenericToggleInteractionTarget.cs.meta new file mode 100644 index 0000000000..f725114946 --- /dev/null +++ b/Assets/Scripts/SS3D/Interactions/GenericToggleInteractionTarget.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b621d3404247f2e4da4ab459ad43eec7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/SS3D/Systems/Audio/AudioSystem.cs b/Assets/Scripts/SS3D/Systems/Audio/AudioSystem.cs index 5eb3975d23..710a9ef007 100644 --- a/Assets/Scripts/SS3D/Systems/Audio/AudioSystem.cs +++ b/Assets/Scripts/SS3D/Systems/Audio/AudioSystem.cs @@ -73,9 +73,10 @@ public void PlayAudioSource(AudioType audioType, AudioClip audioClipId, NetworkO /// Volume, pitch, and ranges are optional. /// [Server] - public void PlayAudioSource(AudioType audioType, AudioClip audioClipId, Vector3 position, NetworkObject parent, float volume = 0.7f, float pitch = 1f, float minRange = 1f, float maxRange = 500f) + public void PlayAudioSource(AudioType audioType, AudioClip audioClipId, Vector3 position, NetworkObject parent, + bool isLooping = false, float volume = 0.7f, float pitch = 1f, float minRange = 1f, float maxRange = 500f) { - RpcPlayAudioSource(audioType, audioClipId.name, position, parent, volume, pitch, minRange, maxRange); + RpcPlayAudioSource(audioType, audioClipId.name, position, parent, isLooping, volume, pitch, minRange, maxRange); } [Server] @@ -97,7 +98,8 @@ public void RPCSetTimeAudioSource(NetworkObject parent, float time) } [ObserversRpc] - public void RpcPlayAudioSource(AudioType type, string audioClip, Vector3 position, NetworkObject parent, float volume = 0.7f, float pitch = 1f, float minRange = 1f, float maxRange = 500f) + public void RpcPlayAudioSource(AudioType type, string audioClip, Vector3 position, NetworkObject parent, + bool isLooping = false, float volume = 0.7f, float pitch = 1f, float minRange = 1f, float maxRange = 500f) { AudioSource audioSource = FindAvailableAudioSource(type); @@ -112,6 +114,7 @@ public void RpcPlayAudioSource(AudioType type, string audioClip, Vector3 positio //This is useful for things that are obviously creating the sound, like a mouse's squeak //-- we don't want the mouse to leave the squeak behind as it travels, but a flying soda can making a sound at the site of impact is probably fine. audioSource.transform.parent = parent == null ? null : parent.transform; + audioSource.loop = isLooping; audioSource.Play(); } diff --git a/Assets/Scripts/SS3D/Systems/Audio/Boombox.cs b/Assets/Scripts/SS3D/Systems/Audio/Boombox.cs index 64622cedac..1800039ab2 100644 --- a/Assets/Scripts/SS3D/Systems/Audio/Boombox.cs +++ b/Assets/Scripts/SS3D/Systems/Audio/Boombox.cs @@ -37,7 +37,8 @@ public void Toggle() } else { - Subsystems.Get().PlayAudioSource(AudioType.Music, _songs[CurrentMusic], GameObject.transform.position, NetworkObject, 0.7f, 1, 1, 5); + Subsystems.Get().PlayAudioSource(AudioType.Music, _songs[CurrentMusic], GameObject.transform.position, NetworkObject, + false, 0.7f, 1, 1, 5); } } @@ -46,7 +47,8 @@ public void ChangeCurrentMusic() Subsystems.Get().StopAudioSource(NetworkObject); Subsystems.Get().SetTimeAudioSource(NetworkObject, 0f); CurrentMusic = (CurrentMusic + 1) % (_songs.Count); - Subsystems.Get().PlayAudioSource(AudioType.Music, _songs[CurrentMusic], GameObject.transform.position, NetworkObject, 0.7f, 1, 1, 5); + Subsystems.Get().PlayAudioSource(AudioType.Music, _songs[CurrentMusic], GameObject.transform.position, NetworkObject, + false, 0.7f, 1, 1, 5); } public bool GetState() diff --git a/Assets/Scripts/SS3D/Systems/Audio/NoisyCollision.cs b/Assets/Scripts/SS3D/Systems/Audio/NoisyCollision.cs index a89a0dd675..ec55bcce64 100644 --- a/Assets/Scripts/SS3D/Systems/Audio/NoisyCollision.cs +++ b/Assets/Scripts/SS3D/Systems/Audio/NoisyCollision.cs @@ -95,7 +95,8 @@ private void OnCollisionEnter(Collision other) private void PlayCollisionSound(AudioClip[] soundPool) { float pitch = Random.Range(_basePitch - _pitchModulationLow, _basePitch + _pitchModulationHigh); - Subsystems.Get().PlayAudioSource(AudioType.Sfx, PickSound(soundPool), gameObject.transform.position, null, _collisionVolume, pitch); + Subsystems.Get().PlayAudioSource(AudioType.Sfx, PickSound(soundPool), gameObject.transform.position, null, + false, _collisionVolume, pitch); } private AudioClip PickSound(AudioClip[] availableSounds) diff --git a/Assets/Scripts/SS3D/Systems/Electricity.meta b/Assets/Scripts/SS3D/Systems/Electricity.meta new file mode 100644 index 0000000000..ec8c56d42d --- /dev/null +++ b/Assets/Scripts/SS3D/Systems/Electricity.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 840d448b128d3854cbed94a8ae81b657 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/SS3D/Systems/Electricity/BasicBattery.cs b/Assets/Scripts/SS3D/Systems/Electricity/BasicBattery.cs new file mode 100644 index 0000000000..3c607bf625 --- /dev/null +++ b/Assets/Scripts/SS3D/Systems/Electricity/BasicBattery.cs @@ -0,0 +1,65 @@ +using FishNet.Object.Synchronizing; +using SS3D.Systems.Tile.Connections; +using UnityEngine; + +namespace System.Electricity +{ + /// + /// A basic implementation of the IpowerStorage interface. + /// + public class BasicBattery : BasicElectricDevice, IPowerStorage + { + [SerializeField][SyncVar] + private float _maxCapacity = 1000; + + [SerializeField][SyncVar] + private float _storedPower = 0; + + [SerializeField][SyncVar] + private float _maxPowerRate = 5f; + + [SyncVar(OnChange = nameof(HandleSyncEnabled))] + protected bool _isOn = true; + + /// + public float StoredPower { get => _storedPower; set => _storedPower = value >= 0 ? MathF.Min(MaxCapacity, value) : MathF.Max(0f, value); } + + /// + public float MaxCapacity => _maxCapacity; + + /// + public float RemainingCapacity => _maxCapacity - _storedPower; + + /// + public float MaxPowerRate => _maxPowerRate; + + /// + public float MaxRemovablePower => _maxPowerRate > _storedPower ? _storedPower : _maxPowerRate; + + /// + public bool IsOn => _isOn; + + + /// + public float AddPower(float amount) + { + if (amount <= 0 || !_isOn) return 0; + + float addedAmount = Mathf.Min(RemainingCapacity, amount); + _storedPower += addedAmount; + return addedAmount; + } + + /// + public float RemovePower(float amount) + { + if (amount <= 0 || !_isOn) return 0; + + float removedAmount = Mathf.Min(_storedPower, amount); + _storedPower -= removedAmount; + return removedAmount; + } + + protected virtual void HandleSyncEnabled(bool oldValue, bool newValue, bool asServer) { } + } +} diff --git a/Assets/Scripts/SS3D/Systems/Electricity/BasicBattery.cs.meta b/Assets/Scripts/SS3D/Systems/Electricity/BasicBattery.cs.meta new file mode 100644 index 0000000000..028a15e3b7 --- /dev/null +++ b/Assets/Scripts/SS3D/Systems/Electricity/BasicBattery.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 325156b09a9a6854e8be8a88064bd275 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/SS3D/Systems/Electricity/BasicPowerConsumer.cs b/Assets/Scripts/SS3D/Systems/Electricity/BasicPowerConsumer.cs new file mode 100644 index 0000000000..634e6630f9 --- /dev/null +++ b/Assets/Scripts/SS3D/Systems/Electricity/BasicPowerConsumer.cs @@ -0,0 +1,28 @@ +using FishNet.Object.Synchronizing; +using SS3D.Core; +using SS3D.Systems.Tile.Connections; +using UnityEngine; + +namespace System.Electricity +{ + /// + /// Script providing a basic implementation for IPowerConsumer. + /// Can be used for things that need a constant amount of power at all time. + /// + public class BasicPowerConsumer : BasicElectricDevice, IPowerConsumer + { + [SerializeField] + private float _powerConsumption = 1f; + + [SyncVar(OnChange = nameof(SyncPowerStatus))] + private PowerStatus _powerStatus; + public float PowerNeeded => _powerConsumption; + public event EventHandler OnPowerStatusUpdated; + public PowerStatus PowerStatus { get => _powerStatus; set => _powerStatus = value; } + + private void SyncPowerStatus(PowerStatus oldValue, PowerStatus newValue, bool asServer) + { + OnPowerStatusUpdated.Invoke(this, newValue); + } + } +} diff --git a/Assets/Scripts/SS3D/Systems/Electricity/BasicPowerConsumer.cs.meta b/Assets/Scripts/SS3D/Systems/Electricity/BasicPowerConsumer.cs.meta new file mode 100644 index 0000000000..985d758317 --- /dev/null +++ b/Assets/Scripts/SS3D/Systems/Electricity/BasicPowerConsumer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b5dc697195ff36649947ce641b391e16 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/SS3D/Systems/Electricity/BasicPowerGenerator.cs b/Assets/Scripts/SS3D/Systems/Electricity/BasicPowerGenerator.cs new file mode 100644 index 0000000000..f42e98020a --- /dev/null +++ b/Assets/Scripts/SS3D/Systems/Electricity/BasicPowerGenerator.cs @@ -0,0 +1,15 @@ +using SS3D.Systems.Tile.Connections; +using UnityEngine; + +namespace System.Electricity +{ + /// + /// very basic power generator, producing constant infinite power. + /// + public class BasicPowerGenerator : BasicElectricDevice, IPowerProducer + { + [SerializeField] + private float _powerProduction = 10f; + public float PowerProduction => _powerProduction; + } +} diff --git a/Assets/Scripts/SS3D/Systems/Electricity/BasicPowerGenerator.cs.meta b/Assets/Scripts/SS3D/Systems/Electricity/BasicPowerGenerator.cs.meta new file mode 100644 index 0000000000..a9cad8dc32 --- /dev/null +++ b/Assets/Scripts/SS3D/Systems/Electricity/BasicPowerGenerator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 20cf131bf52b1f747825e13fdfc296fb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/SS3D/Systems/Electricity/Circuit.cs b/Assets/Scripts/SS3D/Systems/Electricity/Circuit.cs new file mode 100644 index 0000000000..a1f85679b3 --- /dev/null +++ b/Assets/Scripts/SS3D/Systems/Electricity/Circuit.cs @@ -0,0 +1,212 @@ +using SS3D.Utils; +using System.Collections.Generic; +using System.Linq; + +namespace System.Electricity +{ + /// + /// Class to store all connected consumers, producers and storages of electric power. + /// It handles distributing power to all of those. + /// + public class Circuit + { + private List _consumers; + private List _producers; + private List _storages; + private static Random RandomGenerator = new(); + + public Circuit() + { + _consumers = new(); + _producers = new(); + _storages = new(); + } + + /// + /// Add an electric device to the circuit. An electric device can be a consumer and a producer, or + /// a consumer and storage at the same time, or consumer, producer and storage. In this case, the electric device + /// can end up in multiple lists simultaneously. + /// + public void AddElectricDevice(IElectricDevice device) + { + if(device is IPowerConsumer consumer) _consumers.Add(consumer); + if (device is IPowerProducer producer) _producers.Add(producer); + if (device is IPowerStorage storage) _storages.Add(storage); + } + + + /// + /// Do an update on the whole circuit power. Produce power, consume power that needs to be consumed, and charge stuff that can be charged. + /// + public void UpdateCircuitPower() + { + float leftOverPower = ConsumePower(out bool enoughPower, out int firstUnpoweredConsumerIndex); + ChargeStorages(leftOverPower); + UpdateElectricElementStatus(!enoughPower, firstUnpoweredConsumerIndex); + } + + /// + /// Consume power from the producing devices. + /// + /// The available power, produced by producing devices + /// The first unpowered consumer, can be null if all consumers are powered. + /// The leftover power from the producing devices. + private float ConsumePowerFromPowerProducingDevices(float availablePower, out IPowerConsumer firstUnPoweredConsumer) + { + firstUnPoweredConsumer = null; + + // Consume power from the power producing devices. + foreach (IPowerConsumer consumer in _consumers) + { + if (availablePower > consumer.PowerNeeded) + { + availablePower -= consumer.PowerNeeded; + } + else + { + firstUnPoweredConsumer = consumer; + break; + } + } + return availablePower; + } + + /// + /// Consume power from batteries if the producers don't produce enough power for all consumers. + /// + /// The first unpowered consumer in the list of consumers. + /// Index of the first consumer in the consumer list + /// that could not be powered by power storages because there's not enough power. Equals to 0 if there's enough power. + /// True if enough power is present to power all left over consumers, false otherwise. + private bool ConsumePowerFromBatteries(IPowerConsumer firstUnPoweredConsumer, float leftOverPowerFromProducer, + out int firstUnpoweredConsumerByStoragesIndex) + { + firstUnpoweredConsumerByStoragesIndex = 0; + + // We care only about the consumer that could not be alimented by producers. + int firstUnpoweredConsumerByProducersIndex = _consumers.FindIndex(x => x == firstUnPoweredConsumer); + + List storagesWithAvailablePower = _storages.Where(x => x.StoredPower > 0).ToList(); + + // Consume power from batteries, starting from the first unpowered device by producers + for (int i = firstUnpoweredConsumerByProducersIndex; i < _consumers.Count; i++) + { + IPowerConsumer consumer = _consumers[i]; + float powerNeeded = consumer.PowerNeeded; + + if (!DrainBatteries(powerNeeded, storagesWithAvailablePower, i == firstUnpoweredConsumerByProducersIndex ? leftOverPowerFromProducer : 0)) + { + firstUnpoweredConsumerByStoragesIndex = i; + return false; + } + } + + return true; + } + + /// + /// Make the consumers fulfill all their need of power, from producers and storages. + /// + /// Excess produced energy + private float ConsumePower(out bool enoughPower, out int firstUnPoweredConsumerIndex) + { + // Reorder randomly consumers so that if there's not enough power, powered consumers will be different with each tick. + _consumers = _consumers.OrderBy(x => RandomGenerator.Next()).ToList(); + firstUnPoweredConsumerIndex = 0; + float producedPower = _producers.Sum(x => x.PowerProduction); + producedPower = ConsumePowerFromPowerProducingDevices(producedPower, out IPowerConsumer firstUnPoweredConsumer); + + // if the power producing device were enough to cover all needs just return. + // Else continue with using power from batteries. + if (firstUnPoweredConsumer == null) + { + enoughPower = true; + return producedPower; + } + + enoughPower = ConsumePowerFromBatteries(firstUnPoweredConsumer, producedPower, out firstUnPoweredConsumerIndex); + return 0; + } + + /// + /// Distribute available power equally to power storages. + /// TODO : should limit the amount of power a storage can receive in a single update to avoid instant charge. + /// + /// Power available after consuming. + /// Left over power if storages are full. + private float ChargeStorages(float availablePower) + { + if (availablePower <= 0f) return 0f; + List notFullStorages = _storages.Where(x => x.RemainingCapacity > 0 && x.IsOn).ToList(); + float equalAmount; + while (availablePower > 0.1f && notFullStorages.Count > 0) + { + notFullStorages = _storages.Where(x => x.RemainingCapacity > 0 && x.IsOn).ToList(); + if (notFullStorages.Count == 0) break; + equalAmount = availablePower / notFullStorages.Count; + foreach(IPowerStorage storage in notFullStorages) + { + availablePower -= storage.AddPower(equalAmount); + if (availablePower <= 0) break; + } + } + return availablePower; + } + + /// + /// Update the status of all consumers, if they're still powered or not. + /// + /// true if all consumers could not be powered. + /// The first consumer that could not be powered. We don't care about this if notEnoughPower is false. + private void UpdateElectricElementStatus(bool notEnoughPower, int firstUnpoweredIndex) + { + for(int i =0; i < _consumers.Count; i++) + { + if(notEnoughPower && i >= firstUnpoweredIndex) + { + _consumers[i].PowerStatus = PowerStatus.Inactive; + } + else + { + _consumers[i].PowerStatus = PowerStatus.Powered; + } + } + } + + /// + /// Given an amount of needed power, go through all the storages with available power and accumulate energy from them, until + /// it reaches the necessary amount, or fail to do so. The power is picked up in random order for batteries, to avoid batteries + /// draining one by one. This ensures an almost equal distribution of power taken between batteries. + /// + /// The amount of power we're trying to reach. + /// The list of storages with power left. + /// Power left from producers, that could not go into any consumers. + /// True if enough power was accumulated, false otherwise. + private bool DrainBatteries(float powerNeeded, List storagesWithAvailablePower, float leftOverPowerFromProducers) + { + float powerFromStorages = leftOverPowerFromProducers; + while (powerFromStorages < powerNeeded) + { + if (storagesWithAvailablePower.IsNullOrEmpty()) + { + return false; + } + + // Pick a random battery to draw power from. + int randomBatteryIndex = RandomGenerator.Next(0, storagesWithAvailablePower.Count); + if (powerNeeded - powerFromStorages < storagesWithAvailablePower[randomBatteryIndex].MaxRemovablePower) + { + powerFromStorages += storagesWithAvailablePower[randomBatteryIndex].RemovePower(powerNeeded - powerFromStorages); + } + else + { + powerFromStorages += storagesWithAvailablePower[randomBatteryIndex].RemovePower(storagesWithAvailablePower[randomBatteryIndex].MaxRemovablePower); + } + + // Can't take from a battery more than once each tick. + storagesWithAvailablePower.RemoveAt(randomBatteryIndex); + } + return true; + } + } +} diff --git a/Assets/Scripts/SS3D/Systems/Electricity/Circuit.cs.meta b/Assets/Scripts/SS3D/Systems/Electricity/Circuit.cs.meta new file mode 100644 index 0000000000..5e0c2521ab --- /dev/null +++ b/Assets/Scripts/SS3D/Systems/Electricity/Circuit.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4793329a5ce64484d95ddd89db581e58 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/SS3D/Systems/Electricity/ElectricitySystem.cs b/Assets/Scripts/SS3D/Systems/Electricity/ElectricitySystem.cs new file mode 100644 index 0000000000..dd016122bb --- /dev/null +++ b/Assets/Scripts/SS3D/Systems/Electricity/ElectricitySystem.cs @@ -0,0 +1,193 @@ +using SS3D.Core.Behaviours; +using System.Collections.Generic; +using UnityEngine; +using QuikGraph; +using Coimbra.Services.PlayerLoopEvents; +using Coimbra.Services.Events; +using QuikGraph.Algorithms; +using SS3D.Systems.Tile; +using SS3D.Core; +using System.Linq; +using FishNet.Object; + +namespace System.Electricity +{ + /// + /// Handles a graph, that contains all electicity circuits. + /// + /// + /// When removing electrical elements or adding new ones, it doesn't immediately update, instead, + /// it marks the graph dirty and rebuilds the graph on the next tick. + /// + public class ElectricitySystem : NetworkSystem + { + public event Action OnSystemSetUp; + + /// + /// Called each time the electricity system update. All things that need to sync with the electricity updates should suscribe + /// to this event instead of performing their logics in Unity's update loops. + /// + public event Action OnTick; + + public bool IsSetUp { get; private set; } + + /// + /// Record to have a unique set of number for any electric device on the map. + /// None two tile objects should have the same set of coordinates. + /// + private record VerticeCoordinates(short X, short Y, byte Layer, byte Direction); + + /// + /// The graph is considered dirty if there was any changes during the previous frame in the way electric devices are put on the map. + /// + private bool _graphIsDirty; + + /// + /// List of all circuits on the map. + /// + private List _circuits; + + /// + /// Graph representing all electric devices and connections on the map. Each electric device is a vertice in this graph, + /// and each electric connection is an edge. + /// + private UndirectedGraph> _electricityGraph; + + /// + /// Interval between two ticks in seconds. + /// + [SerializeField] + private float _tickRate = 0.2f; + private float _timeElapsed = 0f; + + public override void OnStartServer() + { + base.OnStartServer(); + _electricityGraph = new(); + _circuits = new(); + AddHandle(FixedUpdateEvent.AddListener(HandleFixedUpdate)); + IsSetUp = true; + OnSystemSetUp?.Invoke(); + OnTick += HandleCircuitsUpdate; + } + + [Server] + private void HandleFixedUpdate(ref EventContext context, in FixedUpdateEvent updateEvent) + { + _timeElapsed += Time.deltaTime; + + if(_timeElapsed > _tickRate) + { + RpcInvokeOnTick(); + _timeElapsed = 0; + } + } + + [Server] + private void HandleCircuitsUpdate() + { + // Updating the graph on each change is unreliable in case of events, that change a lot of elements at one time, such as explosions. + // Therefore, the graph updates each tick if it gets dirty. + if (_graphIsDirty) + { + UpdateAllCircuitsTopology(); + _graphIsDirty = false; + } + + foreach (Circuit circuit in _circuits) + { + circuit.UpdateCircuitPower(); + } + } + + /// + /// Add an electric device to the electic graph, setting up vertices and new connections if necessary. + /// + /// The device to add. + [Server] + public void AddElectricalElement(IElectricDevice device) + { + PlacedTileObject tileObject = device.TileObject; + VerticeCoordinates deviceCoordinates = new ((short)tileObject.WorldOrigin.x, (short)tileObject.WorldOrigin.y, + (byte)tileObject.Layer, (byte)tileObject.Direction); + _electricityGraph.AddVertex(deviceCoordinates); + List neighbours = tileObject.Connector.GetNeighbours(); + foreach(PlacedTileObject neighbour in neighbours) + { + VerticeCoordinates neighbourCoordinates = new ((short)neighbour.WorldOrigin.x, (short)neighbour.WorldOrigin.y, + (byte)neighbour.Layer, (byte)neighbour.Direction); + + _electricityGraph.AddVertex(neighbourCoordinates); + _electricityGraph.AddEdge(new (deviceCoordinates, neighbourCoordinates)); + } + _graphIsDirty = true; + } + + /// + /// Remove an electric device from the map. + /// + /// The device to remove. + [Server] + public void RemoveElectricalElement(IElectricDevice device) + { + if (device == null || device.TileObject == null) return; + _electricityGraph.RemoveVertex + ( + new + ( + (short)device.TileObject.WorldOrigin.x, + (short)device.TileObject.WorldOrigin.y, + (byte)device.TileObject.Layer, + (byte)device.TileObject.Direction + ) + ); + _graphIsDirty = true; + } + + // TODO: When removing electrical elements, identify which circuits are affected and only update those. + // TODO: When adding electrical elements, use some kind of metric to determine what circuits might be affected by the adding, and only update those. + // TODO: Maybe simply check which component gets connected to the new device, and update all circuits with those components. + /// + /// Recompute all circuits, should be called when there are some changes on the map regarding how electric devices are placed. + /// + [Server] + private void UpdateAllCircuitsTopology() + { + Dictionary components = new(); + + // Compute all components in the graph. One component is basically one circuit. + // In graph theory, a component is a connected subgraph that is not part of any larger connected subgraph. + _electricityGraph.ConnectedComponents(components); + _circuits.Clear(); + // group all vertice coordinates by the component index they belong to. + Dictionary> graphs = components.GroupBy(pair => pair.Value) + .ToDictionary( + group => group.Key, + group => group.Select(item => item.Key).ToList() + ); + + // Set up the circuits, with their respective storages, producers, and consumers of power. + foreach (List component in graphs.Values) + { + _circuits.Add(new()); + foreach (VerticeCoordinates coord in component) + { + TileSystem tileSystem = Subsystems.Get(); + ITileLocation location = tileSystem.CurrentMap.GetTileLocation((TileLayer)coord.Layer, new(coord.X, 0f, coord.Y)); + + if (!location.TryGetPlacedObject(out PlacedTileObject placedObject, (Direction)coord.Direction)) continue; + + if (!placedObject.TryGetComponent(out IElectricDevice device)) continue; + + _circuits.Last().AddElectricDevice(device); + } + } + } + + [ObserversRpc] + private void RpcInvokeOnTick() + { + OnTick?.Invoke(); + } + } +} diff --git a/Assets/Scripts/SS3D/Systems/Electricity/ElectricitySystem.cs.meta b/Assets/Scripts/SS3D/Systems/Electricity/ElectricitySystem.cs.meta new file mode 100644 index 0000000000..109acc2c04 --- /dev/null +++ b/Assets/Scripts/SS3D/Systems/Electricity/ElectricitySystem.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cec52cc8cb291414f83ee8b575949b02 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/SS3D/Systems/Electricity/FuelPowerGenerator.cs b/Assets/Scripts/SS3D/Systems/Electricity/FuelPowerGenerator.cs new file mode 100644 index 0000000000..3e1ee43ab6 --- /dev/null +++ b/Assets/Scripts/SS3D/Systems/Electricity/FuelPowerGenerator.cs @@ -0,0 +1,98 @@ +using FishNet.Object; +using FishNet.Object.Synchronizing; +using SS3D.Core; +using SS3D.Data.Generated; +using SS3D.Interactions; +using SS3D.Systems.Audio; +using SS3D.Systems.Tile.Connections; +using UnityEngine; +using AudioType = SS3D.Systems.Audio.AudioType; + +namespace System.Electricity +{ + /// + /// Script for the pacman generator, handling light and noise when turning it on and off. + /// + public class FuelPowerGenerator : BasicElectricDevice, IPowerProducer + { + [SerializeField] + private float _powerProduction = 10f; + + [SerializeField] + private SkinnedMeshRenderer _skinnedMeshRenderer; + private const string OnBlendShapeName = "On"; + private const string OutputBlendShapeName = "Output"; + private const string LowFuel = "LowFuel"; + public float PowerProduction => _powerProduction; + + [SyncVar(OnChange = nameof(SyncGeneratorToggle))] + private bool _enabled = false; // If the generator is working. + private float _onPowerProduction = 10f; + + public override void OnStartClient() + { + base.OnStartClient(); + GetComponent().OnToggle += HandleGeneratorToggle; + _onPowerProduction = _powerProduction; + HandlePowerGenerated(false); + } + + [Server] + private void HandleGeneratorToggle(bool isEnabled) + { + _enabled = isEnabled; + } + + private void SyncGeneratorToggle(bool oldValue, bool newValue, bool asServer) + { + if (asServer) return; + + HandleSound(newValue); + HandleLights(newValue); + HandlePowerGenerated(newValue); + GetComponent().Enable = newValue; + } + + private void HandleSound(bool isEnabled) + { + if (!isEnabled) + { + Subsystems.Get().StopAudioSource(NetworkObject); + } + else + { + Subsystems.Get().PlayAudioSource(AudioType.Music, Sounds.FuelPowerGenerator, Position, NetworkObject, + true, 0.7f, 1, 1, 10); + } + } + + private void HandleLights(bool isEnabled) + { + int onblendShapeIndex = _skinnedMeshRenderer.sharedMesh.GetBlendShapeIndex(OnBlendShapeName); + int outputBlendShapeIndex = _skinnedMeshRenderer.sharedMesh.GetBlendShapeIndex(OutputBlendShapeName); + + if (onblendShapeIndex != -1) + { + _skinnedMeshRenderer.SetBlendShapeWeight(onblendShapeIndex, isEnabled ? 100 : 0); + } + else + { + Debug.LogError("Blend shape " + OnBlendShapeName + " not found."); + } + + if (outputBlendShapeIndex != -1) + { + _skinnedMeshRenderer.SetBlendShapeWeight(outputBlendShapeIndex, isEnabled ? 100 : 0); + } + else + { + Debug.LogError("Blend shape " + OnBlendShapeName + " not found."); + } + } + + private void HandlePowerGenerated(bool isEnabled) + { + _powerProduction = isEnabled ? _onPowerProduction : 0f; + } + } +} diff --git a/Assets/Scripts/SS3D/Systems/Electricity/FuelPowerGenerator.cs.meta b/Assets/Scripts/SS3D/Systems/Electricity/FuelPowerGenerator.cs.meta new file mode 100644 index 0000000000..bb05c28bb8 --- /dev/null +++ b/Assets/Scripts/SS3D/Systems/Electricity/FuelPowerGenerator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 328b489d4f8c1f04983e195ee8635c19 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/SS3D/Systems/Electricity/IElectricDevice.cs b/Assets/Scripts/SS3D/Systems/Electricity/IElectricDevice.cs new file mode 100644 index 0000000000..a4af1e9df2 --- /dev/null +++ b/Assets/Scripts/SS3D/Systems/Electricity/IElectricDevice.cs @@ -0,0 +1,12 @@ +using SS3D.Systems.Tile; + +/// +/// IElectricDevice are tile objects that can be connected to an electric circuit in some way. +/// +public interface IElectricDevice +{ + /// + /// Tile object linked to this electric device. + /// + public PlacedTileObject TileObject { get; } +} diff --git a/Assets/Scripts/SS3D/Systems/Electricity/IElectricDevice.cs.meta b/Assets/Scripts/SS3D/Systems/Electricity/IElectricDevice.cs.meta new file mode 100644 index 0000000000..fd3f6596d2 --- /dev/null +++ b/Assets/Scripts/SS3D/Systems/Electricity/IElectricDevice.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: be9ed61aa635ce34d93699b3a770895e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/SS3D/Systems/Electricity/IPowerConsumer.cs b/Assets/Scripts/SS3D/Systems/Electricity/IPowerConsumer.cs new file mode 100644 index 0000000000..bfa750d6fe --- /dev/null +++ b/Assets/Scripts/SS3D/Systems/Electricity/IPowerConsumer.cs @@ -0,0 +1,12 @@ +namespace System.Electricity +{ + /// + /// Interface to use for anything that need power to function, such as lamps, or electric devices. + /// + public interface IPowerConsumer : IElectricDevice + { + public float PowerNeeded { get; } + + public PowerStatus PowerStatus { get; set; } + } +} diff --git a/Assets/Scripts/SS3D/Systems/Electricity/IPowerConsumer.cs.meta b/Assets/Scripts/SS3D/Systems/Electricity/IPowerConsumer.cs.meta new file mode 100644 index 0000000000..0d812308d9 --- /dev/null +++ b/Assets/Scripts/SS3D/Systems/Electricity/IPowerConsumer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 79093b8fa8f4ac94495b09be1c704f05 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/SS3D/Systems/Electricity/IPowerProducer.cs b/Assets/Scripts/SS3D/Systems/Electricity/IPowerProducer.cs new file mode 100644 index 0000000000..62f4325056 --- /dev/null +++ b/Assets/Scripts/SS3D/Systems/Electricity/IPowerProducer.cs @@ -0,0 +1,10 @@ +namespace System.Electricity +{ + /// + /// Interface for anything producing electric power. + /// + public interface IPowerProducer : IElectricDevice + { + public float PowerProduction { get; } + } +} diff --git a/Assets/Scripts/SS3D/Systems/Electricity/IPowerProducer.cs.meta b/Assets/Scripts/SS3D/Systems/Electricity/IPowerProducer.cs.meta new file mode 100644 index 0000000000..69d22f21d4 --- /dev/null +++ b/Assets/Scripts/SS3D/Systems/Electricity/IPowerProducer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dc192d45d53c6e046897dbf33bc28494 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/SS3D/Systems/Electricity/IPowerStorage.cs b/Assets/Scripts/SS3D/Systems/Electricity/IPowerStorage.cs new file mode 100644 index 0000000000..112d249cb8 --- /dev/null +++ b/Assets/Scripts/SS3D/Systems/Electricity/IPowerStorage.cs @@ -0,0 +1,49 @@ +/// +/// Interface for things that can receive, store power and send it back. +/// +public interface IPowerStorage : IElectricDevice +{ + /// + /// How much power is currently stored. + /// + public float StoredPower { get; } + + /// + /// How much power can this store. + /// + public float MaxCapacity { get; } + + /// + /// How much power storage room is left. + /// + public float RemainingCapacity { get; } + + /// + /// How much power one can remove in one update, considering there's enough power left. + /// + public float MaxPowerRate { get; } + + /// + /// How much power one can remove in one update. + /// + public float MaxRemovablePower { get; } + + /// + /// If the storage can send or receive power. + /// + public bool IsOn { get; } + + /// + /// Remove a given amount of power from battery, respecting Max power rate and present amount.* + /// Should also not remove power if the storage is off. + /// + /// Return the power amount removed. + public float RemovePower(float amount); + + /// + /// Add power to battery, respecting maximum. + /// Should also not add power if the storage is off. + /// + /// Return the power amount added. + public float AddPower(float amount); +} diff --git a/Assets/Scripts/SS3D/Systems/Electricity/IPowerStorage.cs.meta b/Assets/Scripts/SS3D/Systems/Electricity/IPowerStorage.cs.meta new file mode 100644 index 0000000000..f1911bf765 --- /dev/null +++ b/Assets/Scripts/SS3D/Systems/Electricity/IPowerStorage.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 665a153d69b5a65478675e7018cb370b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/SS3D/Systems/Electricity/LightPower.cs b/Assets/Scripts/SS3D/Systems/Electricity/LightPower.cs new file mode 100644 index 0000000000..426d74ce58 --- /dev/null +++ b/Assets/Scripts/SS3D/Systems/Electricity/LightPower.cs @@ -0,0 +1,45 @@ +using UnityEngine; + +namespace System.Electricity +{ + /// + /// Simple script that handle toggling a light source on and off depending if power is available or not. + /// + public class LightPower : MonoBehaviour + { + [SerializeField] + private BasicPowerConsumer _consumer; + [SerializeField] + private Light _light; + private float _poweredIntensity; + + private void Start() + { + _consumer.OnPowerStatusUpdated += HandlePowerStatusUpdated; + _poweredIntensity = _light.intensity; + + TurnLightOff(); + } + + private void HandlePowerStatusUpdated(object sender, PowerStatus newStatus) + { + UpdateLights(newStatus); + } + + private void UpdateLights(PowerStatus powerStatus) + { + if (powerStatus == PowerStatus.Powered) TurnLightOn(); + else TurnLightOff(); + } + + private void TurnLightOn() + { + _light.intensity = _poweredIntensity; + } + + private void TurnLightOff() + { + _light.intensity = 0; + } + } +} diff --git a/Assets/Scripts/SS3D/Systems/Electricity/LightPower.cs.meta b/Assets/Scripts/SS3D/Systems/Electricity/LightPower.cs.meta new file mode 100644 index 0000000000..cc18f1b778 --- /dev/null +++ b/Assets/Scripts/SS3D/Systems/Electricity/LightPower.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b693691ec1592874896bee261d991d69 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/SS3D/Systems/Electricity/MachineVibrate.cs b/Assets/Scripts/SS3D/Systems/Electricity/MachineVibrate.cs new file mode 100644 index 0000000000..fb8528408c --- /dev/null +++ b/Assets/Scripts/SS3D/Systems/Electricity/MachineVibrate.cs @@ -0,0 +1,60 @@ +using Coimbra.Services.Events; +using Coimbra.Services.PlayerLoopEvents; +using FishNet; +using SS3D.Core.Behaviours; +using UnityEngine; + +/// +/// Little script to make stuff vibrate back and forth. Mostly useful for electrical furnitures functionning. +/// +public class MachineVibrate : Actor +{ + [SerializeField] + private float _amplitude = 1; // How much is the amplitude of the vibration. + [SerializeField] + private float _frequency = 35; // Vibrating speed. + private Quaternion _initialRotation; // Rotation of the generator at rest. + private Vector3 _directionOfShake; // In which direction the generator shake. + private bool _enable = false; + private float _elapsedTime = 0f; // Elapsed time for the vibrating stuff. + + public bool Enable + { + get => _enable; + set => SetEnable(value); + } + + protected override void OnStart() + { + base.OnStart(); + // do not need to show the vibrating stuff on server + if (InstanceFinder.IsServerOnly) return; + + AddHandle(FixedUpdateEvent.AddListener(HandleFixedUpdate)); + _initialRotation = Rotation; + _directionOfShake = Transform.right; + } + + private void HandleFixedUpdate(ref EventContext context, in FixedUpdateEvent updateEvent) + { + if (_enable) + { + Vibrate(); + } + } + + private void Vibrate() + { + _elapsedTime += Time.fixedDeltaTime; + transform.rotation = _initialRotation * Quaternion.Euler(_directionOfShake * (-_amplitude + Mathf.PingPong(_frequency * _elapsedTime, 2f * _amplitude))); + } + + private void SetEnable(bool enable) + { + _enable = enable; + if (enable) + { + Rotation = _initialRotation; + } + } +} diff --git a/Assets/Scripts/SS3D/Systems/Electricity/MachineVibrate.cs.meta b/Assets/Scripts/SS3D/Systems/Electricity/MachineVibrate.cs.meta new file mode 100644 index 0000000000..76b8abea28 --- /dev/null +++ b/Assets/Scripts/SS3D/Systems/Electricity/MachineVibrate.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c7a41c77d19af89459c70cd823369e19 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/SS3D/Systems/Electricity/PowerStatus.cs b/Assets/Scripts/SS3D/Systems/Electricity/PowerStatus.cs new file mode 100644 index 0000000000..958c09f64d --- /dev/null +++ b/Assets/Scripts/SS3D/Systems/Electricity/PowerStatus.cs @@ -0,0 +1,8 @@ +/// +/// Simple status for powered device, that can be either inactive or powered. +/// +public enum PowerStatus +{ + Inactive = 0, + Powered = 1, +} diff --git a/Assets/Scripts/SS3D/Systems/Electricity/PowerStatus.cs.meta b/Assets/Scripts/SS3D/Systems/Electricity/PowerStatus.cs.meta new file mode 100644 index 0000000000..e17acfe5fb --- /dev/null +++ b/Assets/Scripts/SS3D/Systems/Electricity/PowerStatus.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e3b8a6e4e051a5644a2efb57426a0677 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/SS3D/Systems/Electricity/SmesBattery.cs b/Assets/Scripts/SS3D/Systems/Electricity/SmesBattery.cs new file mode 100644 index 0000000000..aa573ef124 --- /dev/null +++ b/Assets/Scripts/SS3D/Systems/Electricity/SmesBattery.cs @@ -0,0 +1,149 @@ +using FishNet.Object; +using SS3D.Core; +using SS3D.Interactions; +using UnityEngine; +using UnityEngine.Serialization; + +namespace System.Electricity +{ + /// + /// Script for SMES battery, mostly to handle displaying visual indicators on the SMES models. + /// + public class SmesBattery : BasicBattery + { + [FormerlySerializedAs("SmesSkinnedMesh")] + [SerializeField] + private SkinnedMeshRenderer _smesSkinnedMesh; + + // Bunch of blend shape indexes. + private const int ChargeblendIndex = 0; + private const int OnBlendIndex = 12; + private const int OffBlendIndex = 13; + private float _previousPowerStored = 0f; + private int _currentLightOutput = 0; + private int _lightOutputTarget = 0; + + /// + /// How much tick before updating the output lights. + /// + [SerializeField] + private int _updateLightPeriod = 3; + private int _updateCount = 0; + + public override void OnStartClient() + { + base.OnStartClient(); + GetComponent().OnToggle += HandleBatteryToggle; + HandleBatteryToggle(_isOn); + + Subsystems.Get().OnTick += HandleTick; + } + + protected override void OnDestroyed() + { + base.OnDestroyed(); + Subsystems.Get().OnTick -= HandleTick; + } + + [Client] + private void HandleTick() + { + AdjustBatteryLevel(); + AdjustBatteryOutput(); + AdjustBatteryInput(); + _previousPowerStored = StoredPower; + _updateCount++; + } + + /// + /// Adjust the battery level, the liquid thingy going up and down, depending on the amount of stored power. + /// + [Client] + private void AdjustBatteryLevel() + { + float chargeLevelNormalized = StoredPower / MaxCapacity; + _smesSkinnedMesh.SetBlendShapeWeight(ChargeblendIndex, chargeLevelNormalized*100); + } + + /// + /// Just turn on the battery input light, if power was added. Turn it off if no power added, or power removed. + /// + [Client] + private void AdjustBatteryInput() + { + float powerAdded = Mathf.Max(StoredPower - _previousPowerStored, 0f); + + if(powerAdded > 0f) + { + _smesSkinnedMesh.SetBlendShapeWeight(11, 100f); + } + else + { + _smesSkinnedMesh.SetBlendShapeWeight(11, 0f); + } + } + + /// + /// Set the vertical line of output lights so that, at each update, the bar goes up and down toward the light it should reached. + /// Do nothing if the target light is reached. + /// + [Client] + private void AdjustBatteryOutput() + { + ComputeLightOutputTarget(); + + if (_updateCount != _updateLightPeriod) return; + + _updateCount = 0; + + if (_currentLightOutput < _lightOutputTarget) + { + _currentLightOutput += 1; + _smesSkinnedMesh.SetBlendShapeWeight(_currentLightOutput, 100); + } + else if(_currentLightOutput > _lightOutputTarget) + { + _smesSkinnedMesh.SetBlendShapeWeight(_currentLightOutput, 0); + _currentLightOutput -= 1; + } + } + + /// + /// Calculate index of the light that should be turned on. Can be 0 and in that case no light should be on. + /// Assumes the index of blendshapes for the output lights are from 1 to 11. + /// + [Client] + private void ComputeLightOutputTarget() + { + float powerRemoved = Mathf.Max(_previousPowerStored - StoredPower, 0f); + float relativeRate = Mathf.Floor(10 * powerRemoved / MaxPowerRate); + + _lightOutputTarget = (int)relativeRate; + } + + /// + /// Called when the SMES battery is toggled on or off. + /// + /// True if the battery is on. + private void HandleBatteryToggle(bool toggle) + { + _isOn = toggle; + } + + protected override void HandleSyncEnabled(bool oldValue, bool newValue, bool asServer) + { + if (asServer) return; + + if (newValue) + { + _smesSkinnedMesh.SetBlendShapeWeight(OnBlendIndex, 100); + _smesSkinnedMesh.SetBlendShapeWeight(OffBlendIndex, 0); + } + else + { + _smesSkinnedMesh.SetBlendShapeWeight(OnBlendIndex, 0); + _smesSkinnedMesh.SetBlendShapeWeight(OffBlendIndex, 100); + } + } + } +} diff --git a/Assets/Scripts/SS3D/Systems/Electricity/SmesBattery.cs.meta b/Assets/Scripts/SS3D/Systems/Electricity/SmesBattery.cs.meta new file mode 100644 index 0000000000..817a880b5b --- /dev/null +++ b/Assets/Scripts/SS3D/Systems/Electricity/SmesBattery.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3f1cd0d7880cd9c4f98489ed5f9413ad +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/SS3D/Systems/Inventory/Items/Generic/BikeHorn.cs b/Assets/Scripts/SS3D/Systems/Inventory/Items/Generic/BikeHorn.cs index 7b77c46179..a8a321951c 100644 --- a/Assets/Scripts/SS3D/Systems/Inventory/Items/Generic/BikeHorn.cs +++ b/Assets/Scripts/SS3D/Systems/Inventory/Items/Generic/BikeHorn.cs @@ -25,7 +25,8 @@ public class BikeHorn : Item public void Honk() { _animator.SetTrigger(HonkAnimation); - Subsystems.Get().PlayAudioSource(AudioType.Sfx, Sounds.BikeHorn, GameObject.transform.position, NetworkObject, 0.7f, 1, 1, 5); + Subsystems.Get().PlayAudioSource(AudioType.Sfx, Sounds.BikeHorn, GameObject.transform.position, NetworkObject, + false,0.7f, 1, 1, 5); } public bool IsHonking() diff --git a/Assets/Scripts/SS3D/Systems/SS3D.Systems.asmdef b/Assets/Scripts/SS3D/Systems/SS3D.Systems.asmdef index c7c84826f7..2745b90092 100644 --- a/Assets/Scripts/SS3D/Systems/SS3D.Systems.asmdef +++ b/Assets/Scripts/SS3D/Systems/SS3D.Systems.asmdef @@ -21,7 +21,7 @@ "GUID:46e20dca70571ce4e817a6b5874168a0", "GUID:8979f103c1228714eb0115e440b2b33a", "GUID:47588e3d37f573d458b0eaa6cc8109c2", - "GUID:eec0964c48f6f4e40bc3ec2257ccf8c5" + "GUID:cb1568c00c2cb384889306082481b4dc" ], "includePlatforms": [], "excludePlatforms": [], diff --git a/Assets/Scripts/SS3D/Systems/Tile/Connections/BasicElectricDevice.cs b/Assets/Scripts/SS3D/Systems/Tile/Connections/BasicElectricDevice.cs new file mode 100644 index 0000000000..ad7d318d93 --- /dev/null +++ b/Assets/Scripts/SS3D/Systems/Tile/Connections/BasicElectricDevice.cs @@ -0,0 +1,39 @@ +using SS3D.Core; +using SS3D.Core.Behaviours; +using System.Electricity; + +namespace SS3D.Systems.Tile.Connections +{ + /// + /// Put this script on anything that need to be part of an electric circuit. + /// This script add the game object it's on to an electric circuit. + /// + public class BasicElectricDevice : NetworkActor, IElectricDevice + { + public PlacedTileObject TileObject => gameObject.GetComponent(); + + public override void OnStartServer() + { + base.OnStartServer(); + + ElectricitySystem electricitySystem = Subsystems.Get(); + if (electricitySystem.IsSetUp) + electricitySystem.AddElectricalElement(this); + else + electricitySystem.OnSystemSetUp += OnElectricitySystemSetup; + } + + protected override void OnDestroyed() + { + base.OnDestroyed(); + ElectricitySystem electricitySystem = Subsystems.Get(); + electricitySystem.RemoveElectricalElement(this); + } + + private void OnElectricitySystemSetup() + { + ElectricitySystem electricitySystem = Subsystems.Get(); + electricitySystem.AddElectricalElement(this); + } + } +} diff --git a/Assets/Scripts/SS3D/Systems/Tile/Connections/BasicElectricDevice.cs.meta b/Assets/Scripts/SS3D/Systems/Tile/Connections/BasicElectricDevice.cs.meta new file mode 100644 index 0000000000..97966fdbb2 --- /dev/null +++ b/Assets/Scripts/SS3D/Systems/Tile/Connections/BasicElectricDevice.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d30cec7c035cc5649812af01ad936d85 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/SS3D/Systems/Tile/Connections/CablesAdjacencyConnector.cs b/Assets/Scripts/SS3D/Systems/Tile/Connections/CablesAdjacencyConnector.cs new file mode 100644 index 0000000000..20961b6e15 --- /dev/null +++ b/Assets/Scripts/SS3D/Systems/Tile/Connections/CablesAdjacencyConnector.cs @@ -0,0 +1,149 @@ +using SS3D.Logging; +using SS3D.Systems.Tile.Connections.AdjacencyTypes; +using System.Collections.Generic; +using UnityEngine; +using FishNet.Object.Synchronizing; +using FishNet.Object; + +namespace SS3D.Systems.Tile.Connections +{ + /// + /// Cables have their own connector logic because they behave in a particular way. They can "connect" to any electric devices, + /// but no connection will be display. Connections with other cables are the only one being displayed. + /// + public class CablesAdjacencyConnector : ElectricAdjacencyConnector + { + + /// + /// A structure containing data regarding connection of this PlacedTileObject with all 8 + /// adjacent neighbours (cardinal and diagonal connections). + /// + protected AdjacencyMap AdjacencyMap; + + /// + /// The specific mesh this connectable has. + /// + protected MeshFilter Filter; + + /// + /// Script that help with resolving the specific mesh a connectable should take. + /// + [SerializeField] + private SimpleConnector _adjacencyResolver; + + /// + /// A byte, representing the 8 possible connections with neighbours. + /// + [SyncVar(OnChange = nameof(SyncAdjacencies))] + private byte _syncedConnections; + + [Server] + protected override void Setup() + { + if (!Initialized) + { + base.Setup(); + AdjacencyMap = new AdjacencyMap(); + Filter = GetComponent(); + } + } + + [Server] + public override void UpdateAllConnections() + { + Setup(); + + List neighbourObjects = GetNeighbours(); + + bool changed = false; + + foreach (PlacedTileObject neighbourObject in neighbourObjects) + { + if (!NeighbourIsCable(neighbourObject)) continue; + + PlacedObject.NeighbourAtDirectionOf(neighbourObject, out Direction dir); + changed |= UpdateSingleConnection(dir, neighbourObject, true); + } + + if (changed) + { + UpdateMeshAndDirection(); + } + } + + [Server] + public override bool UpdateSingleConnection(Direction dir, PlacedTileObject neighbourObject, bool updateNeighbour) + { + Setup(); + + // should not return here if neighbour object is null, otherwise it would prevent update if a neighbour is removed. + if (neighbourObject != null && !NeighbourIsCable(neighbourObject)) return false; + + bool isConnected = IsConnected(neighbourObject); + + bool isUpdated = AdjacencyMap.SetConnection(dir, new(TileObjectGenericType.None, TileObjectSpecificType.None, isConnected)); + + if (isUpdated && updateNeighbour) + { + neighbourObject?.UpdateSingleAdjacency(TileHelper.GetOpposite(dir), PlacedObject, false); + } + + if(isUpdated) + { + _syncedConnections = AdjacencyMap.SerializeToByte(); + UpdateMeshAndDirection(); + } + + return isUpdated; + } + + /// + /// Update the current mesh of the game object this connector is onto, as well + /// as it's rotation. + /// + [ServerOrClient] + protected virtual void UpdateMeshAndDirection() + { + MeshDirectionInfo info = _adjacencyResolver.GetMeshAndDirection(AdjacencyMap); + + if (Filter == null) + { + Log.Warning(this, "Missing mesh {meshDirectionInfo}", Logs.Generic, info); + } + + Filter.mesh = info.Mesh; + + Quaternion localRotation = transform.localRotation; + Vector3 eulerRotation = localRotation.eulerAngles; + localRotation = Quaternion.Euler(eulerRotation.x, info.Rotation, eulerRotation.z); + + transform.localRotation = localRotation; + } + + /// + /// Sync adjacency map on client, and update mesh and direction using this new map. + /// + [Server] + private void SyncAdjacencies(byte oldValue, byte newValue, bool asServer) + { + if (!asServer) + { + Setup(); + + AdjacencyMap.DeserializeFromByte(newValue); + UpdateMeshAndDirection(); + } + } + + /// + /// Cables can have as neighbour electrical device but they should not physically connect to them, as they pass below them. + /// They only visually connect to other cables. Which is why it's useful to check if a neighbour is a cable or another electric device. + /// > + [Server] + private bool NeighbourIsCable(PlacedTileObject neighbour) + { + return neighbour != null && neighbour.Connector is CablesAdjacencyConnector; + } + + } +} diff --git a/Assets/Scripts/SS3D/Systems/Tile/Connections/CablesAdjacencyConnector.cs.meta b/Assets/Scripts/SS3D/Systems/Tile/Connections/CablesAdjacencyConnector.cs.meta new file mode 100644 index 0000000000..9f0316a4a8 --- /dev/null +++ b/Assets/Scripts/SS3D/Systems/Tile/Connections/CablesAdjacencyConnector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 87c77df6883c7c646b5ebc4c27bff005 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/SS3D/Systems/Tile/Connections/ElectricAdjacencyConnector.cs b/Assets/Scripts/SS3D/Systems/Tile/Connections/ElectricAdjacencyConnector.cs new file mode 100644 index 0000000000..667860a40d --- /dev/null +++ b/Assets/Scripts/SS3D/Systems/Tile/Connections/ElectricAdjacencyConnector.cs @@ -0,0 +1,82 @@ +using SS3D.Core; +using SS3D.Core.Behaviours; +using System.Collections.Generic; +using System.Linq; + +namespace SS3D.Systems.Tile.Connections +{ + /// + /// Base class for stuff that should connect in an electric circuit. + /// + public abstract class ElectricAdjacencyConnector : NetworkActor, IAdjacencyConnector + { + /// + /// The placed object for this disposal pipe. + /// + protected PlacedTileObject PlacedObject; + protected bool Initialized; + + protected virtual void Setup() + { + if (!Initialized) + { + PlacedObject = GetComponent(); + Initialized = true; + } + } + + public List GetNeighbours() + { + Setup(); + List neighbours = GetElectricDevicesOnSameTile(); + neighbours.AddRange(GetNeighbourElectricDevicesOnSameLayer()); + neighbours.RemoveAll(x => x == null); + return neighbours; + } + + public bool IsConnected(PlacedTileObject neighbourObject) + { + return neighbourObject?.Connector is ElectricAdjacencyConnector; + } + + public abstract void UpdateAllConnections(); + + public abstract bool UpdateSingleConnection(Direction dir, PlacedTileObject neighbourObject, bool updateNeighbour); + + private List GetElectricDevicesOnSameTile() + { + TileSystem tileSystem = Subsystems.Get(); + TileMap map = tileSystem.CurrentMap; + + List devicesOnSameTile = new(); + + TileChunk currentChunk = map.GetChunk(PlacedObject.gameObject.transform.position); + List deviceLocations = currentChunk.GetTileLocations(PlacedObject.Origin.x, PlacedObject.Origin.y); + + foreach(ITileLocation location in deviceLocations) + { + foreach(PlacedTileObject tileObject in location.GetAllPlacedObject()) + { + if(tileObject.gameObject.TryGetComponent(out IElectricDevice device)) + { + devicesOnSameTile.Add(tileObject); + } + } + } + + devicesOnSameTile.Remove(PlacedObject); + + return devicesOnSameTile; + } + + private List GetNeighbourElectricDevicesOnSameLayer() + { + TileSystem tileSystem = Subsystems.Get(); + TileMap map = tileSystem.CurrentMap; + IEnumerable electricNeighbours = map.GetCardinalNeighbourPlacedObjects(PlacedObject.Layer, + PlacedObject.gameObject.transform.position).Where(x => x!= null && x.gameObject.TryGetComponent(out IElectricDevice device)); + + return electricNeighbours.ToList(); + } + } +} diff --git a/Assets/Scripts/SS3D/Systems/Tile/Connections/ElectricAdjacencyConnector.cs.meta b/Assets/Scripts/SS3D/Systems/Tile/Connections/ElectricAdjacencyConnector.cs.meta new file mode 100644 index 0000000000..399164e2f8 --- /dev/null +++ b/Assets/Scripts/SS3D/Systems/Tile/Connections/ElectricAdjacencyConnector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2b10c64c2280fd44bb531c6970acf3fb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/SS3D/Systems/Tile/Connections/ElectricDeviceAdjacencyConnector.cs b/Assets/Scripts/SS3D/Systems/Tile/Connections/ElectricDeviceAdjacencyConnector.cs new file mode 100644 index 0000000000..2b221d93de --- /dev/null +++ b/Assets/Scripts/SS3D/Systems/Tile/Connections/ElectricDeviceAdjacencyConnector.cs @@ -0,0 +1,15 @@ +namespace SS3D.Systems.Tile.Connections +{ + /// + /// Very simple class for electric devices that do not need their mesh to be updated when something connect to them; + /// + public class ElectricDeviceAdjacencyConnector : ElectricAdjacencyConnector + { + public override void UpdateAllConnections() { } + + public override bool UpdateSingleConnection(Direction dir, PlacedTileObject neighbourObject, bool updateNeighbour) + { + return true; + } + } +} diff --git a/Assets/Scripts/SS3D/Systems/Tile/Connections/ElectricDeviceAdjacencyConnector.cs.meta b/Assets/Scripts/SS3D/Systems/Tile/Connections/ElectricDeviceAdjacencyConnector.cs.meta new file mode 100644 index 0000000000..c1931c24c6 --- /dev/null +++ b/Assets/Scripts/SS3D/Systems/Tile/Connections/ElectricDeviceAdjacencyConnector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1bbc87ddd49b01f4098910ffdf858004 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/SS3D/Systems/Tile/PlacedObjects/PlacedTileObject.cs b/Assets/Scripts/SS3D/Systems/Tile/PlacedObjects/PlacedTileObject.cs index 1e7901f4b5..5dd2d85fa7 100644 --- a/Assets/Scripts/SS3D/Systems/Tile/PlacedObjects/PlacedTileObject.cs +++ b/Assets/Scripts/SS3D/Systems/Tile/PlacedObjects/PlacedTileObject.cs @@ -86,6 +86,8 @@ public static PlacedTileObject Create(Vector3 worldPosition, Vector2Int origin, public bool HasAdjacencyConnector => _connector != null; + public IAdjacencyConnector Connector => _connector; + /// /// Set up a new PlacedTileObject. /// diff --git a/Assets/Scripts/SS3D/Systems/Tile/TileChunk.cs b/Assets/Scripts/SS3D/Systems/Tile/TileChunk.cs index 699582cd78..b3547f77a4 100644 --- a/Assets/Scripts/SS3D/Systems/Tile/TileChunk.cs +++ b/Assets/Scripts/SS3D/Systems/Tile/TileChunk.cs @@ -142,6 +142,19 @@ public ITileLocation GetTileLocation(TileLayer layer, int x, int y) } } + public List GetTileLocations(int x, int y) + { + + List AllLocationOnTile= new(); + + foreach(TileLayer layer in TileHelper.GetTileLayers()) + { + AllLocationOnTile.Add(GetTileLocation(layer, x, y)); + } + + return AllLocationOnTile; + } + public ITileLocation GetTileObject(TileLayer layer, Vector3 worldPosition) { Vector2Int vector = GetXY(worldPosition); diff --git a/Assets/Scripts/SS3D/Systems/Tile/TileMap.cs b/Assets/Scripts/SS3D/Systems/Tile/TileMap.cs index 3afeb7ec12..08d20a742b 100644 --- a/Assets/Scripts/SS3D/Systems/Tile/TileMap.cs +++ b/Assets/Scripts/SS3D/Systems/Tile/TileMap.cs @@ -110,14 +110,14 @@ public TileChunk GetChunk(Vector3 worldPosition) } } - private ITileLocation GetTileLocation(TileLayer layer, Vector3 worldPosition) + public ITileLocation GetTileLocation(TileLayer layer, Vector3 worldPosition) { TileChunk chunk = GetOrCreateChunk(worldPosition); // TODO: creates unnessary empty chunk when checking whether building can be done return chunk.GetTileObject(layer, worldPosition); } - private ITileLocation[] GetTileLocations(Vector3 worldPosition) + public ITileLocation[] GetTileLocations(Vector3 worldPosition) { ITileLocation[] tileObjects = new ITileLocation[TileHelper.GetTileLayers().Length]; diff --git a/Assets/Scripts/SS3D/Systems/Tile/TileMapCreator/ConstructionHologram.cs b/Assets/Scripts/SS3D/Systems/Tile/TileMapCreator/ConstructionHologram.cs index 30c469817a..bfb291fd64 100644 --- a/Assets/Scripts/SS3D/Systems/Tile/TileMapCreator/ConstructionHologram.cs +++ b/Assets/Scripts/SS3D/Systems/Tile/TileMapCreator/ConstructionHologram.cs @@ -3,6 +3,9 @@ using System.Collections.Generic; using System.Linq; using UnityEngine; +using SS3D.Core.Behaviours; +using Coimbra; +using Actor = SS3D.Core.Behaviours.Actor; namespace SS3D.Systems.Tile.TileMapCreator { @@ -28,10 +31,8 @@ public class ConstructionHologram /// all tile objects. If it's not, it will choose another available direction. public ConstructionHologram(GameObject ghostObject, Vector3 targetPosition, Direction dir, ConstructionMode mode = ConstructionMode.Valid) { - List components = ghostObject.GetComponentsInChildren() - .Where(x => x is not ICustomGhostRotation).ToList(); - components.ForEach(x => x.enabled = false); + DisableBehaviours(ghostObject); Hologram = ghostObject; _targetPosition = targetPosition; @@ -123,5 +124,13 @@ public void Destroy() Hologram.Dispose(true); Hologram = null; } + + private void DisableBehaviours(GameObject ghostObject) + { + List components = ghostObject.GetComponentsInChildren() + .Where(x => x is not ICustomGhostRotation).ToList(); + + components.ForEach(x => x.enabled = false); + } } } \ No newline at end of file