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