From ced03fb39ffe4f555680603474c2d1edf84ee17d Mon Sep 17 00:00:00 2001 From: Jeremy Glazebrook Date: Tue, 19 Dec 2023 18:47:44 -0500 Subject: [PATCH 01/15] Build Mode initial push Changes: Build Mode Lot Camera 3D Build Cursor Catalog (early) Add Terrain Tools (with cheat) Add Foundation Tool Add Wall tool Add Floor tool Add Pond Tool Add Build Mode HUD Elements Refactor --- Assets/Materials/Build.meta | 8 + Assets/Materials/Build/WandAreaBrush.mat | 79 + Assets/Materials/Build/WandAreaBrush.mat.meta | 8 + Assets/Materials/Build/WandTop.mat | 82 + Assets/Materials/Build/WandTop.mat.meta | 8 + Assets/Scenes/Tests/BuildModeTest.unity | 2022 +++++++++++++++++ Assets/Scenes/Tests/BuildModeTest.unity.meta | 7 + Assets/Scripts/OpenTS2/Cameras.meta | 8 + .../OpenTS2/Cameras/TestLotViewCamera.cs | 140 ++ .../OpenTS2/Cameras/TestLotViewCamera.cs.meta | 11 + .../Components/AssetReferenceComponent.cs | 136 +- .../OpenTS2/Components/ScenegraphComponent.cs | 5 - .../OpenTS2/Content/DBPF/WallGraphAsset.cs | 101 +- .../OpenTS2/Diagnostic/BoolpropCheat.cs | 42 + .../OpenTS2/Diagnostic/BoolpropCheat.cs.meta | 11 + .../Scripts/OpenTS2/Diagnostic/CheatSystem.cs | 6 +- Assets/Scripts/OpenTS2/Engine/Modes.meta | 8 + .../Scripts/OpenTS2/Engine/Modes/Build.meta | 8 + .../Engine/Modes/Build/BuildModeServer.cs | 592 +++++ .../Modes/Build/BuildModeServer.cs.meta | 11 + .../OpenTS2/Engine/Modes/Build/Tools.meta | 8 + .../Modes/Build/Tools/AbstractBuildTool.cs | 251 ++ .../Build/Tools/AbstractBuildTool.cs.meta | 11 + .../Engine/Modes/Build/Tools/FloorTool.cs | 83 + .../Modes/Build/Tools/FloorTool.cs.meta | 11 + .../Modes/Build/Tools/FoundationTool.cs | 60 + .../Modes/Build/Tools/FoundationTool.cs.meta | 11 + .../Engine/Modes/Build/Tools/HandTool.cs | 101 + .../Engine/Modes/Build/Tools/HandTool.cs.meta | 11 + .../Modes/Build/Tools/TerrainBrushTool.cs | 108 + .../Build/Tools/TerrainBrushTool.cs.meta | 11 + .../Engine/Modes/Build/Tools/WallTool.cs | 89 + .../Engine/Modes/Build/Tools/WallTool.cs.meta | 11 + .../OpenTS2/Engine/Tests/BuildModeTest.cs | 144 ++ .../Engine/Tests/BuildModeTest.cs.meta | 11 + .../OpenTS2/Scenes/Lot/Extensions.meta | 8 + .../LotArchitectureBuildModeExtensions.cs | 183 ++ ...LotArchitectureBuildModeExtensions.cs.meta | 11 + .../OpenTS2/Scenes/Lot/LotArchitecture.cs | 74 +- .../OpenTS2/Scenes/Lot/LotFloorComponent.cs | 23 +- Assets/Scripts/OpenTS2/Scenes/Lot/LotLoad.cs | 278 +++ .../OpenTS2/Scenes/Lot/LotLoad.cs.meta | 11 + .../OpenTS2/Scenes/Lot/LotTerrainComponent.cs | 3 + .../OpenTS2/Scenes/Lot/LotWallComponent.cs | 43 +- .../Scripts/OpenTS2/Scenes/Lot/PatternMesh.cs | 2 +- .../Scenes/Lot/PatternMeshCollection.cs | 1 + .../OpenTS2/Scenes/Lot/PatternMeshFloor.cs | 4 +- .../OpenTS2/Scenes/Lot/State/WorldState.cs | 5 + Assets/Scripts/OpenTS2/UI/Layouts/Lot.meta | 8 + .../UI/Layouts/Lot/LotViewBuildModeHUD.cs | 588 +++++ .../Layouts/Lot/LotViewBuildModeHUD.cs.meta | 11 + .../OpenTS2/UI/Layouts/Lot/LotViewHUD.cs | 182 ++ .../OpenTS2/UI/Layouts/Lot/LotViewHUD.cs.meta | 11 + .../UI/Layouts/Lot/LotViewHUDController.cs | 33 + .../Layouts/Lot/LotViewHUDController.cs.meta | 11 + .../Scripts/OpenTS2/UI/UIButtonComponent.cs | 17 + Assets/Shaders/Lot/Billboard.shader | 69 + Assets/Shaders/Lot/Billboard.shader.meta | 10 + 58 files changed, 5763 insertions(+), 37 deletions(-) create mode 100644 Assets/Materials/Build.meta create mode 100644 Assets/Materials/Build/WandAreaBrush.mat create mode 100644 Assets/Materials/Build/WandAreaBrush.mat.meta create mode 100644 Assets/Materials/Build/WandTop.mat create mode 100644 Assets/Materials/Build/WandTop.mat.meta create mode 100644 Assets/Scenes/Tests/BuildModeTest.unity create mode 100644 Assets/Scenes/Tests/BuildModeTest.unity.meta create mode 100644 Assets/Scripts/OpenTS2/Cameras.meta create mode 100644 Assets/Scripts/OpenTS2/Cameras/TestLotViewCamera.cs create mode 100644 Assets/Scripts/OpenTS2/Cameras/TestLotViewCamera.cs.meta create mode 100644 Assets/Scripts/OpenTS2/Diagnostic/BoolpropCheat.cs create mode 100644 Assets/Scripts/OpenTS2/Diagnostic/BoolpropCheat.cs.meta create mode 100644 Assets/Scripts/OpenTS2/Engine/Modes.meta create mode 100644 Assets/Scripts/OpenTS2/Engine/Modes/Build.meta create mode 100644 Assets/Scripts/OpenTS2/Engine/Modes/Build/BuildModeServer.cs create mode 100644 Assets/Scripts/OpenTS2/Engine/Modes/Build/BuildModeServer.cs.meta create mode 100644 Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools.meta create mode 100644 Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/AbstractBuildTool.cs create mode 100644 Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/AbstractBuildTool.cs.meta create mode 100644 Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/FloorTool.cs create mode 100644 Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/FloorTool.cs.meta create mode 100644 Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/FoundationTool.cs create mode 100644 Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/FoundationTool.cs.meta create mode 100644 Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/HandTool.cs create mode 100644 Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/HandTool.cs.meta create mode 100644 Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/TerrainBrushTool.cs create mode 100644 Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/TerrainBrushTool.cs.meta create mode 100644 Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/WallTool.cs create mode 100644 Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/WallTool.cs.meta create mode 100644 Assets/Scripts/OpenTS2/Engine/Tests/BuildModeTest.cs create mode 100644 Assets/Scripts/OpenTS2/Engine/Tests/BuildModeTest.cs.meta create mode 100644 Assets/Scripts/OpenTS2/Scenes/Lot/Extensions.meta create mode 100644 Assets/Scripts/OpenTS2/Scenes/Lot/Extensions/LotArchitectureBuildModeExtensions.cs create mode 100644 Assets/Scripts/OpenTS2/Scenes/Lot/Extensions/LotArchitectureBuildModeExtensions.cs.meta create mode 100644 Assets/Scripts/OpenTS2/Scenes/Lot/LotLoad.cs create mode 100644 Assets/Scripts/OpenTS2/Scenes/Lot/LotLoad.cs.meta create mode 100644 Assets/Scripts/OpenTS2/UI/Layouts/Lot.meta create mode 100644 Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewBuildModeHUD.cs create mode 100644 Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewBuildModeHUD.cs.meta create mode 100644 Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewHUD.cs create mode 100644 Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewHUD.cs.meta create mode 100644 Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewHUDController.cs create mode 100644 Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewHUDController.cs.meta create mode 100644 Assets/Shaders/Lot/Billboard.shader create mode 100644 Assets/Shaders/Lot/Billboard.shader.meta diff --git a/Assets/Materials/Build.meta b/Assets/Materials/Build.meta new file mode 100644 index 00000000..d0de8cad --- /dev/null +++ b/Assets/Materials/Build.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b8bc301eacaa25d4a9bbdf35f989ad2e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Materials/Build/WandAreaBrush.mat b/Assets/Materials/Build/WandAreaBrush.mat new file mode 100644 index 00000000..c7c6e3bb --- /dev/null +++ b/Assets/Materials/Build/WandAreaBrush.mat @@ -0,0 +1,79 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 6 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: WandAreaBrush + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: _ALPHAPREMULTIPLY_ON + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: 3000 + stringTagMap: + RenderType: Transparent + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 10 + - _GlossMapScale: 1 + - _Glossiness: 0.5 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 3 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 0 + m_Colors: + - _Color: {r: 0.031886935, g: 1, b: 0, a: 0.48235294} + - _EmissionColor: {r: 0.014443844, g: 0.014443844, b: 0.014443844, a: 1} + m_BuildTextureStacks: [] diff --git a/Assets/Materials/Build/WandAreaBrush.mat.meta b/Assets/Materials/Build/WandAreaBrush.mat.meta new file mode 100644 index 00000000..fce4f1f5 --- /dev/null +++ b/Assets/Materials/Build/WandAreaBrush.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9e00eb9bc0cd7be478e657c251ce0680 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Materials/Build/WandTop.mat b/Assets/Materials/Build/WandTop.mat new file mode 100644 index 00000000..03962f30 --- /dev/null +++ b/Assets/Materials/Build/WandTop.mat @@ -0,0 +1,82 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 6 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: WandTop + m_Shader: {fileID: 4800000, guid: 9027c75630615624b8d7e4b02852aa4e, type: 3} + m_ShaderKeywords: + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _Dst: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0.5 + - _GlossyReflections: 1 + - _Metallic: 0 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _ScaleX: 1 + - _ScaleY: 1 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _Src: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 1, g: 1, b: 1, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + m_BuildTextureStacks: [] diff --git a/Assets/Materials/Build/WandTop.mat.meta b/Assets/Materials/Build/WandTop.mat.meta new file mode 100644 index 00000000..05bed763 --- /dev/null +++ b/Assets/Materials/Build/WandTop.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5d46dd5277a083f49992dd646af64e34 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scenes/Tests/BuildModeTest.unity b/Assets/Scenes/Tests/BuildModeTest.unity new file mode 100644 index 00000000..6d522dbc --- /dev/null +++ b/Assets/Scenes/Tests/BuildModeTest.unity @@ -0,0 +1,2022 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0.44657874, g: 0.49641275, b: 0.5748172, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 12 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 256 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 1 + m_PVRDenoiserTypeDirect: 1 + m_PVRDenoiserTypeIndirect: 1 + m_PVRDenoiserTypeAO: 1 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &89992084 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 89992085} + - component: {fileID: 89992086} + - component: {fileID: 89992087} + m_Layer: 5 + m_Name: Handle + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &89992085 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 89992084} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 420274207} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 20, y: 20} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &89992086 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 89992084} + m_CullTransparentMesh: 1 +--- !u!114 &89992087 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 89992084} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &420274206 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 420274207} + m_Layer: 5 + m_Name: Sliding Area + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &420274207 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 420274206} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 89992085} + m_Father: {fileID: 2062259699} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: -20, y: -20} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &489915452 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 489915453} + - component: {fileID: 489915454} + m_Layer: 0 + m_Name: BuildModeTestController + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &489915453 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 489915452} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 35.671333, y: 1.8509755, z: 31.046001} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1538301813} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &489915454 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 489915452} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 94cb5833fa52cfc4392f5daf80bc17b3, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &548360276 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 548360277} + - component: {fileID: 548360279} + - component: {fileID: 548360278} + m_Layer: 0 + m_Name: curs + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &548360277 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 548360276} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 1.51, z: 0} + m_LocalScale: {x: 0.15, y: 1.5, z: 0.15} + m_Children: [] + m_Father: {fileID: 1458263242} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!23 &548360278 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 548360276} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} + 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 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!33 &548360279 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 548360276} + m_Mesh: {fileID: 10206, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &648965860 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 648965865} + - component: {fileID: 648965864} + - component: {fileID: 648965863} + - component: {fileID: 648965862} + - component: {fileID: 648965861} + m_Layer: 5 + m_Name: Cheat Console Canvas + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &648965861 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 648965860} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: c7d73af69c9e8614080ca76faff3ae13, type: 3} + m_Name: + m_EditorClassIdentifier: + ConsoleParent: {fileID: 1951021496} + CheatInputField: {fileID: 2114196948} + ConsoleOutput: {fileID: 1078632927} + ConsoleScroll: {fileID: 1085664058} +--- !u!114 &648965862 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 648965860} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreReversedGraphics: 1 + m_BlockingObjects: 0 + m_BlockingMask: + serializedVersion: 2 + m_Bits: 4294967295 +--- !u!114 &648965863 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 648965860} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 0 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 800, y: 600} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 0 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 + m_PresetInfoIsWorld: 0 +--- !u!223 &648965864 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 648965860} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 0 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 0 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_AdditionalShaderChannelsFlag: 0 + m_SortingLayerID: 0 + m_SortingOrder: 100 + m_TargetDisplay: 0 +--- !u!224 &648965865 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 648965860} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0, y: 0, z: 0} + m_Children: + - {fileID: 1951021497} + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0, y: 0} +--- !u!1 &783440545 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 783440546} + - component: {fileID: 783440547} + m_Layer: 5 + m_Name: Viewport + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &783440546 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 783440545} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1078632924} + m_Father: {fileID: 1085664059} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: -17, y: 0} + m_Pivot: {x: 0, y: 1} +--- !u!222 &783440547 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 783440545} + m_CullTransparentMesh: 1 +--- !u!1 &1078632923 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1078632924} + - component: {fileID: 1078632926} + - component: {fileID: 1078632927} + - component: {fileID: 1078632925} + m_Layer: 5 + m_Name: Console Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1078632924 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1078632923} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 783440546} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0, y: 1} +--- !u!114 &1078632925 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1078632923} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3245ec927659c4140ac4f8d17403cc18, type: 3} + m_Name: + m_EditorClassIdentifier: + m_HorizontalFit: 0 + m_VerticalFit: 2 +--- !u!222 &1078632926 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1078632923} + m_CullTransparentMesh: 1 +--- !u!114 &1078632927 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1078632923} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 14 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 10 + m_MaxSize: 40 + m_Alignment: 0 + m_AlignByGeometry: 0 + m_RichText: 0 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: +--- !u!1 &1085664057 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1085664059} + - component: {fileID: 1085664060} + - component: {fileID: 1085664058} + m_Layer: 5 + m_Name: Scroll View + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1085664058 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1085664057} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1aa08ab6e0800fa44ae55d278d1423e3, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Content: {fileID: 1078632924} + m_Horizontal: 0 + m_Vertical: 1 + m_MovementType: 2 + m_Elasticity: 0.1 + m_Inertia: 0 + m_DecelerationRate: 0.135 + m_ScrollSensitivity: 40 + m_Viewport: {fileID: 783440546} + m_HorizontalScrollbar: {fileID: 0} + m_VerticalScrollbar: {fileID: 2062259698} + m_HorizontalScrollbarVisibility: 2 + m_VerticalScrollbarVisibility: 1 + m_HorizontalScrollbarSpacing: -3 + m_VerticalScrollbarSpacing: -3 + m_OnValueChanged: + m_PersistentCalls: + m_Calls: [] +--- !u!224 &1085664059 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1085664057} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 783440546} + m_Father: {fileID: 1326854590} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 1.6949463, y: -105.1} + m_SizeDelta: {x: -3.3900743, y: 200} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &1085664060 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1085664057} + m_CullTransparentMesh: 1 +--- !u!1 &1134778609 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1134778610} + - component: {fileID: 1134778611} + m_Layer: 0 + m_Name: LotViewUIController + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1134778610 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1134778609} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1538301813} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1134778611 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1134778609} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9727801f799a10a41875182ace337639, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &1139364661 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1139364662} + - component: {fileID: 1139364665} + - component: {fileID: 1139364664} + m_Layer: 0 + m_Name: Plane + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1139364662 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1139364661} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 3.232, z: 0} + m_LocalScale: {x: 0.75, y: 0.75, z: 0} + m_Children: [] + m_Father: {fileID: 1458263242} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!23 &1139364664 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1139364661} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 5d46dd5277a083f49992dd646af64e34, 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 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!33 &1139364665 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1139364661} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &1157865906 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1157865908} + - component: {fileID: 1157865907} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &1157865907 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1157865906} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_UseViewFrustumForShadowCasterCull: 1 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &1157865908 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1157865906} + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1 &1196709330 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1196709331} + - component: {fileID: 1196709333} + - component: {fileID: 1196709332} + m_Layer: 5 + m_Name: Placeholder + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1196709331 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1196709330} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 2114196945} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -0.5} + m_SizeDelta: {x: -20, y: -13} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1196709332 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1196709330} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 0.5} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 14 + m_FontStyle: 2 + m_BestFit: 0 + m_MinSize: 10 + m_MaxSize: 40 + m_Alignment: 0 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: +--- !u!222 &1196709333 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1196709330} + m_CullTransparentMesh: 1 +--- !u!1 &1267610420 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1267610421} + - component: {fileID: 1267610423} + - component: {fileID: 1267610422} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1267610421 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1267610420} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 2114196945} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -0.5} + m_SizeDelta: {x: -20, y: -13} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1267610422 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1267610420} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 14 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 10 + m_MaxSize: 40 + m_Alignment: 0 + m_AlignByGeometry: 0 + m_RichText: 0 + m_HorizontalOverflow: 1 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: +--- !u!222 &1267610423 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1267610420} + m_CullTransparentMesh: 1 +--- !u!1 &1326854589 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1326854590} + - component: {fileID: 1326854593} + - component: {fileID: 1326854592} + - component: {fileID: 1326854591} + m_Layer: 5 + m_Name: ConsolePanel + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1326854590 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1326854589} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1085664059} + - {fileID: 2062259699} + m_Father: {fileID: 1951021497} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -99.20001} + m_SizeDelta: {x: 0, y: 198.4} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1326854591 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1326854589} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 31a19414c41e5ae4aae2af33fee712f6, type: 3} + m_Name: + m_EditorClassIdentifier: + m_ShowMaskGraphic: 1 +--- !u!114 &1326854592 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1326854589} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1326854593 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1326854589} + m_CullTransparentMesh: 1 +--- !u!1 &1428817267 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1428817268} + - component: {fileID: 1428817270} + - component: {fileID: 1428817269} + m_Layer: 0 + m_Name: curs + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1428817268 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1428817267} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 1.5, z: 0} + m_LocalScale: {x: 0.1, y: 3, z: 0.1} + m_Children: [] + m_Father: {fileID: 1637446162} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!23 &1428817269 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1428817267} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 9e00eb9bc0cd7be478e657c251ce0680, 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 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!33 &1428817270 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1428817267} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &1458263241 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1458263242} + m_Layer: 0 + m_Name: Wand + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1458263242 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1458263241} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 548360277} + - {fileID: 1139364662} + m_Father: {fileID: 0} + m_RootOrder: 6 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1538301812 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1538301813} + m_Layer: 0 + m_Name: Scene + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1538301813 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1538301812} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 2076958800} + - {fileID: 1134778610} + - {fileID: 489915453} + m_Father: {fileID: 0} + m_RootOrder: 5 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1592748653 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1592748656} + - component: {fileID: 1592748655} + - component: {fileID: 1592748654} + m_Layer: 0 + m_Name: EventSystem + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1592748654 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1592748653} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3} + m_Name: + m_EditorClassIdentifier: + m_HorizontalAxis: Horizontal + m_VerticalAxis: Vertical + m_SubmitButton: Submit + m_CancelButton: Cancel + m_InputActionsPerSecond: 10 + m_RepeatDelay: 0.5 + m_ForceModuleActive: 0 +--- !u!114 &1592748655 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1592748653} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3} + m_Name: + m_EditorClassIdentifier: + m_FirstSelected: {fileID: 0} + m_sendNavigationEvents: 1 + m_DragThreshold: 10 +--- !u!4 &1592748656 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1592748653} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1637446161 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1637446162} + m_Layer: 0 + m_Name: debugWandCompanion + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1637446162 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1637446161} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1428817268} + m_Father: {fileID: 0} + m_RootOrder: 7 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1883555802 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1883555808} + - component: {fileID: 1883555804} + - component: {fileID: 1883555803} + - component: {fileID: 1883555806} + - component: {fileID: 1883555807} + - component: {fileID: 1883555805} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &1883555803 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1883555802} + m_Enabled: 1 +--- !u!20 &1883555804 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1883555802} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!114 &1883555805 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1883555802} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreReversedGraphics: 1 + m_BlockingObjects: 0 + m_BlockingMask: + serializedVersion: 2 + m_Bits: 4294967295 +--- !u!114 &1883555806 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1883555802} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 8021982501d05f645a42b19f4a41ab8a, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!223 &1883555807 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1883555802} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 2 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 0 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_AdditionalShaderChannelsFlag: 0 + m_SortingLayerID: 0 + m_SortingOrder: 0 + m_TargetDisplay: 0 +--- !u!224 &1883555808 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1883555802} + m_LocalRotation: {x: 0.35355338, y: 0.35355338, z: -0.1464466, w: 0.8535535} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 45, y: 45, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 8} + m_SizeDelta: {x: 100, y: 100} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &1951021496 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1951021497} + m_Layer: 5 + m_Name: Cheat Console + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1951021497 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1951021496} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 2114196945} + - {fileID: 1326854590} + m_Father: {fileID: 648965865} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &2000707108 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2000707112} + - component: {fileID: 2000707111} + - component: {fileID: 2000707110} + - component: {fileID: 2000707109} + - component: {fileID: 2000707113} + m_Layer: 5 + m_Name: Canvas + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &2000707109 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2000707108} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreReversedGraphics: 1 + m_BlockingObjects: 0 + m_BlockingMask: + serializedVersion: 2 + m_Bits: 4294967295 +--- !u!114 &2000707110 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2000707108} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 0 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 800, y: 600} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 0 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 + m_PresetInfoIsWorld: 0 +--- !u!223 &2000707111 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2000707108} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 0 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 1 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_AdditionalShaderChannelsFlag: 0 + m_SortingLayerID: 0 + m_SortingOrder: 0 + m_TargetDisplay: 0 +--- !u!224 &2000707112 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2000707108} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0, y: 0, z: 0} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0, y: 0} +--- !u!114 &2000707113 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2000707108} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: db3b6e6445c9df84bb2e95b9365382be, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &2062259697 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2062259699} + - component: {fileID: 2062259701} + - component: {fileID: 2062259700} + - component: {fileID: 2062259698} + m_Layer: 5 + m_Name: Scrollbar Vertical + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &2062259698 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2062259697} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2a4db7a114972834c8e4117be1d82ba3, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 89992087} + m_HandleRect: {fileID: 89992085} + m_Direction: 2 + m_Value: 0 + m_Size: 1 + m_NumberOfSteps: 0 + m_OnValueChanged: + m_PersistentCalls: + m_Calls: [] +--- !u!224 &2062259699 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2062259697} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 420274207} + m_Father: {fileID: 1326854590} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0.000015258789} + m_SizeDelta: {x: 20, y: 0} + m_Pivot: {x: 1, y: 1} +--- !u!114 &2062259700 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2062259697} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &2062259701 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2062259697} + m_CullTransparentMesh: 1 +--- !u!1001 &2076958799 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 1538301813} + m_Modifications: + - target: {fileID: 2467515431058217605, guid: 188047b711783b74aa73c17ff9d66147, type: 3} + propertyPath: m_Name + value: Scene Startup + objectReference: {fileID: 0} + - target: {fileID: 2467515431058217606, guid: 188047b711783b74aa73c17ff9d66147, type: 3} + propertyPath: m_RootOrder + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2467515431058217606, guid: 188047b711783b74aa73c17ff9d66147, type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2467515431058217606, guid: 188047b711783b74aa73c17ff9d66147, type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2467515431058217606, guid: 188047b711783b74aa73c17ff9d66147, type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2467515431058217606, guid: 188047b711783b74aa73c17ff9d66147, type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 2467515431058217606, guid: 188047b711783b74aa73c17ff9d66147, type: 3} + propertyPath: m_LocalRotation.x + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 2467515431058217606, guid: 188047b711783b74aa73c17ff9d66147, type: 3} + propertyPath: m_LocalRotation.y + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 2467515431058217606, guid: 188047b711783b74aa73c17ff9d66147, type: 3} + propertyPath: m_LocalRotation.z + value: -0 + objectReference: {fileID: 0} + - target: {fileID: 2467515431058217606, guid: 188047b711783b74aa73c17ff9d66147, type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2467515431058217606, guid: 188047b711783b74aa73c17ff9d66147, type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2467515431058217606, guid: 188047b711783b74aa73c17ff9d66147, type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 188047b711783b74aa73c17ff9d66147, type: 3} +--- !u!4 &2076958800 stripped +Transform: + m_CorrespondingSourceObject: {fileID: 2467515431058217606, guid: 188047b711783b74aa73c17ff9d66147, type: 3} + m_PrefabInstance: {fileID: 2076958799} + m_PrefabAsset: {fileID: 0} +--- !u!1 &2114196944 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2114196945} + - component: {fileID: 2114196947} + - component: {fileID: 2114196946} + - component: {fileID: 2114196948} + m_Layer: 5 + m_Name: InputField + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2114196945 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2114196944} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1196709331} + - {fileID: 1267610421} + m_Father: {fileID: 1951021497} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -213.4} + m_SizeDelta: {x: 0, y: 30} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &2114196946 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2114196944} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10911, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &2114196947 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2114196944} + m_CullTransparentMesh: 1 +--- !u!114 &2114196948 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2114196944} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d199490a83bb2b844b9695cbf13b01ef, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 2114196946} + m_TextComponent: {fileID: 1267610422} + m_Placeholder: {fileID: 1196709332} + m_ContentType: 0 + m_InputType: 0 + m_AsteriskChar: 42 + m_KeyboardType: 0 + m_LineType: 0 + m_HideMobileInput: 0 + m_CharacterValidation: 0 + m_CharacterLimit: 0 + m_OnEndEdit: + m_PersistentCalls: + m_Calls: [] + m_OnValueChanged: + m_PersistentCalls: + m_Calls: [] + m_CaretColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_CustomCaretColor: 0 + m_SelectionColor: {r: 0.65882355, g: 0.80784315, b: 1, a: 0.7529412} + m_Text: + m_CaretBlinkRate: 0.85 + m_CaretWidth: 1 + m_ReadOnly: 0 + m_ShouldActivateOnSelect: 1 diff --git a/Assets/Scenes/Tests/BuildModeTest.unity.meta b/Assets/Scenes/Tests/BuildModeTest.unity.meta new file mode 100644 index 00000000..83aed113 --- /dev/null +++ b/Assets/Scenes/Tests/BuildModeTest.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 74352a833a6dc254ab203706be9743b9 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Cameras.meta b/Assets/Scripts/OpenTS2/Cameras.meta new file mode 100644 index 00000000..c8ef2231 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Cameras.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 47b4f5547f913ba4882d83a6ffa154e4 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Cameras/TestLotViewCamera.cs b/Assets/Scripts/OpenTS2/Cameras/TestLotViewCamera.cs new file mode 100644 index 00000000..fc1f6166 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Cameras/TestLotViewCamera.cs @@ -0,0 +1,140 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +public class TestLotViewCamera : MonoBehaviour +{ + const int HitscanLength = 2000; + + Camera _camera; + Transform _camTransform; + Vector3 mouseholdPosition; + float initialXCamRot; + + //level detection system + /// + /// A set of mesh colliders that the camera will shoot rays at to detect where the mouse cursor is in 3D world space + /// and also where the floor is to adjust its Y position to see the floor appropriately + /// See: + /// + Dictionary floorElevationMeshes; + + // Start is called before the first frame update + void Start() + { + floorElevationMeshes = new Dictionary(); + _camTransform = GetComponentInParent(); + _camera = GetComponentInParent(); + } + + // Update is called once per frame + void Update() + { + if (Input.GetMouseButtonDown(1) || Input.GetMouseButtonDown(2)) // right or middle click + { + mouseholdPosition = Input.mousePosition; + if (Input.GetMouseButtonDown(2)) + initialXCamRot = _camTransform.rotation.eulerAngles.x; + } + + var mouseChange = mouseholdPosition - Input.mousePosition; + + if (Input.GetMouseButton(1)) // Right Click camera translation + { + var change = mouseChange / 10; + _camTransform.TransformDirection(change); + change *= Time.deltaTime; + + _camTransform.position = + new Vector3(_camTransform.position.x - change.x, + _camTransform.position.y, + _camTransform.position.z - change.y); + } + else if (Input.GetMouseButton(2)) // Middle Mouse Click Camera pitch + { + float pitchChange = (mouseChange / 1).y; + var transformedXRot = Math.Max(0, Math.Min(90, initialXCamRot - pitchChange)); + var currentAngle = _camTransform.rotation.eulerAngles; + currentAngle = new Vector3(transformedXRot, currentAngle.y, currentAngle.z); + _camTransform.rotation = Quaternion.Euler(currentAngle); + } + } + + /// + /// Sets the mesh colliders used to detect the height of the floor the camera is looking at. + /// + /// + /// + public void SetCameraDetectionMeshes(int Floor, IEnumerable Colliders) + { + floorElevationMeshes.Remove(Floor); + floorElevationMeshes.Add(Floor, Colliders.Where(x => x != default).ToArray()); + } + + public static Ray GetMouseCursor3DRay(Camera SelectedCamera) + { + //transform scr pos to world + Vector3 mousePosition = Input.mousePosition; + mousePosition.z = 20; + mousePosition = Camera.main.ScreenToWorldPoint(mousePosition); + + //get directional vector + var direction = (mousePosition - SelectedCamera.transform.position); direction.Normalize(); + + //build a ray from camera to terrain + return new Ray(SelectedCamera.transform.position, direction); + } + + /// + /// Potentially expensive!! use with caution + /// + /// + /// + /// + public bool TranslateScreen2WorldPos(int MaxFloor, out Vector3 WorldPosition, out int Floor) + { + WorldPosition = new Vector3(); + Floor = -1; + + if (!floorElevationMeshes.Any()) + { + Debug.LogWarning("No terrain meshes added to the lot camera so hit detection is disabled!"); + return false; + } + + Ray camRay = GetMouseCursor3DRay(_camera); + + //Check each floor by casting the above ray at each collider. + //TODO: (NEEDS REFACTOR TO USE ELEVATION IN LOT DATA) + //also just in general this iteration is really not great should only be used on frames where theres actual movement + RaycastHit hitInfo = default; + bool hitComplete = false; + + //go top down searching for which floor we're looking at + for(int floor = MaxFloor; floor >= floorElevationMeshes.Keys.Min(); floor--) + { + if (!floorElevationMeshes.ContainsKey(floor)) continue; + foreach(var collider in floorElevationMeshes[floor]) + { + if (collider is MeshCollider mCollider) + { + var meshRef = collider.gameObject.GetComponent().sharedMesh; + mCollider.sharedMesh = meshRef; + } + if (collider.Raycast(camRay, out hitInfo, HitscanLength)) + { + hitComplete = true; + Floor = floor; + break; + } + } + if (hitComplete) break; + } + if (!hitComplete) return false; + + WorldPosition = hitInfo.point; + return true; + } +} diff --git a/Assets/Scripts/OpenTS2/Cameras/TestLotViewCamera.cs.meta b/Assets/Scripts/OpenTS2/Cameras/TestLotViewCamera.cs.meta new file mode 100644 index 00000000..2d9470ac --- /dev/null +++ b/Assets/Scripts/OpenTS2/Cameras/TestLotViewCamera.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8021982501d05f645a42b19f4a41ab8a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Components/AssetReferenceComponent.cs b/Assets/Scripts/OpenTS2/Components/AssetReferenceComponent.cs index 2427d0eb..563fba2a 100644 --- a/Assets/Scripts/OpenTS2/Components/AssetReferenceComponent.cs +++ b/Assets/Scripts/OpenTS2/Components/AssetReferenceComponent.cs @@ -1,6 +1,12 @@ -using OpenTS2.Content; +using OpenTS2.Common; +using OpenTS2.Content; +using OpenTS2.Content.DBPF; +using OpenTS2.Content.DBPF.Scenegraph; +using OpenTS2.Files.Formats.DBPF; +using OpenTS2.Scenes.Lot; using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -16,5 +22,133 @@ public void AddReference(params AbstractAsset[] assets) { References.AddRange(assets); } + + /// + /// Indicates that this component should re-evaluate itself for changes made at runtime + /// + public virtual void Invalidate() { } + } + + // Seems like functionality is identical between certain lot components that utilize patterns. + // Moved the duplicated code to one unit so we can make improvements + + //**CURRENTLY UNUSED** + /// + /// Serves functionality for loading pattern assets from a pattern map (floors, walls, etc.) + /// + /// + public abstract class AssetPatternReferenceComponent : AssetReferenceComponent + { + /// + /// The material to use when the requested material could not be loaded using the + /// default implementation + /// + protected abstract string FallbackMaterial { get; } + /// + /// The texture to use for the thickness of the object + /// Walls and floors utilize this to show they're three-dimensional and it applied to [0] + /// + protected abstract string ThicknessTexture { get; } + + protected abstract int FloorCount { get; } + + protected PatternMeshCollection _patterns; + protected PatternDescriptor[] _loadedPatternDescriptions; + + protected abstract Dictionary Map { get; } + protected virtual Dictionary Builtins { get; } = null; + + /// + /// Base load patterns function + /// + protected virtual void LoadPatterns() + { + var contentProvider = ContentProvider.Get(); + var catalogManager = CatalogManager.Get(); + var patternMap = Map; + + ushort highestId = patternMap.Count == 0 ? (ushort)0 : patternMap.Keys.Max(); + PatternDescriptor[] patterns = new PatternDescriptor[highestId + 2]; + + bool changesMade = false; + bool previousStateExisting = _loadedPatternDescriptions != null; + + foreach (StringMapEntry entry in patternMap.Values) + { + //Persistent data -- calls from Invalidate() will call this with data already loaded, in which case + //We can save time by not reloading the same loaded data + // TODO + if (previousStateExisting && _loadedPatternDescriptions.Length == patterns.Length && + _loadedPatternDescriptions[entry.Id + 1].Name != null) // loaded + { // PatternDescriptor is a struct -- check the name see if it's null, if not, the pattern is loaded already + patterns[entry.Id + 1] = _loadedPatternDescriptions[entry.Id + 1]; + continue; + } + changesMade = true; + + string materialName = null; + if (uint.TryParse(entry.Value, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out uint guid)) + { + var catalogEntry = catalogManager.GetEntryById(guid); + + materialName = catalogEntry?.Material ?? FallbackMaterial; + } + else if (Builtins != null && !Builtins.TryGetValue(entry.Value, out materialName)) + { + materialName = entry.Value.StartsWith("wall_") ? (entry.Value + "_base") : ("wall_" + entry.Value + "_base"); + } + + if (materialName == null) + { + // Explicitly remove this pattern. + continue; + } + + // Try fetch the texture using the material name. + var material = LoadMaterial(contentProvider, materialName); + + try + { + // Note: Sometimes walls use the standard material, but we want them to use a special shader for cutaways. + patterns[entry.Id + 1] = new PatternDescriptor( + materialName, + material == null ? null : material?.GetAsUnityMaterial("Wallpaper") + ); + } + catch (Exception e) + { + Debug.LogException(e); + } + } + + if (previousStateExisting) + { + if (!changesMade) return; // no changes to wall patterns since last load + + patterns[0] = _loadedPatternDescriptions[0]; + _loadedPatternDescriptions = patterns; + _patterns.UpdatePatterns(patterns); + return; + } + + PostLoadPatterns(contentProvider, ref patterns); + + _loadedPatternDescriptions = patterns; + //_patterns = new PatternMeshCollection(gameObject, patterns, Array.Empty(), this, FloorCount); + } + + protected virtual ScenegraphMaterialDefinitionAsset LoadMaterial(ContentProvider contentProvider, string name) + { + var material = contentProvider.GetAsset(new ResourceKey($"{name}_txmt", GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_TXMT)); + + AddReference(material); + + return material; + } + + protected virtual void PostLoadPatterns(ContentProvider contentProvider, ref PatternDescriptor[] patterns) + { + + } } } diff --git a/Assets/Scripts/OpenTS2/Components/ScenegraphComponent.cs b/Assets/Scripts/OpenTS2/Components/ScenegraphComponent.cs index a3f67d02..483e9f3e 100644 --- a/Assets/Scripts/OpenTS2/Components/ScenegraphComponent.cs +++ b/Assets/Scripts/OpenTS2/Components/ScenegraphComponent.cs @@ -24,11 +24,6 @@ public class ScenegraphComponent : MonoBehaviour /// /// The returned game object carries a transform to convert it from sims coordinate space to unity space. /// - public static GameObject CreateRootScenegraph(ScenegraphResourceAsset resourceAsset) - { - return CreateRootScenegraph(new []{ resourceAsset }); - } - public static GameObject CreateRootScenegraph(params ScenegraphResourceAsset[] resourceAssets) { var scenegraph = CreateScenegraphComponent(resourceAssets); diff --git a/Assets/Scripts/OpenTS2/Content/DBPF/WallGraphAsset.cs b/Assets/Scripts/OpenTS2/Content/DBPF/WallGraphAsset.cs index f3720d79..ddd9b4e4 100644 --- a/Assets/Scripts/OpenTS2/Content/DBPF/WallGraphAsset.cs +++ b/Assets/Scripts/OpenTS2/Content/DBPF/WallGraphAsset.cs @@ -1,4 +1,7 @@ +using System; using System.Collections.Generic; +using System.Linq; +using UnityEngine; namespace OpenTS2.Content.DBPF { @@ -31,11 +34,12 @@ public class WallGraphAsset : AbstractAsset { public int Width { get; } public int Height { get; } - public int Floors { get; } + public int Floors { get; private set; } public int BaseFloor { get; } public Dictionary Positions { get; } public int[] Rooms { get; } - public WallGraphLineEntry[] Lines { get; } + public WallGraphLineEntry[] Lines { get => _lines; set => _lines = value; } + private WallGraphLineEntry[] _lines; public WallGraphAsset(int width, int height, int floors, int baseFloor, WallGraphPositionEntry[] pos, int[] rooms, WallGraphLineEntry[] lines) { @@ -59,6 +63,97 @@ private Dictionary ToPositionDictionary(WallGraphPo return result; } - } + bool getJuncIdByPosition(Vector2 Position, int Floor, out int juncId, bool createIfNull = true) + { + bool existed = false; + var junctions = Positions.Where(x => x.Value.XPos == Position.x && x.Value.YPos == Position.y && x.Value.Level == Floor); + juncId = -1; + if (junctions.Any()) + { + juncId = junctions.First().Key; // found a matching position + existed = true; + } + else if (createIfNull) + { // make a new position + if (Positions.Any()) + juncId = Positions.Select(x => x.Key).Max() + 1; + else juncId = 0; + Positions.Add(juncId, new WallGraphPositionEntry() + { + Id = juncId, + Level = Floor, + XPos = Position.x, + YPos = Position.y, + }); + } + return existed; + } + + public bool PushWall(Vector2 Pos1, Vector2 Pos2, int Floor, out int LayerID) + { + LayerID = -1; + + bool fromExistedAlready = getJuncIdByPosition(Pos1, Floor, out int fromId); + if (fromId == -1) // unable to create !! + return false; + bool toExistedAlready = getJuncIdByPosition(Pos2, Floor, out int toId); + if (toId == -1) // unable to create !! + return false; + + if (fromExistedAlready && toExistedAlready) + { // wall may already exist + bool exists = _lines.Any(x => x.ToId == toId && x.FromId == fromId); // check if this wall segment exists + if (exists) + return false; // this wall segment already exists. + exists = _lines.Any(x => x.ToId == fromId && x.FromId == toId); + if (exists) + return false; // this wall segment already exists. + } + + int layerId = 99; + if(_lines.Any()) layerId = _lines.Select(x => x.LayerId).Max() + 1; + Array.Resize(ref _lines, Lines.Length + 1); + WallGraphLineEntry line = new WallGraphLineEntry() + { + FromId = fromId, + LayerId = layerId, + ToId = toId, + }; + _lines[_lines.Length - 1] = line; + LayerID = layerId; + if (Floors <= Floor) + Floors++; + return true; + } + + internal bool RemoveWall(Vector2 From, Vector2 To, int Floor, out int LayerID) + { // should be refactored to batch delete a set of segments instead of one at a time due to iterations being potentially large + LayerID = -1; + + getJuncIdByPosition(From, Floor, out int fromId, false); + if (fromId == -1) // wall index doesn't exist? + return false; + getJuncIdByPosition(To, Floor, out int toId, false); + if (toId == -1) // wall index doesn't exist? + return false; + + for (int i = _lines.Length - 1; i >= 0; i--) // reverse order -- since players may more often delete walls they just made + { + var line = _lines[i]; + + if (toId == fromId) throw new Exception("From and To IDs are the same!"); + if (line.ToId != toId && line.ToId != fromId) continue; + if (line.FromId != toId && line.FromId != fromId) continue; + + //found the wall + if (i != _lines.Length - 1) // last wall + _lines[i] = _lines[_lines.Length - 1]; // move last line to this spot + Array.Resize(ref _lines, _lines.Length - 1); // shorten array by one + LayerID = line.LayerId; + return true; + } + return false; // not found + } + } } \ No newline at end of file diff --git a/Assets/Scripts/OpenTS2/Diagnostic/BoolpropCheat.cs b/Assets/Scripts/OpenTS2/Diagnostic/BoolpropCheat.cs new file mode 100644 index 00000000..85c002ac --- /dev/null +++ b/Assets/Scripts/OpenTS2/Diagnostic/BoolpropCheat.cs @@ -0,0 +1,42 @@ +using OpenTS2.Diagnostic; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Unity.Plastic.Newtonsoft.Json; +using UnityEngine; + +/// +/// Houses some common TS2 boolean properties +/// + +namespace Assets.Scripts.OpenTS2.Diagnostic +{ + public class SimpleProperty : IConsoleProperty + { + string serializedValue + { + get => Convert.ToString(myValue); + set => myValue = (T)Convert.ChangeType(value, typeof(T)); + } + + T myValue; + + public SimpleProperty() + { + } + public SimpleProperty(T DefaultValue) : this() + { + myValue = DefaultValue; + } + + public string GetStringValue() => serializedValue; + public Type GetValueType() => typeof(T); + public void SetStringValue(string value) => serializedValue = value; + + public static SimpleProperty Create() => new SimpleProperty(); + public static SimpleProperty Create(T DefaultValue) => new SimpleProperty(DefaultValue); + } +} diff --git a/Assets/Scripts/OpenTS2/Diagnostic/BoolpropCheat.cs.meta b/Assets/Scripts/OpenTS2/Diagnostic/BoolpropCheat.cs.meta new file mode 100644 index 00000000..c0990ca2 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Diagnostic/BoolpropCheat.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fc38f22d7f39dcf45b82f46e2f6f4abc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Diagnostic/CheatSystem.cs b/Assets/Scripts/OpenTS2/Diagnostic/CheatSystem.cs index 664c6879..f342e7c1 100644 --- a/Assets/Scripts/OpenTS2/Diagnostic/CheatSystem.cs +++ b/Assets/Scripts/OpenTS2/Diagnostic/CheatSystem.cs @@ -1,5 +1,4 @@ -using OpenTS2.Engine; -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Reflection; @@ -23,6 +22,9 @@ public static void Initialize() RegisterCheat(); RegisterCheat(); Assemblies.AssemblyHelper.AssemblyProcesses += RegisterPropsForType; + + //ConstrainFloorElevation + RegisterProperty(SimpleProperty.Create(false), "constrainfloorelevation"); } private static void RegisterPropsForType(Type type, Assembly assembly) diff --git a/Assets/Scripts/OpenTS2/Engine/Modes.meta b/Assets/Scripts/OpenTS2/Engine/Modes.meta new file mode 100644 index 00000000..819c8022 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Engine/Modes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1df3d8a68fd8f874eb366660526b7c53 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Engine/Modes/Build.meta b/Assets/Scripts/OpenTS2/Engine/Modes/Build.meta new file mode 100644 index 00000000..378aafd1 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Engine/Modes/Build.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 28f9123fa5bd6d04ea188898ff9c5c80 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Engine/Modes/Build/BuildModeServer.cs b/Assets/Scripts/OpenTS2/Engine/Modes/Build/BuildModeServer.cs new file mode 100644 index 00000000..86dabca9 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Engine/Modes/Build/BuildModeServer.cs @@ -0,0 +1,592 @@ +using OpenTS2.Content.DBPF; +using OpenTS2.Engine.Modes.Build.Tools; +using OpenTS2.Scenes.Lot; +using UnityEngine; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using OpenTS2.Scenes.Lot.Extensions; +using OpenTS2.Scenes.Lot.State; +using log4net.Core; +using UnityEngine.UIElements; +using OpenTS2.Files.Formats.DBPF; +using OpenTS2.Diagnostic; + +namespace OpenTS2.Engine.Modes.Build +{ + internal enum BuildTools + { + None, + Hand, + Wall, + TerrainBrush, + Foundation, + Floor, + } + + /// + /// Controls the flow of changes to the lot architecture and serves the functionality for Build Mode + /// + internal class BuildModeServer : MonoBehaviour + { + /// + /// Modes that walls can be created + /// + public enum WallCreationModes + { + /// + /// A single normal wall + /// + Single, + /// + /// A square area of walls + /// + Room, + /// + /// A diagonally oriented square area of walls + /// + DiagnonalRoom + } + /// + /// Modes that describe the modification being made to the terrain + /// + public enum TerrainModificationModes + { + /// + /// No brush selected + /// + None, + /// + /// Raise the terrain brush + /// + Raise, + /// + /// Lower the terrain brush + /// + Lower, + /// + /// Smooth an area of terrain brush + /// + Smooth, + /// + /// Pond brush + /// + Water, + /// + /// Terrain paints brush + /// + Paint + } + + //STATIC + private static BuildModeServer Current { get; set; } + public static BuildModeServer Get() => Current; + + private static Dictionary _tools; + private ushort dryWallDesignPattern; + /// + /// The floor currently selected using the UI + /// This also is the highest level shown in the lot geometry + /// + public int CurrentFloor => loadedLot.Floor; + + //PRIVATE + private readonly StringBuilder lotHistory = new StringBuilder(); + + private readonly LotLoad loadedLot; + private LotArchitecture architecture => loadedLot.architecture; + + private bool ConstrainedFloorElevation => CheatSystem.GetProperty("constrainfloorelevation").GetStringValue().ToLower() == "true"; + + //PUBLIC + /// + /// The current + /// See: + /// + public WorldState WorldState + { + get => loadedLot.WorldState; set => loadedLot.WorldState = value; + } + /// + /// After making changes to the , use this to apply the changes + /// + public void InvalidateLotState() => loadedLot.InvalidateState(); + /// + /// The tool that the user is currently using (or the one the user more recently selected) + /// + public BuildTools SelectedTool { get; private set;} = BuildTools.None; + /// + /// The handler for the tool the user is currently using + /// + public AbstractBuildTool CurrentTool { get; private set; } = null; + public int BaseFloor => loadedLot.BaseFloor; + public int MaxFloor => loadedLot.MaxFloor; + + private void LogHistory(string Message, string Caption = default, string Sender = default) + { + if (string.IsNullOrWhiteSpace(Sender)) Sender = typeof(BuildModeServer).Name; + var msgTxt = $"OpenTS2::{Sender} -> {(!string.IsNullOrWhiteSpace(Caption) ? $"({Caption})" : "")} {Message}"; + lotHistory.AppendLine(msgTxt); + Debug.Log(msgTxt); + } + + internal BuildModeServer(LotLoad LoadedLot) + { + Current = this; + + loadedLot = LoadedLot; + + SelectedTool = BuildTools.None; + CurrentTool = null; + + MakeTools(); + Init(); + } + + void MakeTools() + { + _tools = new Dictionary + { // funfact: these are added in the order they were implemented .. incase you were wondering + { BuildTools.Wall, new WallTool(this) }, + { BuildTools.Hand, new HandTool(loadedLot, architecture) }, + { BuildTools.TerrainBrush, new TerrainBrushTool(this) }, + { BuildTools.Floor, new FloorTool(this) }, + { BuildTools.Foundation, new FoundationTool(this) } + }; + } + + void Init() + { + //set drywall design pattern (used so frequently we can save a little time frontloading it) + architecture.EnsurePatternReferenced("blank", LotArchitecture.ArchitectureGameObjectTypes.wall, out dryWallDesignPattern, out _); + } + + public void ChangeTool(BuildTools Tool) + { + if (CurrentTool != null) CurrentTool.SetActive(false); + switch(Tool) + { + default: + case BuildTools.None: + CurrentTool = null; break; + case BuildTools.Foundation: + case BuildTools.Hand: + case BuildTools.Wall: + case BuildTools.TerrainBrush: + case BuildTools.Floor: + CurrentTool = _tools[Tool]; + CurrentTool.SetActive(true); + LogHistory($"Selected tool: {Tool} (trans from: {SelectedTool})", "Change Tool"); + break; + } + SelectedTool = Tool; + } + + /// + /// Lists all the points for wall segments in the area of walls provided + /// + /// + /// + /// + /// + public static List<(Vector2Int A, Vector2Int B)> GetWallPoints(Vector2Int From, Vector2Int To, WallCreationModes CreationOption = WallCreationModes.Single) + { + List<(Vector2Int A, Vector2Int B)> walls = new List<(Vector2Int, Vector2Int)>(); + switch (CreationOption) + { + case WallCreationModes.Single: + walls.Add((From, To)); + break; + case WallCreationModes.Room: + walls.Add((From, new Vector2Int(To.x, From.y))); + walls.Add((new Vector2Int(To.x, From.y), To)); + walls.Add((To, new Vector2Int(From.x, To.y))); + walls.Add((new Vector2Int(From.x, To.y), From)); + break; + case WallCreationModes.DiagnonalRoom: break; + } + return walls; + } + + public float PollElevation(Vector2Int Position, int Floor) => architecture.PollElevation(Position, Floor); + + /// + /// Creates walls with the blank wallpaper set with optional creation options like Square area of walls or Single + /// + /// + /// + /// + /// + /// + public void CreateWalls(Vector2Int From, Vector2Int To, int Floor, + WallType Type = WallType.Normal, + WallCreationModes CreationOption = WallCreationModes.Single, + string FrontWallpaperPattern = "blank", string BackWallpaperPattern = "blank") + { + if (From == To) return; + if (CreationOption != WallCreationModes.Single && !RegionValid(From, To)) return; + string argsStr = $"From: {From} To: {To} Floor: {Floor} Type: {Type} Mode: {CreationOption}" + + $"Front: {FrontWallpaperPattern} Back: {BackWallpaperPattern}"; + + //OrderPoints(ref From, ref To); + var walls = GetWallPoints(From, To, CreationOption); + + //WALLPAPERS + ushort front = dryWallDesignPattern; + ushort back = front; + if (FrontWallpaperPattern != "blank") + architecture.EnsurePatternReferenced(FrontWallpaperPattern, LotArchitecture.ArchitectureGameObjectTypes.wall, out front, out _); + if (BackWallpaperPattern != "blank") + architecture.EnsurePatternReferenced(BackWallpaperPattern, LotArchitecture.ArchitectureGameObjectTypes.wall, out back, out _); + + bool? returnValue = true; + foreach (var wall in walls) + returnValue = architecture.CreateWall(wall.A, wall.B, Floor, Type, front, back); + + if (returnValue.HasValue) // walls were placed here + { + loadedLot.InvalidateWalls(); + LogHistory($"Created wall(s). {argsStr}", "Create Walls"); + } + else LogHistory($"Could not create wall(s). {argsStr}", "Create Walls"); + } + /// + /// Clears out all walls in the specified region with the given wall creation options + /// + /// + /// + /// + /// + /// + public void DeleteWalls(Vector2Int From, Vector2Int To, int Floor, WallCreationModes CreationOption = WallCreationModes.Single) + { + var walls = GetWallPoints(From, To, CreationOption); + string argsStr = $"From: {From} To: {To} Floor: {Floor} Mode: {CreationOption}"; + + bool? returnValue = true; + foreach (var wall in walls) + returnValue = architecture.DeleteWall(wall.A, wall.B, Floor); + + if (returnValue.HasValue) // walls were placed here + { + loadedLot.InvalidateWalls(); + LogHistory($"Deleted wall(s). {argsStr}", "Delete Walls"); + } + else LogHistory($"Could not delete wall(s). {argsStr}", "Delete Walls"); + } + + /// + /// Puts the two points in ascending order + /// + void OrderPoints(ref Vector2Int A, ref Vector2Int B) + { + var a = new Vector2Int(Math.Min(A.x, B.x), Math.Min(A.y, B.y)); + var b = new Vector2Int(Math.Max(A.x, B.x), Math.Max(A.y, B.y)); + A = a; + B = b; + } + + /// + /// Checks if the area between two points is nonzero + /// + /// + /// + /// + bool RegionValid(Vector2Int From, Vector2Int To) => Math.Abs(From.x - To.x) * Math.Abs(From.y - To.y) != 0; + + public bool IsFloorAt(Vector2Int Position, int Level = 0) + { + Level = -architecture.BaseFloor + Level; + var mPos = Position; + int index = (mPos.x * architecture.FloorPatterns.Height) + mPos.y; + + var value = architecture.FloorPatterns.Data[Level][index]; + + return value.w != 0 || value.x != 0 || value.y != 0 || value.z != 0; + } + + /// + /// Ensures the provided has layers up to the provided floor level + /// + /// Function used to fill the array's new level(s) if applicable. + /// arg1 is the index in the array being filled + /// arg2 is the value at arg1 on the floor beneath this one. If this is the lowest floor, + /// it will reference itself. + void Ensure3DViewDepth2Floor(_3DArrayView ArrayView, int Floor, Func FillFunc) where T : unmanaged + { + //ensure a layer for elevation exists + if (ArrayView.Depth <= Floor) + { + int fromFloor = ArrayView.Depth; + int toFloor = Floor; + //make new level(s) + ArrayView.Resize(Floor + 1); + for(int f = fromFloor; f <= toFloor; f++) + { // iterate over new level(s) + int underFloor = f - 1; + if (underFloor < BaseFloor) underFloor = BaseFloor; + for (int i = 0; i < ArrayView.Width * ArrayView.Height; i++) + { + T underValue = ArrayView.Data[underFloor][i]; + ArrayView.Data[f][i] = FillFunc(i, underValue); // invoke fillfunc to fill the array + } + } + ArrayView.Commit(); + } + } + /// + /// Ensures the provided has layers up to the provided floor level + /// + /// Value used to fill the newly created array levels + void Ensure3DViewDepth2Floor(_3DArrayView ArrayView, int Floor, T DefaultFillVal) where T : unmanaged + { + //ensure a layer for elevation exists + if (ArrayView.Depth <= Floor) + { + int fromFloor = ArrayView.Depth; + int toFloor = Floor; + //make new level(s) + ArrayView.Resize(Floor + 1); + for (int f = fromFloor; f <= toFloor; f++) + { // iterate over new level(s) + for (int i = 0; i < ArrayView.Width * ArrayView.Height; i++) + ArrayView.Data[f][i] = DefaultFillVal; // invoke fillfunc to fill the array + } + ArrayView.Commit(); + } + } + + public void DeleteFloors(Vector2Int From, Vector2Int To, int Level = 0) => + CreateFloors(From, To, 0, Level, false); + /// + /// Creates an area of flooring with the specified . + /// This function handles adding the pattern reference to the + /// + /// + /// + /// + /// + /// + public void CreateFloors(Vector2Int From, Vector2Int To, string PatternName, int Level = 0, bool ModifyTerrain = true) + { + if (!architecture.EnsurePatternReferenced(PatternName, LotArchitecture.ArchitectureGameObjectTypes.floor, out ushort patternID, out _)) + { + LogHistory($"Could not create flooring due to the pattern: {PatternName} not existing or isn't valid."); + return; + } + CreateFloors(From, To, patternID, Level, ModifyTerrain); + } + public void CreateFloors(Vector2Int From, Vector2Int To, ushort PatternID, int Level = 0, bool ModifyTerrain = true) => + CreateFloors(From, To, new Files.Formats.DBPF.Vector4(PatternID, PatternID, PatternID, PatternID), Level, ModifyTerrain); + public void CreateFloors(Vector2Int From, Vector2Int To, Files.Formats.DBPF.Vector4 QuarterTilePatternIDs, int Level = 0, bool ModifyTerrain = true) + { + if (!RegionValid(From, To)) return; // check area nonzero + + var from = From; var to = To; // order the points in order of closest to origin of the lot first + OrderPoints(ref from, ref to); + + if (ModifyTerrain) // flatten the area of terrain if applicable + { + Vector2Int pollPosition = From; // NE corner of the origin tile always + if(From.y > To.y) // selection is towards NORTH + pollPosition.y -= 1; + else pollPosition.y += 1; + if (From.x > To.x) // selection is towards WEST + ; + else pollPosition.x += 1; + + float elevation = architecture.PollElevation(pollPosition, Level); + LevelRegion(from, to, elevation, Level); // level terrain under floors + } + Level = -architecture.BaseFloor + Level; + _3DArrayView> floorPatterns = architecture.FloorPatterns; + + //ensure a layer for elevation exists + Ensure3DViewDepth2Floor(floorPatterns, Level, new Vector4()); // fill with empty + + ref Vector4[] baseFloorData = ref floorPatterns.Data[Level]; + + int changedFloors = 0; + for (int tx = from.x; tx < to.x; tx++) + { + for (int ty = from.y; ty < to.y; ty++) + { + var mPos = new Vector2Int(tx, ty); + int index = (mPos.x * floorPatterns.Height) + mPos.y; + + if (index > baseFloorData.Length - 1) + index = baseFloorData.Length - 1; + if (index < 0) + index = 0; + + baseFloorData[index] = QuarterTilePatternIDs; + changedFloors++; + } + } + + if (changedFloors <= 0) return; + + LogHistory($"Modified flooring. From: {From} To: {To} PatIDs: {QuarterTilePatternIDs}" + + $" Floor: {Level} TerrainMod?: {ModifyTerrain}", "Modify Flooring"); + loadedLot.InvalidateFloors(); // invalidating floors also may incur a terrain re-evaluation if necessary + } + + public void LevelRegion(Vector2Int From, Vector2Int To, float Elevation = 0, int Floor = 0) + { + if (!RegionValid(From, To)) return; + Floor = -architecture.BaseFloor + Floor; + + var from = From; var to = To; + OrderPoints(ref from, ref to); + + //check the cheat system for constrainfloorelevation cheat + bool cfeProp = ConstrainedFloorElevation; + + _3DArrayView arr = architecture.Elevation; + + //ensure a layer for elevation exists + //fill function will set the entire level to appropriate wall height. + Ensure3DViewDepth2Floor(arr, Floor, (int i, float beneathElevation) => beneathElevation + LotWallComponent.WallHeight); + + ref float[] dataSet = ref arr.Data[Floor]; + bool levelModify = false; + for (int tx = from.x; tx <= to.x; tx++) + { + for(int ty = from.y; ty <= to.y; ty++) + { + var mPos = new Vector2Int(tx, ty); + int index = (mPos.x * arr.Height) + mPos.y; + + if (index > dataSet.Length - 1) + index = dataSet.Length - 1; + if (index < 0) + index = 0; + + if (cfeProp && IsFloorAt(mPos)) + continue; + + dataSet[index] = Elevation; + levelModify = true; + } + } + + if (!levelModify) return; + + LogHistory($"Leveled terrain. From: {From} To: {To} Elevation: {Elevation}" + + $" Floor: {Floor}", "Level Terrain"); + //all changes complete, invalidate mesh + loadedLot.InvalidateFloors(); + } + /// + /// Sets the elevation at the position in lot grid coordinates at the Floor provided by adding it to the elevation of the lower level. + /// + /// + /// + /// + public void SetElevationRelative(float RelativeElevation, int Floor, params Vector2Int[] Positions) + { + Floor = -architecture.BaseFloor + Floor; + + _3DArrayView arr = architecture.Elevation; + //ensure a layer for elevation exists + //fill function will set the entire level to appropriate wall height. + Ensure3DViewDepth2Floor(arr, Floor, (int i, float beneathElevation) => beneathElevation + RelativeElevation); + + ref float[] dataSet = ref arr.Data[Floor]; + foreach (var p in Positions) + { + var mPos = p; + int index = (mPos.x * arr.Height) + mPos.y; + + float lowerElevation = dataSet[index]; + if (Floor > 0) + lowerElevation = arr.Data[Floor - 1][index]; + + dataSet[index] = lowerElevation + RelativeElevation; + } + } + + /// + /// Submits a terrain modification with the supplied parameters + /// + /// The center point of the terrain modification, in lot grid coordinates + /// The radius of the terrain brush being used, in grid cells + /// By how much should the terrain be altered in this call + /// Which modification is requested + /// + public bool ModifyTerrain(Vector2Int Position, int Radius, float Strength, TerrainModificationModes Mode, int Floor = 0) + { + if (Mode == TerrainModificationModes.None) return false; + Floor = -architecture.BaseFloor + Floor; + ref float[] dataSet = ref architecture.Elevation.Data[Floor]; + + var mPos = Position; + int index = (mPos.x * architecture.Elevation.Height) + mPos.y; + + //The Sims 2 won't allow any terrain modifications if the cursor is directly over unexposed terrain + if (ConstrainedFloorElevation && IsFloorAt(mPos)) + return false; + + bool levelModify = false; + + for (int dx = -Radius; dx <= Radius; dx++) + { + for (int dy = -Radius; dy <= Radius; dy++) + { + //get position to edit + mPos = Position + new Vector2Int(dx, dy); + index = (mPos.x * architecture.Elevation.Height) + mPos.y; + + //measure length from center to this point + int length = (int)Math.Round(Vector2.Distance(mPos, Position),0); + if (length > Radius) continue; + + float _stren = Strength; + + //CFE cheat + if (ConstrainedFloorElevation && IsFloorAt(mPos)) + continue; + + //terrain modification + switch (Mode) + { + default: return false; // ?? + case TerrainModificationModes.Water: + case TerrainModificationModes.Lower: + _stren *= -1; + goto case TerrainModificationModes.Raise; + case TerrainModificationModes.Raise: + dataSet[index] += _stren; + levelModify = true; + break; + } + } + } + + if (!levelModify) return false; + + LogHistory($"{Mode}ed terrain. Center: {Position} Radius: {Radius} Strength: {Strength} Level: {Floor}", "Level Terrain"); + //all changes complete, invalidate mesh + loadedLot.InvalidateFloors(); + return true; + } + + /// + /// Resets the lot to having nothing on it and flattened terrain + /// Note: It is highly recommended to alert the user before performing an action like this. + /// + /// + public void FlattenLot(float Elevation = 0) + { + int Floor = 0; + Floor = -architecture.BaseFloor + Floor; + ref float[] dataSet = ref architecture.Elevation.Data[-architecture.BaseFloor]; + for(int i = 0; i < dataSet.Length; i++) + dataSet[i] = Elevation; + //all changes complete, invalidate mesh + loadedLot.InvalidateFloors(); + } + } +} diff --git a/Assets/Scripts/OpenTS2/Engine/Modes/Build/BuildModeServer.cs.meta b/Assets/Scripts/OpenTS2/Engine/Modes/Build/BuildModeServer.cs.meta new file mode 100644 index 00000000..e776a78d --- /dev/null +++ b/Assets/Scripts/OpenTS2/Engine/Modes/Build/BuildModeServer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1e91cfd046356bd4496e1fe219b072b9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools.meta b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools.meta new file mode 100644 index 00000000..502e3bdb --- /dev/null +++ b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4b7ab705d82e6f8419b9d1db9e8ff271 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/AbstractBuildTool.cs b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/AbstractBuildTool.cs new file mode 100644 index 00000000..7320432c --- /dev/null +++ b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/AbstractBuildTool.cs @@ -0,0 +1,251 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace OpenTS2.Engine.Modes.Build.Tools +{ + /// + /// Context passed a parameter for functions on a instance + /// + internal class BuildToolContext + { + /// + /// The position of the 3D mouse cursor in world space + /// + public Vector3 Cursor3DWorldPosition { get; set; } + /// + /// The position of the wand snapped to grid coordinates + /// + public Vector3 WandPosition { get; set; } + /// + /// The position of the wand in the 2D lot grid + /// + public Vector2Int GridPosition { get; set; } + /// + /// The quadrant the 3D mouse cursor is in + /// Chart Quadrants: 1 = top left, 2 = top right, 3 = bottom right, 4 = bottom left + /// + public int GridTileCursorQuadrant { get; set; } + public int CursorFloor { get; internal set; } + } + + /// + /// A build tool with basic Pick-Up and Put-Down functionality + /// + internal abstract class AbstractBuildTool + { + public delegate void OnFinalizeToolHandler(AbstractBuildTool sender); + /// + /// Called when the user releases the tool and the changes will be submitted. + /// + public event OnFinalizeToolHandler OnFinalizeTool; + + /// + /// The name of this tool + /// + public abstract string ToolName { get; } + + public bool IsHolding { get; protected set; } + public bool IsActive { get; private set; } = false; + public Vector3 ToolLotPosition { get; protected set; } + public Vector2 ToolGridPosition { get; protected set; } + + public void SetActive(bool Activated) + { + IsActive = Activated; + OnActiveChanged(Activated); + } + protected abstract void OnActiveChanged(bool NewValue); + + public virtual void OnToolUpdate(BuildToolContext Context) + { + ToolLotPosition = Context.WandPosition; + ToolGridPosition = Context.GridPosition; + } + public abstract void OnToolStart(BuildToolContext Context); + public abstract void OnToolCancel(string Reason = null); + public virtual void OnToolFinalize(BuildToolContext Context) => OnFinalizeTool?.Invoke(this); + } + + /// + /// Represents shared behavior for tools in Build Mode where the user can click and drag an area to manipulate the lot + /// + internal abstract class AbstractRegionSelectBuildTool : AbstractBuildTool + { + //protected fields + /// + /// Defines behaviors for how the cursor should react to moving between levels + /// + protected enum MultilevelBehavior + { + /// + /// If the cursor leaves the level it started dragging, cancel the action immediately. + /// + CancelAction, + /// + /// If the cursor is not at the same level as it started when the action is finished, cancel the action. + /// Unlike , the action won't be cancelled immediately. + /// + Deny, + /// + /// Allows the cursor to freely move between levels and will not intervene. + /// + Allow, + /// + /// Keeps the level the same as when the tool started dragging so the level is retained even when the cursor moves between levels + /// + Constrain, + } + + protected Vector2Int toolDragStart; + protected Vector2Int toolDragEnd; + protected Vector2Int toolLastActionDragEnd; + protected Vector3 toolDragStartWorldPos; + protected int toolDragFloor; + + //public properties + /// + /// Where the user drag gesture initiated, in lot grid coordinates + /// + public Vector2Int ToolDragOrigin => toolDragStart; + /// + /// Where the user drag gesture ended, in lot grid coordinates + /// + public Vector2Int ToolDragDestination => toolDragEnd; + /// + /// Where the user drag gesture started in terms of which floor + /// + public int ToolDragFloor => toolDragFloor; + + //Protected + protected bool DeleteMode { get; set; } + protected static GameObject ToolCursorObject { get; set; } + protected static Transform ToolCursorObjectTransform => ToolCursorObject.transform; + protected static GameObject SelectionStartToolCursor { get; set; } + /// + /// See: + /// + protected virtual MultilevelBehavior MultiLevelBehavior { get; set; } = MultilevelBehavior.Deny; + + protected BuildModeServer BuildModeServer { get; } + + protected AbstractRegionSelectBuildTool(BuildModeServer Server) : base() + { + BuildModeServer = Server; + Init(); + } + + protected virtual void Init() + { + //get the default Wand + if (ToolCursorObject == null) + ToolCursorObject = GameObject.Find("Wand"); + if (SelectionStartToolCursor == null) + { + SelectionStartToolCursor = GameObject.Find("debugWandCompanion"); + SelectionStartToolCursor.SetActive(false); + } + } + + protected override void OnActiveChanged(bool NewValue) + { + ToolCursorObject.SetActive(NewValue); + if (!NewValue) SelectionStartToolCursor.SetActive(false); + } + + public override void OnToolStart(BuildToolContext Context) + { + if (IsHolding) return; // huh? weird edge case here + IsHolding = true; + toolDragStart = toolDragEnd = toolLastActionDragEnd = Context.GridPosition; + toolDragFloor = Context.CursorFloor; + + //set the selection origin cursor + toolDragStartWorldPos = Context.WandPosition; + SelectionStartToolCursor.SetActive(true); + SelectionStartToolCursor.transform.position = Context.WandPosition; + return; + } + + public override void OnToolUpdate(BuildToolContext Context) + { + base.OnToolUpdate(Context); + + var dirtyToolDragEnd = toolDragEnd; + + if (!IsActive) return; + ToolCursorObjectTransform.position = Context.WandPosition; + if (!IsHolding) return; + toolDragEnd = Context.GridPosition; + + if (MultiLevelBehavior == MultilevelBehavior.CancelAction && toolDragFloor != Context.CursorFloor) + {// drag between floors! + OnToolCancel("Start and end positions are not at the same level."); + return; + } + + //check if player change wall creation type + CheckMode(); + + if(dirtyToolDragEnd != toolDragEnd) + //clear any created wall facades + DoHoverAction(true); + toolLastActionDragEnd = toolDragEnd; + + //User let go of the Wand, signal finalize event + if (!Input.GetMouseButton(0)) + { // finalize + OnToolFinalize(Context); + return; + } + + if (dirtyToolDragEnd != toolDragEnd) + //Update facade + DoHoverAction(); + } + + public override void OnToolFinalize(BuildToolContext Context) + { + IsHolding = false; // finish drag gesture + if (toolDragStart == toolDragEnd) return; // misclick + if ((MultiLevelBehavior == MultilevelBehavior.CancelAction || MultiLevelBehavior == MultilevelBehavior.Deny) + && toolDragFloor != Context.CursorFloor) + {// drag between floors! + OnToolCancel("Start and end positions are not at the same level."); + return; + } + + //check if player change creation type + CheckMode(); + //Create / Delete the area + DoAction(); + + SelectionStartToolCursor.SetActive(false); // hide cursor + IsHolding = false; // drop tool + + base.OnToolFinalize(Context); + } + + public override void OnToolCancel(string Reason) + { + DoHoverAction(true); + + SelectionStartToolCursor.SetActive(false); // hide cursor + IsHolding = false; // drop tool + + Debug.Log($"{ToolName} cancelled. Reason: {Reason ?? "none given"}"); + } + + protected virtual void CheckMode() + { + //check if deleting objects + DeleteMode = false; + if (Input.GetKey(KeyCode.LeftControl)) DeleteMode = true; + } + protected abstract void DoAction(bool Undo = false); + protected virtual void DoHoverAction(bool Undo = false) => DoAction(Undo); + } +} diff --git a/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/AbstractBuildTool.cs.meta b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/AbstractBuildTool.cs.meta new file mode 100644 index 00000000..6d4038e1 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/AbstractBuildTool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: be2df28f574842c48b230b4c3cf403dc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/FloorTool.cs b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/FloorTool.cs new file mode 100644 index 00000000..3e8b11f3 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/FloorTool.cs @@ -0,0 +1,83 @@ +namespace OpenTS2.Engine.Modes.Build.Tools +{ + /// + /// Build tools that allow the user to make selections using the catalog in Build Mode + /// + internal interface ICatalogSelectableBuildTool + { + + } + /// + /// Build tool that takes patterns from Build Mode (walls and floors) + /// + internal interface IPatternSelectableBuildTool + { + /// + /// Dictates whether the tool should be using the or property + /// + bool IDPainting { get; } + + /// + /// The name of the pattern's material + /// + string PatternName { get; } + /// + /// The ID of the pattern in the target component map. + /// Walls and Floors (for example) both have individual WallMaps and FloorMaps + /// independent of one another and this mode should generally not be used in favor of . + /// + ushort PatternID { get; } + + /// + /// Sets the pattern the floor tool is currently painting + /// + void SetPaintPattern(string PatternName); + /// + /// Sets the pattern the floor tool is currently painting + /// + void SetPaintPatternID(ushort PatternID); + } + + /// + /// This Build Tool allows the User to drag out areas of flooring. + /// It invokes the for all lot modifications + /// + internal class FloorTool : AbstractRegionSelectBuildTool, IPatternSelectableBuildTool + { + public override string ToolName => "Floor Tool"; + + public bool IDPainting { get; private set; } + public string PatternName { get; private set; } + public ushort PatternID { get; private set; } + + public FloorTool(BuildModeServer Server) : base(Server) { } + + public void SetPaintPattern(string PatternName) + { + IDPainting = false; + this.PatternName = PatternName; + } + public void SetPaintPatternID(ushort PatternID) + { + IDPainting = true; + this.PatternID = PatternID; + } + + protected override void DoAction(bool Undo = false) + { + if (DeleteMode) + BuildModeServer.DeleteFloors(ToolDragOrigin, ToolDragDestination, ToolDragFloor); + else + { + if (IDPainting) + BuildModeServer.CreateFloors(ToolDragOrigin, ToolDragDestination, PatternID, ToolDragFloor); + else BuildModeServer.CreateFloors(ToolDragOrigin, ToolDragDestination, PatternName, ToolDragFloor); + } + } + + protected override void DoHoverAction(bool Undo = false) + { + ; + } + } +} diff --git a/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/FloorTool.cs.meta b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/FloorTool.cs.meta new file mode 100644 index 00000000..50429916 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/FloorTool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: af9a2f90db10abc4390cbda8afdecf9b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/FoundationTool.cs b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/FoundationTool.cs new file mode 100644 index 00000000..d55d5111 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/FoundationTool.cs @@ -0,0 +1,60 @@ +using OpenTS2.Content.DBPF; +using OpenTS2.Engine.Modes.Build.Tools; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace OpenTS2.Engine.Modes.Build.Tools +{ + /// + /// A build tool for creating foundations on the lot + /// This tool can be boiled down to the and put together + /// + internal class FoundationTool : AbstractRegionSelectBuildTool + { + public FoundationTool(BuildModeServer Server) : base(Server) + { + } + + public override string ToolName => "Foundation Tool"; + protected override MultilevelBehavior MultiLevelBehavior { get; set; } = MultilevelBehavior.Constrain; + + protected override void DoAction(bool Undo = false) + { + if (DeleteMode) Undo = !Undo; + float change = 1; + if (ToolDragFloor > 1) + { + OnToolCancel("Foundation can only be placed on terrain."); + return; + } + else if (ToolDragFloor == 1) change = 0; + + int currFloor = 0; + int nextFloor = currFloor + 1; + + float elevation = BuildModeServer.PollElevation(ToolDragOrigin, ToolDragFloor) + change; + BuildModeServer.LevelRegion(ToolDragOrigin, ToolDragDestination, elevation, nextFloor); + if (!Undo) + { + BuildModeServer.CreateWalls(ToolDragOrigin, ToolDragDestination, currFloor, + Content.DBPF.WallType.Foundation, BuildModeServer.WallCreationModes.Room, + "foundationbrick", "foundationbrick"); + BuildModeServer.CreateFloors(ToolDragOrigin, ToolDragDestination, "wood_wide_planks", nextFloor, false); + } + else + { + BuildModeServer.DeleteWalls(ToolDragOrigin, ToolDragDestination, currFloor, BuildModeServer.WallCreationModes.Room); + BuildModeServer.DeleteFloors(ToolDragOrigin, ToolDragDestination, nextFloor); + } + } + + protected override void DoHoverAction(bool Undo = false) + { + ; + } + } +} diff --git a/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/FoundationTool.cs.meta b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/FoundationTool.cs.meta new file mode 100644 index 00000000..b73ebff2 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/FoundationTool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 62528670419620547b98daca6a7118d5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/HandTool.cs b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/HandTool.cs new file mode 100644 index 00000000..552fc1e7 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/HandTool.cs @@ -0,0 +1,101 @@ +using OpenTS2.Components; +using OpenTS2.Scenes.Lot; +using System.Linq; +using UnityEngine; + +namespace OpenTS2.Engine.Modes.Build.Tools +{ + //*** NEEDS A REWORK ONCE SCENEGRAPH RENDERING IS REWORKED BECAUSE THIS IS NOT A GOOD SOLUTION + internal class HandTool : AbstractBuildTool + { + private LotLoad loadedLot; + private LotArchitecture architecture; + + private Transform holdingObjectRoot; + private GameObject holdingObjectReference; + private Vector3 originalPosition; + bool IsHoldingObject => holdingObjectReference != null; + + public override string ToolName => "Hand Tool"; + + /// + /// Creates a new on the specified lot + /// + /// + /// + public HandTool(LotLoad loadedLot, LotArchitecture architecture) + { + this.loadedLot = loadedLot; + this.architecture = architecture; + + Init(); + } + + private void Init() + { + + } + + public override void OnToolCancel(string Reason) + { + if (!IsHoldingObject) return; + + holdingObjectRoot.position = originalPosition; + + holdingObjectReference = null; + holdingObjectRoot = null; + + Debug.Log($"{ToolName} cancelled. Reason: {Reason ?? "null"}"); + } + + public override void OnToolUpdate(BuildToolContext Context) + { + base.OnToolUpdate(Context); + + if (!IsHoldingObject) return; + holdingObjectRoot.position = Context.WandPosition; + + if (Input.GetMouseButtonDown(0)) + OnToolFinalize(Context); + } + + public override void OnToolFinalize(BuildToolContext Context) + { + if (!IsHoldingObject) return; + + holdingObjectRoot.position = Context.WandPosition; + + holdingObjectReference = null; + holdingObjectRoot = null; + + base.OnToolFinalize(Context); + } + + public override void OnToolStart(BuildToolContext Context) + { + // PERFORM OBJECT HITTEST (The colliders are added in ScenegraphComponent) + Ray camRay = TestLotViewCamera.GetMouseCursor3DRay(Camera.main); + var hits = Physics.RaycastAll(camRay); + + if (hits.Any()) + { // find any hits + foreach (RaycastHit hit in hits.OrderBy(x => x.distance)) + { + var parent = hit.collider.gameObject.transform.parent.gameObject; + if (parent.GetComponent() != null) + { + holdingObjectReference = parent; + holdingObjectRoot = holdingObjectReference.transform; + originalPosition = holdingObjectRoot.position; + break; + } + } + } + } + + protected override void OnActiveChanged(bool NewValue) + { + + } + } +} diff --git a/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/HandTool.cs.meta b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/HandTool.cs.meta new file mode 100644 index 00000000..07a9c5d6 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/HandTool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4bac8d546ec25bb4e94cf635b9d3d75f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/TerrainBrushTool.cs b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/TerrainBrushTool.cs new file mode 100644 index 00000000..ce06fd9e --- /dev/null +++ b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/TerrainBrushTool.cs @@ -0,0 +1,108 @@ +using UnityEngine; +using static OpenTS2.Engine.Modes.Build.BuildModeServer; + +namespace OpenTS2.Engine.Modes.Build.Tools +{ + /// + /// Handles the functionality for the Wall Tool interacting with the lot + /// + internal class TerrainBrushTool : AbstractBuildTool + { + /// + /// Radii of terrain brush sizes + /// + public enum TerrainBrushSizes + { + Small = 0, // since this tool is only 1 point, it's not a tile wide + Medium = 2, + Large = 4 + } + + //private + BuildModeServer buildModeServer; + ushort dryWallDesignPattern; + private GameObject rootWallCursor; + private Transform _wallCursorTransform; + + /// + /// The current brush mode the tool is using + /// + public BuildModeServer.TerrainModificationModes CurrentBrushMode { get; set; } + /// + /// The current stroke thickness of the brush + /// + public int BrushSize { get; set; } = (int)TerrainBrushSizes.Large; + public float BrushStrength { get; set; } = 1f; + + /// + /// Creates a new on the specified lot + /// + /// + /// + public TerrainBrushTool(BuildModeServer Server) + { + buildModeServer = Server; + Init(); + } + + void Init() + { + //get the default Wand + rootWallCursor = GameObject.Find("Wand"); + _wallCursorTransform = rootWallCursor.transform; + } + + public override string ToolName => "Terrain Tool"; + + protected override void OnActiveChanged(bool NewValue) + { + rootWallCursor.SetActive(NewValue); + CurrentBrushMode = TerrainModificationModes.Raise; + } + + public override void OnToolCancel(string Reason) + { + IsHolding = false; // drop tool + + Debug.Log($"{ToolName} cancelled. Reason: {Reason ?? "null"}"); + } + + public override void OnToolFinalize(BuildToolContext Context) + { + IsHolding = false; // finish brush stroke + + base.OnToolFinalize(Context); + } + + public override void OnToolStart(BuildToolContext Context) + { + if (IsHolding) return; // huh? weird edge case here + IsHolding = true; // brush stroke start + + CommitToolStroke(Context.GridPosition); // makes single clicks (only lasting a frame) possible + } + + public override void OnToolUpdate(BuildToolContext Context) + { + base.OnToolUpdate(Context); + + if (!IsActive) return; + _wallCursorTransform.position = Context.WandPosition; + if (!IsHolding) return; + + //User let go of the Wand, signal finalize event + if (!Input.GetMouseButton(0)) + { // finalize + OnToolFinalize(Context); + return; + } + //user is still painting + CommitToolStroke(Context.GridPosition); + } + + void CommitToolStroke(Vector2Int position) + { + buildModeServer.ModifyTerrain(position, BrushSize, BrushStrength * Time.deltaTime, CurrentBrushMode); + } + } +} diff --git a/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/TerrainBrushTool.cs.meta b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/TerrainBrushTool.cs.meta new file mode 100644 index 00000000..de132f71 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/TerrainBrushTool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 322a39bbf1f7a8446b4b6194c8ec1abf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/WallTool.cs b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/WallTool.cs new file mode 100644 index 00000000..12e06fc2 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/WallTool.cs @@ -0,0 +1,89 @@ +using OpenTS2.Content.DBPF; +using OpenTS2.Engine.Modes.Build.Tools; +using OpenTS2.Scenes.Lot; +using OpenTS2.Scenes.Lot.Extensions; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; +using static OpenTS2.Engine.Modes.Build.BuildModeServer; + +namespace OpenTS2.Engine.Modes.Build.Tools +{ + /// + /// Handles the functionality for the Wall Tool interacting with the lot + /// + internal class WallTool : AbstractRegionSelectBuildTool + { + // Wall cursor tool + WallCreationModes wallCreateMode = WallCreationModes.Single; + bool deletingWalls => DeleteMode; + + //private + BuildModeServer buildModeServer => BuildModeServer; + + /// + /// Creates a new on the specified lot + /// + /// + /// + public WallTool(BuildModeServer Server) : base(Server) { } + + public override string ToolName => "Wall Tool"; + /// + /// Updates depending on the player's current input + /// + protected override void CheckMode() + { + //creation mode + WallCreationModes mode = WallCreationModes.Single; + if (Input.GetKey(KeyCode.LeftShift)) mode = WallCreationModes.Room; + wallCreateMode = mode; + + //check delete mode + base.CheckMode(); + } + + /// + /// Creates/Deletes the walls in the selected space + /// + protected override void DoAction(bool Undoing = false) + { + //NEEDS REFACTOR REALLY BAD + //Get layer IDs from the created walls when making a facade + //that way, we only delete walls SUCCESSFULLY MADE and also it won't be so buggy + //and performance will be (slightly) better + //please do this soon jeremy >.< + + bool actionSelected = !deletingWalls; + Vector2Int destination = toolDragEnd; + if (deletingWalls) destination = toolLastActionDragEnd; + if (Undoing) + { + if(destination != toolLastActionDragEnd) + destination = toolLastActionDragEnd; + else destination = toolDragEnd; + actionSelected = !actionSelected; + } + if (toolDragStart - destination == new Vector2Int(0, 0)) return; // zero area + if (actionSelected) + { + float startElevation = buildModeServer.PollElevation(toolDragStart, toolDragFloor); + //level upper elevation to ensure the wall is the correct size + foreach (var segment in GetWallPoints(toolDragStart, destination, wallCreateMode)) + { + //level terrain beneath the wall + //buildModeServer.SetElevationRelative(startElevation, toolDragFloor, segment.A, segment.B); + //level above the wall to ensure the height is accurate + buildModeServer.SetElevationRelative(LotWallComponent.WallHeight, toolDragFloor + 1, segment.A, segment.B); + } + buildModeServer.CreateWalls(toolDragStart, destination, toolDragFloor, WallType.Normal, wallCreateMode); + } + else buildModeServer.DeleteWalls(toolDragStart, destination, toolDragFloor, wallCreateMode); + } + + protected override void DoHoverAction(bool Undo = false) => DoAction(Undo); + } +} diff --git a/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/WallTool.cs.meta b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/WallTool.cs.meta new file mode 100644 index 00000000..e49f6257 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/WallTool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7ed8cbcbc0bb3d24f864d9ff7650d4e6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Engine/Tests/BuildModeTest.cs b/Assets/Scripts/OpenTS2/Engine/Tests/BuildModeTest.cs new file mode 100644 index 00000000..11952f36 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Engine/Tests/BuildModeTest.cs @@ -0,0 +1,144 @@ +// JDrocks450 11-22-2023 on GitHub + +using OpenTS2.Common; +using OpenTS2.Content; +using OpenTS2.Content.DBPF.Scenegraph; +using OpenTS2.Content.DBPF; +using OpenTS2.Files.Formats.DBPF; +using OpenTS2.Files; +using OpenTS2.Scenes.Lot.State; +using OpenTS2.Scenes.Lot; +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using UnityEngine; +using static OpenTS2.Content.DBPF.LotObjectAsset; +using OpenTS2.Scenes.Lot.Extensions; +using OpenTS2.Engine.Modes.Build; +using OpenTS2.UI.Layouts; +using OpenTS2.Client; +using System.Linq; +using OpenTS2.UI.Layouts.Lot; +using UnityEditor.SearchService; +using OpenTS2.Engine.Modes.Build.Tools; + +/// +/// Serves the behavior for the Build Mode Test scene +/// +public class BuildModeTest : MonoBehaviour +{ + // Init + LotLoad _loadedLotProvider; + LotArchitecture _architectrue => _loadedLotProvider.architecture; + TestLotViewCamera viewCamera; + BuildModeServer buildServer; + LotViewHUDController hudController; + + void ContentStartup(bool LoadGameContent = true) + { + EPManager.Get().InstalledProducts = 0x3EFFF; + ContentLoading.LoadContentStartup(); + + var settings = Settings.Get(); + settings.CustomContentEnabled = false; + + if (!LoadGameContent) return; + + // Load effects. + EffectsManager.Get().Initialize(); + //load the game content + ContentLoading.LoadGameContentSync(); + + CatalogManager.Get().Initialize(); + } + + void Awake() + { + //Load content + ContentStartup(true); + } + + void Start() + { + //load the default lot for now + _loadedLotProvider = new LotLoad("N001", 80); + + //create the build mode server + buildServer = new BuildModeServer(_loadedLotProvider); + buildServer.ChangeTool(BuildTools.None); + + //set the camera transform + viewCamera = GameObject.Find("Main Camera").GetComponent(); + + //connect to the HUD controller + hudController = GameObject.Find("Scene/LotViewUIController").GetComponent(); + hudController.Puck.SetMode(LotViewHUD.HUD_UILotModes.Build); // set puck display state to be Build mode + hudController.Puck.OnModeChangeRequested += HUD_GameModeRequest; + } + + private void HUD_GameModeRequest(object sender, LotViewHUD.ModeChangeEventArgs e) + { + e.Allow = false; // locked in Build Mode for the time being + } + + // Update is called once per frame + void Update() + { + HandleTool(); + } + + void HandleTool() + { + if (buildServer.CurrentTool == null) return; + + //set cursor position + ReevaluateTerrainMesh(); + bool successful = viewCamera.TranslateScreen2WorldPos(_loadedLotProvider.Floor, out var terrainPosition, out int currentCursorFloor); + if (!successful) return; // do not update the cursor when the mouse leaves the lot boundary. this prevents any events from firing with build tools + var buildCursorPos = new Vector3((float)Math.Round(terrainPosition.x, 0), terrainPosition.y, (float)Math.Round(terrainPosition.z, 0)); + Vector2Int wallcurPos = new Vector2Int((int)buildCursorPos.x, (int)buildCursorPos.z); // flat grid position for wall tool + + //context + BuildToolContext context = new BuildToolContext() + { + Cursor3DWorldPosition = terrainPosition, + WandPosition = buildCursorPos, + GridPosition = wallcurPos, + CursorFloor = currentCursorFloor + }; + + buildServer.CurrentTool.OnToolUpdate(context); // mouse moved + if (Input.GetMouseButtonDown(0)) // mouse left click start + { // start drag + buildServer.CurrentTool.OnToolStart(context); + return; + } + if (Input.GetKeyDown(KeyCode.Escape)) + { + buildServer.CurrentTool.OnToolCancel("User cancelled using the ESC key."); + return; + } + } + + /// + /// Resets the -- this may be necessary when the terrain mesh is updated, for example + /// + void ReevaluateTerrainMesh() + { + var floorComp = _architectrue.GetComponentByType(LotArchitecture.ArchitectureGameObjectTypes.floor); + for(int floor = 0; floor < _architectrue.BaseFloor + _architectrue.Elevation.Depth; floor++) + { + int actualFloor = _architectrue.BaseFloor + floor; + List collidersByFloor = new List(); + if (actualFloor == 0) + { + var terrainObject = GameObject.Find("terrain/Terrain"); + collidersByFloor.Add(terrainObject.GetComponent()); + } + if(floorComp.TryGetCollidersByFloor(floor, out var colliders)) + collidersByFloor.AddRange(colliders); + viewCamera.SetCameraDetectionMeshes(actualFloor, collidersByFloor); + } + } +} diff --git a/Assets/Scripts/OpenTS2/Engine/Tests/BuildModeTest.cs.meta b/Assets/Scripts/OpenTS2/Engine/Tests/BuildModeTest.cs.meta new file mode 100644 index 00000000..96a90ea0 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Engine/Tests/BuildModeTest.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 94cb5833fa52cfc4392f5daf80bc17b3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Scenes/Lot/Extensions.meta b/Assets/Scripts/OpenTS2/Scenes/Lot/Extensions.meta new file mode 100644 index 00000000..faec23cf --- /dev/null +++ b/Assets/Scripts/OpenTS2/Scenes/Lot/Extensions.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a72c7287d7d00824197bc42606cacaca +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Scenes/Lot/Extensions/LotArchitectureBuildModeExtensions.cs b/Assets/Scripts/OpenTS2/Scenes/Lot/Extensions/LotArchitectureBuildModeExtensions.cs new file mode 100644 index 00000000..70a911e4 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Scenes/Lot/Extensions/LotArchitectureBuildModeExtensions.cs @@ -0,0 +1,183 @@ +using Codice.Utils; +using log4net.Core; +using OpenTS2.Content.DBPF; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace OpenTS2.Scenes.Lot.Extensions +{ + //JDrocks450 'Bloaty' 12/9/23 -- Contains all build mode functions with respect to LotArchitecture instances in one unit + + /// + /// Extensions for manipulating instances for build mode operations + /// + internal static class LotArchitectureBuildModeExtensions + { + /// + /// Creates a wall. + /// This function will ensure the following: + /// The Wall is split into 1 unit long segments + /// The Wall has the wallpaper you provide added to each segment created. + /// The Wall is a straight line, diagonally, horizontally or vertically aligned + /// The Wall is of the type provided. + /// The Wall is added to the instance this is called on + /// + /// + /// + /// The point the wall originates + /// The point the wall is destined to + /// Which floor the wall is on + /// The type of wall you wish to create + /// The Pattern1 of the wall + /// The Pattern2 of the wall + /// upon total failure; no walls placed. + /// if some walls were placed. if all wall segments placed. + public static bool? CreateWall(this LotArchitecture Architecture, Vector2 From, + Vector2 To, int Floor, WallType Type = WallType.Normal, ushort PatternFront = ushort.MaxValue, ushort PatternBack = ushort.MaxValue) + { + //get the wall's direction vector + var dirVector = To - From; + dirVector.Normalize(); + + bool diagonal = false; + + if (Math.Abs(dirVector.x) == Math.Abs(dirVector.y)) + { + dirVector = new Vector2(dirVector.x < 0 ? -1 : 1, dirVector.y < 0 ? -1 : 1); + diagonal = true; + } + if ((Math.Abs(dirVector.x) != 1 || dirVector.y != 0) && (Math.Abs(dirVector.y) != 1 || dirVector.x != 0) && + (Math.Abs(dirVector.x) != 1 || Math.Abs(dirVector.y) != 1)) // valid directions for a wall + return false; + + //subdivide the wall into 1 unit lengths (otherwise wall paints will appear stretchy) + var wallLength = (double)Math.Abs(Vector2.Distance(From, To)); + if (diagonal) wallLength *= 0.7; + + int successfulWallSegments = 0, totalSegments = (int)wallLength; + for (int segment = 0; segment < (wallLength); segment++) + { + var fooFrom = From + (dirVector * segment); + var fooTo = From + (dirVector * (segment + 1)); + //Add wall to wallgraph + if (!Architecture.WallGraphAll.PushWall(fooFrom, fooTo, Floor, out int LayerID)) continue; + //Add wall layer data + Architecture.WallLayer.Walls.Add(LayerID, new WallLayerEntry() + { + Id = LayerID, + Pattern1 = PatternFront, + Pattern2 = PatternBack, + WallType = Type + }); + successfulWallSegments++; + } + if (successfulWallSegments <= 0) return null; // total failure + return successfulWallSegments < totalSegments ? false : true; // somewhat / complete success code + } + /// + /// Deletes wall segments between the two points provided on the given floor + /// + /// + /// + /// + /// + public static bool? DeleteWall(this LotArchitecture Architecture, Vector2 From, Vector2 To, int Floor) + { + //get the wall's direction vector + var dirVector = To - From; + dirVector.Normalize(); + + bool diagonal = false; + + if (Math.Abs(dirVector.x) == Math.Abs(dirVector.y)) + { + dirVector = new Vector2(dirVector.x < 0 ? -1 : 1, dirVector.y < 0 ? -1 : 1); + diagonal = true; + } + if ((Math.Abs(dirVector.x) != 1 || dirVector.y != 0) && (Math.Abs(dirVector.y) != 1 || dirVector.x != 0) && + (Math.Abs(dirVector.x) != 1 || Math.Abs(dirVector.y) != 1)) // valid directions for a wall + return false; + + //subdivide the wall into 1 unit lengths (otherwise wall paints will appear stretchy) + var wallLength = (double)Math.Abs(Vector2.Distance(From, To)); + if (diagonal) wallLength *= 0.7; + + int successfulWallSegments = 0, totalSegments = (int)wallLength; + for (int segment = 0; segment < (wallLength); segment++) + { + var fooFrom = From + (dirVector * segment); + var fooTo = From + (dirVector * (segment + 1)); + //Remove wall from wallgraph + if (!Architecture.WallGraphAll.RemoveWall(fooFrom, fooTo, Floor, out int LayerID)) continue; + //Remove wall layer data + Architecture.WallLayer.Walls.Remove(LayerID); + successfulWallSegments++; + } + if (successfulWallSegments <= 0) return null; // total failure + return successfulWallSegments < totalSegments ? false : true; // somewhat / complete success code + } + /// + /// Checks to see if the given pattern name is referenced; if it isn't, will reference it in the + /// and returns the PatternID of the (potentially newly) referenced pattern + /// + /// + /// + /// + /// + /// true if the pattern was already referenced + /// + public static bool EnsurePatternReferenced(this LotArchitecture arch, string PatternName, + LotArchitecture.ArchitectureGameObjectTypes Scope, out ushort PatternID, out bool Existed) + { + Existed = false; + PatternID = 0; + + Dictionary Map = Scope switch + { + LotArchitecture.ArchitectureGameObjectTypes.wall => arch.WallMap.Map, + LotArchitecture.ArchitectureGameObjectTypes.floor => arch.FloorMap.Map, + _ => null + }; + + if (Map == null) return false; + if (Map.Count == 0) + goto create; + var hits = Map.Where(x => x.Value.Value == PatternName); + if (!hits.Any()) + goto create; + Existed = true; + PatternID = hits.FirstOrDefault().Key; + return true; + + //lord forgive me for using goto + create: + PatternID = (ushort)(Map.Count + 1); + if (Map.Any()) + PatternID = Math.Max(PatternID, (ushort)(Map.Keys.Max() + 1)); + Map.Add(PatternID, new StringMapEntry() + { + Id = PatternID, + Value = PatternName, + Unknown = 0 + }); + return true; + } + + public static float PollElevation(this LotArchitecture architecture, Vector2Int Position, int Floor = 0) + { + Floor = -architecture.BaseFloor + Floor; + + float[] dataSet = architecture.Elevation.Data[Floor]; + + var mPos = Position; + int index = (mPos.x * architecture.Elevation.Height) + mPos.y; + + return dataSet[index]; + } + } +} diff --git a/Assets/Scripts/OpenTS2/Scenes/Lot/Extensions/LotArchitectureBuildModeExtensions.cs.meta b/Assets/Scripts/OpenTS2/Scenes/Lot/Extensions/LotArchitectureBuildModeExtensions.cs.meta new file mode 100644 index 00000000..fb58a6c2 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Scenes/Lot/Extensions/LotArchitectureBuildModeExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 118886c7f98c90e44b3d7c13cbab0440 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Scenes/Lot/LotArchitecture.cs b/Assets/Scripts/OpenTS2/Scenes/Lot/LotArchitecture.cs index 738abc99..b9a77aea 100644 --- a/Assets/Scripts/OpenTS2/Scenes/Lot/LotArchitecture.cs +++ b/Assets/Scripts/OpenTS2/Scenes/Lot/LotArchitecture.cs @@ -1,4 +1,5 @@ using OpenTS2.Common; +using OpenTS2.Components; using OpenTS2.Content.DBPF; using OpenTS2.Files.Formats.DBPF; using OpenTS2.Scenes.Lot.Roof; @@ -154,27 +155,72 @@ private void Validate() } } + public T GetComponentByType(ArchitectureGameObjectTypes Type) where T : AssetReferenceComponent => Type switch + { + ArchitectureGameObjectTypes.roof => _roofComponent as T, + ArchitectureGameObjectTypes.wall => _wallComponent as T, + ArchitectureGameObjectTypes.floor => _floorComponent as T, + ArchitectureGameObjectTypes.terrain => _terrainComponent as T, + _ => default + }; + + public void InvalidateComponent(ArchitectureGameObjectTypes Type) => GetComponentByType(Type)?.Invalidate(); + /// /// Creates game objects for the lot architecture, and returns them in the provided list. /// /// List of created game objects public void CreateGameObjects(List componentList) { - var roofObj = new GameObject("roof", typeof(LotRoofComponent)); - _roofComponent = roofObj.GetComponent().CreateFromLotArchitecture(this); - componentList.Add(roofObj); - - var wall = new GameObject("wall", typeof(LotWallComponent)); - _wallComponent = wall.GetComponent().CreateFromLotArchitecture(this); - componentList.Add(wall); + // make gameobjects for each type of object on the lot + for(int type = 0; type < Enum.GetValues(typeof(ArchitectureGameObjectTypes)).Length; type++) + { + ArchitectureGameObjectTypes tType = (ArchitectureGameObjectTypes)type; + if (!CreateGameObjectsOfType(componentList, tType)) + ; // TODO: Handle if this fails + } + } - var floor = new GameObject("floor", typeof(LotFloorComponent)); - _floorComponent = floor.GetComponent().CreateFromLotArchitecture(this); - componentList.Add(floor); + public enum ArchitectureGameObjectTypes + { + roof, + wall, + floor, + terrain + } - var terrain = new GameObject("terrain", typeof(LotTerrainComponent)); - _terrainComponent = terrain.GetComponent().CreateFromLotArchitecture(this); - componentList.Add(terrain); + /// + /// Creates the correspondent GameObject for the type of geometry specified by + /// Adds it to the given component list automatically + /// + /// + /// + /// + public bool CreateGameObjectsOfType(List componentList, ArchitectureGameObjectTypes Type) + { + GameObject obj = default; + switch (Type) + { + case ArchitectureGameObjectTypes.roof: + var roofObj = obj = new GameObject("roof", typeof(LotRoofComponent)); + _roofComponent = roofObj.GetComponent().CreateFromLotArchitecture(this); + break; + case ArchitectureGameObjectTypes.wall: + var wall = obj = new GameObject("wall", typeof(LotWallComponent)); + _wallComponent = wall.GetComponent().CreateFromLotArchitecture(this); + break; + case ArchitectureGameObjectTypes.floor: + var floor = obj = new GameObject("floor", typeof(LotFloorComponent)); + _floorComponent = floor.GetComponent().CreateFromLotArchitecture(this); + break; + case ArchitectureGameObjectTypes.terrain: + var terrain = obj = new GameObject("terrain", typeof(LotTerrainComponent)); + _terrainComponent = terrain.GetComponent().CreateFromLotArchitecture(this); + break; + default: return false; + } + componentList.Add(obj); + return true; } private static int CalculateElevationIndex(int height, int x, int y) @@ -225,6 +271,6 @@ public void UpdateState(WorldState state) _roofComponent.UpdateDisplay(state); _wallComponent.UpdateDisplay(state); _floorComponent.UpdateDisplay(state); - } + } } } \ No newline at end of file diff --git a/Assets/Scripts/OpenTS2/Scenes/Lot/LotFloorComponent.cs b/Assets/Scripts/OpenTS2/Scenes/Lot/LotFloorComponent.cs index 23b11477..be90cb61 100644 --- a/Assets/Scripts/OpenTS2/Scenes/Lot/LotFloorComponent.cs +++ b/Assets/Scripts/OpenTS2/Scenes/Lot/LotFloorComponent.cs @@ -24,10 +24,12 @@ public class LotFloorComponent : AssetReferenceComponent private LotArchitecture _architecture; private PatternMeshCollection _patterns; + private Dictionary> _colliders; public LotFloorComponent CreateFromLotArchitecture(LotArchitecture architecture) { _architecture = architecture; + _colliders = new Dictionary>(); LoadPatterns(); BuildFloorMeshes(); @@ -95,7 +97,7 @@ private void LoadPatterns() PatternDescriptor[] patterns = new PatternDescriptor[highestId + 2]; foreach (StringMapEntry entry in patternMap.Values) - { + { string materialName; if (uint.TryParse(entry.Value, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out uint guid)) { @@ -136,6 +138,7 @@ private void BuildFloorMeshes() int height = patternData.Height; int eHeight = height + 1; + _colliders.Clear(); _patterns.ClearAll(); Vector3[] tileVertices = new Vector3[5]; @@ -191,11 +194,13 @@ void AddThickness(int from, int to) { if (floor == null) { - // Lazy init - don't create the floor unless it's actually being used. + // Lazy init - don't create the floor unless it's actually being used. floor = _patterns.GetFloor(i); PatternMesh thickness = floor.Get(0); thickComp = thickness.Component; } + if (!_colliders.ContainsKey(i)) + _colliders.Add(i, new HashSet()); // Pattern is present. float e0 = elevation[ei]; @@ -225,6 +230,8 @@ void AddThickness(int from, int to) comp.AddVertices(tileVertices, tileUVs); comp.AddTriangle(m1Base, 1, 0, 4); + + _colliders[i].Add(mesh1.Object.GetComponent()); } PatternMesh mesh2 = floor.Get(p.z + 1); @@ -245,6 +252,7 @@ void AddThickness(int from, int to) } comp.AddTriangle(m2Base, 2, 1, 4); + _colliders[i].Add(mesh2.Object.GetComponent()); } PatternMesh mesh3 = floor.Get(p.y + 1); @@ -269,6 +277,7 @@ void AddThickness(int from, int to) } comp.AddTriangle(m3Base, 3, 2, 4); + _colliders[i].Add(mesh3.Object.GetComponent()); } PatternMesh mesh4 = floor.Get(p.x + 1); @@ -296,7 +305,8 @@ void AddThickness(int from, int to) comp.AddVertices(tileVertices, tileUVs); } - comp.AddTriangle(m4Base, 0, 3, 4); + comp.AddTriangle(m4Base, 0, 3, 4); + _colliders[i].Add(mesh4.Object.GetComponent()); } if (i > -baseFloor) @@ -364,5 +374,12 @@ public void UpdateDisplay(WorldState state) { _patterns.UpdateDisplay(state, _architecture.BaseFloor); } + + internal bool TryGetCollidersByFloor(int floor, out IEnumerable Colliders) + { + var success = _colliders.TryGetValue(floor, out var value); + Colliders = value; // cringe out parameter doesn't do implicit casts ;_; + return success; + } } } \ No newline at end of file diff --git a/Assets/Scripts/OpenTS2/Scenes/Lot/LotLoad.cs b/Assets/Scripts/OpenTS2/Scenes/Lot/LotLoad.cs new file mode 100644 index 00000000..aef215c2 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Scenes/Lot/LotLoad.cs @@ -0,0 +1,278 @@ +// JDrocks450 11-22-2023 on GitHub + +#define NEW_INVALIDATE +#undef NEW_INVALIDATE + +using OpenTS2.Common; +using OpenTS2.Content.DBPF.Scenegraph; +using OpenTS2.Content.DBPF; +using OpenTS2.Content; +using OpenTS2.Files.Formats.DBPF; +using OpenTS2.Files; +using OpenTS2.Scenes.Lot.State; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace OpenTS2.Scenes.Lot +{ + /// + /// Standard behavior for loading into the lot view. + /// Provides standard functionality for placing terrain, walls, floors, objects, etc. into the Scene + /// + public class LotLoad : MonoBehaviour + { + /// + /// Settings for how the lot should be loaded + /// + public struct LotLoadSettings + { + [Flags] + public enum LotViewLayers : int + { + None = 0, + Terrain = 1, + Walls = 2, + Floors = 4, + Objects = 8 + } + public const LotViewLayers AllLayers = + LotViewLayers.None | LotViewLayers.Terrain | LotViewLayers.Walls | LotViewLayers.Floors | LotViewLayers.Objects; + /// + /// Specifies which layers of the lot geometry should be loaded + /// + public LotViewLayers LoadLayers; + + public LotLoadSettings(LotViewLayers loadLayers = AllLayers) + { + LoadLayers = loadLayers; + } + } + + public const string Default_NeighborhoodPrefix = "N001"; + public const int Default_LotID = 82; + + public int Floor => _state.Level; + public WallsMode Mode = WallsMode.Roof; + + public int BaseFloor => architecture?.BaseFloor ?? 0; + public int MaxFloor => architecture?.FloorPatterns.Depth ?? 1; + + public WorldState WorldState + { + get => _state; + set + { + _state = value; + Debug.Log($"World state updated: {value}"); + } + } + + private WorldState _state = new WorldState(1, WallsMode.Roof); + + private string _nhood; + private int _lotId; + + private DBPFFile lotPackage; + + /// + /// The currently selected Neighborhood Prefix (N001 by default) + /// + public string NeighborhoodPrefix => _nhood; + /// + /// The currently selected Lot ID in the selected (82 by default) + /// + public int LotID => _lotId; + + private List _lotObject = new List(); + private List _testObjects = new List(); + public LotArchitecture architecture; + + /// + /// Loads the default lot + /// See: and + /// + public LotLoad() : this(Default_NeighborhoodPrefix, Default_LotID) { } + /// + /// Creates a new instance (that can be reused) with the specified Neighborhood and LotID to load + /// + /// + /// + public LotLoad(string Nhood, int LotID) + { + LoadLot(Nhood, LotID); + } + + public void UnloadLot() + { + foreach (var obj in _lotObject) + { + Destroy(obj); + } + + _lotObject.Clear(); + _testObjects.Clear(); + } + + /// + /// Updates and and loads the lot. + /// + /// + /// + /// + public void LoadLot(string neighborhoodPrefix, int id, LotLoadSettings Settings = default) + { + _nhood = neighborhoodPrefix; + _lotId = id; + + LoadLot(Settings); + } + + public void LoadLot(LotLoadSettings Settings = default) + { + //Unload previous session + UnloadLot(); + + var contentProvider = ContentProvider.Get(); + + var lotsFolderPath = Path.Combine(Filesystem.GetUserPath(), $"Neighborhoods/{NeighborhoodPrefix}/Lots"); + var lotFilename = $"{NeighborhoodPrefix}_Lot{LotID}.package"; + var lotFullPath = Path.Combine(lotsFolderPath, lotFilename); + + if (!File.Exists(lotFullPath)) + { + return; + } + + lotPackage = contentProvider.AddPackage(lotFullPath); + + //add objects from scenegraph (primitive need to change to more robust solution later) + InvalidateObjects(); + + architecture = new LotArchitecture(); + + architecture.LoadFromPackage(lotPackage); +#if DEBUG + ArchitecturePreBakeDebug(); +#endif + architecture.CreateGameObjects(_lotObject); + + Mode = WallsMode.Roof; + _state = new WorldState(Floor, Mode); + architecture.UpdateState(_state); + } + + void ArchitecturePreBakeDebug() + { // Bisquicks testing playground :D + + } + + public void InvalidateObjects() + { + //Clear any objects on the scene + UnloadLot(); + + var contentProvider = ContentProvider.Get(); + // Go through each lot object. + foreach (var entry in lotPackage.Entries) + { + if (entry.GlobalTGI.TypeID != TypeIDs.LOT_OBJECT) + { + continue; + } + + try + { + var lotObject = entry.GetAsset(); + var resource = contentProvider.GetAsset( + new ResourceKey(lotObject.Object.ResourceName + "_cres", GroupIDs.Scenegraph, + TypeIDs.SCENEGRAPH_CRES)); + if (resource == null) + { + Debug.Log($"Could not find lot object: {lotObject.Object.ResourceName}"); + continue; + } + + var model = resource.CreateRootGameObject(); + model.transform.GetChild(0).localPosition = lotObject.Object.Position; + model.transform.GetChild(0).localRotation = lotObject.Object.Rotation; + + _lotObject.Add(model); + _testObjects.Add(model); + } + catch (Exception e) + { + Debug.LogException(e); + } + } + } + + void baseInvalidateGroup(LotArchitecture.ArchitectureGameObjectTypes group) + { +#if NEW_INVALIDATE + architecture.InvalidateComponent(group); + return; +#endif + if (group == LotArchitecture.ArchitectureGameObjectTypes.roof) + { + architecture.InvalidateComponent(group); + return; + } + //old + string objectName = group.ToString(); + //destroy existing object + var groupParent = _lotObject.Where(x => x.name == objectName).FirstOrDefault(); + if (groupParent != null) + { // clean walls + Destroy(groupParent); + _lotObject.Remove(groupParent); + } + //rebuild new mesh from memory + architecture.CreateGameObjectsOfType(_lotObject, group); + } + + public void InvalidateFloors() + { + baseInvalidateGroup(LotArchitecture.ArchitectureGameObjectTypes.floor); + InvalidateTerrain(); + } + public void InvalidateWalls() => baseInvalidateGroup(LotArchitecture.ArchitectureGameObjectTypes.wall); + void InvalidateTerrain() => baseInvalidateGroup(LotArchitecture.ArchitectureGameObjectTypes.terrain); + + /// + /// After changing the , use this method to update the visual + /// + internal void InvalidateState() + { + architecture.UpdateState(_state); + UpdateObjectVisibility(_state.Level); + } + + private void SetObjectVisiblity(GameObject obj, bool visible) + { + foreach (MeshRenderer renderer in obj.GetComponentsInChildren()) + { + renderer.shadowCastingMode = visible ? UnityEngine.Rendering.ShadowCastingMode.On : UnityEngine.Rendering.ShadowCastingMode.ShadowsOnly; + } + + foreach (SkinnedMeshRenderer renderer in obj.GetComponentsInChildren()) + { + renderer.shadowCastingMode = visible ? UnityEngine.Rendering.ShadowCastingMode.On : UnityEngine.Rendering.ShadowCastingMode.ShadowsOnly; + } + } + + private void UpdateObjectVisibility(int viewLevel) + { + foreach (GameObject obj in _testObjects) + { + int level = architecture.GetLevelAt(obj.transform.GetChild(0).localPosition); + + SetObjectVisiblity(obj, level < viewLevel); + } + } + } +} diff --git a/Assets/Scripts/OpenTS2/Scenes/Lot/LotLoad.cs.meta b/Assets/Scripts/OpenTS2/Scenes/Lot/LotLoad.cs.meta new file mode 100644 index 00000000..f1b1675a --- /dev/null +++ b/Assets/Scripts/OpenTS2/Scenes/Lot/LotLoad.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bfcccda4cb67ae846aeffc27284e6ded +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Scenes/Lot/LotTerrainComponent.cs b/Assets/Scripts/OpenTS2/Scenes/Lot/LotTerrainComponent.cs index ca6d0dd9..bb075469 100644 --- a/Assets/Scripts/OpenTS2/Scenes/Lot/LotTerrainComponent.cs +++ b/Assets/Scripts/OpenTS2/Scenes/Lot/LotTerrainComponent.cs @@ -47,6 +47,9 @@ public LotTerrainComponent CreateFromLotArchitecture(LotArchitecture architectur BindMaterialAndTextures(); + //Make Mesh Collider for terrain + SetTerrainCollider(_terrain.Component); + return this; } diff --git a/Assets/Scripts/OpenTS2/Scenes/Lot/LotWallComponent.cs b/Assets/Scripts/OpenTS2/Scenes/Lot/LotWallComponent.cs index 68689b62..60a4844f 100644 --- a/Assets/Scripts/OpenTS2/Scenes/Lot/LotWallComponent.cs +++ b/Assets/Scripts/OpenTS2/Scenes/Lot/LotWallComponent.cs @@ -19,7 +19,7 @@ public class LotWallComponent : AssetReferenceComponent, IPatternMaterialConfigu private const string ThicknessTexture = "wall_top"; private const string FallbackMaterial = "wall_wallboard"; private const float HalfWallHeight = 1f; - private const float WallHeight = 3f; + public const float WallHeight = 3f; private const float WallsDownHeight = 0.2f; private const float YBias = 0.001f; private const float Thickness = 0.075f; @@ -65,6 +65,7 @@ public WallIntersection(WallGraphPositionEntry position) private LotArchitecture _architecture; private PatternMeshCollection _patterns; + private PatternDescriptor[] _loadedPatternDescriptions; private Dictionary _intersections; @@ -74,17 +75,22 @@ public LotWallComponent CreateFromLotArchitecture(LotArchitecture architecture) { _architecture = architecture; - LoadPatterns(); - BuildWallIntersections(); - BuildWallMeshes(); - AddFencePosts(); + Invalidate(); gameObject.transform.position = new Vector3(0, -YBias, 0); return this; } - private ScenegraphMaterialDefinitionAsset LoadMaterial(ContentManager contentManager, string name) + public override void Invalidate() + { + LoadPatterns(); + BuildWallIntersections(); + BuildWallMeshes(); + AddFencePosts(); + } + + private ScenegraphMaterialDefinitionAsset LoadMaterial(ContentProvider contentProvider, string name) { var material = contentManager.GetAsset(new ResourceKey($"{name}_txmt", GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_TXMT)); @@ -104,8 +110,22 @@ private void LoadPatterns() ushort highestId = patternMap.Count == 0 ? (ushort)0 : patternMap.Keys.Max(); PatternDescriptor[] patterns = new PatternDescriptor[highestId + 2]; + bool changesMade = false; + bool previousStateExisting = _loadedPatternDescriptions != null; + foreach (StringMapEntry entry in patternMap.Values) { + //Persistent data -- calls from Invalidate() will call this with data already loaded, in which case + //We can save time by not reloading the same loaded data + // TODO + if (previousStateExisting && _loadedPatternDescriptions.Length == patterns.Length && + _loadedPatternDescriptions[entry.Id + 1].Name != null) // loaded + { // PatternDescriptor is a struct -- check the name see if it's null, if not, the pattern is loaded already + patterns[entry.Id + 1] = _loadedPatternDescriptions[entry.Id + 1]; + continue; + } + changesMade = true; + string materialName; if (uint.TryParse(entry.Value, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out uint guid)) { @@ -142,11 +162,22 @@ private void LoadPatterns() } } + if (previousStateExisting) + { + if (!changesMade) return; // no changes to wall patterns since last load + + patterns[0] = _loadedPatternDescriptions[0]; + _loadedPatternDescriptions = patterns; + _patterns.UpdatePatterns(patterns); + return; + } + patterns[0] = new PatternDescriptor( ThicknessTexture, LoadMaterial(contentManager, ThicknessTexture).GetAsUnityMaterial() ); + _loadedPatternDescriptions = patterns; _patterns = new PatternMeshCollection(gameObject, patterns, Array.Empty(), this, _architecture.WallGraphAll.Floors); } diff --git a/Assets/Scripts/OpenTS2/Scenes/Lot/PatternMesh.cs b/Assets/Scripts/OpenTS2/Scenes/Lot/PatternMesh.cs index b31562d2..bf2b11a7 100644 --- a/Assets/Scripts/OpenTS2/Scenes/Lot/PatternMesh.cs +++ b/Assets/Scripts/OpenTS2/Scenes/Lot/PatternMesh.cs @@ -35,7 +35,7 @@ public PatternMesh(GameObject parent, string name, Material material, IPatternMa Component.EnableExtraUV(); } - Object.transform.SetParent(parent.transform); + Object.transform.SetParent(parent.transform); Component.Initialize(_material); } diff --git a/Assets/Scripts/OpenTS2/Scenes/Lot/PatternMeshCollection.cs b/Assets/Scripts/OpenTS2/Scenes/Lot/PatternMeshCollection.cs index a02c2213..9e43e498 100644 --- a/Assets/Scripts/OpenTS2/Scenes/Lot/PatternMeshCollection.cs +++ b/Assets/Scripts/OpenTS2/Scenes/Lot/PatternMeshCollection.cs @@ -54,6 +54,7 @@ public PatternMeshFloor GetFloor(int floor) public void UpdatePatterns(PatternDescriptor[] patterns) { + _patterns = patterns; foreach (var floor in _floors) { floor?.UpdatePatterns(patterns); diff --git a/Assets/Scripts/OpenTS2/Scenes/Lot/PatternMeshFloor.cs b/Assets/Scripts/OpenTS2/Scenes/Lot/PatternMeshFloor.cs index a000d301..b03edb62 100644 --- a/Assets/Scripts/OpenTS2/Scenes/Lot/PatternMeshFloor.cs +++ b/Assets/Scripts/OpenTS2/Scenes/Lot/PatternMeshFloor.cs @@ -88,13 +88,13 @@ public PatternMesh Get(int id, int variantId = 0) Object, $"{descriptor.Name}_{variant.Name}", variant.MaterialTransform != null ? variant.MaterialTransform(descriptor.Material) : descriptor.Material, - _matConfig); + _matConfig); } else { result = new PatternMesh(Object, descriptor.Name, descriptor.Material, _matConfig); } - + result.Object.AddComponent(); // add collider to floors _patternMeshes[key] = result; } diff --git a/Assets/Scripts/OpenTS2/Scenes/Lot/State/WorldState.cs b/Assets/Scripts/OpenTS2/Scenes/Lot/State/WorldState.cs index 6ba48144..dc6770ea 100644 --- a/Assets/Scripts/OpenTS2/Scenes/Lot/State/WorldState.cs +++ b/Assets/Scripts/OpenTS2/Scenes/Lot/State/WorldState.cs @@ -18,5 +18,10 @@ public WorldState(int level, WallsMode walls) Level = level; Walls = walls; } + + public override string ToString() + { + return $"Walls: {Walls}, Level: {Level}"; + } } } \ No newline at end of file diff --git a/Assets/Scripts/OpenTS2/UI/Layouts/Lot.meta b/Assets/Scripts/OpenTS2/UI/Layouts/Lot.meta new file mode 100644 index 00000000..da027278 --- /dev/null +++ b/Assets/Scripts/OpenTS2/UI/Layouts/Lot.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 36c3b264b4416d742b336bab949d1995 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewBuildModeHUD.cs b/Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewBuildModeHUD.cs new file mode 100644 index 00000000..4b8cd53f --- /dev/null +++ b/Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewBuildModeHUD.cs @@ -0,0 +1,588 @@ +using OpenTS2.Common; +using OpenTS2.Content; +using OpenTS2.Content.DBPF; +using OpenTS2.Content.DBPF.Scenegraph; +using OpenTS2.Engine.Modes.Build; +using OpenTS2.Engine.Modes.Build.Tools; +using OpenTS2.Files.Formats.DBPF; +using OpenTS2.Files.Formats.XML; +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using UnityEngine.UI; + +namespace OpenTS2.UI.Layouts.Lot +{ + /// + /// This is a sub-control of the with functionality serving the Build Mode menus in the Lot View UI puck + /// + public class LotViewBuildModeHUD : UILayoutInstance + { + class BuildHUD_CatalogItemComponent : UILayoutInstance + { + //PRIVATE + const uint BaseID = 0xDAFE6503; + const uint PreviewID = 0x00000001; + private CatalogObjectAsset item; + public CatalogObjectAsset SelectedItem => item; + + Material displayMaterial; + + //PROTECTED + protected override ResourceKey UILayoutResourceKey => new ResourceKey(BaseID, 0xA99D8A11, TypeIDs.UI); + + //PUBLIC + public event EventHandler Clicked; + + public BuildHUD_CatalogItemComponent(Transform parent) : base(parent) + { + Init(); + } + + void Init() + { + Components[0].GetChildByID(0x03).OnClick += delegate + { + Clicked?.Invoke(this, SelectedItem); + }; + } + + /// + /// Changes this component's displayed texture and attached catalog asset + /// + /// + public void Display(CatalogObjectAsset Asset) + { + if(displayMaterial != null) + { + UnityEngine.Object.Destroy(displayMaterial); + displayMaterial = null; + } + + item = Asset; + + var content = ContentProvider.Get(); + var material = content.GetAsset( + new ResourceKey($"{Asset.Material}_txmt", GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_TXMT)); + + var preview = Components[0].GetChildByID(PreviewID); + preview.RectTransformComponent.localPosition = new Vector3(8, -8); + preview.RectTransformComponent.sizeDelta = new Vector2(34,34); + preview.gameObject.SetActive(true); + + //Set preview image + var bmp = preview.GetComponent(); + displayMaterial = material.GetAsUnityMaterial(); + bmp.texture = displayMaterial.mainTexture; + } + } + + /// + /// Contains the state of the catelog UI flyout + /// + class BuildHUD_CatalogComponent + { + const int XMARGIN = 10, YMARGIN = 5; // Margins between catalog items in the menu + internal const uint CatalogItemsExtender = 0xAD502BBF; + const uint CatalogItemsComponent = 0x00001006; + const uint PreviousButton = 0x00001004; + const uint NextButton = 0x00001005; + + UIComponent rootElement; + internal bool opened { get; private set; } + + private string subsort = "all"; + int itemsPerPage = 6, currentPage = 1; + + List items = new List(); + /// + /// The list of reusable UIComponent instances that will dynamically update their previews depending on which page we're on + /// + List controls = new List(); + + public BuildHUD_CatalogComponent(UIComponent CatalogComponent) + { + rootElement = CatalogComponent; + + Init(); + Close(); + } + + void Init() + { + var catalogItemsComponent = rootElement.GetChildByID(CatalogItemsComponent); + catalogItemsComponent.gameObject.SetActive(true); + catalogItemsComponent.GetComponent().enabled = false; // background is buggy turn it off + + for(int item = 0; item < itemsPerPage; item++) // create dynamic items + { + int x = item / 2; + int y = item - (x * 2); + + var control = new BuildHUD_CatalogItemComponent(catalogItemsComponent.transform); + var ctrlTransform = control.Components[0].RectTransformComponent; + ctrlTransform.localPosition = new Vector3( // handle padding here + (ctrlTransform.sizeDelta.x + XMARGIN) * x, -(ctrlTransform.sizeDelta.y + YMARGIN) * y); + controls.Add(control); + + //CLICK EVENT + control.Clicked += CatalogItemSelected; + } + + //Rig up next and prev buttons + var prevButton = rootElement.GetChildByID(PreviousButton); + prevButton.OnClick += Previous; + var nextButton = rootElement.GetChildByID(NextButton); + nextButton.OnClick += Advance; + } + + private void CatalogItemSelected(object sender, CatalogObjectAsset e) + { + //If the current build tool is compatible with patterns -- invoke it + (BuildModeServer.Get().CurrentTool as IPatternSelectableBuildTool)?.SetPaintPattern(e.Material); + } + + void Advance() => SwitchPage(currentPage + 1); + void Previous() => SwitchPage(currentPage - 1); + /// + /// Switches to the given page in the catalog by updating the dynamic controls to the new page's contents + /// + /// + void SwitchPage(int PageNumber) + { + currentPage = PageNumber; + if (currentPage < 0) currentPage = 0; + + int startIndex = currentPage * itemsPerPage; + + var itemsFilter = (IEnumerable)items; + if (subsort == "ots2_hiddentiles") + { + itemsFilter = items.Where(x => ((Uint32Prop)x.Properties.Properties["showincatalog"]).Value == 0); + } + else if (subsort != "all") // filter the itemssource if applicable (ignore this filter if "all" is selected) + itemsFilter = items.Where(x => ((StringProp)x.Properties.Properties["subsort"]).Value == subsort); + + for (int item = 0; item < itemsPerPage; item++) + { + //Set buttons hidden at first until some content to show has been found + var control = controls[item]; + control.Components[0].gameObject.SetActive(false); + + //attempt to load the content item + var assetRef = itemsFilter.ElementAtOrDefault(startIndex + item); + if (assetRef == null) continue; // no content here + //found some content, make the button visible and display a preview of the catalog item + control.Components[0].gameObject.SetActive(true); + control.Display(assetRef); + } + } + + public void Close() + { + rootElement.gameObject.SetActive(false); + opened = false; + } + public void Open(string CatelogItemType, string Subsort = "all") + { + if (string.IsNullOrWhiteSpace(Subsort)) + Subsort = "all"; + + rootElement.gameObject.SetActive(true); + opened = true; + + //Update the selection of items to match the definition + subsort = Subsort; + UpdateItemsSource(CatalogManager.Get().Objects.Where(x => x.Type == CatelogItemType)); + } + public void SetLocalPosition(Vector3 Position) => + rootElement.RectTransformComponent.localPosition = Position; + + /// + /// Updates the catalog control's items source property. + /// Use this when changing the selection of items being shown in the catelog. + /// You do not need to account for multiple pages of items, that will be handled automatically by the control. + /// + void UpdateItemsSource(IEnumerable CatalogItems) + { + items.Clear(); + items.AddRange(CatalogItems); + + SwitchPage(0); // switch to page one of the new data + } + + /// + /// Sets a filter on the ItemsSource. + /// See: and + /// + /// + /// + internal void SetSubsort(string Subsort) + { + subsort = Subsort; + SwitchPage(0); + } + } + + #region TopLevelHUDElements + + /// + /// Sorts (pages) for different tools in the build mode hud + /// + enum BuildHUD_Sorts : uint + { + TopLevel = 0x0000A000, + Walls = 0x0000B100, + Foundations = 0x0000B200, + DoorsWindowsArches = 0x0000B300, + Floors = 0x0000B400, + WallPaints = 0x0000B500, + Stairs = 0x0000B600, + Terrain = 0x0000B700, + GardenCenter = 0x0000B800, + Roofs = 0x0000B900, + Garages = 0x0000BB00, + Architecture = 0x0000BC00, + Misc = 0x0000BA00 + } + enum BuildHUD_CollectionPages : uint + { + Normal = 0x000000A8 + } + enum BuildHUD_BasicToolButtons : uint + { + Hand = 0x000000A5, + EyedropperTool = 0x000000A4 + } + + #endregion + + #region Subsorts + + enum BuildHUD_TopLevelButtons : uint + { + TopLevelSortButton = 0x000000A6, + WallsSortButton = 0x0000A100, + FoundationsSortButton = 0x0000A200, + DoorsAndWindowsSortButton = 0x0000A300, + FloorsSortButton = 0x0000A400, + WallPaintsSortButton = 0x0000A500, + StairsSortButton = 0x0000A600, + TerrainCenterButton = 0x0000A700, + GardenCenterButton = 0x0000A800, + RoofsSortButton = 0x0000A900, + MiscButton = 0x0000AA00, + GarageButton = 0x0000AB00, + ArchitectureSortButton = 0x0000AC00, + } + enum BuildHUD_WallsSortButtons : uint + { + WallsNRooms = 0x0000B120, + HalfWalls = 0x0000B130 + } + enum BuildHUD_TerrainSortButtons : uint + { + ElevationTools = 0x0000B720, + TerrainPaints = 0x0000B730, // called 'grass' in UI, pretty cool :0 + Water = 0x0000B740, + FlattenLot = 0x000000AD, + } + enum BuildHUD_TerrainBrushSizeButtons : uint + { + SmallSizeButton = 0x0000B751, + MedSizeButton = 0x0000B752, + LgSizeButton = 0x0000B753, + } + enum BuildHUD_FloorsSubsortButtons : uint + { + StoneButton = 0x0000B420, + BrickButton = 0x0000B430, + WoodButton = 0x0000B440, + CarpetButton = 0x0000B450, + TileButton = 0x0000B460, + LinoleumButton = 0x0000B470, + PouredButton = 0x0000B480, + OtherButton = 0x0000B490, + AllButton = 0x0000B4A0, + } + + #endregion + + const uint BaseID = 0x49060003; + const uint TileBG = 0xB4; // UI Background Panel + const uint EndCap = 0x000000B5; // UI Curvy End Cap + const uint ProdCatelogFlyout = 0x49063004; + const uint AutoRoofOptionsExtender = 0x000000AC; + const uint TerrainPageSizesGroup = 0x0000B750; + + protected override ResourceKey UILayoutResourceKey => new ResourceKey(BaseID, 0xA99D8A11, TypeIDs.UI); + UIComponent rootElement => Components[0]; + + //Pages (Sorts) + + /// + /// Contains information for each sort page in build mode to display it correctly + /// + class BuildHUDSort + { + /// + /// The enum type that has the IDs for the buttons that are inside of this sort that should be Toggled/Untoggled + /// after the sort is opened and dismissed + /// + public Type ButtonIDsEnum { get; set; } = null; + /// + /// The UI ID for this sort + /// + public uint SortGroupID { get; set; } + + //CATALOG PROVIDER + public string CatalogItemType { get; set; } + public bool HasCatalogItems => CatalogItemType != null; + public string CatalogDefaultSubsort { get; set; } = "all"; + + public BuildHUDSort(Type buttonIDsEnum, uint sortGroupID) + { + ButtonIDsEnum = buttonIDsEnum; + SortGroupID = sortGroupID; + } + } + + BuildHUDSort CurrentSort; + /// + /// Links Sort buttons to their corresponding pages in the interface + /// Wall Button links to the Wall Subpage with Half Walls, Regular Walls, Diagonal Room, etc. + /// + Dictionary sortPageMap = new Dictionary() + { + { BuildHUD_Sorts.TopLevel, new BuildHUDSort(typeof(BuildHUD_TopLevelButtons), (uint)BuildHUD_Sorts.TopLevel) }, + { BuildHUD_Sorts.Walls, new BuildHUDSort(typeof(BuildHUD_WallsSortButtons), (uint)BuildHUD_Sorts.Walls) }, + { BuildHUD_Sorts.Terrain, new BuildHUDSort(typeof(BuildHUD_TerrainSortButtons), (uint)BuildHUD_Sorts.Terrain) }, + { BuildHUD_Sorts.Floors, new BuildHUDSort(typeof(BuildHUD_FloorsSubsortButtons), (uint)BuildHUD_Sorts.Floors) + { // activate the catelog page for this sort + CatalogItemType = CatalogObjectType.Floor, + } + }, + }; + + // UI buttons and event system + Dictionary buildHUDButtonCallbacks; // built at runtime + /// + /// All UI buttons added to the event system (See: ) will set this value to + /// themselves prior to the event being called (May change later) + /// + UIButtonComponent CurrentButtonEventContext; + BuildHUD_CatalogComponent Catalog; + + public bool CatalogOpen => Catalog.opened; + + public LotViewBuildModeHUD() : this(MainCanvas) + { + + } + public LotViewBuildModeHUD(Transform Canvas) : base(Canvas) + { + Init(); + BuildUIEventsMap(); + WireUpUIEvents(); + } + + void Init() + { + //Position in bot left + var root = Components[0]; + root.SetAnchor(UIComponent.AnchorType.BottomLeft); + root.transform.position = new Vector3(105, root.transform.position.y, 0); + + //fix sizing + var iconButton = root.GetChildByID((uint)BuildHUD_BasicToolButtons.Hand); + iconButton.RectTransformComponent.sizeDelta = new Vector2(30, 30); + iconButton = root.GetChildByID((uint)BuildHUD_BasicToolButtons.EyedropperTool); + iconButton.RectTransformComponent.sizeDelta = new Vector2(30, 30); + + //turn off all controls except necessary ones + var autoRoofOptions = root.GetChildByID(AutoRoofOptionsExtender); + autoRoofOptions.gameObject.SetActive(false); + Catalog = new BuildHUD_CatalogComponent(root.GetChildByID(BuildHUD_CatalogComponent.CatalogItemsExtender)); + } + + void BuildUIEventsMap() + { + buildHUDButtonCallbacks = new Dictionary() + { + // BASIC BUTTONS + { (uint)BuildHUD_BasicToolButtons.Hand, delegate { ActionChangeTool(BuildTools.Hand); } }, + + // TOP LEVEL SORTS BUTTONS + { (uint)BuildHUD_TopLevelButtons.TopLevelSortButton, delegate { ActionChangeSort(BuildHUD_Sorts.TopLevel); } }, + { (uint)BuildHUD_TopLevelButtons.WallsSortButton, delegate { ActionChangeSort(BuildHUD_Sorts.Walls); } }, + { (uint)BuildHUD_TopLevelButtons.DoorsAndWindowsSortButton, delegate { ActionChangeSort(BuildHUD_Sorts.DoorsWindowsArches); } }, + { (uint)BuildHUD_TopLevelButtons.FloorsSortButton, delegate + { + ActionChangeSort(BuildHUD_Sorts.Floors); + ActionChangeTool(BuildTools.Floor); + } + }, + { (uint)BuildHUD_TopLevelButtons.WallPaintsSortButton, delegate { ActionChangeSort(BuildHUD_Sorts.WallPaints); } }, + { (uint)BuildHUD_TopLevelButtons.ArchitectureSortButton, delegate { ActionChangeSort(BuildHUD_Sorts.Architecture); } }, + { (uint)BuildHUD_TopLevelButtons.GardenCenterButton, delegate { ActionChangeSort(BuildHUD_Sorts.GardenCenter); } }, + { (uint)BuildHUD_TopLevelButtons.TerrainCenterButton, delegate { ActionChangeSort(BuildHUD_Sorts.Terrain); } }, + { (uint)BuildHUD_TopLevelButtons.GarageButton, delegate { ActionChangeSort(BuildHUD_Sorts.Garages); } }, + { (uint)BuildHUD_TopLevelButtons.MiscButton, delegate { ActionChangeSort(BuildHUD_Sorts.Misc); } }, + { (uint)BuildHUD_TopLevelButtons.RoofsSortButton, delegate { ActionChangeSort(BuildHUD_Sorts.Roofs); } }, + { (uint)BuildHUD_TopLevelButtons.FoundationsSortButton, delegate { + ActionChangeSort(BuildHUD_Sorts.Foundations); + ActionChangeTool(BuildTools.Foundation); + } + }, + { (uint)BuildHUD_TopLevelButtons.StairsSortButton, delegate { ActionChangeSort(BuildHUD_Sorts.Stairs); } }, + + // Walls N' Rooms + { (uint)BuildHUD_WallsSortButtons.WallsNRooms, delegate { ActionChangeTool(BuildTools.Wall); } }, + + // Terrain + { (uint)BuildHUD_TerrainSortButtons.ElevationTools, delegate { ActionSetTerrainBrushTool(BuildModeServer.TerrainModificationModes.Raise); } }, + { (uint)BuildHUD_TerrainSortButtons.Water, delegate { ActionSetTerrainBrushTool(BuildModeServer.TerrainModificationModes.Water); } }, + { (uint)BuildHUD_TerrainSortButtons.FlattenLot, delegate { BuildModeServer.Get().FlattenLot(); } }, + { (uint)BuildHUD_TerrainBrushSizeButtons.SmallSizeButton, delegate { ActionModifyTerrainBrushSize(0); } }, + { (uint)BuildHUD_TerrainBrushSizeButtons.MedSizeButton, delegate { ActionModifyTerrainBrushSize(TerrainBrushTool.TerrainBrushSizes.Medium); } }, + { (uint)BuildHUD_TerrainBrushSizeButtons.LgSizeButton, delegate { ActionModifyTerrainBrushSize(TerrainBrushTool.TerrainBrushSizes.Large); } }, + + //Floors + { (uint)BuildHUD_FloorsSubsortButtons.StoneButton, delegate { ActionInvokeSubSort("stone"); } }, + { (uint)BuildHUD_FloorsSubsortButtons.BrickButton, delegate { ActionInvokeSubSort("brick"); } }, + { (uint)BuildHUD_FloorsSubsortButtons.WoodButton, delegate { ActionInvokeSubSort("wood"); } }, + { (uint)BuildHUD_FloorsSubsortButtons.PouredButton, delegate { ActionInvokeSubSort("poured"); } }, + { (uint)BuildHUD_FloorsSubsortButtons.CarpetButton, delegate { ActionInvokeSubSort("carpet"); } }, + { (uint)BuildHUD_FloorsSubsortButtons.OtherButton, delegate { ActionInvokeSubSort("other"); } }, + { (uint)BuildHUD_FloorsSubsortButtons.AllButton, delegate { ActionInvokeSubSort("all"); } }, + { (uint)BuildHUD_FloorsSubsortButtons.TileButton, delegate { ActionInvokeSubSort("tile"); } }, + { (uint)BuildHUD_FloorsSubsortButtons.LinoleumButton, delegate { ActionInvokeSubSort("linoleum"); } }, + }; + } + + void WireUpUIEvents() + { + foreach(var keyValuePair in buildHUDButtonCallbacks) + { + uint compID = keyValuePair.Key; + var button = rootElement.GetChildByID(compID); + button.OnClick += delegate + { + //Set context + CurrentButtonEventContext = button; + //Invoke event + keyValuePair.Value(); + //Remove context + CurrentButtonEventContext = null; + }; + } + } + void EnsureGroupToggled(Type EnumTypeGroup, bool ToggleState = false) => EnsureGroup(EnumTypeGroup, (UIButtonComponent comp) => comp.SetToggled(ToggleState)); + void EnsureGroupHidden(Type EnumUIGroup) => EnsureGroup(EnumUIGroup, (UIComponent comp) => comp.gameObject.SetActive(false)); + void EnsureGroup(Type EnumUIGroup, Action Modification) => EnsureGroup(EnumUIGroup, Modification); + void EnsureGroup(Type EnumUIGroup, Action Modification) where T : UIComponent + { + if (EnumUIGroup == null) return; + foreach (uint groupID in Enum.GetValues(EnumUIGroup)) + Modification(rootElement.GetChildByID(groupID)); + } + void CloseCatalog() + { + Catalog.Close(); + //Set the endcap visible again + rootElement.GetChildByID(EndCap).gameObject.SetActive(true); + } + void OpenCatalog(string ObjectType, string Subsort = "all") + { + Catalog.Open(ObjectType, Subsort); + //Set the endcap invisible + rootElement.GetChildByID(EndCap).gameObject.SetActive(false); + } + + void ActionChangeTool(BuildTools Tool) + { + //Untoggle all basic buttons before transitioning + EnsureGroupToggled(typeof(BuildHUD_BasicToolButtons)); + if (CurrentSort != default) + EnsureGroupToggled(CurrentSort.ButtonIDsEnum); + //set tool button toggled + if (CurrentButtonEventContext != default) + CurrentButtonEventContext.SetToggled(true); + + BuildModeServer.Get().ChangeTool(Tool); + } + + void ActionChangeSort(BuildHUD_Sorts SortPage) + { + ActionChangeTool(BuildTools.None); // drop current tool + + //Hide all other pages before transitioning + EnsureGroupHidden(typeof(BuildHUD_Sorts)); + CloseCatalog(); + + var sortRoot = rootElement.GetChildByID((uint)SortPage); + sortRoot.gameObject.SetActive(true); + // stretch the ui panel to accomodate for the page we just opened up + float desiredWidth = sortRoot.RectTransformComponent.sizeDelta.x; + var TileBGComponent = rootElement.GetChildByID(TileBG).RectTransformComponent; // UI background panel + TileBGComponent.sizeDelta = new Vector2(desiredWidth, TileBGComponent.sizeDelta.y); + //move the endcap over so there's no gaps + var EndCapComp = rootElement.GetChildByID(EndCap).RectTransformComponent; // UI background panel + EndCapComp.localPosition = TileBGComponent.localPosition + new Vector3(desiredWidth, 0, 0); + //move the catelog as well -- whether it is active or not + Catalog.SetLocalPosition(new Vector3(TileBGComponent.localPosition.x + desiredWidth, 0, 0)); + //catelogComp.sizeDelta = new Vector2(catelogComp.position.x - (MainCanvas.transform as RectTransform).sizeDelta.x - 10, + // catelogComp.sizeDelta.y); + + if (sortPageMap.TryGetValue(SortPage, out var map)) + CurrentSort = map; + //Untoggle all buttons in the destination sort as well + EnsureGroupToggled(CurrentSort.ButtonIDsEnum); + + //open the catelog (if applicable) + if (CurrentSort.HasCatalogItems) + OpenCatalog(CurrentSort.CatalogItemType, CurrentSort.CatalogDefaultSubsort); + } + + /// + /// Sorts such as Flooring have subsorts (carpet, stone, etc.), this function will update the + /// subsort for the + /// + /// + void ActionInvokeSubSort(string Subsort) + { + EnsureGroupToggled(CurrentSort.ButtonIDsEnum); + if (Subsort == "all" && Input.GetKey(KeyCode.LeftShift)) // BuildDEBUG + Subsort = "ots2_hiddentiles"; + Catalog.SetSubsort(Subsort); + CurrentButtonEventContext.SetToggled(true); + } + + void ActionSetTerrainBrushTool(BuildModeServer.TerrainModificationModes BrushMode) + { + ActionChangeTool(BuildTools.TerrainBrush); + (BuildModeServer.Get().CurrentTool as TerrainBrushTool).CurrentBrushMode = BrushMode; + ActionModifyTerrainBrushSize(TerrainBrushTool.TerrainBrushSizes.Small); + } + + void ActionModifyTerrainBrushSize(TerrainBrushTool.TerrainBrushSizes Size) + { + EnsureGroupToggled(typeof(BuildHUD_TerrainBrushSizeButtons)); + UIButtonComponent button = rootElement.GetChildByID((uint)BuildHUD_TerrainBrushSizeButtons.SmallSizeButton); + switch (Size) + { + case TerrainBrushTool.TerrainBrushSizes.Medium: // med + button = rootElement.GetChildByID((uint)BuildHUD_TerrainBrushSizeButtons.MedSizeButton); + break; + case TerrainBrushTool.TerrainBrushSizes.Large: // lg + button = rootElement.GetChildByID((uint)BuildHUD_TerrainBrushSizeButtons.LgSizeButton); + break; + default: + Size = TerrainBrushTool.TerrainBrushSizes.Small; break; + } + button.SetToggled(true); + (BuildModeServer.Get().CurrentTool as TerrainBrushTool).BrushSize = (int)Size; + } + } +} diff --git a/Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewBuildModeHUD.cs.meta b/Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewBuildModeHUD.cs.meta new file mode 100644 index 00000000..7615775c --- /dev/null +++ b/Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewBuildModeHUD.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 81a357d2aeaa898479699bb2890f9123 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewHUD.cs b/Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewHUD.cs new file mode 100644 index 00000000..29b0337a --- /dev/null +++ b/Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewHUD.cs @@ -0,0 +1,182 @@ +using OpenTS2.Common; +using OpenTS2.Engine.Modes.Build; +using OpenTS2.Files.Formats.DBPF; +using OpenTS2.Scenes.Lot.State; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace OpenTS2.UI.Layouts +{ + + /// + /// The HUD found when the user is playing in a lot + /// + public class LotViewHUD : UILayoutInstance + { + //CONSTANTS + public enum HUD_UILotModes + { + None, + Live, + Buy, + Build, + Memories, + Settings + } + + const uint WallViewSelectorGadgetID = 0x00004000; + /// + /// probably not necessary since it's the only control in this UIData but im gonna roll w it + /// + const uint LotViewPuckID = 0xF15C6B85; + //Wall View button that invokes the Wall View Selector has 4 states for each wall view mode + const uint FoldButton_WallsDown = 0x00001100, FoldButton_WallsCutaway = 0x00001101, + FoldButton_WallsUp = 0x00001102, FoldButton_Roof = 0x00001103; + //Buttons inside the Wall View selector that change the Wall View Mode + const uint Button_WallsDown = 0x00000001, Button_WallsCutaway = 0x00000002, + Button_WallsUp = 0x00000003, Button_WallsRoof = 0x00000004; + const uint BuildButton = 0x77D97B28, BuyButton = 0x67D97B2A, LiveButton = 0x37D97B25, SettingsButton = 0x67D97B2F; + const uint FloorUpButton = 0x00002001, FloorDownButton = 0x00002000; + + //PRIVATE + UIComponent WallsUpDownSelector; + UIComponent rootElement => Components[0]; + + HUD_UILotModes CurrentMode = HUD_UILotModes.None; + + //EVENTS + public class ModeChangeEventArgs + { + public bool Allow = false; + HUD_UILotModes RequestedMode; + + public ModeChangeEventArgs(HUD_UILotModes requestedMode) + { + RequestedMode = requestedMode; + } + } + public event EventHandler OnModeChangeRequested; + public event EventHandler OnModeChanged; + + protected override ResourceKey UILayoutResourceKey => new ResourceKey(0x4905F85B, 0xA99D8A11, TypeIDs.UI); + public LotViewHUD() : this(MainCanvas) + { + + } + public LotViewHUD(Transform Canvas) : base(Canvas) + { + Init(); + WireUpUIEvents(); + } + + void Toggle(UIComponent comp) => comp.transform.gameObject.SetActive(!comp.transform.gameObject.activeSelf); + + /// + /// Sets the hud elements to default settings for first run + /// + void Init() + { + var root = Components[0]; + root.SetAnchor(UIComponent.AnchorType.Stretch); + var puck = root.GetChildByID(LotViewPuckID); + puck.SetAnchor(UIComponent.AnchorType.BottomLeft); // set gizmo to botleft + puck.transform.position = new Vector3(0, 200, 0); + + WallsUpDownSelector = root.GetChildByID(WallViewSelectorGadgetID, false); + Toggle(WallsUpDownSelector); + } + + /// + /// Sets up all button click event messages + /// + void WireUpUIEvents() + { + void RigUpSequential(uint Base, int count, Action Callback) + { + if (count < 0) return; // :| + if (Base + count > uint.MaxValue) throw new Exception($"UI Element ID overflow in WireUpUIEvents RigUpSeq method! {Base} + {count}"); + for (int i = 0; i < count; i++) + { + var button = rootElement.GetChildByID((uint)(Base + i)); // downcast doesn't matter per above + button.OnClick += Callback; + } + } + //Rig up Wall View Mode tray thing + RigUpSequential(FoldButton_WallsDown, 4, ShowHideWallViewOptions); + var modeButton = rootElement.GetChildByID(BuildButton); + modeButton.OnClick += delegate { SetMode(HUD_UILotModes.Build); }; // build mode button clicked + + //Wall view modes buttons + var wallButton = rootElement.GetChildByID(Button_WallsDown); + wallButton.OnClick += delegate { SetWallsCutawayMode(WallsMode.Down); }; + wallButton = rootElement.GetChildByID(Button_WallsCutaway); + wallButton.OnClick += delegate { SetWallsCutawayMode(WallsMode.Cutaway); }; + wallButton = rootElement.GetChildByID(Button_WallsUp); + wallButton.OnClick += delegate { SetWallsCutawayMode(WallsMode.Up); }; + wallButton = rootElement.GetChildByID(Button_WallsRoof); + wallButton.OnClick += delegate { SetWallsCutawayMode(WallsMode.Roof); }; + + //floor buttons + var floorButton = rootElement.GetChildByID(FloorUpButton); + floorButton.OnClick += delegate { SetFloorLevel(1); }; + floorButton = rootElement.GetChildByID(FloorDownButton); + floorButton.OnClick += delegate { SetFloorLevel(-1); }; + } + + void ShowHideWallViewOptions() + { + Toggle(WallsUpDownSelector); + } + + void SetWallsCutawayMode(WallsMode Mode) + { + var server = BuildModeServer.Get(); + var state = server.WorldState; + server.WorldState = new WorldState(state.Level, Mode); + server.InvalidateLotState(); + ShowHideWallViewOptions(); + } + + void SetFloorLevel(int Change) + { + var server = BuildModeServer.Get(); + var state = server.WorldState; + int level = Math.Max(0,state.Level + Change); // TODO: Make this base floor value... + server.WorldState = new WorldState(level, state.Walls); + server.InvalidateLotState(); + } + + /// + /// Sets the mode shown in the HUD + /// Note: If there are no subscribers to , the mode change will always be successful without verification. + /// + /// + public void SetMode(HUD_UILotModes Mode) + { + if (OnModeChangeRequested != null) + { + var args = new ModeChangeEventArgs(Mode); + OnModeChangeRequested(this, args); + if (!args.Allow) return; + } + //Change allowed + + CurrentMode = Mode; + var buildModeButton = rootElement.GetChildByID(BuildButton); + buildModeButton.SetToggled(false); + + switch(Mode) + { + case HUD_UILotModes.Build: + buildModeButton.SetToggled(true); + break; + } + + OnModeChanged?.Invoke(this, Mode); + } + } +} diff --git a/Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewHUD.cs.meta b/Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewHUD.cs.meta new file mode 100644 index 00000000..b9dc79d2 --- /dev/null +++ b/Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewHUD.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5b5d074308e95ce42b13b0c46dd9eaed +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewHUDController.cs b/Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewHUDController.cs new file mode 100644 index 00000000..278e11aa --- /dev/null +++ b/Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewHUDController.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace OpenTS2.UI.Layouts.Lot +{ + public class LotViewHUDController : MonoBehaviour + { + //UI Parts + public LotViewBuildModeHUD BuildModePanel { get; private set; } + public LotViewHUD Puck { get; private set; } + + void Start() + { + BuildModePanel = new LotViewBuildModeHUD(); + Puck = new LotViewHUD(); + Puck.OnModeChanged += GizmoModeChanged; + } + + private void GizmoModeChanged(object sender, LotViewHUD.HUD_UILotModes e) + { + //TODO: Make UI react to mode changes ... for now not really necessary + } + + void Update() + { + + } + } +} diff --git a/Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewHUDController.cs.meta b/Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewHUDController.cs.meta new file mode 100644 index 00000000..22f6b2f3 --- /dev/null +++ b/Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewHUDController.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9727801f799a10a41875182ace337639 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/UI/UIButtonComponent.cs b/Assets/Scripts/OpenTS2/UI/UIButtonComponent.cs index 4ade9a2b..714d4f8e 100644 --- a/Assets/Scripts/OpenTS2/UI/UIButtonComponent.cs +++ b/Assets/Scripts/OpenTS2/UI/UIButtonComponent.cs @@ -24,6 +24,7 @@ public class UIButtonComponent : UIComponent, IPointerEnterHandler, IPointerExit public ResourceKey ClickSound; private bool _hovering = false; private bool _held = false; + private bool _toggled = false; // some buttons are toggle buttons -- adding this here to account for this scenario private TextureAsset[] _textures; public RawImage RawImageComponent => GetComponent(); public void SetTexture(TextureAsset texture) @@ -52,6 +53,11 @@ void UpdateTexture() RawImageComponent.texture = _textures[0].Texture; else { + if (_toggled) // Toggle Button texture here + { + RawImageComponent.texture = _textures[2].Texture; + return; + } RawImageComponent.texture = _textures[1].Texture; if (_hovering && !UIManager.AnyMouseButtonHeld) RawImageComponent.texture = _textures[3].Texture; @@ -99,5 +105,16 @@ public void OnPointerUp(PointerEventData eventData) OnClick?.Invoke(); _held = false; } + + void Click() + { + OnClick?.Invoke(); + } + + public void SetToggled(bool Toggled) + { + _toggled = Toggled; + UpdateTexture(); + } } } diff --git a/Assets/Shaders/Lot/Billboard.shader b/Assets/Shaders/Lot/Billboard.shader new file mode 100644 index 00000000..a100701b --- /dev/null +++ b/Assets/Shaders/Lot/Billboard.shader @@ -0,0 +1,69 @@ +Shader "Unlit/Billboard" +{ + Properties + { + _MainTex ("Texture", 2D) = "white" {} + } + SubShader + { + Tags{ "Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent" "DisableBatching" = "True" } + + ZWrite Off + Blend SrcAlpha OneMinusSrcAlpha + + Pass + { + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + // make fog work + #pragma multi_compile_fog + + #include "UnityCG.cginc" + + struct appdata + { + float4 vertex : POSITION; + float2 uv : TEXCOORD0; + }; + + struct v2f + { + float2 uv : TEXCOORD0; + UNITY_FOG_COORDS(1) + float4 pos : SV_POSITION; + }; + + sampler2D _MainTex; + float4 _MainTex_ST; + + v2f vert (appdata v) + { + v2f o; + o.pos = UnityObjectToClipPos(v.vertex); + o.uv = v.uv.xy; + + // billboard mesh towards camera + float3 vpos = mul((float3x3)unity_ObjectToWorld, v.vertex.xyz); + float4 worldCoord = float4(unity_ObjectToWorld._m03, unity_ObjectToWorld._m13, unity_ObjectToWorld._m23, 1); + float4 viewPos = mul(UNITY_MATRIX_V, worldCoord) + float4(vpos, 0); + float4 outPos = mul(UNITY_MATRIX_P, viewPos); + + o.pos = outPos; + + UNITY_TRANSFER_FOG(o,o.vertex); + return o; + } + + fixed4 frag (v2f i) : SV_Target + { + // sample the texture + fixed4 col = tex2D(_MainTex, i.uv); + // apply fog + UNITY_APPLY_FOG(i.fogCoord, col); + return col; + } + ENDCG + } + } +} diff --git a/Assets/Shaders/Lot/Billboard.shader.meta b/Assets/Shaders/Lot/Billboard.shader.meta new file mode 100644 index 00000000..775a27a2 --- /dev/null +++ b/Assets/Shaders/Lot/Billboard.shader.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 9027c75630615624b8d7e4b02852aa4e +ShaderImporter: + externalObjects: {} + defaultTextures: [] + nonModifiableTextures: [] + preprocessorOverride: 0 + userData: + assetBundleName: + assetBundleVariant: From 3eee6937b9e325760de9d665639b0b33cc50edd9 Mon Sep 17 00:00:00 2001 From: Jeremy Glazebrook Date: Sun, 21 Jan 2024 19:19:11 -0500 Subject: [PATCH 02/15] Update Foundation Tool to have Wallpaper and Floor Patterning --- .../Modes/Build/Tools/FoundationTool.cs | 38 ++++++++++++++++--- 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/FoundationTool.cs b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/FoundationTool.cs index d55d5111..f73d5ba7 100644 --- a/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/FoundationTool.cs +++ b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/FoundationTool.cs @@ -15,35 +15,61 @@ namespace OpenTS2.Engine.Modes.Build.Tools /// internal class FoundationTool : AbstractRegionSelectBuildTool { - public FoundationTool(BuildModeServer Server) : base(Server) + const float FoundationHeight = 1; + const string FoundationWallpaper = "foundationbrick"; + private const string FoundationFlooring = "wood_wide_planks"; + + /// + /// Sets up a new Foundation Tool with the specified walls and floors + /// By default this is The Sims 2 default values Brick walls and Wood floors + /// + /// + /// + /// + public FoundationTool(BuildModeServer Server, + string Wallpaper = FoundationWallpaper, + string Flooring = FoundationFlooring) : base(Server) { + WallpaperPattern = Wallpaper; + FlooringPattern = Flooring; } public override string ToolName => "Foundation Tool"; + + //**PATTERN + /// + /// The pattern to paint the walls when creating a Foundation + /// + public string WallpaperPattern { get; set; } + /// + /// The pattern to paint the floors when creating a Foundation + /// + public string FlooringPattern { get; set; } + //*** + protected override MultilevelBehavior MultiLevelBehavior { get; set; } = MultilevelBehavior.Constrain; + protected override void DoAction(bool Undo = false) { if (DeleteMode) Undo = !Undo; - float change = 1; if (ToolDragFloor > 1) { OnToolCancel("Foundation can only be placed on terrain."); return; } - else if (ToolDragFloor == 1) change = 0; int currFloor = 0; int nextFloor = currFloor + 1; - float elevation = BuildModeServer.PollElevation(ToolDragOrigin, ToolDragFloor) + change; + float elevation = BuildModeServer.PollElevation(ToolDragOrigin, 0) + FoundationHeight; BuildModeServer.LevelRegion(ToolDragOrigin, ToolDragDestination, elevation, nextFloor); if (!Undo) { BuildModeServer.CreateWalls(ToolDragOrigin, ToolDragDestination, currFloor, Content.DBPF.WallType.Foundation, BuildModeServer.WallCreationModes.Room, - "foundationbrick", "foundationbrick"); - BuildModeServer.CreateFloors(ToolDragOrigin, ToolDragDestination, "wood_wide_planks", nextFloor, false); + WallpaperPattern, WallpaperPattern); + BuildModeServer.CreateFloors(ToolDragOrigin, ToolDragDestination, FlooringPattern, nextFloor, false); } else { From 71f1554246c3fc71b59213d2681a0ffdca1f8bf5 Mon Sep 17 00:00:00 2001 From: Jeremy Glazebrook Date: Sun, 21 Jan 2024 20:40:17 -0500 Subject: [PATCH 03/15] Fix wall facade performance issue when dragging out unplaced walls. --- .../OpenTS2/Content/DBPF/WallGraphAsset.cs | 37 +++++++++++++-- .../Engine/Modes/Build/BuildModeServer.cs | 22 ++++++--- .../Engine/Modes/Build/Tools/WallTool.cs | 47 +++++++++++++++++-- .../LotArchitectureBuildModeExtensions.cs | 26 ++++++++-- 4 files changed, 111 insertions(+), 21 deletions(-) diff --git a/Assets/Scripts/OpenTS2/Content/DBPF/WallGraphAsset.cs b/Assets/Scripts/OpenTS2/Content/DBPF/WallGraphAsset.cs index ddd9b4e4..5b3299bd 100644 --- a/Assets/Scripts/OpenTS2/Content/DBPF/WallGraphAsset.cs +++ b/Assets/Scripts/OpenTS2/Content/DBPF/WallGraphAsset.cs @@ -127,6 +127,15 @@ public bool PushWall(Vector2 Pos1, Vector2 Pos2, int Floor, out int LayerID) return true; } + private void _delWall(int index) + { + int i = index; + //found the wall + if (i != _lines.Length - 1) // last wall + _lines[i] = _lines[_lines.Length - 1]; // move last line to this spot + Array.Resize(ref _lines, _lines.Length - 1); // shorten array by one + } + internal bool RemoveWall(Vector2 From, Vector2 To, int Floor, out int LayerID) { // should be refactored to batch delete a set of segments instead of one at a time due to iterations being potentially large LayerID = -1; @@ -146,14 +155,34 @@ internal bool RemoveWall(Vector2 From, Vector2 To, int Floor, out int LayerID) if (line.ToId != toId && line.ToId != fromId) continue; if (line.FromId != toId && line.FromId != fromId) continue; - //found the wall - if (i != _lines.Length - 1) // last wall - _lines[i] = _lines[_lines.Length - 1]; // move last line to this spot - Array.Resize(ref _lines, _lines.Length - 1); // shorten array by one + _delWall(i); LayerID = line.LayerId; return true; } return false; // not found } + /// + /// Deletes all the wall lines from the selected floor by their LayerID. + /// + /// + /// + /// + internal int RemoveWalls(params int[] WallLayerIDs) + { + int index = -1; + int found = 0; + HashSet deletionIndices = new HashSet(); + foreach(var line in _lines) + { + index++; + if (!WallLayerIDs.Contains(line.LayerId)) continue; + found++; + deletionIndices.Add(index); + } + int deleted = 0; + foreach (int i in deletionIndices) + _delWall(i - deleted++); + return deleted; + } } } \ No newline at end of file diff --git a/Assets/Scripts/OpenTS2/Engine/Modes/Build/BuildModeServer.cs b/Assets/Scripts/OpenTS2/Engine/Modes/Build/BuildModeServer.cs index 86dabca9..95462a30 100644 --- a/Assets/Scripts/OpenTS2/Engine/Modes/Build/BuildModeServer.cs +++ b/Assets/Scripts/OpenTS2/Engine/Modes/Build/BuildModeServer.cs @@ -220,13 +220,13 @@ public void ChangeTool(BuildTools Tool) /// /// /// - public void CreateWalls(Vector2Int From, Vector2Int To, int Floor, + public int[]? CreateWalls(Vector2Int From, Vector2Int To, int Floor, WallType Type = WallType.Normal, WallCreationModes CreationOption = WallCreationModes.Single, string FrontWallpaperPattern = "blank", string BackWallpaperPattern = "blank") { - if (From == To) return; - if (CreationOption != WallCreationModes.Single && !RegionValid(From, To)) return; + if (From == To) return null; + if (CreationOption != WallCreationModes.Single && !RegionValid(From, To)) return null; string argsStr = $"From: {From} To: {To} Floor: {Floor} Type: {Type} Mode: {CreationOption}" + $"Front: {FrontWallpaperPattern} Back: {BackWallpaperPattern}"; @@ -241,16 +241,18 @@ public void CreateWalls(Vector2Int From, Vector2Int To, int Floor, if (BackWallpaperPattern != "blank") architecture.EnsurePatternReferenced(BackWallpaperPattern, LotArchitecture.ArchitectureGameObjectTypes.wall, out back, out _); - bool? returnValue = true; - foreach (var wall in walls) - returnValue = architecture.CreateWall(wall.A, wall.B, Floor, Type, front, back); + int[] createdWallIDs = null; + foreach (var wall in walls) + createdWallIDs = architecture.CreateWall(wall.A, wall.B, Floor, Type, front, back); - if (returnValue.HasValue) // walls were placed here + if (createdWallIDs != null) // walls were placed here { loadedLot.InvalidateWalls(); LogHistory($"Created wall(s). {argsStr}", "Create Walls"); + return createdWallIDs; } else LogHistory($"Could not create wall(s). {argsStr}", "Create Walls"); + return null; } /// /// Clears out all walls in the specified region with the given wall creation options @@ -276,6 +278,12 @@ public void DeleteWalls(Vector2Int From, Vector2Int To, int Floor, WallCreationM } else LogHistory($"Could not delete wall(s). {argsStr}", "Delete Walls"); } + public void DeleteAllWalls(params int[] WallLayerIDs) + { + if (WallLayerIDs.Length == 0) return; + architecture.DeleteAllWalls(WallLayerIDs); + loadedLot.InvalidateWalls(); + } /// /// Puts the two points in ascending order diff --git a/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/WallTool.cs b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/WallTool.cs index 12e06fc2..26e31845 100644 --- a/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/WallTool.cs +++ b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/WallTool.cs @@ -22,7 +22,15 @@ internal class WallTool : AbstractRegionSelectBuildTool bool deletingWalls => DeleteMode; //private + /// + /// This is used when dragging an area of walls. + /// The walls created as a facade have their IDs stored here. + /// When the action is cancelled or the facade changes, these IDs + /// will be used to delete the unneeded walls. + /// + HashSet facadeWallIDs = new HashSet(); BuildModeServer buildModeServer => BuildModeServer; + bool Hovering = false; /// /// Creates a new on the specified lot @@ -56,6 +64,8 @@ protected override void DoAction(bool Undoing = false) //that way, we only delete walls SUCCESSFULLY MADE and also it won't be so buggy //and performance will be (slightly) better //please do this soon jeremy >.< + //--- + //Jan 21st: i did. bool actionSelected = !deletingWalls; Vector2Int destination = toolDragEnd; @@ -67,7 +77,15 @@ protected override void DoAction(bool Undoing = false) else destination = toolDragEnd; actionSelected = !actionSelected; } - if (toolDragStart - destination == new Vector2Int(0, 0)) return; // zero area + if (toolDragStart - destination == new Vector2Int(0, 0)) + { + if (Hovering && facadeWallIDs.Count > 0) + { + buildModeServer.DeleteAllWalls(facadeWallIDs.ToArray()); + facadeWallIDs.Clear(); + } + return; // zero area + } if (actionSelected) { float startElevation = buildModeServer.PollElevation(toolDragStart, toolDragFloor); @@ -78,12 +96,31 @@ protected override void DoAction(bool Undoing = false) //buildModeServer.SetElevationRelative(startElevation, toolDragFloor, segment.A, segment.B); //level above the wall to ensure the height is accurate buildModeServer.SetElevationRelative(LotWallComponent.WallHeight, toolDragFloor + 1, segment.A, segment.B); - } - buildModeServer.CreateWalls(toolDragStart, destination, toolDragFloor, WallType.Normal, wallCreateMode); + } + var createdWallIDs = buildModeServer.CreateWalls(toolDragStart, destination, toolDragFloor, WallType.Normal, wallCreateMode); + if (Hovering) + { + if (createdWallIDs != null) + Array.ForEach(createdWallIDs, (int item) => facadeWallIDs.Add(item)); + } + else if(facadeWallIDs.Any()) facadeWallIDs.Clear(); + } + else + { + if (Hovering && facadeWallIDs.Count > 0) + { + buildModeServer.DeleteAllWalls(facadeWallIDs.ToArray()); + facadeWallIDs.Clear(); + } + buildModeServer.DeleteWalls(toolDragStart, destination, ToolDragFloor, wallCreateMode); } - else buildModeServer.DeleteWalls(toolDragStart, destination, toolDragFloor, wallCreateMode); } - protected override void DoHoverAction(bool Undo = false) => DoAction(Undo); + protected override void DoHoverAction(bool Undo = false) + { + Hovering = true; + DoAction(Undo); + Hovering = false; + } } } diff --git a/Assets/Scripts/OpenTS2/Scenes/Lot/Extensions/LotArchitectureBuildModeExtensions.cs b/Assets/Scripts/OpenTS2/Scenes/Lot/Extensions/LotArchitectureBuildModeExtensions.cs index 70a911e4..dd97a631 100644 --- a/Assets/Scripts/OpenTS2/Scenes/Lot/Extensions/LotArchitectureBuildModeExtensions.cs +++ b/Assets/Scripts/OpenTS2/Scenes/Lot/Extensions/LotArchitectureBuildModeExtensions.cs @@ -1,4 +1,5 @@ -using Codice.Utils; +using Codice.CM.Triggers; +using Codice.Utils; using log4net.Core; using OpenTS2.Content.DBPF; using System; @@ -37,7 +38,7 @@ internal static class LotArchitectureBuildModeExtensions /// The Pattern2 of the wall /// upon total failure; no walls placed. /// if some walls were placed. if all wall segments placed. - public static bool? CreateWall(this LotArchitecture Architecture, Vector2 From, + public static int[]? CreateWall(this LotArchitecture Architecture, Vector2 From, Vector2 To, int Floor, WallType Type = WallType.Normal, ushort PatternFront = ushort.MaxValue, ushort PatternBack = ushort.MaxValue) { //get the wall's direction vector @@ -53,19 +54,22 @@ internal static class LotArchitectureBuildModeExtensions } if ((Math.Abs(dirVector.x) != 1 || dirVector.y != 0) && (Math.Abs(dirVector.y) != 1 || dirVector.x != 0) && (Math.Abs(dirVector.x) != 1 || Math.Abs(dirVector.y) != 1)) // valid directions for a wall - return false; + return null; //subdivide the wall into 1 unit lengths (otherwise wall paints will appear stretchy) var wallLength = (double)Math.Abs(Vector2.Distance(From, To)); - if (diagonal) wallLength *= 0.7; + if (diagonal) wallLength *= 0.8; int successfulWallSegments = 0, totalSegments = (int)wallLength; + int[] createdWallIDs = new int[totalSegments]; + for (int segment = 0; segment < (wallLength); segment++) { var fooFrom = From + (dirVector * segment); var fooTo = From + (dirVector * (segment + 1)); //Add wall to wallgraph if (!Architecture.WallGraphAll.PushWall(fooFrom, fooTo, Floor, out int LayerID)) continue; + createdWallIDs[segment] = LayerID; //Add wall layer data Architecture.WallLayer.Walls.Add(LayerID, new WallLayerEntry() { @@ -77,7 +81,7 @@ internal static class LotArchitectureBuildModeExtensions successfulWallSegments++; } if (successfulWallSegments <= 0) return null; // total failure - return successfulWallSegments < totalSegments ? false : true; // somewhat / complete success code + return createdWallIDs; // somewhat / complete success code } /// /// Deletes wall segments between the two points provided on the given floor @@ -121,6 +125,18 @@ internal static class LotArchitectureBuildModeExtensions if (successfulWallSegments <= 0) return null; // total failure return successfulWallSegments < totalSegments ? false : true; // somewhat / complete success code } + public static void DeleteAllWalls(this LotArchitecture Architecture, params int[] WallLayerIDs) + { + if (WallLayerIDs.Length <= 0) return; + foreach(var ID in WallLayerIDs) + { + //Remove wall from wallgraph + if (Architecture.WallGraphAll.RemoveWalls(WallLayerIDs) == 0) continue; + //Remove wall layer data + foreach(var id in WallLayerIDs) + Architecture.WallLayer.Walls.Remove(id); + } + } /// /// Checks to see if the given pattern name is referenced; if it isn't, will reference it in the /// and returns the PatternID of the (potentially newly) referenced pattern From 854644f2ca6afbbdd19d21147e60333d4b91bcd2 Mon Sep 17 00:00:00 2001 From: Jeremy Glazebrook Date: Sun, 21 Jan 2024 20:40:35 -0500 Subject: [PATCH 04/15] Remove comment. --- .../Scripts/OpenTS2/Engine/Modes/Build/Tools/WallTool.cs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/WallTool.cs b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/WallTool.cs index 26e31845..0cf38947 100644 --- a/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/WallTool.cs +++ b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/WallTool.cs @@ -59,14 +59,6 @@ protected override void CheckMode() /// protected override void DoAction(bool Undoing = false) { - //NEEDS REFACTOR REALLY BAD - //Get layer IDs from the created walls when making a facade - //that way, we only delete walls SUCCESSFULLY MADE and also it won't be so buggy - //and performance will be (slightly) better - //please do this soon jeremy >.< - //--- - //Jan 21st: i did. - bool actionSelected = !deletingWalls; Vector2Int destination = toolDragEnd; if (deletingWalls) destination = toolLastActionDragEnd; From 0ea5225687ebf413bf6f18c0cf9c123d416440d1 Mon Sep 17 00:00:00 2001 From: Jeremy Glazebrook Date: Sun, 21 Jan 2024 23:02:20 -0500 Subject: [PATCH 05/15] Fix bug with detecting floors and implemented feature into terrain leveling to respect elevations of floors beneath this one. --- .../Engine/Modes/Build/BuildModeServer.cs | 74 +++++++++++++++++-- .../Modes/Build/Tools/FoundationTool.cs | 9 ++- .../LotArchitectureBuildModeExtensions.cs | 6 +- 3 files changed, 78 insertions(+), 11 deletions(-) diff --git a/Assets/Scripts/OpenTS2/Engine/Modes/Build/BuildModeServer.cs b/Assets/Scripts/OpenTS2/Engine/Modes/Build/BuildModeServer.cs index 95462a30..5c290d75 100644 --- a/Assets/Scripts/OpenTS2/Engine/Modes/Build/BuildModeServer.cs +++ b/Assets/Scripts/OpenTS2/Engine/Modes/Build/BuildModeServer.cs @@ -304,15 +304,46 @@ void OrderPoints(ref Vector2Int A, ref Vector2Int B) /// bool RegionValid(Vector2Int From, Vector2Int To) => Math.Abs(From.x - To.x) * Math.Abs(From.y - To.y) != 0; - public bool IsFloorAt(Vector2Int Position, int Level = 0) + /// + /// Checks to see if there is a floor at the given location. + /// If is provided as , it will check floors on ALL levels. + /// + /// + /// + /// + public bool IsFloorAt(Vector2Int Position, int? Level = default) { - Level = -architecture.BaseFloor + Level; + bool inquire(int level, int index) + { + var value = architecture.FloorPatterns.Data[level][index]; + return value.w != 0 || value.x != 0 || value.y != 0 || value.z != 0; + } + + int level = 0; + bool allLevels = Level == default; + if (!allLevels) + level = -architecture.BaseFloor + Level.Value; + var mPos = Position; + + bool inquiryList(int level, int index) + { + if (inquire(level, index)) return true; + if (index == 0) return false; + if (inquire(level, index - 1)) return true; + index = ((mPos.x - 1) * architecture.FloorPatterns.Height) + mPos.y; + if (inquire(level, index)) return true; + return false; + } + int index = (mPos.x * architecture.FloorPatterns.Height) + mPos.y; - var value = architecture.FloorPatterns.Data[Level][index]; + if (!allLevels) + return inquiryList(level, index); - return value.w != 0 || value.x != 0 || value.y != 0 || value.z != 0; + for (level = architecture.BaseFloor; level < architecture.FloorPatterns.Data.Length; level++) + if (inquiryList(level, index)) return true; + return false; } /// @@ -388,7 +419,8 @@ public void CreateFloors(Vector2Int From, Vector2Int To, string PatternName, int } public void CreateFloors(Vector2Int From, Vector2Int To, ushort PatternID, int Level = 0, bool ModifyTerrain = true) => CreateFloors(From, To, new Files.Formats.DBPF.Vector4(PatternID, PatternID, PatternID, PatternID), Level, ModifyTerrain); - public void CreateFloors(Vector2Int From, Vector2Int To, Files.Formats.DBPF.Vector4 QuarterTilePatternIDs, int Level = 0, bool ModifyTerrain = true) + public void CreateFloors(Vector2Int From, Vector2Int To, + Vector4 QuarterTilePatternIDs, int Level = 0, bool ModifyTerrain = true) { if (!RegionValid(From, To)) return; // check area nonzero @@ -441,7 +473,18 @@ public void CreateFloors(Vector2Int From, Vector2Int To, Files.Formats.DBPF.Vect loadedLot.InvalidateFloors(); // invalidating floors also may incur a terrain re-evaluation if necessary } - public void LevelRegion(Vector2Int From, Vector2Int To, float Elevation = 0, int Floor = 0) + /// + /// Levels a region of terrain/elevation map. + /// + /// The point to start at + /// The point to go to. + /// What elevation value to level to. + /// Which level of the Elevation Map to perform the modification. + /// If true, will ensure each level beneath does not exceed this elevation. + /// Only greater elevations will be modified, lower ones will be ignored. + /// In the event the terrain on a lower floor exceeds the elevation here on this floor, by how much to + /// decrease to yield the elevation of the terrain on the lower floor? + public void LevelRegion(Vector2Int From, Vector2Int To, float Elevation = 0, int Floor = 0, bool LevelFloorsBeneathMe = true, float LevelBeneathMeDelta = -0f) { if (!RegionValid(From, To)) return; Floor = -architecture.BaseFloor + Floor; @@ -477,6 +520,23 @@ public void LevelRegion(Vector2Int From, Vector2Int To, float Elevation = 0, int dataSet[index] = Elevation; levelModify = true; + + //level beneath me + if (LevelFloorsBeneathMe) + { + try + { + for (int elevationLevel = Floor; elevationLevel > 0; elevationLevel--) + { + ref float[] meValDataSet = ref arr.Data[elevationLevel - 1]; + meValDataSet[index] = Math.Min(Elevation + LevelBeneathMeDelta, meValDataSet[index]); + } + } + catch (Exception e) + { + Debug.LogError($"LevelRegion() :: LevelBeneathMe error: {e.Message}"); + } + } } } @@ -534,7 +594,7 @@ public bool ModifyTerrain(Vector2Int Position, int Radius, float Strength, Terra int index = (mPos.x * architecture.Elevation.Height) + mPos.y; //The Sims 2 won't allow any terrain modifications if the cursor is directly over unexposed terrain - if (ConstrainedFloorElevation && IsFloorAt(mPos)) + if (ConstrainedFloorElevation && IsFloorAt(mPos, Floor)) return false; bool levelModify = false; diff --git a/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/FoundationTool.cs b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/FoundationTool.cs index f73d5ba7..017b4e00 100644 --- a/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/FoundationTool.cs +++ b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/FoundationTool.cs @@ -62,8 +62,13 @@ protected override void DoAction(bool Undo = false) int currFloor = 0; int nextFloor = currFloor + 1; - float elevation = BuildModeServer.PollElevation(ToolDragOrigin, 0) + FoundationHeight; - BuildModeServer.LevelRegion(ToolDragOrigin, ToolDragDestination, elevation, nextFloor); + float elevation = BuildModeServer.PollElevation(ToolDragOrigin, ToolDragFloor); + if (ToolDragFloor == 0) + elevation += FoundationHeight; + //This levels the Elevation map where the floor is on this foundation. + //This makes the walls stubby and the floor appear seamless. This also uses the LevelBeneathMe feature of the function. + //It will ensure all terrain beneath the foundation is less than the elevation -.1f. + BuildModeServer.LevelRegion(ToolDragOrigin, ToolDragDestination, elevation, nextFloor, true, -.1f); if (!Undo) { BuildModeServer.CreateWalls(ToolDragOrigin, ToolDragDestination, currFloor, diff --git a/Assets/Scripts/OpenTS2/Scenes/Lot/Extensions/LotArchitectureBuildModeExtensions.cs b/Assets/Scripts/OpenTS2/Scenes/Lot/Extensions/LotArchitectureBuildModeExtensions.cs index dd97a631..ad48ac49 100644 --- a/Assets/Scripts/OpenTS2/Scenes/Lot/Extensions/LotArchitectureBuildModeExtensions.cs +++ b/Assets/Scripts/OpenTS2/Scenes/Lot/Extensions/LotArchitectureBuildModeExtensions.cs @@ -58,9 +58,9 @@ internal static class LotArchitectureBuildModeExtensions //subdivide the wall into 1 unit lengths (otherwise wall paints will appear stretchy) var wallLength = (double)Math.Abs(Vector2.Distance(From, To)); - if (diagonal) wallLength *= 0.8; + if (diagonal) wallLength *= 0.7; - int successfulWallSegments = 0, totalSegments = (int)wallLength; + int successfulWallSegments = 0, totalSegments = (int)Math.Round(wallLength); int[] createdWallIDs = new int[totalSegments]; for (int segment = 0; segment < (wallLength); segment++) @@ -69,6 +69,8 @@ internal static class LotArchitectureBuildModeExtensions var fooTo = From + (dirVector * (segment + 1)); //Add wall to wallgraph if (!Architecture.WallGraphAll.PushWall(fooFrom, fooTo, Floor, out int LayerID)) continue; + if (createdWallIDs.Length <= segment) + Array.Resize(ref createdWallIDs, segment + 1); createdWallIDs[segment] = LayerID; //Add wall layer data Architecture.WallLayer.Walls.Add(LayerID, new WallLayerEntry() From 67540e6a6d10a284502d5a2542d6416f782b3f1d Mon Sep 17 00:00:00 2001 From: Jeremy Glazebrook Date: Mon, 9 Dec 2024 18:53:55 -0500 Subject: [PATCH 06/15] Add build tools enum for ease of use and start on Runtime Wall Controller and basic room calculation --- .../Engine/Modes/Build/BuildModeServer.cs | 34 +- .../OpenTS2/Engine/Modes/Build/BuildTools.cs | 12 + .../Engine/Modes/Build/BuildTools.cs.meta | 11 + .../Modes/Build/Tools/AbstractBuildTool.cs | 57 ++- .../Engine/Modes/Build/Tools/FloorTool.cs | 2 +- .../Modes/Build/Tools/FoundationTool.cs | 1 + .../Engine/Modes/Build/Tools/HandTool.cs | 1 + .../Modes/Build/Tools/TerrainBrushTool.cs | 1 + .../Engine/Modes/Build/Tools/WallTool.cs | 12 +- .../OpenTS2/Engine/Tests/BuildModeTest.cs | 2 +- Assets/Scripts/OpenTS2/Scenes/Lot/LotLoad.cs | 179 +++++--- Assets/Scripts/OpenTS2/Scenes/Lot/Room.meta | 8 + .../Scenes/Lot/Room/RuntimeWallController.cs | 431 ++++++++++++++++++ .../Lot/Room/RuntimeWallController.cs.meta | 11 + .../UI/Layouts/Lot/LotViewBuildModeHUD.cs | 48 +- UpgradeLog.htm | 276 +++++++++++ 16 files changed, 997 insertions(+), 89 deletions(-) create mode 100644 Assets/Scripts/OpenTS2/Engine/Modes/Build/BuildTools.cs create mode 100644 Assets/Scripts/OpenTS2/Engine/Modes/Build/BuildTools.cs.meta create mode 100644 Assets/Scripts/OpenTS2/Scenes/Lot/Room.meta create mode 100644 Assets/Scripts/OpenTS2/Scenes/Lot/Room/RuntimeWallController.cs create mode 100644 Assets/Scripts/OpenTS2/Scenes/Lot/Room/RuntimeWallController.cs.meta create mode 100644 UpgradeLog.htm diff --git a/Assets/Scripts/OpenTS2/Engine/Modes/Build/BuildModeServer.cs b/Assets/Scripts/OpenTS2/Engine/Modes/Build/BuildModeServer.cs index 5c290d75..25d7ff18 100644 --- a/Assets/Scripts/OpenTS2/Engine/Modes/Build/BuildModeServer.cs +++ b/Assets/Scripts/OpenTS2/Engine/Modes/Build/BuildModeServer.cs @@ -16,15 +16,6 @@ namespace OpenTS2.Engine.Modes.Build { - internal enum BuildTools - { - None, - Hand, - Wall, - TerrainBrush, - Foundation, - Floor, - } /// /// Controls the flow of changes to the lot architecture and serves the functionality for Build Mode @@ -96,8 +87,7 @@ public enum TerrainModificationModes private readonly StringBuilder lotHistory = new StringBuilder(); private readonly LotLoad loadedLot; - private LotArchitecture architecture => loadedLot.architecture; - + private LotArchitecture architecture => loadedLot.Architecture; private bool ConstrainedFloorElevation => CheatSystem.GetProperty("constrainfloorelevation").GetStringValue().ToLower() == "true"; //PUBLIC @@ -162,14 +152,24 @@ void Init() //set drywall design pattern (used so frequently we can save a little time frontloading it) architecture.EnsurePatternReferenced("blank", LotArchitecture.ArchitectureGameObjectTypes.wall, out dryWallDesignPattern, out _); } - + /// + /// Changes the currently used tool by the User. + /// Passing will drop the current tool, if held. + /// + /// public void ChangeTool(BuildTools Tool) { - if (CurrentTool != null) CurrentTool.SetActive(false); + if (CurrentTool != null) + { // A tool is currently being used. + if (Tool == SelectedTool) + return; // the newly selected tool is the same as the one currently held, exit. + CurrentTool.OnToolCancel(Tool != BuildTools.None ? "The user selected a different tool." : "The current tool has been dropped."); + CurrentTool.SetActive(false); + } switch(Tool) { default: - case BuildTools.None: + case BuildTools.None: CurrentTool = null; break; case BuildTools.Foundation: case BuildTools.Hand: @@ -246,7 +246,7 @@ public void ChangeTool(BuildTools Tool) createdWallIDs = architecture.CreateWall(wall.A, wall.B, Floor, Type, front, back); if (createdWallIDs != null) // walls were placed here - { + { loadedLot.InvalidateWalls(); LogHistory($"Created wall(s). {argsStr}", "Create Walls"); return createdWallIDs; @@ -255,6 +255,10 @@ public void ChangeTool(BuildTools Tool) return null; } /// + /// Causes the room detection system to re-evaluate the lot. + /// + public void SignalRoomsInvalidate() => loadedLot.EvaluateRoomMap(); + /// /// Clears out all walls in the specified region with the given wall creation options /// /// diff --git a/Assets/Scripts/OpenTS2/Engine/Modes/Build/BuildTools.cs b/Assets/Scripts/OpenTS2/Engine/Modes/Build/BuildTools.cs new file mode 100644 index 00000000..626c10ae --- /dev/null +++ b/Assets/Scripts/OpenTS2/Engine/Modes/Build/BuildTools.cs @@ -0,0 +1,12 @@ +namespace OpenTS2.Engine.Modes.Build +{ + internal enum BuildTools + { + None, + Hand, + Wall, + TerrainBrush, + Foundation, + Floor, + } +} diff --git a/Assets/Scripts/OpenTS2/Engine/Modes/Build/BuildTools.cs.meta b/Assets/Scripts/OpenTS2/Engine/Modes/Build/BuildTools.cs.meta new file mode 100644 index 00000000..979e247e --- /dev/null +++ b/Assets/Scripts/OpenTS2/Engine/Modes/Build/BuildTools.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: be91059a50da924489cf226bdd5d6d45 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/AbstractBuildTool.cs b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/AbstractBuildTool.cs index 7320432c..878da93a 100644 --- a/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/AbstractBuildTool.cs +++ b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/AbstractBuildTool.cs @@ -47,26 +47,61 @@ internal abstract class AbstractBuildTool /// The name of this tool /// public abstract string ToolName { get; } - + /// + /// The current type of tool this instance is acting as + /// + public abstract BuildTools ToolType { get; } + /// + /// True when the tool is actively being used by the user. (A wall is being created, for instance) + /// public bool IsHolding { get; protected set; } + /// + /// True when the tool is not being actively used but is ready for user input + /// public bool IsActive { get; private set; } = false; + /// + /// The position within the lot boundaries of the tool at the current time + /// public Vector3 ToolLotPosition { get; protected set; } + /// + /// The position on the grid that the tool is currently nearest to + /// public Vector2 ToolGridPosition { get; protected set; } - + /// + /// Sets the property + /// + /// public void SetActive(bool Activated) { IsActive = Activated; OnActiveChanged(Activated); } protected abstract void OnActiveChanged(bool NewValue); - + /// + /// Called once per frame for the tool to process changes between frames + /// + /// public virtual void OnToolUpdate(BuildToolContext Context) { ToolLotPosition = Context.WandPosition; ToolGridPosition = Context.GridPosition; } + /// + /// Called when a tool begins to be used by the user + /// + /// public abstract void OnToolStart(BuildToolContext Context); + /// + /// Called when a tool is cancelled. + /// Note: Calling this at any time will immediately cancel the current tool action, you can give a reason to add clarity + /// to why this was called. + /// + /// public abstract void OnToolCancel(string Reason = null); + /// + /// Called when the user commits to an action. (Left click) + /// + /// public virtual void OnToolFinalize(BuildToolContext Context) => OnFinalizeTool?.Invoke(this); } @@ -188,7 +223,7 @@ public override void OnToolUpdate(BuildToolContext Context) } //check if player change wall creation type - CheckMode(); + CheckDeleteMode(); if(dirtyToolDragEnd != toolDragEnd) //clear any created wall facades @@ -219,7 +254,7 @@ public override void OnToolFinalize(BuildToolContext Context) } //check if player change creation type - CheckMode(); + CheckDeleteMode(); //Create / Delete the area DoAction(); @@ -239,13 +274,23 @@ public override void OnToolCancel(string Reason) Debug.Log($"{ToolName} cancelled. Reason: {Reason ?? "none given"}"); } - protected virtual void CheckMode() + protected virtual void CheckDeleteMode() { //check if deleting objects DeleteMode = false; if (Input.GetKey(KeyCode.LeftControl)) DeleteMode = true; } + /// + /// Performs the action that this tool advertises. + /// Note: This is not the same thing as as that is distinctly + /// when the user finishes the action. can be called many times depending on the implementation. + /// + /// protected abstract void DoAction(bool Undo = false); + /// + /// Same as except with the intention of previewing the action before committing it + /// + /// protected virtual void DoHoverAction(bool Undo = false) => DoAction(Undo); } } diff --git a/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/FloorTool.cs b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/FloorTool.cs index 3e8b11f3..6a8a745a 100644 --- a/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/FloorTool.cs +++ b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/FloorTool.cs @@ -45,7 +45,7 @@ internal interface IPatternSelectableBuildTool internal class FloorTool : AbstractRegionSelectBuildTool, IPatternSelectableBuildTool { public override string ToolName => "Floor Tool"; - + public override BuildTools ToolType => BuildTools.Floor; public bool IDPainting { get; private set; } public string PatternName { get; private set; } public ushort PatternID { get; private set; } diff --git a/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/FoundationTool.cs b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/FoundationTool.cs index 017b4e00..6f714be4 100644 --- a/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/FoundationTool.cs +++ b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/FoundationTool.cs @@ -35,6 +35,7 @@ public FoundationTool(BuildModeServer Server, } public override string ToolName => "Foundation Tool"; + public override BuildTools ToolType => BuildTools.Foundation; //**PATTERN /// diff --git a/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/HandTool.cs b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/HandTool.cs index 552fc1e7..f2123bd2 100644 --- a/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/HandTool.cs +++ b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/HandTool.cs @@ -17,6 +17,7 @@ internal class HandTool : AbstractBuildTool bool IsHoldingObject => holdingObjectReference != null; public override string ToolName => "Hand Tool"; + public override BuildTools ToolType => BuildTools.Hand; /// /// Creates a new on the specified lot diff --git a/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/TerrainBrushTool.cs b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/TerrainBrushTool.cs index ce06fd9e..78882de4 100644 --- a/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/TerrainBrushTool.cs +++ b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/TerrainBrushTool.cs @@ -53,6 +53,7 @@ void Init() } public override string ToolName => "Terrain Tool"; + public override BuildTools ToolType => BuildTools.TerrainBrush; protected override void OnActiveChanged(bool NewValue) { diff --git a/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/WallTool.cs b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/WallTool.cs index 0cf38947..b2721ce3 100644 --- a/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/WallTool.cs +++ b/Assets/Scripts/OpenTS2/Engine/Modes/Build/Tools/WallTool.cs @@ -40,10 +40,12 @@ internal class WallTool : AbstractRegionSelectBuildTool public WallTool(BuildModeServer Server) : base(Server) { } public override string ToolName => "Wall Tool"; + public override BuildTools ToolType => BuildTools.Wall; + /// /// Updates depending on the player's current input /// - protected override void CheckMode() + protected override void CheckDeleteMode() { //creation mode WallCreationModes mode = WallCreationModes.Single; @@ -51,7 +53,7 @@ protected override void CheckMode() wallCreateMode = mode; //check delete mode - base.CheckMode(); + base.CheckDeleteMode(); } /// @@ -95,7 +97,11 @@ protected override void DoAction(bool Undoing = false) if (createdWallIDs != null) Array.ForEach(createdWallIDs, (int item) => facadeWallIDs.Add(item)); } - else if(facadeWallIDs.Any()) facadeWallIDs.Clear(); + else if (facadeWallIDs.Any()) + { + facadeWallIDs.Clear(); + buildModeServer.SignalRoomsInvalidate(); + } } else { diff --git a/Assets/Scripts/OpenTS2/Engine/Tests/BuildModeTest.cs b/Assets/Scripts/OpenTS2/Engine/Tests/BuildModeTest.cs index 11952f36..7a6885f7 100644 --- a/Assets/Scripts/OpenTS2/Engine/Tests/BuildModeTest.cs +++ b/Assets/Scripts/OpenTS2/Engine/Tests/BuildModeTest.cs @@ -30,7 +30,7 @@ public class BuildModeTest : MonoBehaviour { // Init LotLoad _loadedLotProvider; - LotArchitecture _architectrue => _loadedLotProvider.architecture; + LotArchitecture _architectrue => _loadedLotProvider.Architecture; TestLotViewCamera viewCamera; BuildModeServer buildServer; LotViewHUDController hudController; diff --git a/Assets/Scripts/OpenTS2/Scenes/Lot/LotLoad.cs b/Assets/Scripts/OpenTS2/Scenes/Lot/LotLoad.cs index aef215c2..4588e6ef 100644 --- a/Assets/Scripts/OpenTS2/Scenes/Lot/LotLoad.cs +++ b/Assets/Scripts/OpenTS2/Scenes/Lot/LotLoad.cs @@ -4,18 +4,16 @@ #undef NEW_INVALIDATE using OpenTS2.Common; -using OpenTS2.Content.DBPF.Scenegraph; -using OpenTS2.Content.DBPF; using OpenTS2.Content; -using OpenTS2.Files.Formats.DBPF; +using OpenTS2.Content.DBPF; +using OpenTS2.Content.DBPF.Scenegraph; using OpenTS2.Files; +using OpenTS2.Files.Formats.DBPF; using OpenTS2.Scenes.Lot.State; using System; using System.Collections.Generic; using System.IO; using System.Linq; -using System.Text; -using System.Threading.Tasks; using UnityEngine; namespace OpenTS2.Scenes.Lot @@ -26,42 +24,95 @@ namespace OpenTS2.Scenes.Lot /// public class LotLoad : MonoBehaviour { + #region private + private WorldState _state = new WorldState(1, WallsMode.Roof); + + private string _nhood; + private int _lotId; + + private DBPFFile _lotPackage; + + private List _lotObject = new List(); + private List _testObjects = new List(); + + private RuntimeWallController _wallController = new RuntimeWallController(); + #endregion + + #region public /// - /// Settings for how the lot should be loaded + /// Settings to dictate how the lot should be loaded /// public struct LotLoadSettings { [Flags] public enum LotViewLayers : int { + /// + /// Default - Do not display any architecture or objects + /// None = 0, + /// + /// Flag - Loads terrain when set + /// Terrain = 1, + /// + /// Flag - Loads walls when set + /// Walls = 2, + /// + /// Flag - Loads floors when set + /// Floors = 4, + /// + /// Flag - Loads objects when set + /// Objects = 8 } + /// + /// Generates the flags necessary to load all layers + /// public const LotViewLayers AllLayers = LotViewLayers.None | LotViewLayers.Terrain | LotViewLayers.Walls | LotViewLayers.Floors | LotViewLayers.Objects; /// /// Specifies which layers of the lot geometry should be loaded /// public LotViewLayers LoadLayers; - + /// + /// Makes a new using the specified layers. + /// Default is value -- to load all layers on the lot + /// + /// public LotLoadSettings(LotViewLayers loadLayers = AllLayers) { LoadLayers = loadLayers; } } - + /// + /// (Debug) N001 + /// public const string Default_NeighborhoodPrefix = "N001"; + /// + /// (Debug) 82 + /// public const int Default_LotID = 82; + /// + /// The current floor selected in the + /// public int Floor => _state.Level; - public WallsMode Mode = WallsMode.Roof; - - public int BaseFloor => architecture?.BaseFloor ?? 0; - public int MaxFloor => architecture?.FloorPatterns.Depth ?? 1; + /// + /// The current ViewMode in the + /// + /// + public WallsMode ViewMode = WallsMode.Roof; + public int BaseFloor => Architecture?.BaseFloor ?? 0; + public int MaxFloor => Architecture?.FloorPatterns.Depth ?? 1; + /// + /// The current which indicates how the level should appear + /// Changing this directly will log in the console, but should be followed up with to ensure + /// changes can be perceived in the world. + /// public WorldState WorldState { get => _state; @@ -70,14 +121,7 @@ public WorldState WorldState _state = value; Debug.Log($"World state updated: {value}"); } - } - - private WorldState _state = new WorldState(1, WallsMode.Roof); - - private string _nhood; - private int _lotId; - - private DBPFFile lotPackage; + } /// /// The currently selected Neighborhood Prefix (N001 by default) @@ -87,10 +131,11 @@ public WorldState WorldState /// The currently selected Lot ID in the selected (82 by default) /// public int LotID => _lotId; - - private List _lotObject = new List(); - private List _testObjects = new List(); - public LotArchitecture architecture; + /// + /// The base that this instance used to load the scene + /// + public LotArchitecture Architecture { get; private set; } + #endregion /// /// Loads the default lot @@ -106,7 +151,9 @@ public LotLoad(string Nhood, int LotID) { LoadLot(Nhood, LotID); } - + /// + /// Unloads the current lot and destroys each object instance in memory. + /// public void UnloadLot() { foreach (var obj in _lotObject) @@ -120,7 +167,7 @@ public void UnloadLot() /// /// Updates and and loads the lot. - /// + /// See: /// /// /// @@ -131,46 +178,43 @@ public void LoadLot(string neighborhoodPrefix, int id, LotLoadSettings Settings LoadLot(Settings); } - + /// + /// Unloads the current lot (if applicable) and loads the lot provided by + /// + /// The settings to use to load the lot public void LoadLot(LotLoadSettings Settings = default) { //Unload previous session UnloadLot(); var contentProvider = ContentProvider.Get(); - + //Find package file for the lot given var lotsFolderPath = Path.Combine(Filesystem.GetUserPath(), $"Neighborhoods/{NeighborhoodPrefix}/Lots"); var lotFilename = $"{NeighborhoodPrefix}_Lot{LotID}.package"; var lotFullPath = Path.Combine(lotsFolderPath, lotFilename); if (!File.Exists(lotFullPath)) { - return; + throw new FileNotFoundException($"LoadLot(): File not found. {lotFullPath}"); } - lotPackage = contentProvider.AddPackage(lotFullPath); + _lotPackage = contentProvider.AddPackage(lotFullPath); //add objects from scenegraph (primitive need to change to more robust solution later) InvalidateObjects(); - architecture = new LotArchitecture(); + Architecture = new LotArchitecture(); - architecture.LoadFromPackage(lotPackage); -#if DEBUG - ArchitecturePreBakeDebug(); -#endif - architecture.CreateGameObjects(_lotObject); + Architecture.LoadFromPackage(_lotPackage); + Architecture.CreateGameObjects(_lotObject); - Mode = WallsMode.Roof; - _state = new WorldState(Floor, Mode); - architecture.UpdateState(_state); + ViewMode = WallsMode.Roof; // Default value is Roof + _state = new WorldState(Floor, ViewMode); + InvalidateState(); } - - void ArchitecturePreBakeDebug() - { // Bisquicks testing playground :D - - } - + /// + /// Flushes all currently loaded objects and reloads them from package + /// public void InvalidateObjects() { //Clear any objects on the scene @@ -178,7 +222,7 @@ public void InvalidateObjects() var contentProvider = ContentProvider.Get(); // Go through each lot object. - foreach (var entry in lotPackage.Entries) + foreach (var entry in _lotPackage.Entries) { if (entry.GlobalTGI.TypeID != TypeIDs.LOT_OBJECT) { @@ -210,8 +254,11 @@ public void InvalidateObjects() } } } - - void baseInvalidateGroup(LotArchitecture.ArchitectureGameObjectTypes group) + /// + /// Invalidates the specified group supplied by + /// + /// + void BaseInvalidateGroup(LotArchitecture.ArchitectureGameObjectTypes group) { #if NEW_INVALIDATE architecture.InvalidateComponent(group); @@ -219,7 +266,7 @@ void baseInvalidateGroup(LotArchitecture.ArchitectureGameObjectTypes group) #endif if (group == LotArchitecture.ArchitectureGameObjectTypes.roof) { - architecture.InvalidateComponent(group); + Architecture.InvalidateComponent(group); return; } //old @@ -232,26 +279,30 @@ void baseInvalidateGroup(LotArchitecture.ArchitectureGameObjectTypes group) _lotObject.Remove(groupParent); } //rebuild new mesh from memory - architecture.CreateGameObjectsOfType(_lotObject, group); + Architecture.CreateGameObjectsOfType(_lotObject, group); } public void InvalidateFloors() { - baseInvalidateGroup(LotArchitecture.ArchitectureGameObjectTypes.floor); + BaseInvalidateGroup(LotArchitecture.ArchitectureGameObjectTypes.floor); InvalidateTerrain(); } - public void InvalidateWalls() => baseInvalidateGroup(LotArchitecture.ArchitectureGameObjectTypes.wall); - void InvalidateTerrain() => baseInvalidateGroup(LotArchitecture.ArchitectureGameObjectTypes.terrain); + public void InvalidateWalls() => BaseInvalidateGroup(LotArchitecture.ArchitectureGameObjectTypes.wall); + public void InvalidateTerrain() => BaseInvalidateGroup(LotArchitecture.ArchitectureGameObjectTypes.terrain); /// /// After changing the , use this method to update the visual /// - internal void InvalidateState() + public void InvalidateState() { - architecture.UpdateState(_state); + Architecture.UpdateState(_state); UpdateObjectVisibility(_state.Level); } - + /// + /// Sets the given object's visibility to be Visible/Invisible + /// + /// + /// private void SetObjectVisiblity(GameObject obj, bool visible) { foreach (MeshRenderer renderer in obj.GetComponentsInChildren()) @@ -264,15 +315,27 @@ private void SetObjectVisiblity(GameObject obj, bool visible) renderer.shadowCastingMode = visible ? UnityEngine.Rendering.ShadowCastingMode.On : UnityEngine.Rendering.ShadowCastingMode.ShadowsOnly; } } - + /// + /// Sets objects to be visible based on if they should be seen by the player or not. + /// This uses the to determine up to which floor an object should be viewable. + /// + /// private void UpdateObjectVisibility(int viewLevel) { foreach (GameObject obj in _testObjects) { - int level = architecture.GetLevelAt(obj.transform.GetChild(0).localPosition); + int level = Architecture.GetLevelAt(obj.transform.GetChild(0).localPosition); SetObjectVisiblity(obj, level < viewLevel); } } + + /// + /// Regenerates the RoomMap from scratch. [BETA] + /// + internal void EvaluateRoomMap() + { + _wallController.GenerateAll(Architecture); + } } } diff --git a/Assets/Scripts/OpenTS2/Scenes/Lot/Room.meta b/Assets/Scripts/OpenTS2/Scenes/Lot/Room.meta new file mode 100644 index 00000000..8c428f6d --- /dev/null +++ b/Assets/Scripts/OpenTS2/Scenes/Lot/Room.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ba84f982724998349b0988abe41c5515 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Scenes/Lot/Room/RuntimeWallController.cs b/Assets/Scripts/OpenTS2/Scenes/Lot/Room/RuntimeWallController.cs new file mode 100644 index 00000000..471fb78f --- /dev/null +++ b/Assets/Scripts/OpenTS2/Scenes/Lot/Room/RuntimeWallController.cs @@ -0,0 +1,431 @@ +// JDrocks450 11-22-2023 on GitHub + +#define NEW_INVALIDATE +#undef NEW_INVALIDATE + +using OpenTS2.Content.DBPF; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Unity.Plastic.Newtonsoft.Json; +using UnityEngine; + +namespace OpenTS2.Scenes.Lot +{ + /// + /// BETA implementation. + /// Needs a lot of work to be shippable. + /// Will need to revisit this concept. + /// + internal class RuntimeWallController + { + [Serializable] + public struct GraphPlot + { + public GraphPlot(float x, float y) + { + X = x; + Y = y; + } + public float X { get; set; } + public float Y { get; set; } + } + [Serializable] + public struct GraphLine + { + public GraphLine(int fromID, int toID) + { + FromPlotID = fromID; + ToPlotID = toID; + } + + /// + /// The this line originates + /// + public int FromPlotID { get; set; } + /// + /// The this line ends at + /// + public int ToPlotID { get; set; } + + public override string ToString() => $"({FromPlotID} -> {ToPlotID})"; + } + + /// + /// A map of all positions in the WallGraph + /// For only points that are on line segments, see: + /// + public Dictionary Positions { get; private set; } = new Dictionary(); + /// + /// that are at the corners of two connected line segments + /// + public HashSet JointPositions { get; private set; } = new HashSet(); + /// + /// Lines between that form a straight wall of at least 1 unit length + /// + public Dictionary Lines { get; private set; } = new Dictionary(); + /// + /// Groups of that all form one enclosed shape (Room) on the lineplot + /// + public Dictionary> Rooms { get; private set; } = new Dictionary>(); + + /// + /// A serialized RoomState -- the current state of the walls on the lot + /// + [Serializable] + public class RoomPackage + { + public Dictionary Positions; + public HashSet JointPositions; + public Dictionary Lines; + public Dictionary> Rooms; + public int Width, Height; + } + /// + /// Simple distance formula, calculates the distance in units between two coordinates + /// + /// + /// + /// + double Distance(Vector2 p1, Vector2 p2) + { + return Math.Sqrt(Math.Pow(p1.x - p2.x, 2) + Math.Pow(p1.y - p2.y, 2)); + } + /// + /// Determines if three points create a triangle, can be used to detect straight walls versus joints + /// + /// + /// + /// + /// + bool IsTriangle(Vector2 p1, Vector2 p2, Vector2 p3) + { + // Calculate the lengths of the sides + double a = Distance(p1, p2); + double b = Distance(p2, p3); + double c = Distance(p3, p1); + + // Check if the triangle inequality theorem holds for all sides + return a + b > c && b + c > a && c + a > b; + } + /// + /// Regenerates the room map by discarding the previous data + /// + /// + public void GenerateAll(LotArchitecture architecture) + { + var graph = architecture.WallGraphAll; + Dictionary positionsData = graph.Positions; + WallGraphLineEntry[] wallData = graph.Lines; + + if (!wallData.Any()) return; + if (!positionsData.Any()) return; + + System.Diagnostics.Stopwatch debugTimer = new System.Diagnostics.Stopwatch(); + debugTimer.Start(); + + GenerateLineGraph(positionsData, wallData); + long genLineGraph = debugTimer.ElapsedMilliseconds; + debugTimer.Restart(); + + GenerateRoomMap(); + long genRoomMap = debugTimer.ElapsedMilliseconds; + debugTimer.Restart(); + + PackageRoomMap(graph.Width, graph.Height); + long genPkg = debugTimer.ElapsedMilliseconds; + debugTimer.Stop(); + + long tTime = genLineGraph + genRoomMap + genPkg; + + UnityEngine.Debug.Log($"RoomMap(): Lines took {genLineGraph}ms, Rooms took {genRoomMap}ms, Package took {genPkg}ms" + + $" and altogether took {tTime}ms. "); + //GenerateImage(positionsData, graph.Width, graph.Height); + } + + private void PackageRoomMap(int Width, int Height) + { + //Serialize this to file + using (StringWriter strJson = new StringWriter()) + { + JsonSerializer.CreateDefault().Serialize(strJson, new RoomPackage() + { + JointPositions = JointPositions, + Lines = Lines, + Positions = Positions, + Rooms = Rooms, + Width = Width, + Height = Height + }, typeof(RoomPackage)); + File.WriteAllText("C:\\Users\\xXJDr\\OneDrive\\Desktop\\roommapts2.txt", strJson.ToString()); + } + } + + /// + /// This function takes the wall graph from package and processes it into a lineplot + /// of only significant points -- as in points that form corners to build shapes. + /// This function will also create the network of lines between the points. + /// + /// + /// + private void GenerateLineGraph(Dictionary positionsData, WallGraphLineEntry[] wallData) + { + //build a map of points that are referenced by lines. + //Position ID to List of LineIDs in WallGraph + Dictionary> PositionIDReferences = new Dictionary>(); + + void AddPositionReference(int PositionID, int LayerID) + { + //Check if the point exists in our wall graph + if (!positionsData.ContainsKey(PositionID)) return; + //position existing + if (PositionIDReferences.TryGetValue(PositionID, out HashSet references)) + references.Add(LayerID); + else + { + PositionIDReferences.Add(PositionID, new HashSet() { LayerID }); + if (!Positions.ContainsKey(PositionID)) + Positions.Add(PositionID, new GraphPlot(positionsData[PositionID].XPos, + positionsData[PositionID].YPos)); + } + } + + //find all points that are referenced by wall lines + foreach (var wall in wallData) + { + AddPositionReference(wall.FromId, wall.LayerId); + AddPositionReference(wall.ToId, wall.LayerId); + } + + //map lines to their layerIds + Dictionary lineMap = new Dictionary(); + foreach (var line in wallData) + lineMap.Add(line.LayerId, line); + + List processed = new List(); + HashSet WallLayerIDsOnLine = new HashSet(); + Lines.Clear(); + + //filter out positions that form straight lines to get a + //lineplot of all significant points -- e.g. the ones that form + //corners + //-- + //This is done by taking two connected wall lines and seeing if all three points + //on these two lines form a triangle with any area -- if they do, it's a bend + foreach (var positionItem in PositionIDReferences) + { + if (positionItem.Value.Count <= 1) // 1 or less connections can never form a wall + continue; // this is due to them being open-ended + else if (positionItem.Value.Count == 2 && processed.Contains(positionItem.Key)) + continue; // only two connections means it's already been processed and cannot be anything more + + int lineFrom = -1, lineTo = -1; + + //tunnelling function -- watch out for stack overflow by using cautiously + //keep scope to only one level on the lot at a time, and this function tree will + //end as soon as a line segment is found + // -- todo: set limit on tunnelling level to be diagonal line from lot corner to corner + void Try(int meID, int tunneled) + { + if (JointPositions.Contains(meID)) + { // already a joint -- don't bother with the detection + lineTo = meID; + return; + } + var references = PositionIDReferences[meID]; // find all wall lines that contain this point + if (references.Count <= 1) goto exit; // none references!! + if (references.Count > 2) + { + JointPositions.Add(meID); + lineTo = meID; + if (tunneled == 0) + return; + } + //very bad -- change ASAP + WallGraphLineEntry line1 = lineMap[references.ElementAt(0)]; + WallGraphLineEntry line2 = lineMap[references.ElementAt(1)]; + int other1 = line1.ToId == meID ? line1.FromId : line1.ToId; // which end isn't the current point? + if (other1 == meID) + goto exit; // catastropic error -- both ends are the same and also this point... how would this happen? + int other2 = line2.ToId == meID ? line2.FromId : line2.ToId; // which end isn't the current point or other point? + if (other2 == meID) + goto exit; // catastropic error -- see above + if (other1 == other2) + goto exit; // catastropic error -- see above + + //form a triangle using all three points + Vector2 pos1 = new Vector2(positionsData[other1].XPos, positionsData[other1].YPos); + Vector2 pos2 = new Vector2(positionsData[other2].XPos, positionsData[other2].YPos); + Vector2 center = new Vector2(positionsData[meID].XPos, positionsData[meID].YPos); + + //check if this is a bend -- has an area + if (!IsTriangle(center, pos1, pos2)) + { + processed.Add(meID); // point is spent + int next = processed.Contains(other2) ? other1 : other2; // pick the point we haven't visited yet + if (lineFrom == -1) + lineFrom = next == other2 ? other1 : other2; // from point is the origin point + Try(next, tunneled + 1); // tunnel until bend is found to complete the segment + return; + } + //found a bend ... close and complete this tunnel + JointPositions.Add(meID); + lineTo = meID; + return; + exit:; + } + + lineFrom = lineTo = -1; + //begin -- walk the current line until it finds a bend + //adds what it finds to Lines if it is indeed a line + //also adds to Joints collection + Try(positionItem.Key, 0); + + if (lineFrom != -1 && lineTo != -1 && lineFrom != lineTo) + Lines.Add(Lines.Count + 1, new GraphLine(lineFrom, lineTo)); + } + } + + /// + /// This function will walk the lineplot created during + /// finding lines that connect to one another to form shapes making up enclosed spaces. + /// + private void GenerateRoomMap() + { + IDictionary> dirtyRooms = new Dictionary>(); + Stack currentlyVisitingRoomPositions = new Stack(); + + foreach (var line in Lines) + { + int findingPositionID = line.Value.FromPlotID; + bool FindRoom(int currentLineID, int fromPositionID) + { + currentlyVisitingRoomPositions.Push(currentLineID); + var lineValue = Lines[currentLineID]; + var nextPoint = lineValue.ToPlotID != fromPositionID ? lineValue.ToPlotID : lineValue.FromPlotID; + if (nextPoint == findingPositionID) + { + //found a room + int[] points = currentlyVisitingRoomPositions.ToArray(); + //ensure room is valid + //AssertRoomValid(points); + //does this room already exist -- also calls AssertRoomValid() + if (!RoomExisting(-1, dirtyRooms, points)) + dirtyRooms.Add(dirtyRooms.Count + 1, points); // doesn't, add it + return true; + } + var results = Lines.Where(x => x.Value.FromPlotID == nextPoint || x.Value.ToPlotID == nextPoint); + int nextLineID = -1; + foreach (var result in results) + { + if (result.Key == currentLineID) continue; + nextLineID = result.Key; + } + if (nextLineID == -1) return false; + return FindRoom(nextLineID, nextPoint); + } + currentlyVisitingRoomPositions.Clear(); + FindRoom(line.Key, findingPositionID); + } + + Rooms.Clear(); + foreach(var item in dirtyRooms) + Rooms.Add(item.Key, item.Value); + } + + /// + /// Assures the supplied set of points can make a valid room. + /// + /// + /// + /// + public void AssertRoomValid(params int[] RoomPoints) + { + if (RoomPoints == default) + throw new NullReferenceException("RoomPoints passed as null reference."); + if (RoomPoints.Length < 4) + throw new InvalidDataException($"Rooms must have at least four points. This one supplied has {RoomPoints.Length}"); + } + + /// + /// Tests to see if the given room exists in + /// Supplying the RoomID will ensure the current room isn't compared to itself in the map. + /// It is determined to be the same room if all the points supplied match all the points on a given + /// Room in the room map. + /// + /// + /// + /// + public bool RoomExisting(int RoomID, params int[] RoomPoints) => RoomExisting(RoomID, Rooms, RoomPoints); + + /// + /// Tests to see if the given room exists in + /// Supplying the RoomID will ensure the current room isn't compared to itself in the map. + /// It is determined to be the same room if all the points supplied match all the points on a given + /// Room in the room map. + /// + /// + /// + /// + public bool RoomExisting(int RoomID, IDictionary> RoomCollection, params int[] RoomPoints) + { + AssertRoomValid(RoomPoints); + bool duplicate = false; + foreach (var otherRoom in RoomCollection) + { + if (otherRoom.Key == RoomID) + continue; // same as the room I'm comparing + if (otherRoom.Value.Count() != RoomPoints.Length) + continue; // not the same number of points + foreach (var point in otherRoom.Value) + { + duplicate = RoomPoints.Contains(point); + if (!duplicate) break; + } + if (duplicate) break; + } + return duplicate; + } + + public void GenerateImage(string exportFileName, Dictionary positionsData, int Width, int Height) + { + Texture2D roomMap = new Texture2D(Width, Height); + + Color[] colors = new Color[] { + Color.green, + Color.cyan, + Color.magenta, + Color.grey, + Color.yellow, + Color.blue + }; + + foreach (var drawLine in Lines.Values) + { + var position = positionsData[drawLine.FromPlotID]; + roomMap.SetPixel((int)position.XPos, (int)position.YPos, Color.red); + position = positionsData[drawLine.ToPlotID]; + roomMap.SetPixel((int)position.XPos, (int)position.YPos, Color.red); + } + + int index = -1; + foreach (var room in Rooms) + { + index++; + + Color drawColor = colors[index]; + foreach (var lineID in room.Value) + { + var drawLine = Lines[lineID]; + var position = positionsData[drawLine.FromPlotID]; + roomMap.SetPixel((int)position.XPos, (int)position.YPos, drawColor); + position = positionsData[drawLine.ToPlotID]; + roomMap.SetPixel((int)position.XPos, (int)position.YPos, drawColor); + } + } + + File.WriteAllBytes(exportFileName, roomMap.EncodeToPNG()); + } + } +} diff --git a/Assets/Scripts/OpenTS2/Scenes/Lot/Room/RuntimeWallController.cs.meta b/Assets/Scripts/OpenTS2/Scenes/Lot/Room/RuntimeWallController.cs.meta new file mode 100644 index 00000000..eae74992 --- /dev/null +++ b/Assets/Scripts/OpenTS2/Scenes/Lot/Room/RuntimeWallController.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 989c8164467e1524d9013a6579681d65 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewBuildModeHUD.cs b/Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewBuildModeHUD.cs index 4b8cd53f..aa14809b 100644 --- a/Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewBuildModeHUD.cs +++ b/Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewBuildModeHUD.cs @@ -151,8 +151,32 @@ private void CatalogItemSelected(object sender, CatalogObjectAsset e) /// void SwitchPage(int PageNumber) { + void EnableButtons() + { + var button = rootElement.GetChildByID(PreviousButton); + button.gameObject.SetActive(true); + button = rootElement.GetChildByID(NextButton); + button.gameObject.SetActive(true); + } + void DisableForward() + { + var button = rootElement.GetChildByID(NextButton); + button.gameObject.SetActive(false); + } + void DisableBackward() + { + var button = rootElement.GetChildByID(PreviousButton); + button.gameObject.SetActive(false); + } + + EnableButtons(); // any buttons that are disabled should be re-enabled for safety. + currentPage = PageNumber; - if (currentPage < 0) currentPage = 0; + if (currentPage <= 0) + { + currentPage = 0; + DisableBackward(); // first page, disable back button + } int startIndex = currentPage * itemsPerPage; @@ -177,6 +201,9 @@ void SwitchPage(int PageNumber) control.Components[0].gameObject.SetActive(true); control.Display(assetRef); } + + if (startIndex + itemsPerPage >= itemsFilter.Count()) // end of last page + DisableForward(); // disable forward button } public void Close() @@ -457,7 +484,7 @@ void BuildUIEventsMap() { (uint)BuildHUD_FloorsSubsortButtons.OtherButton, delegate { ActionInvokeSubSort("other"); } }, { (uint)BuildHUD_FloorsSubsortButtons.AllButton, delegate { ActionInvokeSubSort("all"); } }, { (uint)BuildHUD_FloorsSubsortButtons.TileButton, delegate { ActionInvokeSubSort("tile"); } }, - { (uint)BuildHUD_FloorsSubsortButtons.LinoleumButton, delegate { ActionInvokeSubSort("linoleum"); } }, + { (uint)BuildHUD_FloorsSubsortButtons.LinoleumButton, delegate { ActionInvokeSubSort("lino"); } }, }; } @@ -512,7 +539,12 @@ void ActionChangeTool(BuildTools Tool) BuildModeServer.Get().ChangeTool(Tool); } - + /// + /// Updates the User Interface to show the selected sort + /// See: to change the Subsort for this Sort + /// Note: This will cause whatever tool is currently being used to be cancelled. + /// + /// void ActionChangeSort(BuildHUD_Sorts SortPage) { ActionChangeTool(BuildTools.None); // drop current tool @@ -558,14 +590,20 @@ void ActionInvokeSubSort(string Subsort) Catalog.SetSubsort(Subsort); CurrentButtonEventContext.SetToggled(true); } - + /// + /// Invokes the Terrain brush tool and sets the size to Small by default + /// + /// void ActionSetTerrainBrushTool(BuildModeServer.TerrainModificationModes BrushMode) { ActionChangeTool(BuildTools.TerrainBrush); (BuildModeServer.Get().CurrentTool as TerrainBrushTool).CurrentBrushMode = BrushMode; ActionModifyTerrainBrushSize(TerrainBrushTool.TerrainBrushSizes.Small); } - + /// + /// Updates the User Interface and the Terrain tool to match the selected size + /// + /// void ActionModifyTerrainBrushSize(TerrainBrushTool.TerrainBrushSizes Size) { EnsureGroupToggled(typeof(BuildHUD_TerrainBrushSizeButtons)); diff --git a/UpgradeLog.htm b/UpgradeLog.htm new file mode 100644 index 00000000..bf44b1f8 --- /dev/null +++ b/UpgradeLog.htm @@ -0,0 +1,276 @@ + + + + Migration Report +

+ Migration Report -

\ No newline at end of file From f30f2cb52959f37ffe13ca3a41f77321992cd6a1 Mon Sep 17 00:00:00 2001 From: Ammar Askar Date: Fri, 20 Mar 2026 21:27:13 -0400 Subject: [PATCH 07/15] Fix merging with master --- Assets/Scenes/Tests/BuildModeTest.unity | 4 ++++ .../Components/AssetReferenceComponent.cs | 8 ++++---- Assets/Scripts/OpenTS2/Diagnostic/CheatSystem.cs | 2 ++ .../OpenTS2/Engine/Tests/BuildModeTest.cs | 16 +++++++--------- Assets/Scripts/OpenTS2/Scenes/Lot/LotLoad.cs | 6 +++--- .../OpenTS2/Scenes/Lot/LotTerrainComponent.cs | 13 +++++++++++++ .../OpenTS2/Scenes/Lot/LotWallComponent.cs | 2 +- .../UI/Layouts/Lot/LotViewBuildModeHUD.cs | 4 ++-- .../UI/Layouts/Lot/LotViewHUDController.cs.meta | 2 +- 9 files changed, 37 insertions(+), 20 deletions(-) diff --git a/Assets/Scenes/Tests/BuildModeTest.unity b/Assets/Scenes/Tests/BuildModeTest.unity index 6d522dbc..1af942d3 100644 --- a/Assets/Scenes/Tests/BuildModeTest.unity +++ b/Assets/Scenes/Tests/BuildModeTest.unity @@ -1870,6 +1870,10 @@ PrefabInstance: propertyPath: m_LocalEulerAnglesHint.z value: 0 objectReference: {fileID: 0} + - target: {fileID: 7238001765745231388, guid: 188047b711783b74aa73c17ff9d66147, type: 3} + propertyPath: TargetScene + value: + objectReference: {fileID: 0} m_RemovedComponents: [] m_SourcePrefab: {fileID: 100100000, guid: 188047b711783b74aa73c17ff9d66147, type: 3} --- !u!4 &2076958800 stripped diff --git a/Assets/Scripts/OpenTS2/Components/AssetReferenceComponent.cs b/Assets/Scripts/OpenTS2/Components/AssetReferenceComponent.cs index 563fba2a..06c54f49 100644 --- a/Assets/Scripts/OpenTS2/Components/AssetReferenceComponent.cs +++ b/Assets/Scripts/OpenTS2/Components/AssetReferenceComponent.cs @@ -63,8 +63,8 @@ public abstract class AssetPatternReferenceComponent : AssetReferenceComponent ///
protected virtual void LoadPatterns() { - var contentProvider = ContentProvider.Get(); - var catalogManager = CatalogManager.Get(); + var contentProvider = ContentManager.Instance; + var catalogManager = CatalogManager.Instance; var patternMap = Map; ushort highestId = patternMap.Count == 0 ? (ushort)0 : patternMap.Keys.Max(); @@ -137,7 +137,7 @@ protected virtual void LoadPatterns() //_patterns = new PatternMeshCollection(gameObject, patterns, Array.Empty(), this, FloorCount); } - protected virtual ScenegraphMaterialDefinitionAsset LoadMaterial(ContentProvider contentProvider, string name) + protected virtual ScenegraphMaterialDefinitionAsset LoadMaterial(ContentManager contentProvider, string name) { var material = contentProvider.GetAsset(new ResourceKey($"{name}_txmt", GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_TXMT)); @@ -146,7 +146,7 @@ protected virtual ScenegraphMaterialDefinitionAsset LoadMaterial(ContentProvider return material; } - protected virtual void PostLoadPatterns(ContentProvider contentProvider, ref PatternDescriptor[] patterns) + protected virtual void PostLoadPatterns(ContentManager contentProvider, ref PatternDescriptor[] patterns) { } diff --git a/Assets/Scripts/OpenTS2/Diagnostic/CheatSystem.cs b/Assets/Scripts/OpenTS2/Diagnostic/CheatSystem.cs index f342e7c1..91c1a950 100644 --- a/Assets/Scripts/OpenTS2/Diagnostic/CheatSystem.cs +++ b/Assets/Scripts/OpenTS2/Diagnostic/CheatSystem.cs @@ -4,6 +4,8 @@ using System.Reflection; using System.Text; using System.Threading.Tasks; +using Assets.Scripts.OpenTS2.Diagnostic; +using OpenTS2.Engine; using UnityEngine; namespace OpenTS2.Diagnostic diff --git a/Assets/Scripts/OpenTS2/Engine/Tests/BuildModeTest.cs b/Assets/Scripts/OpenTS2/Engine/Tests/BuildModeTest.cs index 7a6885f7..e81950da 100644 --- a/Assets/Scripts/OpenTS2/Engine/Tests/BuildModeTest.cs +++ b/Assets/Scripts/OpenTS2/Engine/Tests/BuildModeTest.cs @@ -17,8 +17,8 @@ using OpenTS2.Scenes.Lot.Extensions; using OpenTS2.Engine.Modes.Build; using OpenTS2.UI.Layouts; -using OpenTS2.Client; using System.Linq; +using OpenTS2.Engine; using OpenTS2.UI.Layouts.Lot; using UnityEditor.SearchService; using OpenTS2.Engine.Modes.Build.Tools; @@ -37,20 +37,18 @@ public class BuildModeTest : MonoBehaviour void ContentStartup(bool LoadGameContent = true) { - EPManager.Get().InstalledProducts = 0x3EFFF; + EPManager.Instance.InstalledProducts = 0x3EFFF; ContentLoading.LoadContentStartup(); - var settings = Settings.Get(); - settings.CustomContentEnabled = false; + GameGlobals.allowCustomContent = false; if (!LoadGameContent) return; - // Load effects. - EffectsManager.Get().Initialize(); //load the game content ContentLoading.LoadGameContentSync(); - - CatalogManager.Get().Initialize(); + CatalogManager.Instance.Initialize(); + // Load effects. + EffectsManager.Instance.Initialize(); } void Awake() @@ -62,7 +60,7 @@ void Awake() void Start() { //load the default lot for now - _loadedLotProvider = new LotLoad("N001", 80); + _loadedLotProvider = new LotLoad("N001", 80); //create the build mode server buildServer = new BuildModeServer(_loadedLotProvider); diff --git a/Assets/Scripts/OpenTS2/Scenes/Lot/LotLoad.cs b/Assets/Scripts/OpenTS2/Scenes/Lot/LotLoad.cs index 4588e6ef..cce86654 100644 --- a/Assets/Scripts/OpenTS2/Scenes/Lot/LotLoad.cs +++ b/Assets/Scripts/OpenTS2/Scenes/Lot/LotLoad.cs @@ -187,9 +187,9 @@ public void LoadLot(LotLoadSettings Settings = default) //Unload previous session UnloadLot(); - var contentProvider = ContentProvider.Get(); + var contentProvider = ContentManager.Instance; //Find package file for the lot given - var lotsFolderPath = Path.Combine(Filesystem.GetUserPath(), $"Neighborhoods/{NeighborhoodPrefix}/Lots"); + var lotsFolderPath = Path.Combine(Filesystem.UserDataDirectory, $"Neighborhoods/{NeighborhoodPrefix}/Lots"); var lotFilename = $"{NeighborhoodPrefix}_Lot{LotID}.package"; var lotFullPath = Path.Combine(lotsFolderPath, lotFilename); @@ -220,7 +220,7 @@ public void InvalidateObjects() //Clear any objects on the scene UnloadLot(); - var contentProvider = ContentProvider.Get(); + var contentProvider = ContentManager.Instance; // Go through each lot object. foreach (var entry in _lotPackage.Entries) { diff --git a/Assets/Scripts/OpenTS2/Scenes/Lot/LotTerrainComponent.cs b/Assets/Scripts/OpenTS2/Scenes/Lot/LotTerrainComponent.cs index bb075469..b89c3349 100644 --- a/Assets/Scripts/OpenTS2/Scenes/Lot/LotTerrainComponent.cs +++ b/Assets/Scripts/OpenTS2/Scenes/Lot/LotTerrainComponent.cs @@ -53,6 +53,19 @@ public LotTerrainComponent CreateFromLotArchitecture(LotArchitecture architectur return this; } + /// + /// Adds a mesh collider matching the shape of the terrain to the current object + /// + /// + /// + private MeshCollider SetTerrainCollider(LotArchitectureMeshComponent TerrainComponent) + { + var gameobj = TerrainComponent.gameObject; + var comp = gameobj.AddComponent(); + comp.isTrigger = false; + return comp; + } + private (ScenegraphTextureAsset color, ScenegraphTextureAsset bump) LoadTexture(ContentManager contentManager, string name) { var result = ( diff --git a/Assets/Scripts/OpenTS2/Scenes/Lot/LotWallComponent.cs b/Assets/Scripts/OpenTS2/Scenes/Lot/LotWallComponent.cs index 60a4844f..8a23a26b 100644 --- a/Assets/Scripts/OpenTS2/Scenes/Lot/LotWallComponent.cs +++ b/Assets/Scripts/OpenTS2/Scenes/Lot/LotWallComponent.cs @@ -90,7 +90,7 @@ public override void Invalidate() AddFencePosts(); } - private ScenegraphMaterialDefinitionAsset LoadMaterial(ContentProvider contentProvider, string name) + private ScenegraphMaterialDefinitionAsset LoadMaterial(ContentManager contentManager, string name) { var material = contentManager.GetAsset(new ResourceKey($"{name}_txmt", GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_TXMT)); diff --git a/Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewBuildModeHUD.cs b/Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewBuildModeHUD.cs index aa14809b..11674fb7 100644 --- a/Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewBuildModeHUD.cs +++ b/Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewBuildModeHUD.cs @@ -62,7 +62,7 @@ public void Display(CatalogObjectAsset Asset) item = Asset; - var content = ContentProvider.Get(); + var content = ContentManager.Instance; var material = content.GetAsset( new ResourceKey($"{Asset.Material}_txmt", GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_TXMT)); @@ -221,7 +221,7 @@ public void Open(string CatelogItemType, string Subsort = "all") //Update the selection of items to match the definition subsort = Subsort; - UpdateItemsSource(CatalogManager.Get().Objects.Where(x => x.Type == CatelogItemType)); + UpdateItemsSource(CatalogManager.Instance.Objects.Where(x => x.Type == CatelogItemType)); } public void SetLocalPosition(Vector3 Position) => rootElement.RectTransformComponent.localPosition = Position; diff --git a/Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewHUDController.cs.meta b/Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewHUDController.cs.meta index 22f6b2f3..895daa9a 100644 --- a/Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewHUDController.cs.meta +++ b/Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewHUDController.cs.meta @@ -4,7 +4,7 @@ MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] - executionOrder: 0 + executionOrder: -10 icon: {instanceID: 0} userData: assetBundleName: From 6eac4e6dba62e1b4615060afdd6b942b754b4350 Mon Sep 17 00:00:00 2001 From: Ammar Askar Date: Fri, 20 Mar 2026 22:35:09 -0400 Subject: [PATCH 08/15] Other fixes --- .../OpenTS2/Engine/Modes/Build/BuildModeServer.cs | 4 ++-- Assets/Scripts/OpenTS2/Engine/Tests/BuildModeTest.cs | 9 +++++---- Assets/Scripts/OpenTS2/Scenes/Lot/LotLoad.cs | 8 ++++++-- Assets/Scripts/OpenTS2/Scenes/Lot/LotRoofComponent.cs | 6 ++++++ .../OpenTS2/UI/Layouts/Lot/LotViewBuildModeHUD.cs | 5 +++++ 5 files changed, 24 insertions(+), 8 deletions(-) diff --git a/Assets/Scripts/OpenTS2/Engine/Modes/Build/BuildModeServer.cs b/Assets/Scripts/OpenTS2/Engine/Modes/Build/BuildModeServer.cs index 25d7ff18..84036f9e 100644 --- a/Assets/Scripts/OpenTS2/Engine/Modes/Build/BuildModeServer.cs +++ b/Assets/Scripts/OpenTS2/Engine/Modes/Build/BuildModeServer.cs @@ -86,7 +86,7 @@ public enum TerrainModificationModes //PRIVATE private readonly StringBuilder lotHistory = new StringBuilder(); - private readonly LotLoad loadedLot; + private LotLoad loadedLot; private LotArchitecture architecture => loadedLot.Architecture; private bool ConstrainedFloorElevation => CheatSystem.GetProperty("constrainfloorelevation").GetStringValue().ToLower() == "true"; @@ -122,7 +122,7 @@ private void LogHistory(string Message, string Caption = default, string Sender Debug.Log(msgTxt); } - internal BuildModeServer(LotLoad LoadedLot) + public void Initialize(LotLoad LoadedLot) { Current = this; diff --git a/Assets/Scripts/OpenTS2/Engine/Tests/BuildModeTest.cs b/Assets/Scripts/OpenTS2/Engine/Tests/BuildModeTest.cs index e81950da..35dbe571 100644 --- a/Assets/Scripts/OpenTS2/Engine/Tests/BuildModeTest.cs +++ b/Assets/Scripts/OpenTS2/Engine/Tests/BuildModeTest.cs @@ -46,9 +46,8 @@ void ContentStartup(bool LoadGameContent = true) //load the game content ContentLoading.LoadGameContentSync(); + Core.OnFinishedLoading.Invoke(); CatalogManager.Instance.Initialize(); - // Load effects. - EffectsManager.Instance.Initialize(); } void Awake() @@ -60,10 +59,12 @@ void Awake() void Start() { //load the default lot for now - _loadedLotProvider = new LotLoad("N001", 80); + _loadedLotProvider = gameObject.AddComponent(); + _loadedLotProvider.LoadLot("N001", 80); //create the build mode server - buildServer = new BuildModeServer(_loadedLotProvider); + buildServer = gameObject.AddComponent(); + buildServer.Initialize(_loadedLotProvider); buildServer.ChangeTool(BuildTools.None); //set the camera transform diff --git a/Assets/Scripts/OpenTS2/Scenes/Lot/LotLoad.cs b/Assets/Scripts/OpenTS2/Scenes/Lot/LotLoad.cs index cce86654..056ae6d7 100644 --- a/Assets/Scripts/OpenTS2/Scenes/Lot/LotLoad.cs +++ b/Assets/Scripts/OpenTS2/Scenes/Lot/LotLoad.cs @@ -141,13 +141,17 @@ public WorldState WorldState /// Loads the default lot /// See: and ///
- public LotLoad() : this(Default_NeighborhoodPrefix, Default_LotID) { } + public void Load() + { + Load(Default_NeighborhoodPrefix, Default_LotID); + } + /// /// Creates a new instance (that can be reused) with the specified Neighborhood and LotID to load /// /// /// - public LotLoad(string Nhood, int LotID) + public void Load(string Nhood, int LotID) { LoadLot(Nhood, LotID); } diff --git a/Assets/Scripts/OpenTS2/Scenes/Lot/LotRoofComponent.cs b/Assets/Scripts/OpenTS2/Scenes/Lot/LotRoofComponent.cs index f9699840..53e3984f 100644 --- a/Assets/Scripts/OpenTS2/Scenes/Lot/LotRoofComponent.cs +++ b/Assets/Scripts/OpenTS2/Scenes/Lot/LotRoofComponent.cs @@ -10,6 +10,7 @@ using System.Collections.Generic; using System; using OpenTS2.Scenes.Lot.State; +using UnityEngine; namespace OpenTS2.Scenes.Lot { @@ -74,6 +75,11 @@ public void LoadPatterns(uint guid) if (roof == null) { + if (guid == RoofCollection.DefaultGUID) + { + Debug.LogWarning($"Could not load roof pattern for default guid: {RoofCollection.DefaultGUID:X}"); + return; + } LoadPatterns(RoofCollection.DefaultGUID); return; } diff --git a/Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewBuildModeHUD.cs b/Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewBuildModeHUD.cs index 11674fb7..7e2ed723 100644 --- a/Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewBuildModeHUD.cs +++ b/Assets/Scripts/OpenTS2/UI/Layouts/Lot/LotViewBuildModeHUD.cs @@ -494,6 +494,11 @@ void WireUpUIEvents() { uint compID = keyValuePair.Key; var button = rootElement.GetChildByID(compID); + if (!button) + { + Debug.Log($"No button for 0x{compID:X}"); + continue; + } button.OnClick += delegate { //Set context From 6a7c4e4f8d2548f63520ddbc46a4fc7b4792bedb Mon Sep 17 00:00:00 2001 From: Ammar Askar Date: Fri, 20 Mar 2026 23:01:48 -0400 Subject: [PATCH 09/15] Fix some style issues --- .../OpenTS2/Cameras/TestLotViewCamera.cs | 62 ++++---- .../Components/AssetReferenceComponent.cs | 133 +----------------- .../OpenTS2/Components/ScenegraphComponent.cs | 5 + .../OpenTS2/Content/DBPF/WallGraphAsset.cs | 51 +++---- .../OpenTS2/Diagnostic/BoolpropCheat.cs | 42 ------ .../OpenTS2/Diagnostic/BoolpropCheat.cs.meta | 11 -- .../Scripts/OpenTS2/Diagnostic/CheatSystem.cs | 4 - 7 files changed, 65 insertions(+), 243 deletions(-) delete mode 100644 Assets/Scripts/OpenTS2/Diagnostic/BoolpropCheat.cs delete mode 100644 Assets/Scripts/OpenTS2/Diagnostic/BoolpropCheat.cs.meta diff --git a/Assets/Scripts/OpenTS2/Cameras/TestLotViewCamera.cs b/Assets/Scripts/OpenTS2/Cameras/TestLotViewCamera.cs index fc1f6166..78f04bc5 100644 --- a/Assets/Scripts/OpenTS2/Cameras/TestLotViewCamera.cs +++ b/Assets/Scripts/OpenTS2/Cameras/TestLotViewCamera.cs @@ -6,12 +6,12 @@ public class TestLotViewCamera : MonoBehaviour { - const int HitscanLength = 2000; + private const int HitscanLength = 2000; - Camera _camera; - Transform _camTransform; - Vector3 mouseholdPosition; - float initialXCamRot; + private Camera _camera; + private Transform _camTransform; + private Vector3 _mouseHoldPosition; + private float _initialXCamRot; //level detection system /// @@ -19,27 +19,27 @@ public class TestLotViewCamera : MonoBehaviour /// and also where the floor is to adjust its Y position to see the floor appropriately /// See: /// - Dictionary floorElevationMeshes; + Dictionary _floorElevationMeshes; // Start is called before the first frame update - void Start() + private void Start() { - floorElevationMeshes = new Dictionary(); + _floorElevationMeshes = new Dictionary(); _camTransform = GetComponentInParent(); _camera = GetComponentInParent(); } // Update is called once per frame - void Update() + private void Update() { if (Input.GetMouseButtonDown(1) || Input.GetMouseButtonDown(2)) // right or middle click { - mouseholdPosition = Input.mousePosition; + _mouseHoldPosition = Input.mousePosition; if (Input.GetMouseButtonDown(2)) - initialXCamRot = _camTransform.rotation.eulerAngles.x; + _initialXCamRot = _camTransform.rotation.eulerAngles.x; } - var mouseChange = mouseholdPosition - Input.mousePosition; + var mouseChange = _mouseHoldPosition - Input.mousePosition; if (Input.GetMouseButton(1)) // Right Click camera translation { @@ -55,7 +55,7 @@ void Update() else if (Input.GetMouseButton(2)) // Middle Mouse Click Camera pitch { float pitchChange = (mouseChange / 1).y; - var transformedXRot = Math.Max(0, Math.Min(90, initialXCamRot - pitchChange)); + var transformedXRot = Math.Max(0, Math.Min(90, _initialXCamRot - pitchChange)); var currentAngle = _camTransform.rotation.eulerAngles; currentAngle = new Vector3(transformedXRot, currentAngle.y, currentAngle.z); _camTransform.rotation = Quaternion.Euler(currentAngle); @@ -66,14 +66,14 @@ void Update() /// Sets the mesh colliders used to detect the height of the floor the camera is looking at. /// ///
- /// - public void SetCameraDetectionMeshes(int Floor, IEnumerable Colliders) + /// + public void SetCameraDetectionMeshes(int floor, IEnumerable colliders) { - floorElevationMeshes.Remove(Floor); - floorElevationMeshes.Add(Floor, Colliders.Where(x => x != default).ToArray()); + _floorElevationMeshes.Remove(floor); + _floorElevationMeshes.Add(floor, colliders.Where(x => x != default).ToArray()); } - public static Ray GetMouseCursor3DRay(Camera SelectedCamera) + public static Ray GetMouseCursor3DRay(Camera selectedCamera) { //transform scr pos to world Vector3 mousePosition = Input.mousePosition; @@ -81,24 +81,24 @@ public static Ray GetMouseCursor3DRay(Camera SelectedCamera) mousePosition = Camera.main.ScreenToWorldPoint(mousePosition); //get directional vector - var direction = (mousePosition - SelectedCamera.transform.position); direction.Normalize(); + var direction = (mousePosition - selectedCamera.transform.position); direction.Normalize(); //build a ray from camera to terrain - return new Ray(SelectedCamera.transform.position, direction); + return new Ray(selectedCamera.transform.position, direction); } /// /// Potentially expensive!! use with caution /// - /// - /// + /// + /// /// - public bool TranslateScreen2WorldPos(int MaxFloor, out Vector3 WorldPosition, out int Floor) + public bool TranslateScreen2WorldPos(int maxFloor, out Vector3 worldPosition, out int floor) { - WorldPosition = new Vector3(); - Floor = -1; + worldPosition = new Vector3(); + floor = -1; - if (!floorElevationMeshes.Any()) + if (!_floorElevationMeshes.Any()) { Debug.LogWarning("No terrain meshes added to the lot camera so hit detection is disabled!"); return false; @@ -113,10 +113,10 @@ public bool TranslateScreen2WorldPos(int MaxFloor, out Vector3 WorldPosition, ou bool hitComplete = false; //go top down searching for which floor we're looking at - for(int floor = MaxFloor; floor >= floorElevationMeshes.Keys.Min(); floor--) + for(int candidateFloor = maxFloor; candidateFloor >= _floorElevationMeshes.Keys.Min(); candidateFloor--) { - if (!floorElevationMeshes.ContainsKey(floor)) continue; - foreach(var collider in floorElevationMeshes[floor]) + if (!_floorElevationMeshes.ContainsKey(candidateFloor)) continue; + foreach(var collider in _floorElevationMeshes[candidateFloor]) { if (collider is MeshCollider mCollider) { @@ -126,7 +126,7 @@ public bool TranslateScreen2WorldPos(int MaxFloor, out Vector3 WorldPosition, ou if (collider.Raycast(camRay, out hitInfo, HitscanLength)) { hitComplete = true; - Floor = floor; + floor = candidateFloor; break; } } @@ -134,7 +134,7 @@ public bool TranslateScreen2WorldPos(int MaxFloor, out Vector3 WorldPosition, ou } if (!hitComplete) return false; - WorldPosition = hitInfo.point; + worldPosition = hitInfo.point; return true; } } diff --git a/Assets/Scripts/OpenTS2/Components/AssetReferenceComponent.cs b/Assets/Scripts/OpenTS2/Components/AssetReferenceComponent.cs index 06c54f49..acdfca05 100644 --- a/Assets/Scripts/OpenTS2/Components/AssetReferenceComponent.cs +++ b/Assets/Scripts/OpenTS2/Components/AssetReferenceComponent.cs @@ -1,12 +1,6 @@ -using OpenTS2.Common; -using OpenTS2.Content; -using OpenTS2.Content.DBPF; -using OpenTS2.Content.DBPF.Scenegraph; -using OpenTS2.Files.Formats.DBPF; -using OpenTS2.Scenes.Lot; +using OpenTS2.Content; using System; using System.Collections.Generic; -using System.Globalization; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -26,129 +20,6 @@ public void AddReference(params AbstractAsset[] assets) /// /// Indicates that this component should re-evaluate itself for changes made at runtime /// - public virtual void Invalidate() { } - } - - // Seems like functionality is identical between certain lot components that utilize patterns. - // Moved the duplicated code to one unit so we can make improvements - - //**CURRENTLY UNUSED** - /// - /// Serves functionality for loading pattern assets from a pattern map (floors, walls, etc.) - /// - /// - public abstract class AssetPatternReferenceComponent : AssetReferenceComponent - { - /// - /// The material to use when the requested material could not be loaded using the - /// default implementation - /// - protected abstract string FallbackMaterial { get; } - /// - /// The texture to use for the thickness of the object - /// Walls and floors utilize this to show they're three-dimensional and it applied to [0] - /// - protected abstract string ThicknessTexture { get; } - - protected abstract int FloorCount { get; } - - protected PatternMeshCollection _patterns; - protected PatternDescriptor[] _loadedPatternDescriptions; - - protected abstract Dictionary Map { get; } - protected virtual Dictionary Builtins { get; } = null; - - /// - /// Base load patterns function - /// - protected virtual void LoadPatterns() - { - var contentProvider = ContentManager.Instance; - var catalogManager = CatalogManager.Instance; - var patternMap = Map; - - ushort highestId = patternMap.Count == 0 ? (ushort)0 : patternMap.Keys.Max(); - PatternDescriptor[] patterns = new PatternDescriptor[highestId + 2]; - - bool changesMade = false; - bool previousStateExisting = _loadedPatternDescriptions != null; - - foreach (StringMapEntry entry in patternMap.Values) - { - //Persistent data -- calls from Invalidate() will call this with data already loaded, in which case - //We can save time by not reloading the same loaded data - // TODO - if (previousStateExisting && _loadedPatternDescriptions.Length == patterns.Length && - _loadedPatternDescriptions[entry.Id + 1].Name != null) // loaded - { // PatternDescriptor is a struct -- check the name see if it's null, if not, the pattern is loaded already - patterns[entry.Id + 1] = _loadedPatternDescriptions[entry.Id + 1]; - continue; - } - changesMade = true; - - string materialName = null; - if (uint.TryParse(entry.Value, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out uint guid)) - { - var catalogEntry = catalogManager.GetEntryById(guid); - - materialName = catalogEntry?.Material ?? FallbackMaterial; - } - else if (Builtins != null && !Builtins.TryGetValue(entry.Value, out materialName)) - { - materialName = entry.Value.StartsWith("wall_") ? (entry.Value + "_base") : ("wall_" + entry.Value + "_base"); - } - - if (materialName == null) - { - // Explicitly remove this pattern. - continue; - } - - // Try fetch the texture using the material name. - var material = LoadMaterial(contentProvider, materialName); - - try - { - // Note: Sometimes walls use the standard material, but we want them to use a special shader for cutaways. - patterns[entry.Id + 1] = new PatternDescriptor( - materialName, - material == null ? null : material?.GetAsUnityMaterial("Wallpaper") - ); - } - catch (Exception e) - { - Debug.LogException(e); - } - } - - if (previousStateExisting) - { - if (!changesMade) return; // no changes to wall patterns since last load - - patterns[0] = _loadedPatternDescriptions[0]; - _loadedPatternDescriptions = patterns; - _patterns.UpdatePatterns(patterns); - return; - } - - PostLoadPatterns(contentProvider, ref patterns); - - _loadedPatternDescriptions = patterns; - //_patterns = new PatternMeshCollection(gameObject, patterns, Array.Empty(), this, FloorCount); - } - - protected virtual ScenegraphMaterialDefinitionAsset LoadMaterial(ContentManager contentProvider, string name) - { - var material = contentProvider.GetAsset(new ResourceKey($"{name}_txmt", GroupIDs.Scenegraph, TypeIDs.SCENEGRAPH_TXMT)); - - AddReference(material); - - return material; - } - - protected virtual void PostLoadPatterns(ContentManager contentProvider, ref PatternDescriptor[] patterns) - { - - } + public virtual void Invalidate() { } } } diff --git a/Assets/Scripts/OpenTS2/Components/ScenegraphComponent.cs b/Assets/Scripts/OpenTS2/Components/ScenegraphComponent.cs index 483e9f3e..a3f67d02 100644 --- a/Assets/Scripts/OpenTS2/Components/ScenegraphComponent.cs +++ b/Assets/Scripts/OpenTS2/Components/ScenegraphComponent.cs @@ -24,6 +24,11 @@ public class ScenegraphComponent : MonoBehaviour /// /// The returned game object carries a transform to convert it from sims coordinate space to unity space. ///
+ public static GameObject CreateRootScenegraph(ScenegraphResourceAsset resourceAsset) + { + return CreateRootScenegraph(new []{ resourceAsset }); + } + public static GameObject CreateRootScenegraph(params ScenegraphResourceAsset[] resourceAssets) { var scenegraph = CreateScenegraphComponent(resourceAssets); diff --git a/Assets/Scripts/OpenTS2/Content/DBPF/WallGraphAsset.cs b/Assets/Scripts/OpenTS2/Content/DBPF/WallGraphAsset.cs index 5b3299bd..7372e10b 100644 --- a/Assets/Scripts/OpenTS2/Content/DBPF/WallGraphAsset.cs +++ b/Assets/Scripts/OpenTS2/Content/DBPF/WallGraphAsset.cs @@ -63,40 +63,44 @@ private Dictionary ToPositionDictionary(WallGraphPo return result; } - bool getJuncIdByPosition(Vector2 Position, int Floor, out int juncId, bool createIfNull = true) + + bool GetJuncIdByPosition(Vector2 position, int floor, out int juncId, bool createIfNull = true) { bool existed = false; - var junctions = Positions.Where(x => x.Value.XPos == Position.x && x.Value.YPos == Position.y && x.Value.Level == Floor); + var junctions = Positions.Where(x => + x.Value.XPos == position.x && x.Value.YPos == position.y && x.Value.Level == floor); juncId = -1; if (junctions.Any()) { - juncId = junctions.First().Key; // found a matching position + juncId = junctions.First().Key; // found a matching position existed = true; } else if (createIfNull) - { // make a new position + { + // make a new position if (Positions.Any()) juncId = Positions.Select(x => x.Key).Max() + 1; else juncId = 0; Positions.Add(juncId, new WallGraphPositionEntry() { Id = juncId, - Level = Floor, - XPos = Position.x, - YPos = Position.y, + Level = floor, + XPos = position.x, + YPos = position.y, }); } + return existed; } - public bool PushWall(Vector2 Pos1, Vector2 Pos2, int Floor, out int LayerID) + public bool PushWall(Vector2 pos1, Vector2 pos2, int floor, out int layerID) { - LayerID = -1; + layerID = -1; - bool fromExistedAlready = getJuncIdByPosition(Pos1, Floor, out int fromId); + bool fromExistedAlready = GetJuncIdByPosition(pos1, floor, out int fromId); if (fromId == -1) // unable to create !! return false; - bool toExistedAlready = getJuncIdByPosition(Pos2, Floor, out int toId); + bool toExistedAlready = GetJuncIdByPosition(pos2, floor, out int toId); if (toId == -1) // unable to create !! return false; @@ -121,8 +125,8 @@ public bool PushWall(Vector2 Pos1, Vector2 Pos2, int Floor, out int LayerID) ToId = toId, }; _lines[_lines.Length - 1] = line; - LayerID = layerId; - if (Floors <= Floor) + layerID = layerId; + if (Floors <= floor) Floors++; return true; } @@ -136,14 +140,14 @@ private void _delWall(int index) Array.Resize(ref _lines, _lines.Length - 1); // shorten array by one } - internal bool RemoveWall(Vector2 From, Vector2 To, int Floor, out int LayerID) + internal bool RemoveWall(Vector2 from, Vector2 to, int floor, out int layerID) { // should be refactored to batch delete a set of segments instead of one at a time due to iterations being potentially large - LayerID = -1; + layerID = -1; - getJuncIdByPosition(From, Floor, out int fromId, false); + GetJuncIdByPosition(from, floor, out int fromId, false); if (fromId == -1) // wall index doesn't exist? return false; - getJuncIdByPosition(To, Floor, out int toId, false); + GetJuncIdByPosition(to, floor, out int toId, false); if (toId == -1) // wall index doesn't exist? return false; @@ -156,7 +160,7 @@ internal bool RemoveWall(Vector2 From, Vector2 To, int Floor, out int LayerID) if (line.FromId != toId && line.FromId != fromId) continue; _delWall(i); - LayerID = line.LayerId; + layerID = line.LayerId; return true; } return false; // not found @@ -164,18 +168,17 @@ internal bool RemoveWall(Vector2 From, Vector2 To, int Floor, out int LayerID) /// /// Deletes all the wall lines from the selected floor by their LayerID. /// - /// - /// + /// /// - internal int RemoveWalls(params int[] WallLayerIDs) + internal int RemoveWalls(params int[] wallLayerIDs) { int index = -1; int found = 0; - HashSet deletionIndices = new HashSet(); + var deletionIndices = new HashSet(); foreach(var line in _lines) { index++; - if (!WallLayerIDs.Contains(line.LayerId)) continue; + if (!wallLayerIDs.Contains(line.LayerId)) continue; found++; deletionIndices.Add(index); } @@ -185,4 +188,4 @@ internal int RemoveWalls(params int[] WallLayerIDs) return deleted; } } -} \ No newline at end of file +} diff --git a/Assets/Scripts/OpenTS2/Diagnostic/BoolpropCheat.cs b/Assets/Scripts/OpenTS2/Diagnostic/BoolpropCheat.cs deleted file mode 100644 index 85c002ac..00000000 --- a/Assets/Scripts/OpenTS2/Diagnostic/BoolpropCheat.cs +++ /dev/null @@ -1,42 +0,0 @@ -using OpenTS2.Diagnostic; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Unity.Plastic.Newtonsoft.Json; -using UnityEngine; - -/// -/// Houses some common TS2 boolean properties -/// - -namespace Assets.Scripts.OpenTS2.Diagnostic -{ - public class SimpleProperty : IConsoleProperty - { - string serializedValue - { - get => Convert.ToString(myValue); - set => myValue = (T)Convert.ChangeType(value, typeof(T)); - } - - T myValue; - - public SimpleProperty() - { - } - public SimpleProperty(T DefaultValue) : this() - { - myValue = DefaultValue; - } - - public string GetStringValue() => serializedValue; - public Type GetValueType() => typeof(T); - public void SetStringValue(string value) => serializedValue = value; - - public static SimpleProperty Create() => new SimpleProperty(); - public static SimpleProperty Create(T DefaultValue) => new SimpleProperty(DefaultValue); - } -} diff --git a/Assets/Scripts/OpenTS2/Diagnostic/BoolpropCheat.cs.meta b/Assets/Scripts/OpenTS2/Diagnostic/BoolpropCheat.cs.meta deleted file mode 100644 index c0990ca2..00000000 --- a/Assets/Scripts/OpenTS2/Diagnostic/BoolpropCheat.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: fc38f22d7f39dcf45b82f46e2f6f4abc -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Scripts/OpenTS2/Diagnostic/CheatSystem.cs b/Assets/Scripts/OpenTS2/Diagnostic/CheatSystem.cs index 91c1a950..7c9ce8fd 100644 --- a/Assets/Scripts/OpenTS2/Diagnostic/CheatSystem.cs +++ b/Assets/Scripts/OpenTS2/Diagnostic/CheatSystem.cs @@ -4,7 +4,6 @@ using System.Reflection; using System.Text; using System.Threading.Tasks; -using Assets.Scripts.OpenTS2.Diagnostic; using OpenTS2.Engine; using UnityEngine; @@ -24,9 +23,6 @@ public static void Initialize() RegisterCheat(); RegisterCheat(); Assemblies.AssemblyHelper.AssemblyProcesses += RegisterPropsForType; - - //ConstrainFloorElevation - RegisterProperty(SimpleProperty.Create(false), "constrainfloorelevation"); } private static void RegisterPropsForType(Type type, Assembly assembly) From 93dd0eb74f03518bb2281361bdbfa8f0f5da61c3 Mon Sep 17 00:00:00 2001 From: Ammar Askar Date: Fri, 20 Mar 2026 23:02:30 -0400 Subject: [PATCH 10/15] Remove upgrade log file --- UpgradeLog.htm | 276 ------------------------------------------------- 1 file changed, 276 deletions(-) delete mode 100644 UpgradeLog.htm diff --git a/UpgradeLog.htm b/UpgradeLog.htm deleted file mode 100644 index bf44b1f8..00000000 --- a/UpgradeLog.htm +++ /dev/null @@ -1,276 +0,0 @@ - - - - Migration Report -

- Migration Report -

\ No newline at end of file From ec9a7e82dad50425fc060a63eded5d21e5ddfd74 Mon Sep 17 00:00:00 2001 From: Ammar Askar Date: Fri, 20 Mar 2026 23:03:39 -0400 Subject: [PATCH 11/15] Revert changes to CheatSystem --- Assets/Scripts/OpenTS2/Diagnostic/CheatSystem.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Assets/Scripts/OpenTS2/Diagnostic/CheatSystem.cs b/Assets/Scripts/OpenTS2/Diagnostic/CheatSystem.cs index 7c9ce8fd..664c6879 100644 --- a/Assets/Scripts/OpenTS2/Diagnostic/CheatSystem.cs +++ b/Assets/Scripts/OpenTS2/Diagnostic/CheatSystem.cs @@ -1,10 +1,10 @@ -using System; +using OpenTS2.Engine; +using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; -using OpenTS2.Engine; using UnityEngine; namespace OpenTS2.Diagnostic From e2314eb2150d9d2f9cb85716dc797436cee2c722 Mon Sep 17 00:00:00 2001 From: Ammar Askar Date: Fri, 20 Mar 2026 23:08:51 -0400 Subject: [PATCH 12/15] fix unecessary diff in pattern mesh floor --- Assets/Scripts/OpenTS2/Scenes/Lot/PatternMeshFloor.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Assets/Scripts/OpenTS2/Scenes/Lot/PatternMeshFloor.cs b/Assets/Scripts/OpenTS2/Scenes/Lot/PatternMeshFloor.cs index b03edb62..21d97757 100644 --- a/Assets/Scripts/OpenTS2/Scenes/Lot/PatternMeshFloor.cs +++ b/Assets/Scripts/OpenTS2/Scenes/Lot/PatternMeshFloor.cs @@ -88,13 +88,14 @@ public PatternMesh Get(int id, int variantId = 0) Object, $"{descriptor.Name}_{variant.Name}", variant.MaterialTransform != null ? variant.MaterialTransform(descriptor.Material) : descriptor.Material, - _matConfig); + _matConfig); } else { result = new PatternMesh(Object, descriptor.Name, descriptor.Material, _matConfig); } - result.Object.AddComponent(); // add collider to floors + + result.Object.AddComponent(); // add collider to floors _patternMeshes[key] = result; } From c0c1b1f51ad52b6a6502523566805db8adc81cc9 Mon Sep 17 00:00:00 2001 From: Ammar Askar Date: Fri, 20 Mar 2026 23:12:32 -0400 Subject: [PATCH 13/15] More style changes --- .../Scripts/OpenTS2/Scenes/Lot/LotTerrainComponent.cs | 11 ++++------- Assets/Scripts/OpenTS2/Scenes/Lot/PatternMesh.cs | 2 +- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/Assets/Scripts/OpenTS2/Scenes/Lot/LotTerrainComponent.cs b/Assets/Scripts/OpenTS2/Scenes/Lot/LotTerrainComponent.cs index b89c3349..9ce804ca 100644 --- a/Assets/Scripts/OpenTS2/Scenes/Lot/LotTerrainComponent.cs +++ b/Assets/Scripts/OpenTS2/Scenes/Lot/LotTerrainComponent.cs @@ -48,7 +48,7 @@ public LotTerrainComponent CreateFromLotArchitecture(LotArchitecture architectur BindMaterialAndTextures(); //Make Mesh Collider for terrain - SetTerrainCollider(_terrain.Component); + MakeTerrainCollider(); return this; } @@ -56,14 +56,11 @@ public LotTerrainComponent CreateFromLotArchitecture(LotArchitecture architectur /// /// Adds a mesh collider matching the shape of the terrain to the current object /// - /// - /// - private MeshCollider SetTerrainCollider(LotArchitectureMeshComponent TerrainComponent) + /// + private void MakeTerrainCollider() { - var gameobj = TerrainComponent.gameObject; - var comp = gameobj.AddComponent(); + var comp = _terrain.Component.gameObject.AddComponent(); comp.isTrigger = false; - return comp; } private (ScenegraphTextureAsset color, ScenegraphTextureAsset bump) LoadTexture(ContentManager contentManager, string name) diff --git a/Assets/Scripts/OpenTS2/Scenes/Lot/PatternMesh.cs b/Assets/Scripts/OpenTS2/Scenes/Lot/PatternMesh.cs index bf2b11a7..b31562d2 100644 --- a/Assets/Scripts/OpenTS2/Scenes/Lot/PatternMesh.cs +++ b/Assets/Scripts/OpenTS2/Scenes/Lot/PatternMesh.cs @@ -35,7 +35,7 @@ public PatternMesh(GameObject parent, string name, Material material, IPatternMa Component.EnableExtraUV(); } - Object.transform.SetParent(parent.transform); + Object.transform.SetParent(parent.transform); Component.Initialize(_material); } From 667b06a364e05ad4ec6aa04f1c855d74f224d0c8 Mon Sep 17 00:00:00 2001 From: Ammar Askar Date: Fri, 20 Mar 2026 23:20:40 -0400 Subject: [PATCH 14/15] more style fixes --- Assets/Scripts/OpenTS2/Scenes/Lot/LotArchitecture.cs | 2 +- Assets/Scripts/OpenTS2/Scenes/Lot/LotFloorComponent.cs | 4 ++-- Assets/Scripts/OpenTS2/Scenes/Lot/LotRoofComponent.cs | 6 ------ Assets/Scripts/OpenTS2/Scenes/Lot/LotTerrainComponent.cs | 2 +- 4 files changed, 4 insertions(+), 10 deletions(-) diff --git a/Assets/Scripts/OpenTS2/Scenes/Lot/LotArchitecture.cs b/Assets/Scripts/OpenTS2/Scenes/Lot/LotArchitecture.cs index b9a77aea..f5ded5d4 100644 --- a/Assets/Scripts/OpenTS2/Scenes/Lot/LotArchitecture.cs +++ b/Assets/Scripts/OpenTS2/Scenes/Lot/LotArchitecture.cs @@ -271,6 +271,6 @@ public void UpdateState(WorldState state) _roofComponent.UpdateDisplay(state); _wallComponent.UpdateDisplay(state); _floorComponent.UpdateDisplay(state); - } + } } } \ No newline at end of file diff --git a/Assets/Scripts/OpenTS2/Scenes/Lot/LotFloorComponent.cs b/Assets/Scripts/OpenTS2/Scenes/Lot/LotFloorComponent.cs index be90cb61..70d0fe7d 100644 --- a/Assets/Scripts/OpenTS2/Scenes/Lot/LotFloorComponent.cs +++ b/Assets/Scripts/OpenTS2/Scenes/Lot/LotFloorComponent.cs @@ -97,7 +97,7 @@ private void LoadPatterns() PatternDescriptor[] patterns = new PatternDescriptor[highestId + 2]; foreach (StringMapEntry entry in patternMap.Values) - { + { string materialName; if (uint.TryParse(entry.Value, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out uint guid)) { @@ -194,7 +194,7 @@ void AddThickness(int from, int to) { if (floor == null) { - // Lazy init - don't create the floor unless it's actually being used. + // Lazy init - don't create the floor unless it's actually being used. floor = _patterns.GetFloor(i); PatternMesh thickness = floor.Get(0); thickComp = thickness.Component; diff --git a/Assets/Scripts/OpenTS2/Scenes/Lot/LotRoofComponent.cs b/Assets/Scripts/OpenTS2/Scenes/Lot/LotRoofComponent.cs index 53e3984f..f9699840 100644 --- a/Assets/Scripts/OpenTS2/Scenes/Lot/LotRoofComponent.cs +++ b/Assets/Scripts/OpenTS2/Scenes/Lot/LotRoofComponent.cs @@ -10,7 +10,6 @@ using System.Collections.Generic; using System; using OpenTS2.Scenes.Lot.State; -using UnityEngine; namespace OpenTS2.Scenes.Lot { @@ -75,11 +74,6 @@ public void LoadPatterns(uint guid) if (roof == null) { - if (guid == RoofCollection.DefaultGUID) - { - Debug.LogWarning($"Could not load roof pattern for default guid: {RoofCollection.DefaultGUID:X}"); - return; - } LoadPatterns(RoofCollection.DefaultGUID); return; } diff --git a/Assets/Scripts/OpenTS2/Scenes/Lot/LotTerrainComponent.cs b/Assets/Scripts/OpenTS2/Scenes/Lot/LotTerrainComponent.cs index 9ce804ca..b5b0800d 100644 --- a/Assets/Scripts/OpenTS2/Scenes/Lot/LotTerrainComponent.cs +++ b/Assets/Scripts/OpenTS2/Scenes/Lot/LotTerrainComponent.cs @@ -47,7 +47,7 @@ public LotTerrainComponent CreateFromLotArchitecture(LotArchitecture architectur BindMaterialAndTextures(); - //Make Mesh Collider for terrain + // Make Mesh Collider for terrain MakeTerrainCollider(); return this; From 3601a89f8b359acd2963c48b41c24249417c5f29 Mon Sep 17 00:00:00 2001 From: Ammar Askar Date: Fri, 20 Mar 2026 23:29:41 -0400 Subject: [PATCH 15/15] Fix cheat property, remove hardcoded file name --- .../Scripts/OpenTS2/Engine/Modes/Build/BuildModeServer.cs | 3 ++- .../OpenTS2/Scenes/Lot/Room/RuntimeWallController.cs | 6 +----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/Assets/Scripts/OpenTS2/Engine/Modes/Build/BuildModeServer.cs b/Assets/Scripts/OpenTS2/Engine/Modes/Build/BuildModeServer.cs index 84036f9e..d5c582ad 100644 --- a/Assets/Scripts/OpenTS2/Engine/Modes/Build/BuildModeServer.cs +++ b/Assets/Scripts/OpenTS2/Engine/Modes/Build/BuildModeServer.cs @@ -88,7 +88,8 @@ public enum TerrainModificationModes private LotLoad loadedLot; private LotArchitecture architecture => loadedLot.Architecture; - private bool ConstrainedFloorElevation => CheatSystem.GetProperty("constrainfloorelevation").GetStringValue().ToLower() == "true"; + [GameProperty("constrainfloorelevation", userProp:true)] + private static bool ConstrainedFloorElevation = false; //PUBLIC /// diff --git a/Assets/Scripts/OpenTS2/Scenes/Lot/Room/RuntimeWallController.cs b/Assets/Scripts/OpenTS2/Scenes/Lot/Room/RuntimeWallController.cs index 471fb78f..ffeaae71 100644 --- a/Assets/Scripts/OpenTS2/Scenes/Lot/Room/RuntimeWallController.cs +++ b/Assets/Scripts/OpenTS2/Scenes/Lot/Room/RuntimeWallController.cs @@ -1,8 +1,5 @@ // JDrocks450 11-22-2023 on GitHub -#define NEW_INVALIDATE -#undef NEW_INVALIDATE - using OpenTS2.Content.DBPF; using System; using System.Collections.Generic; @@ -158,8 +155,7 @@ private void PackageRoomMap(int Width, int Height) Width = Width, Height = Height }, typeof(RoomPackage)); - File.WriteAllText("C:\\Users\\xXJDr\\OneDrive\\Desktop\\roommapts2.txt", strJson.ToString()); - } + } } ///