From 10b496dfaea68fc63de6154df36226f57f68028c Mon Sep 17 00:00:00 2001 From: dal4segno Date: Mon, 2 Feb 2026 04:24:14 +0900 Subject: [PATCH] =?UTF-8?q?=EB=84=A4=ED=8A=B8=EC=9B=8C=ED=81=AC=20?= =?UTF-8?q?=EB=A9=80=ED=8B=B0=ED=94=8C=EB=A0=88=EC=9D=B4=20=ED=99=98?= =?UTF-8?q?=EA=B2=BD=20=EB=AC=B8=EC=A0=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 관련 문제가 다시 발생하면 이 커밋으로 돌아올 것 --- AUTOMATED_PREFAB_PIPELINE.md | 120 -- Assembly-CSharp.csproj | 6 + Assets/DefaultNetworkPrefabs.asset | 10 + Assets/InputSystem_Actions.cs | 78 ++ Assets/InputSystem_Actions.inputactions | 40 + Assets/Prefabs/Bat.prefab | 122 ++ Assets/Prefabs/Bat.prefab.meta | 7 + Assets/Prefabs/Pickaxe.prefab | 122 ++ Assets/Prefabs/Pickaxe.prefab.meta | 7 + Assets/Prefabs/Player/Player.prefab | 134 +- Assets/Resources.meta | 8 + Assets/Scenes/GameMain.unity | 2 +- Assets/Scripts/Core.cs | 36 +- Assets/Scripts/DebugLogUI.cs | 160 +++ Assets/Scripts/DebugLogUI.cs.meta | 2 + Assets/Scripts/EquipmentSocket.cs | 173 ++- Assets/Scripts/ForceRecompile.txt | 0 Assets/Scripts/ForceRecompile.txt.meta | 7 + Assets/Scripts/NetworkConnectionHandler.cs | 95 +- Assets/Scripts/NetworkDebug.cs | 86 ++ Assets/Scripts/NetworkDebug.cs.meta | 2 + Assets/Scripts/NetworkEquipmentSocket.cs | 162 +++ Assets/Scripts/NetworkEquipmentSocket.cs.meta | 2 + Assets/Scripts/NetworkManagerUI.cs | 47 +- Assets/Scripts/PlayerInteraction.cs | 4 +- Assets/Scripts/PlayerResourceInventory.cs | 99 +- Assets/Scripts/Resource.cs | 52 +- Assets/Scripts/ResourcePickup.cs | 59 +- Assets/Scripts/ServerResourceManager.cs | 101 ++ Assets/Scripts/ServerResourceManager.cs.meta | 2 + Assets/Scripts/ShortcutNetworkStarter.cs | 50 + Assets/Scripts/ShortcutNetworkStarter.cs.meta | 2 + Assets/Settings/Build Profiles.meta | 8 + Assets/Settings/Build Profiles/Windows.asset | 94 ++ .../Build Profiles/Windows.asset.meta | 8 + Assets/Settings/Northbound Flatkit URP.asset | 12 +- ...niversalRenderPipelineGlobalSettings.asset | 14 +- BUILDING_SYSTEM_SETUP.md | 323 ----- DISCORD_HOOK_GUIDE.md | 63 - GENERIC_IMPORTER.md | 154 -- GRID_BASED_COLLISION.md | 283 ---- INPUT_ACTIONS_SETUP.md | 128 -- Northbound.Game.csproj | 1240 +++++++++++++++++ Packages/manifest.json.backup | 64 + ProjectSettings/ProjectSettings.asset | 8 +- ProjectSettings/UnityConnectSettings.asset | 2 +- TOWER_CSV_IMPORTER.md | 138 -- TOWER_QUICKSLOT_SETUP.md | 120 -- TROUBLESHOOTING_GHOST.md | 196 --- 49 files changed, 2860 insertions(+), 1792 deletions(-) delete mode 100644 AUTOMATED_PREFAB_PIPELINE.md create mode 100644 Assets/Prefabs/Bat.prefab create mode 100644 Assets/Prefabs/Bat.prefab.meta create mode 100644 Assets/Prefabs/Pickaxe.prefab create mode 100644 Assets/Prefabs/Pickaxe.prefab.meta create mode 100644 Assets/Resources.meta create mode 100644 Assets/Scripts/DebugLogUI.cs create mode 100644 Assets/Scripts/DebugLogUI.cs.meta create mode 100644 Assets/Scripts/ForceRecompile.txt create mode 100644 Assets/Scripts/ForceRecompile.txt.meta create mode 100644 Assets/Scripts/NetworkDebug.cs create mode 100644 Assets/Scripts/NetworkDebug.cs.meta create mode 100644 Assets/Scripts/NetworkEquipmentSocket.cs create mode 100644 Assets/Scripts/NetworkEquipmentSocket.cs.meta create mode 100644 Assets/Scripts/ServerResourceManager.cs create mode 100644 Assets/Scripts/ServerResourceManager.cs.meta create mode 100644 Assets/Scripts/ShortcutNetworkStarter.cs create mode 100644 Assets/Scripts/ShortcutNetworkStarter.cs.meta create mode 100644 Assets/Settings/Build Profiles.meta create mode 100644 Assets/Settings/Build Profiles/Windows.asset create mode 100644 Assets/Settings/Build Profiles/Windows.asset.meta delete mode 100644 BUILDING_SYSTEM_SETUP.md delete mode 100644 DISCORD_HOOK_GUIDE.md delete mode 100644 GENERIC_IMPORTER.md delete mode 100644 GRID_BASED_COLLISION.md delete mode 100644 INPUT_ACTIONS_SETUP.md create mode 100644 Northbound.Game.csproj create mode 100644 Packages/manifest.json.backup delete mode 100644 TOWER_CSV_IMPORTER.md delete mode 100644 TOWER_QUICKSLOT_SETUP.md delete mode 100644 TROUBLESHOOTING_GHOST.md diff --git a/AUTOMATED_PREFAB_PIPELINE.md b/AUTOMATED_PREFAB_PIPELINE.md deleted file mode 100644 index 53f5778..0000000 --- a/AUTOMATED_PREFAB_PIPELINE.md +++ /dev/null @@ -1,120 +0,0 @@ -# Automated Prefab Generation Pipeline - -## Overview -This system automates the creation of monster prefabs from CSV data. No manual prefab setup required! - -## How It Works - -1. **CSV Data** → **ScriptableObject (SO)** → **Prefab** (automatically generated) -2. Template prefabs define required components and defaults -3. CSV importer creates complete prefabs with mesh, components, and SO references - -## Setup Instructions - -### Step 1: Create Template Prefab - -1. In Unity, go to `Tools > Data > Create Monster Template` -2. This creates `Assets/Data/Templates/MonsterTemplate.prefab` -3. The template includes all required components: - - NetworkObject - - EnemyUnit - - MonsterDataComponent (links to SO) - - NavMeshAgent - - EnemyAIController - - CapsuleCollider - - MeshFilter & MeshRenderer - -4. **Customize the template if needed:** - - Adjust default AI behavior - - Set default collider size - - Add visual effects - - Configure NavMeshAgent settings - -### Step 2: Update CSV with Mesh Path - -Add `meshPath` column to your `Monster.csv`: - -```csv -id,name,memo,moveSpeed,maxHp,atkRange,atkDamage,atkIntervalSec,meshPath,cost,weight -101,Grunt,Basic Monster,2.6,30,1,3,1.2,Assets/Models/Monsters/Monster101.fbx,1,1.0 -102,Fast,Fast/Weak,3.4,18,1,2,1,Assets/Models/Monsters/Monster102.fbx,2,0.5 -``` - -### Step 3: Import Data - -1. In Unity, go to `Tools > Data > Import All CSV` -2. The importer will: - - Create/update SO files in `Assets/Data/ScriptableObjects/Monster/` - - Create/update prefabs in `Assets/Prefabs/Monster/` - - Apply mesh from `meshPath` column - - Link SO reference to prefab's MonsterDataComponent - -### Step 4: Use Prefabs - -Your generated prefabs are ready to use! Example with EnemyPortal: -- Open EnemyPortal prefab -- Click "Load Monster Data" button -- All monster prefabs are automatically loaded - -## File Structure - -``` -Assets/ -├── Data/ -│ ├── ScriptableObjects/ -│ │ └── Monster/ # SO files (generated from CSV) -│ └── Templates/ # Template prefabs (created once) -│ └── MonsterTemplate.prefab -├── Prefabs/ -│ └── Monster/ # Generated monster prefabs -│ ├── Monster101.prefab -│ ├── Monster102.prefab -│ └── ... -└── GameData/ - └── Monster.csv # Source data (editable) -``` - -## Benefits - -- ✅ **One source of truth**: Edit CSV, everything updates -- ✅ **No manual setup**: Prefabs generated automatically -- ✅ **Designer-friendly**: Templates visual, CSV simple -- ✅ **Error-proof**: All components guaranteed to exist -- ✅ **Easy customization**: Edit template once, applies to all - -## Customization - -### Adding New Components -1. Open `MonsterTemplate.prefab` -2. Add the component -3. Configure defaults -4. Save template -5. All future imports will include it - -### Modifying Existing Monsters -- Edit the prefab directly (changes persist on next import) -- OR modify CSV and re-import (will update SO link and mesh) - -### Creating Other Data Types -Use the same pattern: -1. Create template: `Tools > Data > Create Tower Template` -2. Add meshPath column to Tower.csv -3. Import: `Tools > Data > Import All CSV` - -## Troubleshooting - -**Prefab not created?** -- Check if template exists in `Assets/Data/Templates/` -- Verify `meshPath` column in CSV - -**Mesh not showing?** -- Verify `meshPath` is correct in CSV -- Check that mesh file exists at specified path - -**Components not configured?** -- Edit template prefab -- Re-import CSV to apply template changes to new prefabs - -**Want to keep manual prefab edits?** -- Prefabs created by importer are NOT overwritten -- Edits persist on next import (SO and mesh only update) diff --git a/Assembly-CSharp.csproj b/Assembly-CSharp.csproj index e5ab05f..39a2197 100644 --- a/Assembly-CSharp.csproj +++ b/Assembly-CSharp.csproj @@ -69,6 +69,7 @@ + @@ -82,6 +83,7 @@ + @@ -103,13 +105,16 @@ + + + @@ -132,6 +137,7 @@ + diff --git a/Assets/DefaultNetworkPrefabs.asset b/Assets/DefaultNetworkPrefabs.asset index 1635cda..99381b2 100644 --- a/Assets/DefaultNetworkPrefabs.asset +++ b/Assets/DefaultNetworkPrefabs.asset @@ -104,3 +104,13 @@ MonoBehaviour: SourcePrefabToOverride: {fileID: 0} SourceHashToOverride: 0 OverridingTargetPrefab: {fileID: 0} + - Override: 0 + Prefab: {fileID: 7603736553692962085, guid: f03e71a1b147c77498145a41db9d5c6e, type: 3} + SourcePrefabToOverride: {fileID: 0} + SourceHashToOverride: 0 + OverridingTargetPrefab: {fileID: 0} + - Override: 0 + Prefab: {fileID: 8294708185945415980, guid: eda89876457aa6143b1bef3330e8f7fb, type: 3} + SourcePrefabToOverride: {fileID: 0} + SourceHashToOverride: 0 + OverridingTargetPrefab: {fileID: 0} diff --git a/Assets/InputSystem_Actions.cs b/Assets/InputSystem_Actions.cs index 2b02cbc..dd9edff 100644 --- a/Assets/InputSystem_Actions.cs +++ b/Assets/InputSystem_Actions.cs @@ -280,6 +280,24 @@ public partial class @PlayerInputActions: IInputActionCollection2, IDisposable ""processors"": """", ""interactions"": """", ""initialStateCheck"": false + }, + { + ""name"": ""StartAsClient"", + ""type"": ""Button"", + ""id"": ""3cdb7b19-b155-4d50-bd36-d132b9290400"", + ""expectedControlType"": """", + ""processors"": """", + ""interactions"": """", + ""initialStateCheck"": false + }, + { + ""name"": ""DebugPanel"", + ""type"": ""Button"", + ""id"": ""2d93558e-a811-4563-9591-6ef734155d8d"", + ""expectedControlType"": """", + ""processors"": """", + ""interactions"": """", + ""initialStateCheck"": false } ], ""bindings"": [ @@ -799,6 +817,28 @@ public partial class @PlayerInputActions: IInputActionCollection2, IDisposable ""action"": ""Cancel"", ""isComposite"": false, ""isPartOfComposite"": false + }, + { + ""name"": """", + ""id"": ""492d997c-1c69-463e-a63f-dd327d7881b8"", + ""path"": ""/c"", + ""interactions"": """", + ""processors"": """", + ""groups"": "";Keyboard&Mouse"", + ""action"": ""StartAsClient"", + ""isComposite"": false, + ""isPartOfComposite"": false + }, + { + ""name"": """", + ""id"": ""c286789c-b46b-4160-8724-23412c73cb67"", + ""path"": ""/backquote"", + ""interactions"": """", + ""processors"": """", + ""groups"": "";Keyboard&Mouse"", + ""action"": ""DebugPanel"", + ""isComposite"": false, + ""isPartOfComposite"": false } ] }, @@ -1405,6 +1445,8 @@ public partial class @PlayerInputActions: IInputActionCollection2, IDisposable m_Player_QuickSlot7 = m_Player.FindAction("QuickSlot7", throwIfNotFound: true); m_Player_QuickSlot8 = m_Player.FindAction("QuickSlot8", throwIfNotFound: true); m_Player_Cancel = m_Player.FindAction("Cancel", throwIfNotFound: true); + m_Player_StartAsClient = m_Player.FindAction("StartAsClient", throwIfNotFound: true); + m_Player_DebugPanel = m_Player.FindAction("DebugPanel", throwIfNotFound: true); // UI m_UI = asset.FindActionMap("UI", throwIfNotFound: true); m_UI_Navigate = m_UI.FindAction("Navigate", throwIfNotFound: true); @@ -1519,6 +1561,8 @@ public partial class @PlayerInputActions: IInputActionCollection2, IDisposable private readonly InputAction m_Player_QuickSlot7; private readonly InputAction m_Player_QuickSlot8; private readonly InputAction m_Player_Cancel; + private readonly InputAction m_Player_StartAsClient; + private readonly InputAction m_Player_DebugPanel; /// /// Provides access to input actions defined in input action map "Player". /// @@ -1615,6 +1659,14 @@ public partial class @PlayerInputActions: IInputActionCollection2, IDisposable /// public InputAction @Cancel => m_Wrapper.m_Player_Cancel; /// + /// Provides access to the underlying input action "Player/StartAsClient". + /// + public InputAction @StartAsClient => m_Wrapper.m_Player_StartAsClient; + /// + /// Provides access to the underlying input action "Player/DebugPanel". + /// + public InputAction @DebugPanel => m_Wrapper.m_Player_DebugPanel; + /// /// Provides access to the underlying input action map instance. /// public InputActionMap Get() { return m_Wrapper.m_Player; } @@ -1703,6 +1755,12 @@ public partial class @PlayerInputActions: IInputActionCollection2, IDisposable @Cancel.started += instance.OnCancel; @Cancel.performed += instance.OnCancel; @Cancel.canceled += instance.OnCancel; + @StartAsClient.started += instance.OnStartAsClient; + @StartAsClient.performed += instance.OnStartAsClient; + @StartAsClient.canceled += instance.OnStartAsClient; + @DebugPanel.started += instance.OnDebugPanel; + @DebugPanel.performed += instance.OnDebugPanel; + @DebugPanel.canceled += instance.OnDebugPanel; } /// @@ -1777,6 +1835,12 @@ public partial class @PlayerInputActions: IInputActionCollection2, IDisposable @Cancel.started -= instance.OnCancel; @Cancel.performed -= instance.OnCancel; @Cancel.canceled -= instance.OnCancel; + @StartAsClient.started -= instance.OnStartAsClient; + @StartAsClient.performed -= instance.OnStartAsClient; + @StartAsClient.canceled -= instance.OnStartAsClient; + @DebugPanel.started -= instance.OnDebugPanel; + @DebugPanel.performed -= instance.OnDebugPanel; + @DebugPanel.canceled -= instance.OnDebugPanel; } /// @@ -2224,6 +2288,20 @@ public partial class @PlayerInputActions: IInputActionCollection2, IDisposable /// /// void OnCancel(InputAction.CallbackContext context); + /// + /// Method invoked when associated input action "StartAsClient" is either , or . + /// + /// + /// + /// + void OnStartAsClient(InputAction.CallbackContext context); + /// + /// Method invoked when associated input action "DebugPanel" is either , or . + /// + /// + /// + /// + void OnDebugPanel(InputAction.CallbackContext context); } /// /// Interface to implement callback methods for all input action callbacks associated with input actions defined by "UI" which allows adding and removing callbacks. diff --git a/Assets/InputSystem_Actions.inputactions b/Assets/InputSystem_Actions.inputactions index 0923e2a..26c3a05 100644 --- a/Assets/InputSystem_Actions.inputactions +++ b/Assets/InputSystem_Actions.inputactions @@ -194,6 +194,24 @@ "processors": "", "interactions": "", "initialStateCheck": false + }, + { + "name": "StartAsClient", + "type": "Button", + "id": "3cdb7b19-b155-4d50-bd36-d132b9290400", + "expectedControlType": "", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "DebugPanel", + "type": "Button", + "id": "2d93558e-a811-4563-9591-6ef734155d8d", + "expectedControlType": "", + "processors": "", + "interactions": "", + "initialStateCheck": false } ], "bindings": [ @@ -713,6 +731,28 @@ "action": "Cancel", "isComposite": false, "isPartOfComposite": false + }, + { + "name": "", + "id": "492d997c-1c69-463e-a63f-dd327d7881b8", + "path": "/c", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "StartAsClient", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "c286789c-b46b-4160-8724-23412c73cb67", + "path": "/backquote", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "DebugPanel", + "isComposite": false, + "isPartOfComposite": false } ] }, diff --git a/Assets/Prefabs/Bat.prefab b/Assets/Prefabs/Bat.prefab new file mode 100644 index 0000000..935aa1b --- /dev/null +++ b/Assets/Prefabs/Bat.prefab @@ -0,0 +1,122 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &7603736553692962085 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1194557353959628612} + - component: {fileID: 6659565122963588399} + m_Layer: 0 + m_Name: Bat + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1194557353959628612 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7603736553692962085} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -1.57958, y: 1.00001, z: -1.56753} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 3616642548623739450} + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &6659565122963588399 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7603736553692962085} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d5a57f767e5e46a458fc5d3c628d0cbb, type: 3} + m_Name: + m_EditorClassIdentifier: Unity.Netcode.Runtime::Unity.Netcode.NetworkObject + GlobalObjectIdHash: 4268566319 + InScenePlacedSourceGlobalObjectIdHash: 0 + DeferredDespawnTick: 0 + Ownership: 1 + AlwaysReplicateAsRoot: 0 + SynchronizeTransform: 1 + ActiveSceneSynchronization: 0 + SceneMigrationSynchronization: 0 + SpawnWithObservers: 1 + DontDestroyWithOwner: 0 + AutoObjectParentSync: 1 + SyncOwnerTransformWhenParented: 1 + AllowOwnerToParent: 0 +--- !u!1001 &3871508264071294417 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + serializedVersion: 3 + m_TransformParent: {fileID: 1194557353959628612} + m_Modifications: + - target: {fileID: -8679921383154817045, guid: 1261145a64d4f3e43bee728a02c1b5e3, type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: 1261145a64d4f3e43bee728a02c1b5e3, type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: 1261145a64d4f3e43bee728a02c1b5e3, type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: 1261145a64d4f3e43bee728a02c1b5e3, type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: 1261145a64d4f3e43bee728a02c1b5e3, type: 3} + propertyPath: m_LocalRotation.x + value: 0.000000021855694 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: 1261145a64d4f3e43bee728a02c1b5e3, type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: 1261145a64d4f3e43bee728a02c1b5e3, type: 3} + propertyPath: m_LocalRotation.z + value: -0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: 1261145a64d4f3e43bee728a02c1b5e3, type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: 1261145a64d4f3e43bee728a02c1b5e3, type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: 1261145a64d4f3e43bee728a02c1b5e3, type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 919132149155446097, guid: 1261145a64d4f3e43bee728a02c1b5e3, type: 3} + propertyPath: m_Name + value: Bat + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 1261145a64d4f3e43bee728a02c1b5e3, type: 3} +--- !u!4 &3616642548623739450 stripped +Transform: + m_CorrespondingSourceObject: {fileID: -8679921383154817045, guid: 1261145a64d4f3e43bee728a02c1b5e3, type: 3} + m_PrefabInstance: {fileID: 3871508264071294417} + m_PrefabAsset: {fileID: 0} diff --git a/Assets/Prefabs/Bat.prefab.meta b/Assets/Prefabs/Bat.prefab.meta new file mode 100644 index 0000000..cbd346e --- /dev/null +++ b/Assets/Prefabs/Bat.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: f03e71a1b147c77498145a41db9d5c6e +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Prefabs/Pickaxe.prefab b/Assets/Prefabs/Pickaxe.prefab new file mode 100644 index 0000000..4736d3d --- /dev/null +++ b/Assets/Prefabs/Pickaxe.prefab @@ -0,0 +1,122 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &8294708185945415980 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4786869462106053255} + - component: {fileID: 7258747535635499414} + m_Layer: 0 + m_Name: Pickaxe + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &4786869462106053255 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8294708185945415980} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -1.57958, y: 1.00001, z: -1.56753} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 5490866329018943490} + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &7258747535635499414 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8294708185945415980} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d5a57f767e5e46a458fc5d3c628d0cbb, type: 3} + m_Name: + m_EditorClassIdentifier: Unity.Netcode.Runtime::Unity.Netcode.NetworkObject + GlobalObjectIdHash: 1911485989 + InScenePlacedSourceGlobalObjectIdHash: 0 + DeferredDespawnTick: 0 + Ownership: 1 + AlwaysReplicateAsRoot: 0 + SynchronizeTransform: 1 + ActiveSceneSynchronization: 0 + SceneMigrationSynchronization: 0 + SpawnWithObservers: 1 + DontDestroyWithOwner: 0 + AutoObjectParentSync: 1 + SyncOwnerTransformWhenParented: 1 + AllowOwnerToParent: 0 +--- !u!1001 &5456604255163953129 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + serializedVersion: 3 + m_TransformParent: {fileID: 4786869462106053255} + m_Modifications: + - target: {fileID: -8679921383154817045, guid: 804d477fc7f114c498aa6f95452be893, type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: 804d477fc7f114c498aa6f95452be893, type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: 804d477fc7f114c498aa6f95452be893, type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: 804d477fc7f114c498aa6f95452be893, type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: 804d477fc7f114c498aa6f95452be893, type: 3} + propertyPath: m_LocalRotation.x + value: 0.00000008146034 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: 804d477fc7f114c498aa6f95452be893, type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: 804d477fc7f114c498aa6f95452be893, type: 3} + propertyPath: m_LocalRotation.z + value: -0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: 804d477fc7f114c498aa6f95452be893, type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: 804d477fc7f114c498aa6f95452be893, type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: 804d477fc7f114c498aa6f95452be893, type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 919132149155446097, guid: 804d477fc7f114c498aa6f95452be893, type: 3} + propertyPath: m_Name + value: pickaxe + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 804d477fc7f114c498aa6f95452be893, type: 3} +--- !u!4 &5490866329018943490 stripped +Transform: + m_CorrespondingSourceObject: {fileID: -8679921383154817045, guid: 804d477fc7f114c498aa6f95452be893, type: 3} + m_PrefabInstance: {fileID: 5456604255163953129} + m_PrefabAsset: {fileID: 0} diff --git a/Assets/Prefabs/Pickaxe.prefab.meta b/Assets/Prefabs/Pickaxe.prefab.meta new file mode 100644 index 0000000..3aed040 --- /dev/null +++ b/Assets/Prefabs/Pickaxe.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: eda89876457aa6143b1bef3330e8f7fb +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Prefabs/Player/Player.prefab b/Assets/Prefabs/Player/Player.prefab index ea50b18..fab860f 100644 --- a/Assets/Prefabs/Player/Player.prefab +++ b/Assets/Prefabs/Player/Player.prefab @@ -11,7 +11,6 @@ GameObject: - component: {fileID: 5887522270574905679} - component: {fileID: 2636831972010436653} - component: {fileID: 3792365921352178844} - - component: {fileID: 1698609800605343773} - component: {fileID: 3007098678582223509} - component: {fileID: 1883169379180791275} - component: {fileID: 8729870597719024730} @@ -20,6 +19,9 @@ GameObject: - component: {fileID: 6066313428661204362} - component: {fileID: 2443072964133329520} - component: {fileID: 2148255267416253297} + - component: {fileID: 1698609800605343773} + - component: {fileID: -4348726977448206869} + - component: {fileID: 7148704114816793672} m_Layer: 9 m_Name: Player m_TagString: Untagged @@ -55,7 +57,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: d5a57f767e5e46a458fc5d3c628d0cbb, type: 3} m_Name: m_EditorClassIdentifier: Unity.Netcode.Runtime::Unity.Netcode.NetworkObject - GlobalObjectIdHash: 1360081626 + GlobalObjectIdHash: 4211758632 InScenePlacedSourceGlobalObjectIdHash: 4211758632 DeferredDespawnTick: 0 Ownership: 1 @@ -88,28 +90,6 @@ MonoBehaviour: showHealthBar: 1 damageEffectPrefab: {fileID: 0} deathEffectPrefab: {fileID: 0} ---- !u!95 &1698609800605343773 -Animator: - serializedVersion: 7 - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1314983689436087486} - m_Enabled: 1 - m_Avatar: {fileID: 9000000, guid: 2632f2cc035d62d41bca411a318fbe36, type: 3} - m_Controller: {fileID: 9100000, guid: bb242bb2298e65941bcb502d7ae219cd, type: 2} - m_CullingMode: 0 - m_UpdateMode: 0 - m_ApplyRootMotion: 0 - m_LinearVelocityBlending: 0 - m_StabilizeFeet: 0 - m_AnimatePhysics: 0 - m_WarningMessage: - m_HasTransformHierarchy: 1 - m_AllowConstantClipSamplingOptimization: 1 - m_KeepAnimatorStateOnDisable: 0 - m_WriteDefaultValuesOnDisable: 0 --- !u!143 &3007098678582223509 CharacterController: m_ObjectHideFlags: 0 @@ -175,6 +155,7 @@ MonoBehaviour: interactableLayer: serializedVersion: 2 m_Bits: 128 + workPower: 10 rayOrigin: {fileID: 0} useForwardDirection: 1 playAnimations: 1 @@ -182,6 +163,7 @@ MonoBehaviour: blockDuringAnimation: 1 useEquipment: 1 showDebugRay: 1 + assignedWorker: {fileID: 0} --- !u!114 &5217638038410020423 MonoBehaviour: m_ObjectHideFlags: 0 @@ -243,10 +225,14 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: ac908541bf903c745a1794d409a5f048, type: 3} m_Name: m_EditorClassIdentifier: Assembly-CSharp::Northbound.EquipmentSocket + ShowTopMostFoldoutHeaderGroup: 1 sockets: - socketName: handslot.r socketTransform: {fileID: 2844947653216056832} currentEquipment: {fileID: 0} + equipmentPrefabs: + - {fileID: 7603736553692962085, guid: f03e71a1b147c77498145a41db9d5c6e, type: 3} + - {fileID: 8294708185945415980, guid: eda89876457aa6143b1bef3330e8f7fb, type: 3} --- !u!114 &2443072964133329520 MonoBehaviour: m_ObjectHideFlags: 0 @@ -275,6 +261,106 @@ MonoBehaviour: m_EditorClassIdentifier: Assembly-CSharp::Northbound.PlayerVisionProvider ShowTopMostFoldoutHeaderGroup: 1 visionRange: 20 +--- !u!95 &1698609800605343773 +Animator: + serializedVersion: 7 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1314983689436087486} + m_Enabled: 1 + m_Avatar: {fileID: 9000000, guid: 2632f2cc035d62d41bca411a318fbe36, type: 3} + m_Controller: {fileID: 9100000, guid: bb242bb2298e65941bcb502d7ae219cd, type: 2} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_AnimatePhysics: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 + m_WriteDefaultValuesOnDisable: 0 +--- !u!114 &-4348726977448206869 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1314983689436087486} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: e8d0727d5ae3244e3b569694d3912374, type: 3} + m_Name: + m_EditorClassIdentifier: Unity.Netcode.Runtime::Unity.Netcode.Components.NetworkAnimator + ShowTopMostFoldoutHeaderGroup: 1 + NetworkAnimatorExpanded: 0 + AuthorityMode: 0 + m_Animator: {fileID: 1698609800605343773} + TransitionStateInfoList: [] + AnimatorParameterEntries: + ParameterEntries: + - name: MoveSpeed + NameHash: 526065662 + Synchronize: 1 + ParameterType: 1 + - name: Mining + NameHash: 577859424 + Synchronize: 1 + ParameterType: 9 + - name: Attack + NameHash: 1080829965 + Synchronize: 1 + ParameterType: 9 + AnimatorParametersExpanded: 0 +--- !u!114 &7148704114816793672 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1314983689436087486} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: e96cb6065543e43c4a752faaa1468eb1, type: 3} + m_Name: + m_EditorClassIdentifier: Unity.Netcode.Runtime::Unity.Netcode.Components.NetworkTransform + ShowTopMostFoldoutHeaderGroup: 1 + NetworkTransformExpanded: 0 + AutoOwnerAuthorityTickOffset: 1 + PositionInterpolationType: 0 + RotationInterpolationType: 0 + ScaleInterpolationType: 0 + PositionLerpSmoothing: 1 + PositionMaxInterpolationTime: 0.1 + RotationLerpSmoothing: 1 + RotationMaxInterpolationTime: 0.1 + ScaleLerpSmoothing: 1 + ScaleMaxInterpolationTime: 0.1 + AuthorityMode: 0 + TickSyncChildren: 0 + UseUnreliableDeltas: 0 + SyncPositionX: 1 + SyncPositionY: 1 + SyncPositionZ: 1 + SyncRotAngleX: 1 + SyncRotAngleY: 1 + SyncRotAngleZ: 1 + SyncScaleX: 1 + SyncScaleY: 1 + SyncScaleZ: 1 + PositionThreshold: 0.001 + RotAngleThreshold: 0.01 + ScaleThreshold: 0.01 + UseQuaternionSynchronization: 0 + UseQuaternionCompression: 0 + UseHalfFloatPrecision: 0 + InLocalSpace: 0 + SwitchTransformSpaceWhenParented: 0 + Interpolate: 1 + SlerpPosition: 0 --- !u!1001 &1445453803682481668 PrefabInstance: m_ObjectHideFlags: 0 diff --git a/Assets/Resources.meta b/Assets/Resources.meta new file mode 100644 index 0000000..54cbb52 --- /dev/null +++ b/Assets/Resources.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 963daf2309f087a4192afcb548328e22 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scenes/GameMain.unity b/Assets/Scenes/GameMain.unity index 6c19d75..d569a03 100644 --- a/Assets/Scenes/GameMain.unity +++ b/Assets/Scenes/GameMain.unity @@ -1799,7 +1799,7 @@ MonoBehaviour: EnableNetworkLogs: 1 NetworkTopology: 1 UseCMBService: 0 - AutoSpawnPlayerPrefabClientSide: 1 + AutoSpawnPlayerPrefabClientSide: 0 NetworkMessageMetrics: 1 NetworkProfilingMetrics: 1 OldPrefabList: [] diff --git a/Assets/Scripts/Core.cs b/Assets/Scripts/Core.cs index fe0cfd1..17043d5 100644 --- a/Assets/Scripts/Core.cs +++ b/Assets/Scripts/Core.cs @@ -259,19 +259,14 @@ namespace Northbound if (!CanInteract(playerId)) return; - // 플레이어 인벤토리 가져오기 - var playerObject = NetworkManager.Singleton.ConnectedClients[playerId].PlayerObject; - if (playerObject == null) - return; - - var playerInventory = playerObject.GetComponent(); - if (playerInventory == null) + var resourceManager = ServerResourceManager.Instance; + if (resourceManager == null) { - Debug.LogWarning($"플레이어 {playerId}에게 PlayerResourceInventory 컴포넌트가 없습니다."); + Debug.LogWarning("ServerResourceManager 인스턴스를 찾을 수 없습니다."); return; } - int playerResourceAmount = playerInventory.CurrentResourceAmount; + int playerResourceAmount = resourceManager.GetPlayerResourceAmount(playerId); if (playerResourceAmount <= 0) { Debug.Log($"플레이어 {playerId}가 건낼 자원이 없습니다."); @@ -282,16 +277,13 @@ namespace Northbound if (depositAll) { - // 전부 건네기 depositAmount = playerResourceAmount; } else { - // 일부만 건네기 depositAmount = Mathf.Min(depositAmountPerInteraction, playerResourceAmount); } - // 무제한 저장소가 아니면 용량 제한 확인 if (!unlimitedStorage) { int availableSpace = maxStorageCapacity - _totalResources.Value; @@ -304,10 +296,8 @@ namespace Northbound return; } - // 플레이어로부터 자원 차감 - playerInventory.RemoveResourceServerRpc(depositAmount); - - // 코어에 자원 추가 + resourceManager.RemoveResource(playerId, depositAmount); + UpdatePlayerResourcesClientRpc(playerId); _totalResources.Value += depositAmount; Debug.Log($"[Core] 플레이어 {playerId}가 {depositAmount} 자원을 건넸습니다. 코어 총 자원: {_totalResources.Value}" + @@ -316,6 +306,20 @@ namespace Northbound ShowDepositEffectClientRpc(); } + [Rpc(SendTo.ClientsAndHost)] + private void UpdatePlayerResourcesClientRpc(ulong playerId) + { + var playerObject = NetworkManager.Singleton.ConnectedClients[playerId].PlayerObject; + if (playerObject != null) + { + var playerInventory = playerObject.GetComponent(); + if (playerInventory != null) + { + playerInventory.RequestResourceUpdateServerRpc(); + } + } + } + [Rpc(SendTo.ClientsAndHost)] private void ShowDepositEffectClientRpc() { diff --git a/Assets/Scripts/DebugLogUI.cs b/Assets/Scripts/DebugLogUI.cs new file mode 100644 index 0000000..81581b6 --- /dev/null +++ b/Assets/Scripts/DebugLogUI.cs @@ -0,0 +1,160 @@ +using UnityEngine; +using UnityEngine.UI; +using System.Collections.Generic; + +namespace Northbound +{ + public class DebugLogUI : MonoBehaviour + { + [Header("Settings")] + public int maxLogMessages = 50; + public float logDisplayDuration = 5f; + public KeyCode toggleKey = KeyCode.BackQuote; + + [Header("UI References")] + public GameObject logPanel; + public Text logText; + public GameObject scrollContent; + public ScrollRect scrollRect; + + private Queue _logMessages = new Queue(); + private bool _isVisible = true; + + private void Start() + { + // 이미 씬에 있는지 확인 + if (logPanel != null) + { + logPanel = CreateLogPanel(); + _isVisible = true; + } + } + + private void Update() + { + if (Input.GetKeyDown(toggleKey)) + { + ToggleLogPanel(); + } + } + + private void OnEnable() + { + if (logPanel != null) + { + Application.logMessageReceived += HandleLog; + } + } + + private void OnDisable() + { + if (logPanel != null) + { + Application.logMessageReceived -= HandleLog; + } + } + + private GameObject CreateLogPanel() + { + GameObject panel = new GameObject("DebugLogPanel"); + panel.AddComponent(); + Canvas canvas = panel.GetComponent(); + canvas.renderMode = RenderMode.ScreenSpaceOverlay; + canvas.sortingOrder = 9999; + + RectTransform canvasRect = canvas.GetComponent(); + canvasRect.anchorMin = Vector2.zero; + canvasRect.anchorMax = new Vector2(Screen.width, Screen.height); + canvasRect.sizeDelta = Vector2.zero; + canvasRect.localScale = Vector3.one; + + // 배경 + GameObject background = new GameObject("Background"); + background.transform.SetParent(canvas.transform, false); + Image bgImage = background.AddComponent(); + bgImage.color = new Color(0, 0, 0, 0.8f); + + RectTransform bgRect = background.AddComponent(); + bgRect.anchorMin = Vector2.zero; + bgRect.anchorMax = Vector2.one; + bgRect.sizeDelta = new Vector2(600, 300); + bgRect.localPosition = new Vector2(-300, -150); + + // 로그 내용 + GameObject content = new GameObject("Content"); + content.transform.SetParent(background.transform, false); + + RectTransform contentRect = content.AddComponent(); + contentRect.anchorMin = Vector2.zero; + contentRect.anchorMax = Vector2.one; + contentRect.sizeDelta = new Vector2(580, 280); + contentRect.localPosition = new Vector2(-290, -140); + + // 텍스트 + Text logTextComponent = content.AddComponent(); + logTextComponent.fontSize = 14; + logTextComponent.alignment = TextAnchor.UpperLeft; + logTextComponent.color = Color.white; + + // 스크롤뷰 + GameObject scrollView = new GameObject("ScrollView"); + scrollView.transform.SetParent(content.transform, false); + scrollRect = scrollView.AddComponent(); + scrollRect.content = contentRect; + scrollRect.viewport = new RectTransform(); + scrollRect.horizontal = false; + scrollRect.vertical = true; + scrollRect.scrollSensitivity = 1; + + return panel; + } + + private void HandleLog(string logString, string stackTrace, LogType type) + { + string timestamp = System.DateTime.Now.ToString("HH:mm:ss"); + string logMessage = $"[{timestamp}] {logString}"; + + _logMessages.Enqueue(logMessage); + if (_logMessages.Count > maxLogMessages) + { + _logMessages.Dequeue(); + } + + UpdateLogText(); + } + + private void UpdateLogText() + { + if (logText == null) return; + + System.Text.StringBuilder sb = new System.Text.StringBuilder(); + foreach (string msg in _logMessages) + { + sb.AppendLine(msg); + } + + logText.text = sb.ToString(); + } + + public void ToggleLogPanel() + { + if (logPanel != null) + { + _isVisible = !_isVisible; + logPanel.SetActive(_isVisible); + } + } + + public void Log(string message) + { + if (logPanel != null) + { + logPanel.SetActive(true); + _isVisible = true; + } + + Debug.Log($"[DebugLogUI] {message}"); + Debug.Log($"[DebugLogUI] 로그 패널 활성됨: {message}"); + } + } +} diff --git a/Assets/Scripts/DebugLogUI.cs.meta b/Assets/Scripts/DebugLogUI.cs.meta new file mode 100644 index 0000000..b7b1c9b --- /dev/null +++ b/Assets/Scripts/DebugLogUI.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: dd4b979683b78954bb4d9b224ec4c61d \ No newline at end of file diff --git a/Assets/Scripts/EquipmentSocket.cs b/Assets/Scripts/EquipmentSocket.cs index a54c3e0..924dee0 100644 --- a/Assets/Scripts/EquipmentSocket.cs +++ b/Assets/Scripts/EquipmentSocket.cs @@ -1,29 +1,34 @@ using UnityEngine; using System.Collections.Generic; +using Unity.Netcode; namespace Northbound { /// /// 플레이어의 장비 소켓 관리 (손, 등, 허리 등) /// - public class EquipmentSocket : MonoBehaviour + public class EquipmentSocket : NetworkBehaviour { [System.Serializable] public class Socket { - public string socketName; // "RightHand", "LeftHand", "Back" 등 - public Transform socketTransform; // 실제 본 Transform - [HideInInspector] public GameObject currentEquipment; // 현재 장착된 장비 + public string socketName; + public Transform socketTransform; + [HideInInspector] public GameObject currentEquipment; } [Header("Available Sockets")] public List sockets = new List(); + [Header("Equipment Prefabs")] + public GameObject[] equipmentPrefabs; + private Dictionary _socketDict = new Dictionary(); + private Dictionary _prefabDict = new Dictionary(); private void Awake() { - // 빠른 검색을 위한 딕셔너리 생성 + _socketDict.Clear(); foreach (var socket in sockets) { if (!string.IsNullOrEmpty(socket.socketName)) @@ -31,82 +36,124 @@ namespace Northbound _socketDict[socket.socketName] = socket; } } - } - /// - /// 소켓에 장비 부착 - /// - public GameObject AttachToSocket(string socketName, GameObject equipmentPrefab) - { - if (!_socketDict.TryGetValue(socketName, out Socket socket)) + _prefabDict.Clear(); + if (equipmentPrefabs != null) { - Debug.LogWarning($"소켓을 찾을 수 없습니다: {socketName}"); - return null; - } - - if (socket.socketTransform == null) - { - Debug.LogWarning($"소켓 Transform이 없습니다: {socketName}"); - return null; - } - - // 기존 장비 제거 - DetachFromSocket(socketName); - - // 새 장비 생성 - if (equipmentPrefab != null) - { - GameObject equipment = Instantiate(equipmentPrefab, socket.socketTransform); - equipment.transform.localPosition = Vector3.zero; - equipment.transform.localRotation = Quaternion.identity; - socket.currentEquipment = equipment; - - return equipment; - } - - return null; - } - - /// - /// 소켓에서 장비 제거 - /// - public void DetachFromSocket(string socketName) - { - if (!_socketDict.TryGetValue(socketName, out Socket socket)) - return; - - if (socket.currentEquipment != null) - { - Destroy(socket.currentEquipment); - socket.currentEquipment = null; + foreach (var prefab in equipmentPrefabs) + { + if (prefab != null) + { + _prefabDict[prefab.name] = prefab; + } + } } } - /// - /// 모든 소켓에서 장비 제거 - /// - public void DetachAll() + public override void OnNetworkDespawn() { foreach (var socket in sockets) { if (socket.currentEquipment != null) { - Destroy(socket.currentEquipment); + Object.Destroy(socket.currentEquipment); socket.currentEquipment = null; } } + base.OnNetworkDespawn(); + } + + public GameObject AttachToSocket(string socketName, GameObject equipmentPrefab) + { + if (equipmentPrefab != null) + { + AttachToSocketServerRpc(socketName, equipmentPrefab.name); + } + return null; + } + + [Rpc(SendTo.Server)] + private void AttachToSocketServerRpc(string socketName, string prefabName) + { + AttachToSocketClientRpc(socketName, prefabName); + } + + [Rpc(SendTo.ClientsAndHost)] + private void AttachToSocketClientRpc(string socketName, string prefabName) + { + if (!_socketDict.ContainsKey(socketName)) + return; + + var socket = sockets.Find(s => s.socketName == socketName); + if (socket == null || socket.socketTransform == null) + return; + + DetachFromSocketInternal(socketName); + + GameObject prefab = FindPrefab(prefabName); + if (prefab != null) + { + GameObject equipment = Object.Instantiate(prefab, socket.socketTransform); + equipment.transform.localPosition = Vector3.zero; + equipment.transform.localRotation = Quaternion.identity; + socket.currentEquipment = equipment; + } + } + + public void DetachFromSocket(string socketName) + { + DetachFromSocketServerRpc(socketName); + } + + [Rpc(SendTo.Server)] + private void DetachFromSocketServerRpc(string socketName) + { + DetachFromSocketClientRpc(socketName); + } + + [Rpc(SendTo.ClientsAndHost)] + private void DetachFromSocketClientRpc(string socketName) + { + DetachFromSocketInternal(socketName); + } + + private void DetachFromSocketInternal(string socketName) + { + var socket = sockets.Find(s => s.socketName == socketName); + if (socket == null) return; + + if (socket.currentEquipment != null) + { + Object.Destroy(socket.currentEquipment); + socket.currentEquipment = null; + } } - /// - /// 특정 소켓에 장비가 있는지 확인 - /// public bool HasEquipment(string socketName) { - if (_socketDict.TryGetValue(socketName, out Socket socket)) + var socket = sockets.Find(s => s.socketName == socketName); + return socket != null && socket.currentEquipment != null; + } + + public GameObject GetEquipment(string socketName) + { + var socket = sockets.Find(s => s.socketName == socketName); + return socket != null ? socket.currentEquipment : null; + } + + private GameObject FindPrefab(string name) + { + if (_prefabDict.TryGetValue(name, out var prefab)) { - return socket.currentEquipment != null; + return prefab; } - return false; + + prefab = Resources.Load($"Prefabs/{name}"); + if (prefab != null) + { + return prefab; + } + return Resources.Load(name); } } -} \ No newline at end of file +} diff --git a/Assets/Scripts/ForceRecompile.txt b/Assets/Scripts/ForceRecompile.txt new file mode 100644 index 0000000..e69de29 diff --git a/Assets/Scripts/ForceRecompile.txt.meta b/Assets/Scripts/ForceRecompile.txt.meta new file mode 100644 index 0000000..59652e3 --- /dev/null +++ b/Assets/Scripts/ForceRecompile.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 871f9f40b5b3cb54ab7c0a76b592bc47 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/NetworkConnectionHandler.cs b/Assets/Scripts/NetworkConnectionHandler.cs index 569659a..17f3663 100644 --- a/Assets/Scripts/NetworkConnectionHandler.cs +++ b/Assets/Scripts/NetworkConnectionHandler.cs @@ -32,6 +32,7 @@ namespace Northbound { NetworkManager.Singleton.ConnectionApprovalCallback = ApprovalCheck; NetworkManager.Singleton.OnServerStarted += OnServerStarted; + NetworkManager.Singleton.OnClientConnectedCallback += OnClientConnected; Debug.Log("[Connection] ConnectionApprovalCallback 등록됨"); } else @@ -50,7 +51,7 @@ namespace Northbound spawnPoints.Clear(); foreach (var point in sortedPoints) { - if (point.isAvailable) + if (point != null && point.transform != null && point.isAvailable) { spawnPoints.Add(point.transform); } @@ -62,30 +63,92 @@ namespace Northbound private void OnServerStarted() { Debug.Log("[Connection] 서버 시작됨"); + + if (ServerResourceManager.Instance == null) + { + GameObject resourceManagerObj = new GameObject("ServerResourceManager"); + ServerResourceManager manager = resourceManagerObj.AddComponent(); + + NetworkObject networkObject = resourceManagerObj.GetComponent(); + if (networkObject == null) + { + networkObject = resourceManagerObj.AddComponent(); + } + + networkObject.Spawn(); + Debug.Log("[Connection] ServerResourceManager spawned."); + } + + if (NetworkManager.Singleton.IsHost) + { + SpawnPlayer(NetworkManager.Singleton.LocalClientId); + } + } + + private void OnClientConnected(ulong clientId) + { + if (!NetworkManager.Singleton.IsServer) return; + if (clientId == NetworkManager.Singleton.LocalClientId) return; + + Debug.Log($"[Connection] 클라이언트 {clientId} 연결됨"); + + if (!NetworkManager.Singleton.ConnectedClients.TryGetValue(clientId, out var client) || client.PlayerObject != null) + { + Debug.Log($"[Connection] 클라이언트 {clientId}의 플레이어가 이미 존재합니다."); + return; + } + + SpawnPlayer(clientId); + } + + private void SpawnPlayer(ulong clientId) + { + Vector3 spawnPosition = GetSpawnPosition(clientId); + Quaternion spawnRotation = GetSpawnRotation(clientId); + + GameObject playerPrefab = NetworkManager.Singleton.NetworkConfig.PlayerPrefab; + if (playerPrefab == null) + { + Debug.LogError("[Connection] PlayerPrefab이 null입니다!"); + return; + } + + GameObject playerObject = Instantiate(playerPrefab, spawnPosition, spawnRotation); + NetworkObject networkObject = playerObject.GetComponent(); + if (networkObject == null) + { + Debug.LogError("[Connection] PlayerPrefab에 NetworkObject가 없습니다!"); + return; + } + + networkObject.SpawnAsPlayerObject(clientId); + + Debug.Log($"[Connection] 플레이어 {clientId} 스폰됨: {spawnPosition}"); } private void ApprovalCheck( NetworkManager.ConnectionApprovalRequest request, NetworkManager.ConnectionApprovalResponse response) { - // 🔍 디버깅: 스폰 포인트 상태 확인 + spawnPoints.RemoveAll(p => p == null); + if (spawnPoints.Count == 0) { Debug.LogError($"[Connection] 스폰 포인트가 없습니다! 씬에 PlayerSpawnPoint가 있는지 확인하세요."); } response.Approved = true; - response.CreatePlayerObject = true; - - // 스폰 위치 설정 - response.Position = GetSpawnPosition(request.ClientNetworkId); - response.Rotation = GetSpawnRotation(request.ClientNetworkId); - - Debug.Log($"[Connection] 클라이언트 {request.ClientNetworkId} 승인됨. 스폰 위치: {response.Position}"); + response.CreatePlayerObject = false; + response.Position = Vector3.zero; + response.Rotation = Quaternion.identity; + + Debug.Log($"[Connection] 클라이언트 {request.ClientNetworkId} 승인됨. 수동 스폰으로 대기."); } private Vector3 GetSpawnPosition(ulong clientId) { + spawnPoints.RemoveAll(p => p == null); + if (spawnPoints.Count == 0) { Debug.LogWarning("[Connection] 스폰 포인트가 없습니다. 기본 위치 반환."); @@ -106,6 +169,12 @@ namespace Northbound _nextSpawnIndex = (_nextSpawnIndex + 1) % spawnPoints.Count; } spawnIndex = _clientSpawnIndices[clientId]; + + if (spawnIndex >= spawnPoints.Count) + { + Debug.LogWarning($"[Connection] 스폰 인덱스 {spawnIndex}가 범위를 벗어났습니다. 기본값으로 조정."); + spawnIndex = spawnIndex % spawnPoints.Count; + } } Debug.Log($"[Connection] 클라이언트 {clientId}에게 스폰 인덱스 {spawnIndex} 할당"); @@ -114,12 +183,19 @@ namespace Northbound private Quaternion GetSpawnRotation(ulong clientId) { + spawnPoints.RemoveAll(p => p == null); + if (spawnPoints.Count == 0) return Quaternion.identity; int spawnIndex = _clientSpawnIndices.ContainsKey(clientId) ? _clientSpawnIndices[clientId] : 0; + + if (spawnIndex >= spawnPoints.Count) + { + spawnIndex = spawnIndex % spawnPoints.Count; + } return spawnPoints[spawnIndex].rotation; } @@ -130,6 +206,7 @@ namespace Northbound { NetworkManager.Singleton.ConnectionApprovalCallback = null; NetworkManager.Singleton.OnServerStarted -= OnServerStarted; + NetworkManager.Singleton.OnClientConnectedCallback -= OnClientConnected; } } } diff --git a/Assets/Scripts/NetworkDebug.cs b/Assets/Scripts/NetworkDebug.cs new file mode 100644 index 0000000..f48823c --- /dev/null +++ b/Assets/Scripts/NetworkDebug.cs @@ -0,0 +1,86 @@ +using System.Collections; +using UnityEngine; +using Unity.Netcode; +using Northbound; + +public class NetworkDebug : MonoBehaviour +{ + private void Start() + { + Debug.Log("=== NETWORK DEBUG INFO ==="); + + // 1. NetworkManager 상태 + if (NetworkManager.Singleton != null) + { + Debug.Log($"NetworkManager: IsServer={NetworkManager.Singleton.IsServer}, IsClient={NetworkManager.Singleton.IsClient}, IsHost={NetworkManager.Singleton.IsHost}"); + } + + // 2. 스폰 포인트 검색 + PlayerSpawnPoint[] spawnPoints = FindObjectsByType(FindObjectsSortMode.None); + Debug.Log($"PlayerSpawnPoints: Found {spawnPoints.Length} objects"); + foreach (var sp in spawnPoints) + { + Debug.Log($" - {sp.name} at {sp.transform.position}, isAvailable={sp.isAvailable}, spawnIndex={sp.spawnIndex}"); + } + + // 3. NetworkConnectionHandler 확인 + var connectionHandler = FindObjectOfType(); + if (connectionHandler != null) + { + Debug.Log($"NetworkConnectionHandler: spawnPoints.Count={connectionHandler.spawnPoints.Count}, findAuto={connectionHandler.findSpawnPointsAutomatically}"); + } + + // 4. NetworkSpawnManager 확인 + var spawnManager = FindObjectOfType(); + if (spawnManager != null) + { + Debug.Log($"NetworkSpawnManager: spawnPoints.Count={spawnManager.spawnPoints.Count}, findAuto={spawnManager.findSpawnPointsAutomatically}"); + } + + // 플레이어가 스폰될 때까지 대기 + StartCoroutine(CheckPlayerAfterSpawn()); + } + + private IEnumerator CheckPlayerAfterSpawn() + { + // 플레이어가 스폰될 때까지 최대 5초 대기 + for (int i = 0; i < 50; i++) + { + yield return new WaitForSeconds(0.1f); + + var players = GameObject.FindObjectsByType(FindObjectsSortMode.None); + if (players != null && players.Length > 0) + { + Debug.Log($"Found {players.Length} player(s) - checking equipment..."); + + foreach (var playerCtrl in players) + { + Debug.Log($"Player found: {playerCtrl.name}, IsOwner={playerCtrl.IsOwner}"); + + var equipmentSocketOnPlayer = playerCtrl.GetComponent(); + var networkEquipSocketOnPlayer = playerCtrl.GetComponent(); + + if (equipmentSocketOnPlayer != null) + Debug.Log($"Player has EquipmentSocket: YES"); + else + Debug.LogWarning($"Player has EquipmentSocket: NO"); + + if (networkEquipSocketOnPlayer != null) + Debug.Log($"Player has NetworkEquipmentSocket: YES"); + else + Debug.LogWarning($"Player has NetworkEquipmentSocket: NO"); + } + + Debug.Log("=== DEBUG INFO END ==="); + yield break; + } + } + + // 5초 후에도 플레이어가 없는지 확인 + var finalCheck = GameObject.FindObjectsByType(FindObjectsSortMode.None); + if (finalCheck == null || finalCheck.Length == 0) + { + Debug.LogWarning($"Player did not spawn within 5 seconds!"); + } + } +} diff --git a/Assets/Scripts/NetworkDebug.cs.meta b/Assets/Scripts/NetworkDebug.cs.meta new file mode 100644 index 0000000..9315c77 --- /dev/null +++ b/Assets/Scripts/NetworkDebug.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: c4d562c43da292a4082bb22cb0d3e361 \ No newline at end of file diff --git a/Assets/Scripts/NetworkEquipmentSocket.cs b/Assets/Scripts/NetworkEquipmentSocket.cs new file mode 100644 index 0000000..699a0c5 --- /dev/null +++ b/Assets/Scripts/NetworkEquipmentSocket.cs @@ -0,0 +1,162 @@ +using UnityEngine; +using System.Collections.Generic; +using Unity.Netcode; + +namespace Northbound +{ + /// + /// 네트워크 환경에서 작동하는 장비 소켓 관리 + /// + public class NetworkEquipmentSocket : NetworkBehaviour + { + [System.Serializable] + public class Socket + { + public string socketName; // "RightHand", "LeftHand", "Back" 등 + public Transform socketTransform; // 실제 본 Transform + [HideInInspector] public NetworkObject currentEquipmentNetworkObj; // 현재 장착된 장비 NetworkObject + [HideInInspector] public GameObject currentEquipment; // 현재 장착된 장비 GameObject + } + + [Header("Available Sockets")] + public List sockets = new List(); + + private Dictionary _socketDict = new Dictionary(); + + private void Awake() + { + // 빠른 검색을 위한 딕셔너리 생성 + foreach (var socket in sockets) + { + if (!string.IsNullOrEmpty(socket.socketName)) + { + _socketDict[socket.socketName] = socket; + } + } + } + + /// + /// 소켓에 장비 부착 (네트워크 스폰) + /// + public GameObject AttachToSocket(string socketName, GameObject equipmentPrefab) + { + if (!IsServer) + { + Debug.LogWarning("[NetworkEquipmentSocket] 서버에서만 장비를 장착할 수 있습니다."); + return null; + } + + if (!_socketDict.TryGetValue(socketName, out Socket socket)) + { + Debug.LogWarning($"[NetworkEquipmentSocket] 소켓을 찾을 수 없습니다: {socketName}"); + return null; + } + + if (socket.socketTransform == null) + { + Debug.LogWarning($"[NetworkEquipmentSocket] 소켓 Transform이 없습니다: {socketName}"); + return null; + } + + // 기존 장비 제거 + DetachFromSocket(socketName); + + // 새 장비 생성 + if (equipmentPrefab != null) + { + GameObject equipment = Instantiate(equipmentPrefab, socket.socketTransform); + equipment.transform.localPosition = Vector3.zero; + equipment.transform.localRotation = Quaternion.identity; + + // NetworkObject 확인 + NetworkObject netObj = equipment.GetComponent(); + if (netObj == null) + { + Debug.LogWarning($"[NetworkEquipmentSocket] 장비 프리팹에 NetworkObject가 없습니다: {equipmentPrefab.name}"); + Destroy(equipment); + return null; + } + + // 네트워크에 스폰 + netObj.Spawn(true); // true = 소유자가 파괴되면 장비도 파괴 + socket.currentEquipment = equipment; + socket.currentEquipmentNetworkObj = netObj; + + Debug.Log($"[NetworkEquipmentSocket] 장비 장착됨: {socketName} -> {equipmentPrefab.name}"); + return equipment; + } + + return null; + } + + /// + /// 소켓에서 장비 제거 (네트워크 디스폰) + /// + public void DetachFromSocket(string socketName) + { + if (!IsServer) + { + Debug.LogWarning("[NetworkEquipmentSocket] 서버에서만 장비를 제거할 수 있습니다."); + return; + } + + if (!_socketDict.TryGetValue(socketName, out Socket socket)) + return; + + if (socket.currentEquipment != null) + { + // 네트워크에서 디스폰 + if (socket.currentEquipmentNetworkObj != null && socket.currentEquipmentNetworkObj.IsSpawned) + { + socket.currentEquipmentNetworkObj.Despawn(true); + } + + // 로컬 파괴 + if (socket.currentEquipment != null) + { + Destroy(socket.currentEquipment); + } + + socket.currentEquipment = null; + socket.currentEquipmentNetworkObj = null; + + Debug.Log($"[NetworkEquipmentSocket] 장비 제거됨: {socketName}"); + } + } + + /// + /// 모든 소켓에서 장비 제거 + /// + public void DetachAll() + { + if (!IsServer) return; + + foreach (var socket in sockets) + { + if (socket.currentEquipment != null) + { + if (socket.currentEquipmentNetworkObj != null && socket.currentEquipmentNetworkObj.IsSpawned) + { + socket.currentEquipmentNetworkObj.Despawn(true); + } + + Destroy(socket.currentEquipment); + socket.currentEquipment = null; + socket.currentEquipmentNetworkObj = null; + } + } + } + + /// + /// 특정 소켓에 장비가 있는지 확인 + /// + public bool HasEquipment(string socketName) + { + if (_socketDict.TryGetValue(socketName, out Socket socket)) + { + return socket.currentEquipment != null; + } + return false; + } + } +} diff --git a/Assets/Scripts/NetworkEquipmentSocket.cs.meta b/Assets/Scripts/NetworkEquipmentSocket.cs.meta new file mode 100644 index 0000000..7c802a8 --- /dev/null +++ b/Assets/Scripts/NetworkEquipmentSocket.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 58c239d2e984593429db90ada66cbdcf \ No newline at end of file diff --git a/Assets/Scripts/NetworkManagerUI.cs b/Assets/Scripts/NetworkManagerUI.cs index aa94a60..3fff606 100644 --- a/Assets/Scripts/NetworkManagerUI.cs +++ b/Assets/Scripts/NetworkManagerUI.cs @@ -1,35 +1,30 @@ -using Unity.Netcode; using UnityEngine; using UnityEngine.UI; -public class NetworkManagerUI : MonoBehaviour +namespace Northbound { - [Header("UI Buttons")] - [SerializeField] private Button hostButton; - [SerializeField] private Button clientButton; - [SerializeField] private Button serverButton; - - private void Start() + /// + /// 키보드 단축키로 클라이언트/호스트 모드 시작 + /// + public class ShortcutNetworkStarterUI : MonoBehaviour { - if (hostButton != null) - hostButton.onClick.AddListener(() => NetworkManager.Singleton.StartHost()); + [Header("UI Reference")] + [SerializeField] private Text statusText; - if (clientButton != null) - clientButton.onClick.AddListener(() => NetworkManager.Singleton.StartClient()); + private void Start() + { + if (statusText != null) + { + statusText.text = "'C' 키를 누르면 클라이언트 모드 시작"; + } + } - if (serverButton != null) - serverButton.onClick.AddListener(() => NetworkManager.Singleton.StartServer()); - } - - private void OnDestroy() - { - if (hostButton != null) - hostButton.onClick.RemoveAllListeners(); - - if (clientButton != null) - clientButton.onClick.RemoveAllListeners(); - - if (serverButton != null) - serverButton.onClick.RemoveAllListeners(); + private void Update() + { + if (Input.GetKeyDown(KeyCode.BackQuote)) + { + statusText.gameObject.SetActive(!statusText.gameObject.activeSelf); + } + } } } diff --git a/Assets/Scripts/PlayerInteraction.cs b/Assets/Scripts/PlayerInteraction.cs index a8fb3e9..4733156 100644 --- a/Assets/Scripts/PlayerInteraction.cs +++ b/Assets/Scripts/PlayerInteraction.cs @@ -194,13 +194,15 @@ namespace Northbound public void OnInteractionComplete() { + if (!IsOwner) return; + if (_interactionTimeoutCoroutine != null) { StopCoroutine(_interactionTimeoutCoroutine); _interactionTimeoutCoroutine = null; } _isInteracting = false; - Debug.Log("[PlayerInteraction] 상호작용 완료"); + Debug.Log($"[PlayerInteraction] Owner {OwnerClientId} - 상호작용 완료"); } // ======================================== diff --git a/Assets/Scripts/PlayerResourceInventory.cs b/Assets/Scripts/PlayerResourceInventory.cs index 63b41ff..222dd25 100644 --- a/Assets/Scripts/PlayerResourceInventory.cs +++ b/Assets/Scripts/PlayerResourceInventory.cs @@ -3,74 +3,57 @@ using UnityEngine; namespace Northbound { - /// - /// 플레이어의 자원 인벤토리 관리 - /// public class PlayerResourceInventory : NetworkBehaviour { - [Header("Inventory Settings")] - public int maxResourceCapacity = 100; // 최대 자원 보유량 + public int maxResourceCapacity = 100; + private int _displayAmount = 0; - private NetworkVariable _currentResourceAmount = new NetworkVariable( - 0, - NetworkVariableReadPermission.Everyone, - NetworkVariableWritePermission.Server - ); - - public int CurrentResourceAmount => _currentResourceAmount.Value; + public int CurrentResourceAmount => _displayAmount; public int MaxResourceCapacity => maxResourceCapacity; - /// - /// 자원을 추가할 수 있는지 확인 - /// + public override void OnNetworkSpawn() + { + if (IsClient && IsOwner) + { + RequestResourceUpdateServerRpc(); + } + } + + [Rpc(SendTo.Server)] + public void RequestResourceUpdateServerRpc() + { + var resourceManager = ServerResourceManager.Instance; + if (resourceManager != null) + { + int amount = resourceManager.GetPlayerResourceAmount(OwnerClientId); + UpdateResourceAmountClientRpc(amount); + } + } + + [Rpc(SendTo.ClientsAndHost)] + private void UpdateResourceAmountClientRpc(int amount) + { + _displayAmount = amount; + } + public bool CanAddResource(int amount) { - return _currentResourceAmount.Value + amount <= maxResourceCapacity; + var resourceManager = ServerResourceManager.Instance; + if (resourceManager != null) + { + return resourceManager.CanAddResource(OwnerClientId, amount); + } + return false; } - /// - /// 추가 가능한 최대 자원량 계산 - /// public int GetAvailableSpace() { - return maxResourceCapacity - _currentResourceAmount.Value; - } - - /// - /// 자원 추가 (서버에서만 호출) - /// - [Rpc(SendTo.Server, InvokePermission = RpcInvokePermission.Everyone)] - public void AddResourceServerRpc(int amount) - { - if (amount <= 0) return; - - int actualAmount = Mathf.Min(amount, maxResourceCapacity - _currentResourceAmount.Value); - _currentResourceAmount.Value += actualAmount; - - Debug.Log($"플레이어 {OwnerClientId} - 자원 추가: +{actualAmount}, 현재: {_currentResourceAmount.Value}/{maxResourceCapacity}"); - } - - /// - /// 자원 제거 (서버에서만 호출) - /// - [Rpc(SendTo.Server, InvokePermission = RpcInvokePermission.Everyone)] - public void RemoveResourceServerRpc(int amount) - { - if (amount <= 0) return; - - int actualAmount = Mathf.Min(amount, _currentResourceAmount.Value); - _currentResourceAmount.Value -= actualAmount; - - Debug.Log($"플레이어 {OwnerClientId} - 자원 사용: -{actualAmount}, 현재: {_currentResourceAmount.Value}/{maxResourceCapacity}"); - } - - /// - /// 자원 설정 (서버에서만 호출) - /// - [Rpc(SendTo.Server, InvokePermission = RpcInvokePermission.Everyone)] - public void SetResourceServerRpc(int amount) - { - _currentResourceAmount.Value = Mathf.Clamp(amount, 0, maxResourceCapacity); + var resourceManager = ServerResourceManager.Instance; + if (resourceManager != null) + { + return resourceManager.GetAvailableSpace(OwnerClientId); + } + return 0; } } -} \ No newline at end of file +} diff --git a/Assets/Scripts/Resource.cs b/Assets/Scripts/Resource.cs index 199a07d..a3662ed 100644 --- a/Assets/Scripts/Resource.cs +++ b/Assets/Scripts/Resource.cs @@ -1,5 +1,6 @@ using Unity.Netcode; using UnityEngine; +using System.Collections.Generic; namespace Northbound { @@ -112,6 +113,7 @@ namespace Northbound { _currentResources.Value = maxResources; _lastRechargeTime = Time.time; + _lastGatheringTime = Time.time - gatheringCooldown; } } @@ -137,28 +139,17 @@ namespace Northbound public bool CanInteract(ulong playerId) { - // 자원 노드에 자원이 없으면 상호작용 불가 if (_currentResources.Value <= 0) return false; - // 쿨다운 확인 if (Time.time - _lastGatheringTime < gatheringCooldown) return false; - // 플레이어 인벤토리 확인 - if (NetworkManager.Singleton != null && - NetworkManager.Singleton.ConnectedClients.TryGetValue(playerId, out var client)) + var resourceManager = ServerResourceManager.Instance; + if (resourceManager != null) { - if (client.PlayerObject != null) - { - var playerInventory = client.PlayerObject.GetComponent(); - if (playerInventory != null) - { - // 플레이어가 받을 수 있는 공간이 없으면 상호작용 불가 - if (playerInventory.GetAvailableSpace() <= 0) - return false; - } - } + if (resourceManager.GetAvailableSpace(playerId) <= 0) + return false; } return true; @@ -211,17 +202,11 @@ namespace Northbound if (!CanInteract(playerId)) return; - var playerObject = NetworkManager.Singleton.ConnectedClients[playerId].PlayerObject; - if (playerObject == null) + var resourceManager = ServerResourceManager.Instance; + if (resourceManager == null) return; - var playerInventory = playerObject.GetComponent(); - if (playerInventory == null) - { - return; - } - - int playerAvailableSpace = playerInventory.GetAvailableSpace(); + int playerAvailableSpace = resourceManager.GetAvailableSpace(playerId); int gatheredAmount = Mathf.Min( resourcesPerGathering, @@ -237,12 +222,27 @@ namespace Northbound _currentResources.Value -= gatheredAmount; _lastGatheringTime = Time.time; - playerInventory.AddResourceServerRpc(gatheredAmount); + resourceManager.AddResource(playerId, gatheredAmount); + UpdatePlayerResourcesClientRpc(playerId); ShowGatheringEffectClientRpc(); } [Rpc(SendTo.ClientsAndHost)] + private void UpdatePlayerResourcesClientRpc(ulong playerId) + { + var playerObject = NetworkManager.Singleton.ConnectedClients[playerId].PlayerObject; + if (playerObject != null) + { + var playerInventory = playerObject.GetComponent(); + if (playerInventory != null) + { + playerInventory.RequestResourceUpdateServerRpc(); + } + } + } + + [Rpc(SendTo.NotServer)] private void ShowGatheringEffectClientRpc() { if (gatheringEffectPrefab != null && effectSpawnPoint != null) @@ -275,4 +275,4 @@ namespace Northbound return transform; } } -} \ No newline at end of file +} diff --git a/Assets/Scripts/ResourcePickup.cs b/Assets/Scripts/ResourcePickup.cs index 2a21fee..2e70a50 100644 --- a/Assets/Scripts/ResourcePickup.cs +++ b/Assets/Scripts/ResourcePickup.cs @@ -32,24 +32,14 @@ namespace Northbound public bool CanInteract(ulong playerId) { - // 이미 수집됨 if (_isCollected) return false; - // 플레이어 인벤토리 확인 - if (NetworkManager.Singleton != null && - NetworkManager.Singleton.ConnectedClients.TryGetValue(playerId, out var client)) + var resourceManager = ServerResourceManager.Instance; + if (resourceManager != null) { - if (client.PlayerObject != null) - { - var playerInventory = client.PlayerObject.GetComponent(); - if (playerInventory != null) - { - // 플레이어가 받을 수 있는 공간이 없으면 상호작용 불가 - if (playerInventory.GetAvailableSpace() <= 0) - return false; - } - } + if (resourceManager.GetAvailableSpace(playerId) <= 0) + return false; } return true; @@ -69,49 +59,52 @@ namespace Northbound if (!CanInteract(playerId)) return; - // 중복 수집 방지 if (_isCollected) return; _isCollected = true; - // 플레이어의 인벤토리 확인 - var playerObject = NetworkManager.Singleton.ConnectedClients[playerId].PlayerObject; - if (playerObject == null) - return; - - var playerInventory = playerObject.GetComponent(); - if (playerInventory == null) + var resourceManager = ServerResourceManager.Instance; + if (resourceManager == null) { - Debug.LogWarning($"플레이어 {playerId}에게 PlayerResourceInventory 컴포넌트가 없습니다."); + Debug.LogWarning("ServerResourceManager 인스턴스를 찾을 수 없습니다."); + _isCollected = false; return; } - // 플레이어가 받을 수 있는 최대량 계산 - int playerAvailableSpace = playerInventory.GetAvailableSpace(); - - // 실제 지급할 양 계산 + int playerAvailableSpace = resourceManager.GetAvailableSpace(playerId); int collectedAmount = Mathf.Min(resourceAmount, playerAvailableSpace); if (collectedAmount <= 0) { Debug.Log($"플레이어 {playerId}의 인벤토리가 가득 찼습니다."); - _isCollected = false; // 수집 실패 시 다시 시도 가능하도록 + _isCollected = false; return; } - // 플레이어에게 자원 추가 - playerInventory.AddResourceServerRpc(collectedAmount); + resourceManager.AddResource(playerId, collectedAmount); + UpdatePlayerResourcesClientRpc(playerId); Debug.Log($"플레이어 {playerId}가 {collectedAmount} {resourceName}을(를) 획득했습니다."); - // 이펙트 표시 및 오브젝트 제거 ShowPickupEffectClientRpc(); - - // 짧은 딜레이 후 제거 (이펙트를 위해) Invoke(nameof(DestroyPickup), 0.1f); } + [Rpc(SendTo.ClientsAndHost)] + private void UpdatePlayerResourcesClientRpc(ulong playerId) + { + var playerObject = NetworkManager.Singleton.ConnectedClients[playerId].PlayerObject; + if (playerObject != null) + { + var playerInventory = playerObject.GetComponent(); + if (playerInventory != null) + { + playerInventory.RequestResourceUpdateServerRpc(); + } + } + } + [Rpc(SendTo.ClientsAndHost)] private void ShowPickupEffectClientRpc() { diff --git a/Assets/Scripts/ServerResourceManager.cs b/Assets/Scripts/ServerResourceManager.cs new file mode 100644 index 0000000..27e0c46 --- /dev/null +++ b/Assets/Scripts/ServerResourceManager.cs @@ -0,0 +1,101 @@ +using Unity.Netcode; +using UnityEngine; +using System.Collections.Generic; + +namespace Northbound +{ + public class ServerResourceManager : NetworkBehaviour + { + public static ServerResourceManager Instance { get; private set; } + + private Dictionary _playerResources = new Dictionary(); + private NetworkVariable _resourcesData = new NetworkVariable(); + + private void Awake() + { + if (Instance != null && Instance != this) + { + Destroy(gameObject); + return; + } + Instance = this; + } + + public override void OnNetworkSpawn() + { + if (IsServer) + { + Instance = this; + NetworkManager.Singleton.OnClientConnectedCallback += OnClientConnected; + NetworkManager.Singleton.OnClientDisconnectCallback += OnClientDisconnected; + } + } + + public override void OnNetworkDespawn() + { + if (IsServer) + { + if (NetworkManager.Singleton != null) + { + NetworkManager.Singleton.OnClientConnectedCallback -= OnClientConnected; + NetworkManager.Singleton.OnClientDisconnectCallback -= OnClientDisconnected; + } + } + } + + private void OnClientConnected(ulong clientId) + { + _playerResources[clientId] = 0; + } + + private void OnClientDisconnected(ulong clientId) + { + _playerResources.Remove(clientId); + } + + public int GetPlayerResourceAmount(ulong clientId) + { + if (_playerResources.TryGetValue(clientId, out var resource)) + { + return resource; + } + return 0; + } + + public bool CanAddResource(ulong clientId, int amount) + { + if (_playerResources.TryGetValue(clientId, out var resource)) + { + return resource + amount <= 100; + } + return false; + } + + public int GetAvailableSpace(ulong clientId) + { + if (_playerResources.TryGetValue(clientId, out var resource)) + { + return 100 - resource; + } + return 0; + } + + public void AddResource(ulong clientId, int amount) + { + if (_playerResources.TryGetValue(clientId, out var resource)) + { + int actualAmount = Mathf.Min(amount, 100 - resource); + _playerResources[clientId] = resource + actualAmount; + } + } + + public void RemoveResource(ulong clientId, int amount) + { + if (_playerResources.TryGetValue(clientId, out var resource)) + { + int actualAmount = Mathf.Min(amount, resource); + _playerResources[clientId] = resource - actualAmount; + } + } + } +} diff --git a/Assets/Scripts/ServerResourceManager.cs.meta b/Assets/Scripts/ServerResourceManager.cs.meta new file mode 100644 index 0000000..33955ae --- /dev/null +++ b/Assets/Scripts/ServerResourceManager.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 1cf781ac9fc26344a883a69b98104373 \ No newline at end of file diff --git a/Assets/Scripts/ShortcutNetworkStarter.cs b/Assets/Scripts/ShortcutNetworkStarter.cs new file mode 100644 index 0000000..80ef420 --- /dev/null +++ b/Assets/Scripts/ShortcutNetworkStarter.cs @@ -0,0 +1,50 @@ +using UnityEngine; +using UnityEngine.InputSystem; +using Unity.Netcode; + +namespace Northbound +{ + public class ShortcutNetworkStarter : MonoBehaviour + { + [Header("Input Actions")] + [SerializeField] private InputActionReference startAsClientAction; + + private bool _isClientStarted = false; + + private void Start() + { + if (startAsClientAction != null && startAsClientAction.action != null) + { + startAsClientAction.action.performed += StartAsClient; + } + } + + private void OnDestroy() + { + if (startAsClientAction != null && startAsClientAction.action != null) + { + startAsClientAction.action.performed -= StartAsClient; + } + } + + private void StartAsClient(InputAction.CallbackContext context) + { + if (NetworkManager.Singleton == null) + { + Debug.LogError("[ShortcutNetworkStarter] NetworkManager.Singleton이 null입니다!"); + return; + } + + if (NetworkManager.Singleton.IsClient) + { + Debug.Log("[ShortcutNetworkStarter] 이미 클라이언트 모드입니다."); + return; + } + + _isClientStarted = true; + + Debug.Log("[ShortcutNetworkStarter] 클라이언트 모드로 시작합니다..."); + NetworkManager.Singleton.StartClient(); + } + } +} diff --git a/Assets/Scripts/ShortcutNetworkStarter.cs.meta b/Assets/Scripts/ShortcutNetworkStarter.cs.meta new file mode 100644 index 0000000..68c6ac9 --- /dev/null +++ b/Assets/Scripts/ShortcutNetworkStarter.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: c83db7812a3e91149a9626a2302f43cd \ No newline at end of file diff --git a/Assets/Settings/Build Profiles.meta b/Assets/Settings/Build Profiles.meta new file mode 100644 index 0000000..7f9fef2 --- /dev/null +++ b/Assets/Settings/Build Profiles.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7231ff870d55b254384c1a74dbeaf7f6 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Settings/Build Profiles/Windows.asset b/Assets/Settings/Build Profiles/Windows.asset new file mode 100644 index 0000000..61f61f1 --- /dev/null +++ b/Assets/Settings/Build Profiles/Windows.asset @@ -0,0 +1,94 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 15003, guid: 0000000000000000e000000000000000, type: 0} + m_Name: Windows + m_EditorClassIdentifier: UnityEditor.dll::UnityEditor.Build.Profile.BuildProfile + m_AssetVersion: 1 + m_BuildTarget: 19 + m_Subtarget: 2 + m_PlatformId: 4e3c793746204150860bf175a9a41a05 + m_PlatformBuildProfile: + rid: 4349351379921797208 + m_OverrideGlobalSceneList: 0 + m_Scenes: [] + m_HasScriptingDefines: 0 + m_ScriptingDefines: [] + m_PlayerSettingsYaml: + m_Settings: [] + references: + version: 2 + RefIds: + - rid: 4349351379921797208 + type: {class: WindowsPlatformSettings, ns: UnityEditor.WindowsStandalone, asm: UnityEditor.WindowsStandalone.Extensions} + data: + m_Development: 0 + m_ConnectProfiler: 0 + m_BuildWithDeepProfilingSupport: 0 + m_AllowDebugging: 0 + m_WaitForManagedDebugger: 0 + m_ManagedDebuggerFixedPort: 0 + m_ExplicitNullChecks: 0 + m_ExplicitDivideByZeroChecks: 0 + m_ExplicitArrayBoundsChecks: 0 + m_CompressionType: 0 + m_InstallInBuildFolder: 0 + m_InsightsSettingsContainer: + m_BuildProfileEngineDiagnosticsState: 2 + m_AdaptivePerformanceEnabled: 0 + m_WindowsBuildAndRunDeployTarget: 0 + m_Architecture: 0 + m_CreateSolution: 0 + m_CopyPDBFiles: 0 + m_WindowsDevicePortalAddress: + m_WindowsDevicePortalUsername: +--- !u!114 &5293933444619661119 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 15009, guid: 0000000000000000e000000000000000, type: 0} + m_Name: Graphics Settings + m_EditorClassIdentifier: UnityEditor.dll::UnityEditor.Build.Profile.BuildProfileGraphicsSettings + m_LightmapStripping: 0 + m_LightmapKeepPlain: 1 + m_LightmapKeepDirCombined: 1 + m_LightmapKeepDynamicPlain: 1 + m_LightmapKeepDynamicDirCombined: 1 + m_LightmapKeepShadowMask: 1 + m_LightmapKeepSubtractive: 1 + m_FogStripping: 0 + m_FogKeepLinear: 1 + m_FogKeepExp: 1 + m_FogKeepExp2: 1 + m_InstancingStripping: 0 + m_BrgStripping: 0 + m_LogWhenShaderIsCompiled: 0 + m_CameraRelativeLightCulling: 0 + m_CameraRelativeShadowCulling: 0 + m_VideoShadersIncludeMode: 2 + m_AlwaysIncludedShaders: + - {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 15104, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 15105, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 15106, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 10753, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 10770, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 10783, guid: 0000000000000000f000000000000000, type: 0} + m_LightProbeOutsideHullStrategy: 0 + m_PreloadedShaders: [] + m_PreloadShadersBatchTimeLimit: -1 + m_ShaderBuildSettings: + keywordDeclarationOverrides: [] diff --git a/Assets/Settings/Build Profiles/Windows.asset.meta b/Assets/Settings/Build Profiles/Windows.asset.meta new file mode 100644 index 0000000..bdef16f --- /dev/null +++ b/Assets/Settings/Build Profiles/Windows.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b278d7bcf7e5c5b46ae41f7fa05f9d49 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Settings/Northbound Flatkit URP.asset b/Assets/Settings/Northbound Flatkit URP.asset index eaaa3c0..95274a5 100644 --- a/Assets/Settings/Northbound Flatkit URP.asset +++ b/Assets/Settings/Northbound Flatkit URP.asset @@ -15,7 +15,7 @@ MonoBehaviour: k_AssetVersion: 13 k_AssetPreviousVersion: 13 m_RendererType: 1 - m_RendererData: {fileID: 11400000, guid: 618d298269e66c542b306de85db1faea, type: 2} + m_RendererData: {fileID: 0} m_RendererDataList: - {fileID: 11400000, guid: 569816eb300be8149adcef0c7c162f8c, type: 2} m_DefaultRendererIndex: 0 @@ -128,14 +128,14 @@ MonoBehaviour: m_PrefilterSoftShadowsQualityHigh: 1 m_PrefilterSoftShadows: 0 m_PrefilterScreenCoord: 1 - m_PrefilterScreenSpaceIrradiance: 0 + m_PrefilterScreenSpaceIrradiance: 1 m_PrefilterNativeRenderPass: 1 m_PrefilterUseLegacyLightmaps: 0 m_PrefilterBicubicLightmapSampling: 1 - m_PrefilterReflectionProbeRotation: 0 - m_PrefilterReflectionProbeBlending: 0 - m_PrefilterReflectionProbeBoxProjection: 0 - m_PrefilterReflectionProbeAtlas: 0 + m_PrefilterReflectionProbeRotation: 1 + m_PrefilterReflectionProbeBlending: 1 + m_PrefilterReflectionProbeBoxProjection: 1 + m_PrefilterReflectionProbeAtlas: 1 m_ShaderVariantLogLevel: 0 m_ShadowCascades: 2 m_Textures: diff --git a/Assets/UniversalRenderPipelineGlobalSettings.asset b/Assets/UniversalRenderPipelineGlobalSettings.asset index b3bad10..838995a 100644 --- a/Assets/UniversalRenderPipelineGlobalSettings.asset +++ b/Assets/UniversalRenderPipelineGlobalSettings.asset @@ -66,7 +66,19 @@ MonoBehaviour: - rid: 235636870086918150 - rid: 235636870086918151 m_RuntimeSettings: - m_List: [] + m_List: + - rid: 7752762179098771456 + - rid: 7752762179098771459 + - rid: 7752762179098771461 + - rid: 7752762179098771462 + - rid: 7752762179098771463 + - rid: 7752762179098771464 + - rid: 7752762179098771466 + - rid: 7752762179098771468 + - rid: 7752762179098771472 + - rid: 7752762179098771476 + - rid: 3114554777721110529 + - rid: 3114554777721110530 m_AssetVersion: 9 m_ObsoleteDefaultVolumeProfile: {fileID: 0} m_RenderingLayerNames: diff --git a/BUILDING_SYSTEM_SETUP.md b/BUILDING_SYSTEM_SETUP.md deleted file mode 100644 index 067aa2f..0000000 --- a/BUILDING_SYSTEM_SETUP.md +++ /dev/null @@ -1,323 +0,0 @@ -# Building System Setup Guide - -## Overview -The building system allows players to place buildings with: -- **Grid-based snapping** for aligned placement -- **Overlap detection** to prevent buildings from colliding -- **Ground validation** to ensure buildings are placed on terrain -- **Ghost preview** with green (valid) / red (invalid) visual feedback -- **Network synchronization** across all players - -## Components - -### 1. BuildingData (ScriptableObject) -Defines properties for each building type: -- Building name and prefab reference -- Grid size (width, length, height) -- Placement offset and rotation settings - -### 2. Building (MonoBehaviour) -Component attached to placed building instances. Tracks: -- Grid position -- Rotation (0-3, representing 0°, 90°, 180°, 270°) -- Reference to BuildingData - -### 3. BuildingManager (NetworkBehaviour - Singleton) -Central manager that: -- Maintains list of all placed buildings -- Validates placement (ground check + overlap detection) -- Handles grid snapping -- Spawns buildings on network via ServerRpc - -### 4. BuildingPlacement (NetworkBehaviour) -Player-side building interface: -- Uses new Input System (`PlayerInputActions`, `Keyboard.current`, `Mouse.current`) -- Handles input (B key to toggle, Q/E to rotate, click to place) -- Shows ghost preview at mouse position -- Updates preview material (green/red) based on validity -- Proper input lifecycle management (enable/disable/dispose) - -## Setup Instructions - -### Step 0: Setup Input Actions (Required First!) -**Before using the building system, you MUST add the required input actions.** - -See **INPUT_ACTIONS_SETUP.md** for detailed instructions. - -Quick summary - Add these to your Player action map in `InputSystem_Actions.inputactions`: -1. **ToggleBuildMode** (Button) → Keyboard B -2. **Rotate** (Value/Axis) → Keyboard R -3. **Build** (Button) → Mouse Left Button - -After adding, save the asset to regenerate the code. - -### Step 1: Create BuildingData Assets -1. Right-click in Project window → Create → Northbound → Building Data -2. Configure your building: - - Assign the building prefab - - Set grid size (width, length, height) - - Adjust placement offset if needed - - Enable/disable rotation - -### Step 2: Setup Building Prefabs -For each building prefab: -1. Add `NetworkObject` component -2. Add `Building` component -3. Ensure it has a `Renderer` for preview -4. Add colliders for gameplay (player collision, physics) -5. **Important:** Colliders are NOT used for placement validation - only BuildingData grid size matters -6. Set the prefab's layer to anything EXCEPT the Ground layer (buildings will be raycast-ignored during placement) - -### Step 3: Setup BuildingManager -1. Create empty GameObject in your scene named "BuildingManager" -2. Add `BuildingManager` component -3. Add `NetworkObject` component -4. Configure settings: - - **Grid Size**: Size of one grid unit (default: 1) - - **Ground Layer**: Layer mask for valid ground (e.g., "Ground") - - **Available Buildings**: Add your BuildingData assets - -### Step 4: Add BuildingPlacement to Player -1. Open your Player prefab -2. Add `BuildingPlacement` component -3. Configure: - - **Ground Layer**: Same as BuildingManager - - **Max Placement Distance**: How far player can place (default: 100) - - **Valid Material**: Green transparent material (auto-created if null) - - **Invalid Material**: Red transparent material (auto-created if null) - -### Step 5: Setup Layers -1. Create a layer named "Ground" (or your preferred name) -2. Assign this layer to terrain/ground objects -3. **Important:** Make sure building prefabs are on a **different** layer (not Ground) - - This allows raycasting through buildings to hit the ground - - You can place buildings even when cursor is over existing buildings - -## Controls - -Default bindings (customizable in Input Actions): -- **B**: Toggle build mode on/off -- **R**: Rotate building (90° increments) -- **Left Mouse Button**: Place building (if valid position) -- **Mouse Movement**: Move preview to placement location - -## Input System - -The building system uses Unity's **new Input System** with action callbacks: -- Actions: `ToggleBuildMode`, `Rotate`, `Build` -- Subscribe to `.performed` events in `OnNetworkSpawn` -- Unsubscribe in `OnNetworkDespawn` -- No hardcoded keys - all controls defined in Input Actions asset -- Easy to rebind without code changes - -**Pattern:** -```csharp -_inputActions.Player.ToggleBuildMode.performed += OnToggleBuildMode; -_inputActions.Player.Rotate.performed += OnRotate; -_inputActions.Player.Build.performed += OnBuild; -``` - -This uses callback-based input, similar to the pattern shown in `InputSystem_Actions.cs` examples. - -## Technical Implementation - -### Modern Input System (Callback Pattern) -```csharp -// Initialization in OnNetworkSpawn -_inputActions = new PlayerInputActions(); -_inputActions.Player.ToggleBuildMode.performed += OnToggleBuildMode; -_inputActions.Player.Rotate.performed += OnRotate; -_inputActions.Player.Build.performed += OnBuild; -_inputActions.Enable(); - -// Callback handlers -private void OnToggleBuildMode(InputAction.CallbackContext context) -{ - ToggleBuildMode(); -} - -private void OnRotate(InputAction.CallbackContext context) -{ - float rotateValue = context.ReadValue(); - // Positive = rotate right, Negative = rotate left -} - -private void OnBuild(InputAction.CallbackContext context) -{ - TryPlaceBuilding(); -} - -// Cleanup in OnNetworkDespawn -_inputActions.Player.ToggleBuildMode.performed -= OnToggleBuildMode; -_inputActions.Player.Rotate.performed -= OnRotate; -_inputActions.Player.Build.performed -= OnBuild; -_inputActions.Disable(); -_inputActions.Dispose(); -``` - -### Modern Netcode RPC Pattern -```csharp -[ServerRpc(RequireOwnership = false)] -public void PlaceBuildingServerRpc(int buildingIndex, Vector3 position, int rotation, ServerRpcParams serverRpcParams = default) -{ - // Validation - if (!IsValidPlacement(...)) return; - - // Server-side spawn - GameObject obj = Instantiate(...); - NetworkObject netObj = obj.GetComponent(); - netObj.Spawn(); // Automatically syncs to all clients -} -``` - -## How It Works - -### Build Mode Flow -1. Player presses **B** → enters build mode -2. Preview appears at mouse cursor position -3. System raycasts to find ground (two-stage): - - **Method 1:** Direct raycast to ground, ignoring building colliders - - **Method 2:** If ground not visible (buildings blocking), raycast to anything, then cast downward from that point to find ground below - - This allows placement even in completely surrounded cells -4. System checks placement validity: - - Is there ground below? - - Does grid bounds overlap with existing buildings? -5. Preview shows **green** if valid, **red** if invalid -6. Player rotates with **R** if desired -7. Player clicks to confirm placement -8. **ServerRpc** sent to server to spawn building -9. Building synchronized to all clients - -### Validation System (Grid-Based) -``` -IsValidPlacement() checks: -├── Ground Check: Raycast down to find ground -└── Overlap Check: Compare GRID BOUNDS (not colliders!) - ├── Uses BuildingData width/length/height - ├── NOT the actual collider size - └── Rotates grid size automatically (90°/180°/270°) -``` - -**Important:** Collision detection uses the **grid size** from `BuildingData`, not the physical colliders on the building prefab. This means: -- A building with `width=2, length=3, height=2` occupies a 2x3 grid area -- Even if the visual model is smaller/larger, the grid size determines overlap -- This allows consistent, predictable building placement - -### Grid Snapping -- World position → rounded to nearest grid size -- Example: gridSize=2, position (3.7, 0, 5.2) → snaps to (4, 0, 6) - -### Rotation System -- Rotation values: 0, 1, 2, 3 → 0°, 90°, 180°, 270° -- Building size auto-swaps width/length when rotated 90° or 270° - -## Example Building Setup - -### Small House (2x2) -``` -Name: Small House -Prefab: SmallHousePrefab -Width: 2 -Length: 2 -Height: 3 -Allow Rotation: true -``` - -### Wall Segment (1x3) -``` -Name: Wall -Prefab: WallPrefab -Width: 1 -Length: 3 -Height: 2 -Allow Rotation: true -``` - -## Debug Visualization - -The system includes visual debugging to help you understand grid placement: - -**In Scene View (when build mode is active):** -- **Green/Red Wire Cube**: Shows the grid bounds being checked - - Green = valid placement - - Red = invalid (overlapping or no ground) -- **Yellow Grid Cells**: Shows individual grid cells occupied -- **Yellow Sphere**: Grid origin point (snapped position) - -**On Placed Buildings:** -- **Cyan Wire Cube**: Shows the grid bounds of placed buildings -- **Yellow Wire Cube** (when selected): Highlights the selected building's grid -- **Magenta Sphere**: Grid position origin - -Enable/disable with: -- BuildingPlacement → Show Grid Bounds -- Building → Show Grid Bounds - -## Troubleshooting - -**Preview doesn't appear:** -- Check if BuildingManager.Instance exists -- Verify availableBuildings list has BuildingData -- Ensure Ground layer is set correctly - -**Can't place buildings:** -- Check ground layer mask matches terrain -- Verify building prefabs have NetworkObject -- Ensure BuildingManager has NetworkObject and is spawned - -**Buildings overlap despite visual gap:** -- Remember: Collision uses **grid size** from BuildingData, not visual model size -- Check the grid bounds in Scene view (cyan wire cubes) -- Adjust width/length/height in BuildingData to match desired grid footprint - -**Can't place buildings when cursor is near existing buildings:** -- FIXED: System now uses RaycastAll and ignores building colliders -- Raycasts pass through buildings to hit the ground -- You can place buildings even when cursor is hovering over old ones -- Just make sure buildings are NOT on the Ground layer - -**Can't place in center cell when surrounded by buildings:** -- FIXED: Two-stage raycast system -- If direct ground raycast fails, system raycasts to any object then down to find ground -- Works even when all adjacent cells are built and blocking the ground view -- You can fill in gaps surrounded by buildings - -**Network issues:** -- BuildingManager must be spawned on network -- Ensure player has BuildingPlacement component with IsOwner - -## Extending the System - -### Add Building Categories -Edit `BuildingData.cs` and add: -```csharp -public enum BuildingCategory { Housing, Production, Defense } -public BuildingCategory category; -``` - -### Add Resource Costs -```csharp -[Header("Cost")] -public int woodCost; -public int stoneCost; -``` - -Then check resources in `BuildingManager.PlaceBuildingServerRpc()` - -### Add Build Range Limit -In `BuildingPlacement.UpdatePreviewPosition()`: -```csharp -float distanceToPlayer = Vector3.Distance(transform.position, snappedPosition); -if (distanceToPlayer > maxBuildRange) - isValid = false; -``` - -### Multiple Building Selection -Add UI buttons that change `selectedBuildingIndex` in BuildingPlacement - -## Notes - -- Buildings are spawned on the **server** via ServerRpc -- Preview is **local-only** (each player sees their own preview) -- Ground layer should include all walkable/buildable surfaces -- Grid size should match your game's scale (larger buildings = larger grid) diff --git a/DISCORD_HOOK_GUIDE.md b/DISCORD_HOOK_GUIDE.md deleted file mode 100644 index 994325f..0000000 --- a/DISCORD_HOOK_GUIDE.md +++ /dev/null @@ -1,63 +0,0 @@ -# Git Discord Notification Hook - -Send commit notifications to Discord with Korean text support. - -## Requirements - -- **Node.js** (required for Korean text support) - - Download from: https://nodejs.org/ - - Install the LTS version - -## Installation - -1. **Open your project folder** - -2. **Run the setup script:** - ```powershell - .\setup-hooks.ps1 - ``` - -3. **Configure your Discord webhook URL:** - - Open `git-hooks/send-discord.js` in a text editor (Notepad, VS Code, etc.) - - Find line with `webhookUrl =` - - Replace the URL with your Discord webhook URL - - Save the file - - Run `.\setup-hooks.ps1` again to apply changes - -**That's it!** Now every commit will send a notification to Discord. - -## How to Get Discord Webhook URL - -1. Open your Discord server settings -2. Go to **Integrations** → **Webhooks** -3. Click **New Webhook** -4. Copy the **Webhook URL** -5. Paste it into `git-hooks/send-discord.js` - -## What Gets Sent to Discord - -- Commit hash -- Author name -- Commit message (supports Korean/other languages) -- List of changed files - -## Troubleshooting - -**Hook not running?** -- Make sure you ran `.\setup-hooks.ps1` after cloning the repo -- Check that `.git/hooks/post-commit` file exists - -**Korean text showing as `???`?** -- Make sure Node.js is installed -- Run `node --version` in terminal to check - -**Hook sending errors?** -- Verify your Discord webhook URL is correct -- Check that the webhook has permission to send messages - -## Uninstalling - -Run this to remove the hooks: -```bash -rm .git/hooks/post-commit .git/hooks/send-discord.js -``` diff --git a/GENERIC_IMPORTER.md b/GENERIC_IMPORTER.md deleted file mode 100644 index a1fc6d1..0000000 --- a/GENERIC_IMPORTER.md +++ /dev/null @@ -1,154 +0,0 @@ -# Generic CSV Importer System - -## Overview - -The CSV importer now works with **any data type**, not just monsters! Each data type has its own prefab setup logic. - -## How It Works - -``` -CSV File (any type) - ↓ Importer -ScriptableObject (data) - ↓ Prefab Setup -Prefab (with components, models, etc.) -``` - -## Architecture - -### 1. IPrefabSetup Interface - -```csharp -public interface IPrefabSetup -{ - string GetTemplateName(); // Which template to use - void SetupPrefab(GameObject prefab, ScriptableObject data); // How to setup -} -``` - -### 2. Prefab Setup Handlers - -Each data type has its own setup class: - -**MonsterPrefabSetup.cs** -- Handles MonsterData -- Applies FBX models -- Sets Animator controllers -- Updates MonsterDataComponent - -**To add new types:** -1. Create `NewTypePrefabSetup.cs` implementing `IPrefabSetup` -2. Register in `CSVToSOImporter.RegisterPrefabSetups()` -3. Done! - -### 3. Templates - -Each data type has its own template: -``` -Assets/Data/Templates/ -├── MonsterTemplate.prefab → For monsters -├── TowerTemplate.prefab → For towers (to create) -└── PlayerTemplate.prefab → For players (to create) -``` - -Templates define: -- Required components -- Component defaults -- Layer settings -- etc. - -## Adding New Data Types - -### Step 1: Create Template - -```csharp -// TemplateCreator.cs -Tools > Data > Create [TypeName] Template -``` - -### Step 2: Create Setup Handler - -```csharp -// TowerPrefabSetup.cs -using UnityEditor; -using UnityEngine; - -namespace Northbound.Editor -{ - public class TowerPrefabSetup : IPrefabSetup - { - public string GetTemplateName() - { - return "TowerTemplate"; - } - - public void SetupPrefab(GameObject prefab, ScriptableObject data) - { - // Your custom logic here - // e.g., add models, apply stats, etc. - Debug.Log($"[TowerPrefabSetup] Setting up {data.name}"); - } - } -} -``` - -### Step 3: Register Handler - -```csharp -// CSVToSOImporter.cs - RegisterPrefabSetups() -prefabSetups["Tower"] = new TowerPrefabSetup(); -``` - -### Step 4: Create CSV - -``` -GameData/Tower.csv -id,name,cost,... -101,ArrowTower,50,... -``` - -### Step 5: Import - -``` -Tools > Data > Import All CSV -``` - -Done! Prefabs auto-generated for Towers. - -## Benefits - -✅ **Generic**: Works for ANY data type -✅ **Extensible**: Easy to add new types -✅ **Type-Safe**: Each type has its own logic -✅ **Maintainable**: No monster-specific code in importer -✅ **Automated**: CSV → SO → Prefab in one click - -## Example: Complete Flow for Monster - -1. **Designer edits CSV**: `GameData/Monster.csv` -2. **Imports data**: `Tools > Data > Import All CSV` -3. **Importer**: - - Reads CSV rows - - Creates Monster101.asset (SO) - - Clones MonsterTemplate.prefab - - Calls MonsterPrefabSetup.SetupPrefab() - - Saves as Monster101.prefab -4. **MonsterPrefabSetup**: - - Links SO to MonsterDataComponent - - Applies FBX model - - Sets Animator controller -5. **Result**: Complete prefab ready to use! - -## Troubleshooting - -**"No prefab setup found for [Type]"** -- Create `TypePrefabSetup.cs` implementing `IPrefabSetup` -- Register it in `RegisterPrefabSetups()` - -**"No template found for [Type]"** -- Create `[Type]Template.prefab` using `Tools > Data > Create Template` -- Ensure name matches `GetTemplateName()` return value - -**Prefabs not updating** -- Check that your setup logic is in `SetupPrefab()` -- Verify SO fields are being read correctly diff --git a/GRID_BASED_COLLISION.md b/GRID_BASED_COLLISION.md deleted file mode 100644 index a10bde8..0000000 --- a/GRID_BASED_COLLISION.md +++ /dev/null @@ -1,283 +0,0 @@ -# Grid-Based Collision System - -## How It Works - -The building system uses **grid-based collision detection**, NOT the actual colliders on building prefabs. - -### Grid Bounds vs Collider Bounds - -``` -❌ OLD WAY (Collider-based): -Building A has BoxCollider (2.5 x 3.7 x 4.2) -Building B has MeshCollider (complex shape) -→ Hard to predict, inconsistent placement - -✅ NEW WAY (Grid-based): -Building A has width=2, length=3, height=2 in BuildingData -Building B has width=1, length=4, height=3 in BuildingData -→ Predictable, consistent grid placement -``` - -## Why Grid-Based? - -### Advantages -1. **Predictable**: Buildings snap to grid, easy to understand -2. **Consistent**: Same rules for all buildings, regardless of visual model -3. **Flexible**: Visual model can be any size/shape -4. **Network-Friendly**: Simple data to sync (just grid position + rotation) -5. **Performance**: Fast AABB (Axis-Aligned Bounding Box) checks - -### Comparison - -| Aspect | Collider-Based | Grid-Based | -|--------|---------------|------------| -| Placement | Visual, complex shapes | Predictable grid cells | -| Performance | Slower (physics queries) | Faster (simple bounds check) | -| Network Sync | Complex mesh data | Simple int coordinates | -| Rotation | Complex recalculation | Swap width/length | -| Debugging | Hard to visualize | Easy (grid gizmos) | - -## How Grid Size Works - -### BuildingData Settings - -```csharp -[Header("Grid Size")] -public int width = 2; // X-axis grid cells -public int length = 3; // Z-axis grid cells -public float height = 2f; // Y-axis size (can be float) -``` - -### Rotation Effect - -``` -Building: width=2, length=3 - -Rotation 0° (0): Rotation 90° (1): -┌─────┐ ┌───────┐ -│ 2 │ │ 3 │ -│ x │ │ x │ -│ 3 │ └───────┘ -└─────┘ 2 - -Rotation 180° (2): Rotation 270° (3): -┌─────┐ ┌───────┐ -│ 3 │ │ 2 │ -│ x │ │ x │ -│ 2 │ └───────┘ -└─────┘ 3 -``` - -The `GetSize(rotation)` method automatically swaps width/length for 90° and 270° rotations. - -## Visual Examples - -### Example 1: Small House -```yaml -BuildingData: - width: 2 - length: 2 - height: 3 - -Grid Footprint (top view): -┌─┬─┐ -├─┼─┤ Occupies 4 grid cells (2x2) -└─┴─┘ - -Visual Model: Can be any size! -- Model might be 1.8 x 1.8 (smaller than grid) -- Model might be 2.3 x 2.3 (larger than grid) -- Collision still uses 2x2 grid -``` - -### Example 2: Wall Segment -```yaml -BuildingData: - width: 1 - length: 4 - height: 2 - -Grid Footprint: -┌───────────┐ -│ 1 x 4 │ Occupies 4 grid cells (1x4) -└───────────┘ - -When rotated 90°: -┌─┐ -├─┤ -├─┤ Becomes 4x1 -├─┤ -└─┘ -``` - -### Example 3: Large Building -```yaml -BuildingData: - width: 4 - length: 5 - height: 4 - -Grid Footprint: -┌─┬─┬─┬─┬─┐ -├─┼─┼─┼─┼─┤ -├─┼─┼─┼─┼─┤ Occupies 20 grid cells (4x5) -├─┼─┼─┼─┼─┤ -└─┴─┴─┴─┴─┘ -``` - -## Collision Detection Code - -### IsValidPlacement (BuildingManager.cs) - -```csharp -// Get grid size from BuildingData (NOT collider) -Vector3 gridSize = data.GetSize(rotation); - -// Shrink bounds slightly to allow adjacent placement -// Without this, Bounds.Intersects() returns true for touching bounds -Vector3 shrunkSize = gridSize - Vector3.one * 0.01f; -Bounds checkBounds = new Bounds( - groundPosition + Vector3.up * gridSize.y * 0.5f, - shrunkSize -); - -// Check against all placed buildings' GRID bounds -foreach (var building in placedBuildings) -{ - Bounds buildingGridBounds = building.GetGridBounds(); - if (checkBounds.Intersects(buildingGridBounds)) - return false; // Overlap detected -} -``` - -**Why shrink by 0.01f?** -Unity's `Bounds.Intersects()` returns `true` when bounds are touching (edge-to-edge), not just overlapping. By shrinking the bounds by a tiny amount (0.01 units), we allow buildings to be placed directly adjacent without triggering a false overlap detection. - -### GetGridBounds (Building.cs) - -```csharp -public Bounds GetGridBounds() -{ - // Uses BuildingData size, not collider - Vector3 gridSize = buildingData.GetSize(rotation); - - // Shrink slightly to allow adjacent buildings - Vector3 shrunkSize = gridSize - Vector3.one * 0.01f; - return new Bounds( - transform.position + Vector3.up * gridSize.y * 0.5f, - shrunkSize - ); -} -``` - -**Note:** The 0.01f shrink is tiny and not visible, but prevents false overlap detection for adjacent buildings. - -## Visualizing Grid Bounds - -### In Scene View - -1. **Enter Build Mode** (Press B) -2. **Look at Scene View** (not Game view) -3. You'll see: - - **Green/Red Wire Cube**: Preview's grid bounds - - **Yellow Grid Cells**: Individual cells - - **Cyan Wire Cubes**: Placed buildings' grid bounds - -### Debug Settings - -**BuildingPlacement:** -- `Show Grid Bounds` - Shows preview grid visualization - -**Building:** -- `Show Grid Bounds` - Shows cyan wire cube for this building -- `Grid Bounds Color` - Customize visualization color - -### Example Scene - -``` -Scene View: - Preview (Green) - ┌─────┐ - │ 2x3 │ - └─────┘ - Placed Building (Cyan) - ┌───┐ - │1x2│ - └───┘ - -Grid Cells (Yellow): -┌─┬─┬─┬─┬─┬─┐ -├─┼─┼─┼─┼─┼─┤ -└─┴─┴─┴─┴─┴─┘ -``` - -## Best Practices - -### 1. Match Grid Size to Gameplay -```csharp -// Small decorations -width: 1, length: 1, height: 1 - -// Medium buildings -width: 2-3, length: 2-3, height: 2-3 - -// Large buildings -width: 4-6, length: 4-6, height: 3-5 -``` - -### 2. Visual Model Can Differ -The visual model doesn't need to match grid size exactly: -- Overhang/decorations can extend beyond grid -- Model can be smaller, leaving empty grid space -- Use `placementOffset` to adjust visual alignment - -### 3. Height Consideration -```csharp -height: 2f // Building is 2 units tall -``` -- Used for vertical bounds checking -- Prevents buildings on top of each other -- Can be float (e.g., 2.5f for tall buildings) - -### 4. Colliders Still Needed -Building prefabs should still have colliders for: -- Player/entity collision during gameplay -- Physics interactions -- Raycast detection - -But these are NOT used for placement validation! - -## Common Questions - -**Q: Why is my small model blocking a large area?** -A: Check the `width` and `length` in BuildingData. The grid size determines collision, not the visual model. - -**Q: Buildings overlap visually but can't place?** -A: Grid bounds are overlapping. Check Scene view with "Show Grid Bounds" enabled. - -**Q: How do I make a building take less space?** -A: Reduce `width` and `length` in BuildingData. The visual model size doesn't matter. - -**Q: Can I use fractional grid sizes?** -A: `width` and `length` are integers (whole grid cells). Only `height` can be a float. - -**Q: What if my model is rotated strangely?** -A: Grid rotation is separate from model rotation. Grid always aligns to world axes. Adjust model's prefab rotation or use `placementOffset`. - -**Q: Can buildings be placed directly next to each other with no gap?** -A: Yes! The system shrinks bounds by 0.01f to allow adjacent placement. Buildings can touch edge-to-edge. - -**Q: I want a gap between buildings. How?** -A: Increase the `width` and `length` values in BuildingData by 1. For example, change a 2x2 building to 3x3 to add a 1-cell buffer zone. - -## Summary - -✅ **Use BuildingData grid size** for collision -✅ **Visual model can be any size** -✅ **Predictable, grid-aligned placement** -✅ **Easy debugging with gizmos** -✅ **Fast performance** - -❌ **Don't rely on collider size** -❌ **Don't expect pixel-perfect visual collision** -❌ **Don't use colliders for placement validation** diff --git a/INPUT_ACTIONS_SETUP.md b/INPUT_ACTIONS_SETUP.md deleted file mode 100644 index f17421c..0000000 --- a/INPUT_ACTIONS_SETUP.md +++ /dev/null @@ -1,128 +0,0 @@ -# Building System Input Actions Setup - -## Required Input Actions - -Add these three actions to your `InputSystem_Actions.inputactions` file in the **Player** action map: - -### 1. ToggleBuildMode (Button) -- **Action Type**: Button -- **Control Type**: Button -- **Binding**: Keyboard B - -### 2. Rotate (Value) -- **Action Type**: Value -- **Control Type**: Axis -- **Binding**: Keyboard R (positive value) -- Alternative: You can use a 1D Axis composite with: - - Negative: Q - - Positive: E - -### 3. Build (Button) -- **Action Type**: Button -- **Control Type**: Button -- **Binding**: Mouse Left Button - -## Step-by-Step Setup in Unity - -1. **Open Input Actions Asset** - - Navigate to `Assets/InputSystem_Actions.inputactions` - - Double-click to open the Input Actions window - -2. **Select Player Action Map** - - In the left panel, click on "Player" action map - -3. **Add ToggleBuildMode Action** - - Click the "+" button in the Actions column - - Name it: `ToggleBuildMode` - - Action Type: Button - - Add binding: Keyboard → B - -4. **Add Rotate Action** - - Click the "+" button in the Actions column - - Name it: `Rotate` - - Action Type: Value - - Control Type: Axis - - **Option A (Simple - Single key):** - - Add binding: Keyboard → R - - **Option B (Advanced - Q/E rotation):** - - Right-click → Add 1D Axis Composite - - Negative: Keyboard → Q - - Positive: Keyboard → E - -5. **Add Build Action** - - Click the "+" button in the Actions column - - Name it: `Build` - - Action Type: Button - - Add binding: Mouse → Left Button - -6. **Save and Regenerate** - - Click "Save Asset" button - - The `InputSystem_Actions.cs` script will auto-regenerate - -## How It Works in Code - -The BuildingPlacement script subscribes to these actions: - -```csharp -// Setup in OnNetworkSpawn -_inputActions.Player.ToggleBuildMode.performed += OnToggleBuildMode; -_inputActions.Player.Rotate.performed += OnRotate; -_inputActions.Player.Build.performed += OnBuild; - -// Cleanup in OnNetworkDespawn -_inputActions.Player.ToggleBuildMode.performed -= OnToggleBuildMode; -_inputActions.Player.Rotate.performed -= OnRotate; -_inputActions.Player.Build.performed -= OnBuild; -``` - -### ToggleBuildMode -- Triggers when B is pressed -- Toggles build mode on/off -- Shows/hides building preview - -### Rotate -- Triggers when R is pressed (or Q/E if using composite) -- Reads value: positive = rotate right, negative = rotate left -- Rotates building preview by 90° - -### Build -- Triggers when left mouse button is pressed -- Only works when build mode is active -- Places the building at the preview position - -## Customizing Controls - -To change the key bindings: -1. Open `InputSystem_Actions.inputactions` -2. Click on the binding you want to change -3. Click "Path" dropdown -4. Select new key/button -5. Save Asset - -No code changes needed - the script uses the action names, not specific keys! - -## Testing - -After setup: -1. Enter Play mode -2. Press **B** → Should see "Entered Build Mode" in console -3. Press **R** → Building preview should rotate -4. Click **Left Mouse Button** → Should place building (if valid position) -5. Press **B** again → Should exit build mode - -## Troubleshooting - -**Error: "ToggleBuildMode does not exist"** -- Make sure you named the action exactly `ToggleBuildMode` (case-sensitive) -- Save the Input Actions asset to regenerate the code - -**Rotation doesn't work:** -- Check the action name is exactly `Rotate` -- If using composite, make sure it's a 1D Axis composite -- Verify the action type is "Value" not "Button" - -**Build action triggers during movement:** -- Make sure Build action is mapped to Mouse Left Button, not Attack -- Check that Build mode is active (press B first) diff --git a/Northbound.Game.csproj b/Northbound.Game.csproj new file mode 100644 index 0000000..43ccd59 --- /dev/null +++ b/Northbound.Game.csproj @@ -0,0 +1,1240 @@ + + + + Temp\obj\$(MSBuildProjectName) + $(BaseIntermediateOutputPath) + false + true + Temp\bin\Debug\ + + + + + + + + false + false + 9.0 + Northbound + Library + Northbound.Game + netstandard2.1 + . + + + 0169;USG0001 + UNITY_6000_3_5;UNITY_6000_3;UNITY_6000;UNITY_5_3_OR_NEWER;UNITY_5_4_OR_NEWER;UNITY_5_5_OR_NEWER;UNITY_5_6_OR_NEWER;UNITY_2017_1_OR_NEWER;UNITY_2017_2_OR_NEWER;UNITY_2017_3_OR_NEWER;UNITY_2017_4_OR_NEWER;UNITY_2018_1_OR_NEWER;UNITY_2018_2_OR_NEWER;UNITY_2018_3_OR_NEWER;UNITY_2018_4_OR_NEWER;UNITY_2019_1_OR_NEWER;UNITY_2019_2_OR_NEWER;UNITY_2019_3_OR_NEWER;UNITY_2019_4_OR_NEWER;UNITY_2020_1_OR_NEWER;UNITY_2020_2_OR_NEWER;UNITY_2020_3_OR_NEWER;UNITY_2021_1_OR_NEWER;UNITY_2021_2_OR_NEWER;UNITY_2021_3_OR_NEWER;UNITY_2022_1_OR_NEWER;UNITY_2022_2_OR_NEWER;UNITY_2022_3_OR_NEWER;UNITY_2023_1_OR_NEWER;UNITY_2023_2_OR_NEWER;UNITY_2023_3_OR_NEWER;UNITY_6000_0_OR_NEWER;UNITY_6000_1_OR_NEWER;UNITY_6000_2_OR_NEWER;UNITY_6000_3_OR_NEWER;PLATFORM_ARCH_64;UNITY_64;UNITY_INCLUDE_TESTS;ENABLE_AR;ENABLE_AUDIO;ENABLE_AUDIO_SCRIPTABLE_PIPELINE;ENABLE_CACHING;ENABLE_CLOTH;ENABLE_EVENT_QUEUE;ENABLE_MICROPHONE;ENABLE_MULTIPLE_DISPLAYS;ENABLE_PHYSICS;ENABLE_TEXTURE_STREAMING;ENABLE_VIRTUALTEXTURING;ENABLE_LZMA;ENABLE_UNITYEVENTS;ENABLE_VR;ENABLE_WEBCAM;ENABLE_UNITYWEBREQUEST;ENABLE_WWW;ENABLE_CLOUD_SERVICES;ENABLE_CLOUD_SERVICES_ADS;ENABLE_CLOUD_SERVICES_USE_WEBREQUEST;ENABLE_UNITY_CONSENT;ENABLE_UNITY_CLOUD_IDENTIFIERS;ENABLE_CLOUD_SERVICES_CRASH_REPORTING;ENABLE_CLOUD_SERVICES_NATIVE_CRASH_REPORTING;ENABLE_CLOUD_SERVICES_PURCHASING;ENABLE_CLOUD_SERVICES_ANALYTICS;ENABLE_CLOUD_SERVICES_BUILD;ENABLE_EDITOR_GAME_SERVICES;ENABLE_UNITY_GAME_SERVICES_ANALYTICS_SUPPORT;ENABLE_CLOUD_LICENSE;ENABLE_EDITOR_HUB_LICENSE;ENABLE_WEBSOCKET_CLIENT;ENABLE_GENERATE_NATIVE_PLUGINS_FOR_ASSEMBLIES_API;ENABLE_DIRECTOR_AUDIO;ENABLE_DIRECTOR_TEXTURE;ENABLE_MANAGED_JOBS;ENABLE_MANAGED_TRANSFORM_JOBS;ENABLE_MANAGED_ANIMATION_JOBS;ENABLE_MANAGED_AUDIO_JOBS;ENABLE_MANAGED_UNITYTLS;INCLUDE_DYNAMIC_GI;ENABLE_SCRIPTING_GC_WBARRIERS;PLATFORM_SUPPORTS_MONO;RENDER_SOFTWARE_CURSOR;ENABLE_MARSHALLING_TESTS;ENABLE_VIDEO;ENABLE_NAVIGATION_OFFMESHLINK_TO_NAVMESHLINK;ENABLE_ACCELERATOR_CLIENT_DEBUGGING;ENABLE_ACCESSIBILITY_SCREEN_READER;TEXTCORE_1_0_OR_NEWER;EDITOR_ONLY_NAVMESH_BUILDER_DEPRECATED;PLATFORM_STANDALONE_WIN;PLATFORM_STANDALONE;UNITY_STANDALONE_WIN;UNITY_STANDALONE;ENABLE_RUNTIME_GI;ENABLE_MOVIES;ENABLE_NETWORK;ENABLE_NVIDIA;ENABLE_AMD;ENABLE_CRUNCH_TEXTURE_COMPRESSION;ENABLE_CLOUD_SERVICES_ENGINE_DIAGNOSTICS;ENABLE_OUT_OF_PROCESS_CRASH_HANDLER;ENABLE_CLUSTER_SYNC;ENABLE_CLUSTERINPUT;PLATFORM_UPDATES_TIME_OUTSIDE_OF_PLAYER_LOOP;GFXDEVICE_WAITFOREVENT_MESSAGEPUMP;PLATFORM_USES_EXPLICIT_MEMORY_MANAGER_INITIALIZER;PLATFORM_SUPPORTS_WAIT_FOR_PRESENTATION;PLATFORM_SUPPORTS_SPLIT_GRAPHICS_JOBS;ENABLE_MONO;NET_STANDARD_2_0;NET_STANDARD;NET_STANDARD_2_1;NETSTANDARD;NETSTANDARD2_1;ENABLE_PROFILER;DEBUG;TRACE;UNITY_ASSERTIONS;UNITY_EDITOR;UNITY_EDITOR_64;UNITY_EDITOR_WIN;ENABLE_UNITY_COLLECTIONS_CHECKS;ENABLE_BURST_AOT;UNITY_TEAM_LICENSE;ENABLE_CUSTOM_RENDER_TEXTURE;ENABLE_DIRECTOR;ENABLE_LOCALIZATION;ENABLE_SPRITES;ENABLE_TERRAIN;ENABLE_TILEMAP;ENABLE_TIMELINE;ENABLE_INPUT_SYSTEM;TEXTCORE_FONT_ENGINE_1_5_OR_NEWER;TEXTCORE_TEXT_ENGINE_1_5_OR_NEWER;TEXTCORE_FONT_ENGINE_1_6_OR_NEWER;CSHARP_7_OR_LATER;CSHARP_7_3_OR_NEWER + False + + + true + true + true + true + MSB3277 + + + Package + 2.0.26 + SDK + Game:1 + StandaloneWindows64:19 + 6000.3.5f2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.AIModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.ARModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.AccessibilityModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.AdaptivePerformanceModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.AndroidJNIModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.AnimationModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.AssetBundleModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.AudioModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.ClothModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.ClusterInputModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.ClusterRendererModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.ContentLoadModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.CoreModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.CrashReportingModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.DSPGraphModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.DirectorModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.GIModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.GameCenterModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.GraphicsStateCollectionSerializerModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.GridModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.HierarchyCoreModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.HotReloadModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.IMGUIModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.IdentifiersModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.ImageConversionModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.InputModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.InputForUIModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.InputLegacyModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.InsightsModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.JSONSerializeModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.LocalizationModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.MarshallingModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.MultiplayerModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.ParticleSystemModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.PerformanceReportingModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.PhysicsModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.Physics2DModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.PhysicsBackendPhysXModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.PropertiesModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.RenderAs2DModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.RuntimeInitializeOnLoadManagerInitializerModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.ScreenCaptureModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.ShaderRuntimeModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.ShaderVariantAnalyticsModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.SharedInternalsModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.SpriteMaskModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.SpriteShapeModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.StreamingModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.SubstanceModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.SubsystemsModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.TLSModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.TerrainModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.TerrainPhysicsModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.TextCoreFontEngineModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.TextCoreTextEngineModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.TextRenderingModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.TilemapModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.UIModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.UIElementsModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.UmbraModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.UnityAnalyticsModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.UnityAnalyticsCommonModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.UnityConnectModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.UnityConsentModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.UnityCurlModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.UnityWebRequestModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.UnityWebRequestAssetBundleModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.UnityWebRequestAudioModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.UnityWebRequestTextureModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.UnityWebRequestWWWModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.VFXModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.VRModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.VectorGraphicsModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.VehiclesModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.VideoModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.VirtualTexturingModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.WindModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEngine.XRModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.AccessibilityModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.AdaptivePerformanceModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.AssetComplianceModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.BuildProfileModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.ClothModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.CoreBusinessMetricsModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.CoreModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.DeviceSimulatorModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.DiagnosticsModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.EditorToolbarModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.EmbreeModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.GIModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.GraphViewModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.GraphicsStateCollectionSerializerModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.GridAndSnapModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.GridModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.HierarchyModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.InAppPurchasingModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.LevelPlayModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.MediaModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.MultiplayerModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.Physics2DModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.PhysicsModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.PlayModeModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.PresetsUIModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.PropertiesModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.QuickSearchModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.SafeModeModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.SceneTemplateModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.SceneViewModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.ShaderBuildSettingsModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.ShaderCompilationModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.ShaderFoundryModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.SketchUpModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.SpriteMaskModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.SpriteShapeModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.SubstanceModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.TerrainModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.TextCoreFontEngineModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.TextCoreTextEngineModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.TextRenderingModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.TilemapModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.TreeModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.UIAutomationModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.UIBuilderModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.UIElementsModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.UIElementsSamplesModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.UIToolkitAuthoringModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.UmbraModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.UnityConnectModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.VFXModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.VectorGraphicsModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.VideoModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEngine\UnityEditor.XRModule.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Managed\UnityEditor.Graphs.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\PlaybackEngines\WindowsStandaloneSupport\UnityEditor.WindowsStandalone.Extensions.dll + False + + + Library\PackageCache\com.unity.services.wire@9a73acde80cc\Plugins\websocket-sharp.dll + False + + + Library\PackageCache\com.unity.visualscripting@191c0d7e3b69\Editor\VisualScripting.Core\Dependencies\YamlDotNet\Unity.VisualScripting.YamlDotNet.dll + False + + + Library\PackageCache\com.unity.collections@aea9d3bd5e19\Unity.Collections.LowLevel.ILSupport\Unity.Collections.LowLevel.ILSupport.dll + False + + + Library\PackageCache\com.unity.ext.nunit@d8c07649098d\net40\unity-custom\nunit.framework.dll + False + + + Library\PackageCache\com.unity.collab-proxy@1ec4e416a4af\Lib\Editor\Unity.Plastic.Antlr3.Runtime.dll + False + + + Library\PackageCache\com.unity.collab-proxy@1ec4e416a4af\Lib\Editor\Unity.Plastic.Newtonsoft.Json.dll + False + + + Library\PackageCache\com.unity.collab-proxy@1ec4e416a4af\Lib\Editor\log4netPlastic.dll + False + + + Library\PackageCache\com.unity.visualscripting@191c0d7e3b69\Editor\VisualScripting.Core\Dependencies\DotNetZip\Unity.VisualScripting.IonicZip.dll + False + + + Library\PackageCache\com.unity.collections@aea9d3bd5e19\Unity.Collections.Tests\System.IO.Hashing\System.IO.Hashing.dll + False + + + Library\PackageCache\com.unity.collab-proxy@1ec4e416a4af\Lib\Editor\unityplastic.dll + False + + + Library\PackageCache\com.unity.visualscripting@191c0d7e3b69\Runtime\VisualScripting.Flow\Dependencies\NCalc\Unity.VisualScripting.Antlr3.Runtime.dll + False + + + Library\PackageCache\com.unity.nuget.newtonsoft-json@4dfd81071c64\Runtime\Newtonsoft.Json.dll + False + + + Library\PackageCache\com.unity.visualscripting@191c0d7e3b69\Editor\VisualScripting.Core\EditorAssetResources\Unity.VisualScripting.TextureAssets.dll + False + + + Library\PackageCache\com.unity.nuget.mono-cecil@ecb9724e46ff\Mono.Cecil.dll + False + + + Library\PackageCache\com.unity.collections@aea9d3bd5e19\Unity.Collections.Tests\System.Runtime.CompilerServices.Unsafe\System.Runtime.CompilerServices.Unsafe.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\ref\2.1.0\netstandard.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\Microsoft.Win32.Primitives.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.AppContext.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Buffers.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Collections.Concurrent.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Collections.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Collections.NonGeneric.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Collections.Specialized.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.ComponentModel.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.ComponentModel.EventBasedAsync.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.ComponentModel.Primitives.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.ComponentModel.TypeConverter.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Console.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Data.Common.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Diagnostics.Contracts.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Diagnostics.Debug.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Diagnostics.FileVersionInfo.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Diagnostics.Process.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Diagnostics.StackTrace.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Diagnostics.TextWriterTraceListener.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Diagnostics.Tools.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Diagnostics.TraceSource.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Diagnostics.Tracing.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Drawing.Primitives.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Dynamic.Runtime.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Globalization.Calendars.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Globalization.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Globalization.Extensions.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.IO.Compression.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.IO.Compression.ZipFile.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.IO.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.IO.FileSystem.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.IO.FileSystem.DriveInfo.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.IO.FileSystem.Primitives.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.IO.FileSystem.Watcher.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.IO.IsolatedStorage.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.IO.MemoryMappedFiles.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.IO.Pipes.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.IO.UnmanagedMemoryStream.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Linq.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Linq.Expressions.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Linq.Parallel.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Linq.Queryable.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Memory.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Net.Http.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Net.NameResolution.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Net.NetworkInformation.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Net.Ping.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Net.Primitives.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Net.Requests.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Net.Security.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Net.Sockets.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Net.WebHeaderCollection.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Net.WebSockets.Client.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Net.WebSockets.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Numerics.Vectors.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.ObjectModel.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Reflection.DispatchProxy.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Reflection.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Reflection.Emit.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Reflection.Emit.ILGeneration.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Reflection.Emit.Lightweight.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Reflection.Extensions.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Reflection.Primitives.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Resources.Reader.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Resources.ResourceManager.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Resources.Writer.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Runtime.CompilerServices.VisualC.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Runtime.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Runtime.Extensions.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Runtime.Handles.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Runtime.InteropServices.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Runtime.InteropServices.RuntimeInformation.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Runtime.Numerics.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Runtime.Serialization.Formatters.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Runtime.Serialization.Json.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Runtime.Serialization.Primitives.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Runtime.Serialization.Xml.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Security.Claims.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Security.Cryptography.Algorithms.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Security.Cryptography.Csp.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Security.Cryptography.Encoding.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Security.Cryptography.Primitives.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Security.Cryptography.X509Certificates.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Security.Principal.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Security.SecureString.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Text.Encoding.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Text.Encoding.Extensions.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Text.RegularExpressions.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Threading.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Threading.Overlapped.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Threading.Tasks.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Threading.Tasks.Extensions.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Threading.Tasks.Parallel.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Threading.Thread.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Threading.ThreadPool.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Threading.Timer.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.ValueTuple.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Xml.ReaderWriter.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Xml.XDocument.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Xml.XmlDocument.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Xml.XmlSerializer.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Xml.XPath.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netstandard\System.Xml.XPath.XDocument.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\Extensions\2.0.0\System.Runtime.InteropServices.WindowsRuntime.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netfx\mscorlib.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netfx\System.ComponentModel.Composition.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netfx\System.Core.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netfx\System.Data.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netfx\System.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netfx\System.Drawing.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netfx\System.IO.Compression.FileSystem.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netfx\System.Net.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netfx\System.Numerics.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netfx\System.Runtime.Serialization.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netfx\System.ServiceModel.Web.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netfx\System.Transactions.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netfx\System.Web.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netfx\System.Windows.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netfx\System.Xml.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netfx\System.Xml.Linq.dll + False + + + C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\NetStandard\compat\2.1.0\shims\netfx\System.Xml.Serialization.dll + False + + + Library\ScriptAssemblies\Unity.Netcode.Runtime.dll + False + + + Library\ScriptAssemblies\Unity.Collections.dll + False + + + Library\ScriptAssemblies\UnityEditor.UI.dll + False + + + Library\ScriptAssemblies\UnityEngine.UI.dll + False + + + + + + + + + + + + + + + + diff --git a/Packages/manifest.json.backup b/Packages/manifest.json.backup new file mode 100644 index 0000000..6604f2f --- /dev/null +++ b/Packages/manifest.json.backup @@ -0,0 +1,64 @@ +{ + "dependencies": { + "com.unity.2d.animation": "13.0.4", + "com.unity.2d.aseprite": "3.0.1", + "com.unity.2d.psdimporter": "12.0.1", + "com.unity.2d.sprite": "1.0.0", + "com.unity.2d.spriteshape": "13.0.0", + "com.unity.2d.tilemap": "1.0.0", + "com.unity.2d.tilemap.extras": "6.0.1", + "com.unity.2d.tooling": "1.0.0", + "com.unity.ai.navigation": "2.0.9", + "com.unity.cinemachine": "3.1.5", + "com.unity.collab-proxy": "2.11.2", + "com.unity.ide.rider": "3.0.38", + "com.unity.ide.visualstudio": "2.0.26", + "com.unity.inputsystem": "1.17.0", + "com.unity.multiplayer.center": "1.0.1", + "com.unity.multiplayer.center.quickstart": "1.1.1", + "com.unity.multiplayer.playmode": "2.0.1", + "com.unity.multiplayer.tools": "2.2.7", + "com.unity.netcode.gameobjects": "2.8.1", + "com.unity.render-pipelines.universal": "17.3.0", + "com.unity.services.multiplayer": "2.1.1", + "com.unity.services.vivox": "16.9.0", + "com.unity.test-framework": "1.6.0", + "com.unity.timeline": "1.8.10", + "com.unity.ugui": "2.0.0", + "com.unity.visualscripting": "1.9.9", + "com.unity.modules.accessibility": "1.0.0", + "com.unity.modules.adaptiveperformance": "1.0.0", + "com.unity.modules.ai": "1.0.0", + "com.unity.modules.androidjni": "1.0.0", + "com.unity.modules.animation": "1.0.0", + "com.unity.modules.assetbundle": "1.0.0", + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.cloth": "1.0.0", + "com.unity.modules.director": "1.0.0", + "com.unity.modules.imageconversion": "1.0.0", + "com.unity.modules.imgui": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.particlesystem": "1.0.0", + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.physics2d": "1.0.0", + "com.unity.modules.screencapture": "1.0.0", + "com.unity.modules.terrain": "1.0.0", + "com.unity.modules.terrainphysics": "1.0.0", + "com.unity.modules.tilemap": "1.0.0", + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.uielements": "1.0.0", + "com.unity.modules.umbra": "1.0.0", + "com.unity.modules.unityanalytics": "1.0.0", + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.unitywebrequestassetbundle": "1.0.0", + "com.unity.modules.unitywebrequestaudio": "1.0.0", + "com.unity.modules.unitywebrequesttexture": "1.0.0", + "com.unity.modules.unitywebrequestwww": "1.0.0", + "com.unity.modules.vectorgraphics": "1.0.0", + "com.unity.modules.vehicles": "1.0.0", + "com.unity.modules.video": "1.0.0", + "com.unity.modules.vr": "1.0.0", + "com.unity.modules.wind": "1.0.0", + "com.unity.modules.xr": "1.0.0" + } +} diff --git a/ProjectSettings/ProjectSettings.asset b/ProjectSettings/ProjectSettings.asset index b90c236..54021a3 100644 --- a/ProjectSettings/ProjectSettings.asset +++ b/ProjectSettings/ProjectSettings.asset @@ -144,7 +144,8 @@ PlayerSettings: visionOSBundleVersion: 1.0 tvOSBundleVersion: 1.0 bundleVersion: 1.0 - preloadedAssets: [] + preloadedAssets: + - {fileID: -944628639613478452, guid: 2bcd2660ca9b64942af0de543d8d7100, type: 3} metroInputSource: 0 wsaTransparentSwapchain: 0 m_HolographicPauseOnTrackingLoss: 1 @@ -296,7 +297,10 @@ PlayerSettings: androidSymbolsSizeThreshold: 800 m_BuildTargetIcons: [] m_BuildTargetPlatformIcons: [] - m_BuildTargetBatching: [] + m_BuildTargetBatching: + - m_BuildTarget: Standalone + m_StaticBatching: 1 + m_DynamicBatching: 1 m_BuildTargetShaderSettings: [] m_BuildTargetGraphicsJobs: [] m_BuildTargetGraphicsJobMode: [] diff --git a/ProjectSettings/UnityConnectSettings.asset b/ProjectSettings/UnityConnectSettings.asset index 029ad8b..7a17e8f 100644 --- a/ProjectSettings/UnityConnectSettings.asset +++ b/ProjectSettings/UnityConnectSettings.asset @@ -4,7 +4,7 @@ UnityConnectSettings: m_ObjectHideFlags: 0 serializedVersion: 1 - m_Enabled: 0 + m_Enabled: 1 m_TestMode: 0 m_EventOldUrl: https://api.uca.cloud.unity3d.com/v1/events m_EventUrl: https://cdp.cloud.unity3d.com/v1/events diff --git a/TOWER_CSV_IMPORTER.md b/TOWER_CSV_IMPORTER.md deleted file mode 100644 index b49e3bf..0000000 --- a/TOWER_CSV_IMPORTER.md +++ /dev/null @@ -1,138 +0,0 @@ -# Tower CSV Importer Guide - -## Overview -The tower CSV importer allows you to create tower prefabs from CSV data in one step, similar to the monster importer. - -## Files Created -1. **TowerDataComponent.cs** - Component that applies TowerData to a GameObject -2. **TowerPrefabSetup.cs** - Implementation of IPrefabSetup for tower prefab generation -3. **CSVToSOImporter.cs** - Generic CSV importer that works with any data type - -## How to Use - -### Step 1: Ensure Tower Template Exists -If you haven't created the TowerTemplate yet: -1. In Unity, go to `Tools > Data > Create Tower Template` -2. This creates `Assets/Data/Templates/TowerTemplate.prefab` with all required components: - - NetworkObject - - Building - - TowerDataComponent - - MeshFilter & MeshRenderer - - BoxCollider - - NavMeshObstacle - -### Step 2: Update Tower.csv -Edit `GameData/Tower.csv` with your tower data. The CSV uses camelCase field names matching TowerData class: - -```csv -id,memo,mana,manpower,sizeX,sizeY,maxHp,atkRange,atkDamage,atkIntervalSec,modelPath -1,타워,25,10,3,3,50,10,5,2,Assets/Meshes/building_tower_B_blue.fbx -2,벽,5,5,1,1,30,0,0,0,Assets/Meshes/building_tower_B_blue.fbx -``` - -**Field Descriptions:** -- `id`: Unique tower ID -- `memo`: Tower name/description -- `mana`: Mana cost to build -- `manpower`: Construction work required -- `sizeX`: Grid width -- `sizeY`: Grid length -- `maxHp`: Maximum health -- `atkRange`: Attack range -- `atkDamage`: Attack damage -- `atkIntervalSec`: Attack interval in seconds -- `modelPath`: Path to FBX model or mesh asset - -### Step 3: Import CSV -In Unity, go to `Tools > Data > Import All CSV` - -The importer will: -1. Create ScriptableObject files in `Assets/Data/ScriptableObjects/Tower/` -2. Create/Update prefabs in `Assets/Prefabs/Tower/` -3. Apply models from `modelPath` column -4. Configure components based on CSV data -5. Link TowerData to TowerDataComponent - -### Step 4: Use Tower Prefabs -Your generated tower prefabs are ready to use in the BuildingManager system! - -## File Structure After Import -``` -Assets/ -├── Data/ -│ ├── ScriptableObjects/ -│ │ └── Tower/ # SO files (generated from CSV) -│ │ ├── Tower1.asset -│ │ └── Tower2.asset -│ └── Templates/ # Template prefabs (created once) -│ └── TowerTemplate.prefab -├── Prefabs/ -│ └── Tower/ # Generated tower prefabs -│ ├── Tower1.prefab -│ └── Tower2.prefab -└── GameData/ - └── Tower.csv # Source data (editable) -``` - -## How It Works - -### CSV Import Pipeline -``` -Tower.csv (CSV data) - ↓ CSVToSOImporter -TowerData (ScriptableObject) - ↓ TowerPrefabSetup -Tower.prefab (GameObject with components) -``` - -### TowerPrefabSetup Logic -1. **TowerDataComponent**: Links TowerData SO to the prefab -2. **Model Application**: Loads and applies FBX model from modelPath -3. **Collider Setup**: Creates BoxCollider sized to tower dimensions -4. **Building Integration**: Converts TowerData to BuildingData for Building component - -## Benefits -- ✅ **One-click import**: Import all towers from CSV at once -- ✅ **Consistent structure**: All towers have the same components -- ✅ **Easy updates**: Edit CSV and re-import to update all towers -- ✅ **Designer-friendly**: Non-programmers can add new towers -- ✅ **Type-safe**: TowerData class ensures data integrity - -## Troubleshooting - -**"No prefab setup found for Tower"** -- Make sure TowerPrefabSetup.cs is in the Assets/Scripts/Editor folder -- Restart Unity Editor to ensure the script is compiled - -**"Template not found"** -- Run `Tools > Data > Create Tower Template` first -- Verify TowerTemplate.prefab exists in Assets/Data/Templates/ - -**Prefabs not created** -- Check the Console for error messages -- Verify Tower.csv exists in GameData folder -- Ensure modelPath in CSV points to valid assets - -**Model not showing** -- Verify modelPath in CSV is correct -- Check that the FBX file exists at the specified path -- Ensure the model has valid materials assigned - -## Customization - -### Adding New Components to All Towers -1. Open `Assets/Data/Templates/TowerTemplate.prefab` -2. Add the component -3. Configure defaults -4. Save template -5. Re-import CSV to apply changes to new towers - -### Modifying Existing Towers -- Edit the prefab directly (changes persist on next import) -- OR modify Tower.csv and re-import (will update SO link and model) - -## Notes -- TowerDataComponent converts TowerData to BuildingData for compatibility with the existing Building system -- The importer creates prefabs if they don't exist, or updates existing ones -- Prefab edits (other than SO and model) are preserved on re-import -- CSV field names must match TowerData class property names exactly (case-sensitive, camelCase) diff --git a/TOWER_QUICKSLOT_SETUP.md b/TOWER_QUICKSLOT_SETUP.md deleted file mode 100644 index 060925c..0000000 --- a/TOWER_QUICKSLOT_SETUP.md +++ /dev/null @@ -1,120 +0,0 @@ -# Tower Quickslot Setup Guide - -## 🎯 ULTRA-SIMPLE 1-CLICK SETUP (For Non-Programmers!) - -### Just ONE Step! - -Edit your `GameData/Tower.csv` file with tower data, then in Unity: - -``` -Tools > Data > Import All CSV -``` - -**THAT'S IT!** This automatically does everything: -- ✅ Creates TowerData from CSV (TowerData now extends BuildingData!) -- ✅ Creates Tower prefabs with TowerDataComponent -- ✅ **Auto-configures BuildingManager with all TowerData!** - -### Testing -Press **B** in-game → All towers appear in quickslot! 🎉 - ---- - -## 📝 Adding New Towers - -1. Add row to `GameData/Tower.csv` -2. Run `Tools > Data > Import All CSV` -3. Done! 🚀 - -Everything is automatic! - ---- - -## 🔧 Troubleshooting - -### Error: "BuildingManager not found in scene" - -**Cause:** Your scene doesn't have a GameObject with BuildingManager component. - -**Fix:** -1. Create a new GameObject (e.g., "BuildingManager") -2. Add BuildingManager component to it -3. Run `Tools > Data > Import All CSV` again -4. Done! - -### Error: "MissingReferenceException: prefab doesn't exist" - -**Cause:** TowerData doesn't have prefab reference. - -**Fix:** -1. Run `Northbound > Diagnose Tower System` -2. Check which TowerData shows `✗ MISSING PREFAB` -3. Run `Tools > Data > Import All CSV` to fix -4. Done! - -### No towers appear in quickslot - -**Cause:** BuildingManager wasn't found or configured. - -**Fix:** -1. Run `Northbound > Diagnose Tower System` -2. Check if BuildingManager is found and has TowerData in list -3. If not, add BuildingManager to your scene -4. Run `Tools > Data > Import All CSV` - ---- - -## 🎮 Menu Commands - -| Command | What it does | When to use | -|---------|--------------|--------------| -| `Tools > Data > Import All CSV` | **ONE-CLICK SETUP** - Import all CSV files, create prefabs, auto-configure BuildingManager with TowerData | After editing Tower.csv or anytime you want to update towers | -| `Northbound > Diagnose Tower System` | Check tower system health and find issues | When something doesn't work | - ---- - -## ✅ Why This is Awesome - -- ✅ **ONE CLICK** - Edit CSV, run importer, done! -- ✅ **One folder for towers** - `Assets/Prefabs/Tower/` only -- ✅ **No duplicates** - No manual copying anywhere -- ✅ **Fully automatic** - BuildingManager configured automatically -- ✅ **Non-programmer friendly** - Just edit CSV and click one button! -- ✅ **Works in builds** - Everything is pre-populated -- ✅ **Instant testing** - Press B and see all towers! -- ✅ **Unified data structure** - TowerData extends BuildingData, no redundant data! - ---- - -## 🎉 Complete Workflow for New Teammates - -1. Open Unity project -2. Add BuildingManager GameObject to scene (once) -3. Edit `GameData/Tower.csv` with tower data -4. Run `Tools > Data > Import All CSV` -5. Play game, press **B**, build towers! 🏗️ - -**That's literally it! No manual configuration needed!** - ---- - -## 🏗️ Technical Details - -### Unified Data Structure - -**Before:** Two separate data systems -- TowerData (CSV, tower-specific stats) -- BuildingData (auto-generated, building stats) - -**Now:** Single unified system -- TowerData extends BuildingData -- TowerData has all tower-specific fields (atkRange, atkDamage, etc.) -- TowerData automatically maps to BuildingData fields (width, length, maxHealth, etc.) -- BuildingManager uses TowerData directly (no conversion needed!) - -### Benefits of Unified Structure -- ✅ No duplicate data -- ✅ Single source of truth -- ✅ Cleaner code -- ✅ Easier to maintain -- ✅ Tower prefabs can be used directly without intermediate BuildingData files diff --git a/TROUBLESHOOTING_GHOST.md b/TROUBLESHOOTING_GHOST.md deleted file mode 100644 index 1167303..0000000 --- a/TROUBLESHOOTING_GHOST.md +++ /dev/null @@ -1,196 +0,0 @@ -# Building Ghost Preview Troubleshooting - -## FIXED: Preview Activated But Not Visible - -If console shows "Preview activated" but you can't see it, this was a **material/transparency issue**. - -**Solution implemented:** -- Better material creation supporting both URP and Standard RP -- Proper transparency setup for ghost materials -- Multiple material slots handled correctly -- Auto-creates debug cube if prefab has no renderer - -**Test the fix:** -1. Press Play -2. Press B to enter build mode -3. Move mouse over ground -4. You should now see a **green transparent ghost** of your building -5. Invalid positions show **red transparent ghost** - -If still not visible after update, continue with checklist below. - ---- - -## Quick Checklist - -Run through these checks in order: - -### 1. Check Console Logs -Press B to enter build mode and look for these messages: -- ✅ "Entered Build Mode" -- ✅ "[BuildingPlacement] Created preview: BuildingPreview" -- ✅ "[BuildingPlacement] Found X renderers" -- ✅ "[BuildingPlacement] Applied valid material to preview" -- ✅ "[BuildingPlacement] Preview activated at (x, y, z)" - -**If you see errors:** -- ❌ "BuildingManager.Instance is null" → Go to Step 2 -- ❌ "No buildings available" → Go to Step 3 -- ❌ "Prefab is null" → Go to Step 4 -- ❌ "Preview deactivated - no ground hit" → Go to Step 5 - -### 2. Check BuildingManager Setup -1. In Hierarchy, find "BuildingManager" GameObject -2. Verify it has: - - `BuildingManager` component - - `NetworkObject` component -3. In BuildingManager component: - - **Grid Size**: Should be > 0 (e.g., 1) - - **Ground Layer**: Should be set (e.g., "Default" or "Ground") - - **Available Buildings**: Should have at least 1 BuildingData - -**Fix:** If BuildingManager doesn't exist, create it: -- Create Empty GameObject → Name: "BuildingManager" -- Add Component → BuildingManager -- Add Component → NetworkObject -- Configure settings - -### 3. Check BuildingData Asset -1. Project window → Find your BuildingData asset -2. Select it and check Inspector: - - **Building Name**: Should have a name - - **Prefab**: Should be assigned (not "None") - - **Width/Length/Height**: Should be > 0 -3. Verify this BuildingData is in BuildingManager's "Available Buildings" list - -**Fix:** If BuildingData missing: -- Right-click in Project → Create → Northbound → Building Data -- Assign a prefab -- Add to BuildingManager's Available Buildings list - -### 4. Check Building Prefab -1. Find your building prefab in Project -2. Open it and verify: - - Has a `MeshRenderer` or `SkinnedMeshRenderer` component - - Renderer has a `Material` assigned - - Has a `Collider` (for placement validation) - - Optionally has `NetworkObject` (will be removed from preview) - -**Fix:** If prefab is missing components: -- Add a 3D object (Cube, for testing) -- Save as prefab -- Assign to BuildingData - -### 5. Check Ground Layer -The preview won't show if the raycast can't hit the ground. - -1. In Scene view, select your terrain/ground -2. Check its **Layer** (top of Inspector) -3. In BuildingManager: - - **Ground Layer** mask should include this layer -4. In BuildingPlacement (on Player): - - **Ground Layer** mask should match BuildingManager - -**Fix:** -- Set terrain Layer to "Default" or create "Ground" layer -- In BuildingManager/BuildingPlacement → Ground Layer → Check "Default" (or your ground layer) - -### 6. Check Camera -1. Verify `Camera.main` exists in scene -2. Camera should be able to see the ground - -**Fix:** -- Make sure Main Camera has tag "MainCamera" -- Camera should be positioned to see the scene - -### 7. Check Player Setup -1. Find your Player prefab -2. Verify it has: - - `BuildingPlacement` component - - **Ground Layer** is set - - **Max Placement Distance** > 0 (e.g., 100) - -### 8. Visual Check in Scene View -1. Press B to enter build mode -2. Open **Hierarchy** window -3. Look for object named "BuildingPreview" -4. If it exists: - - Click on it - - Check if it's active (checkbox next to name) - - Look at its position in Inspector - - Switch to **Scene** view and look for it - - Check if materials are assigned in Renderer component - -### 9. Test with Simple Cube -Create a minimal test setup: -1. Create a Cube in scene → Save as Prefab → Delete from scene -2. Create BuildingData → Assign Cube prefab -3. Add to BuildingManager → Available Buildings -4. Create a Plane → Position at (0, 0, 0) -5. Press Play → Press B → Move mouse over Plane - -You should see the transparent cube preview. - -## Common Issues - -### Preview exists but is invisible -**Cause:** Materials not rendering or transparent issues -**Fix (Now Automated):** -- The system now auto-detects your render pipeline (URP or Standard) -- Creates proper transparent materials automatically -- If prefab has no renderer, adds a debug cube - -**Manual Test:** -1. Add `GhostMaterialTest` component to any object with a renderer -2. Press Play -3. Object should become transparent green -4. If it works, the ghost system will work too - -### Preview doesn't follow mouse -**Cause:** Ground layer not set correctly or no ground detected -**Fix:** -- Check console for "no ground hit" message -- Verify Ground Layer includes your terrain -- Increase Max Placement Distance -- Make sure you're pointing at ground, not sky - -### Preview spawns at (0,0,0) and doesn't move -**Cause:** Raycast not hitting ground -**Fix:** -- Same as above - Ground Layer issue - -### Materials are black/pink -**Cause:** Shader/material issues -**Fix:** -- Make sure you're using the correct render pipeline shaders -- Standard RP: Use "Standard" shader -- URP: Use "Universal Render Pipeline/Lit" shader - -## Debug Commands - -Add these temporary debug lines to check: - -In `CreatePreview()` after instantiation: -```csharp -Debug.Log($"Preview position: {previewObject.transform.position}"); -Debug.Log($"Preview active: {previewObject.activeSelf}"); -Debug.Log($"Renderers: {previewRenderers.Length}"); -``` - -In `UpdatePreviewPosition()`: -```csharp -Debug.DrawRay(ray.origin, ray.direction * maxPlacementDistance, Color.red); -``` - -This shows the raycast in Scene view (red line from camera to mouse). - -## Still Not Working? - -Check these final items: -1. Input Actions are set up (ToggleBuildMode, Rotate, Build) -2. BuildingManager is spawned on network (in scene, not prefab) -3. You're the owner of the player (IsOwner = true) -4. No errors in Console -5. Build mode is actually active (check console for "Entered Build Mode") - -If all else fails, check the Console for any errors and share them!