diff --git a/Assets/Scenes/Test.unity b/Assets/Scenes/Test.unity
index 0fda99c4..f09de158 100644
--- a/Assets/Scenes/Test.unity
+++ b/Assets/Scenes/Test.unity
@@ -261,6 +261,18 @@ PrefabInstance:
propertyPath: m_SizeDelta.y
value: 80
objectReference: {fileID: 0}
+ - target: {fileID: 1384280946776679044, guid: 99f359b6678b0064dbd20508482d6d64, type: 3}
+ propertyPath: m_LocalScale.x
+ value: 0.8
+ objectReference: {fileID: 0}
+ - target: {fileID: 1384280946776679044, guid: 99f359b6678b0064dbd20508482d6d64, type: 3}
+ propertyPath: m_LocalScale.y
+ value: 0.8
+ objectReference: {fileID: 0}
+ - target: {fileID: 1384280946776679044, guid: 99f359b6678b0064dbd20508482d6d64, type: 3}
+ propertyPath: m_LocalScale.z
+ value: 1
+ objectReference: {fileID: 0}
- target: {fileID: 1384280946776679044, guid: 99f359b6678b0064dbd20508482d6d64, type: 3}
propertyPath: m_LocalPosition.x
value: 0
@@ -295,7 +307,7 @@ PrefabInstance:
objectReference: {fileID: 0}
- target: {fileID: 1384280946776679044, guid: 99f359b6678b0064dbd20508482d6d64, type: 3}
propertyPath: m_AnchoredPosition.y
- value: -420
+ value: -430
objectReference: {fileID: 0}
- target: {fileID: 1384280946776679044, guid: 99f359b6678b0064dbd20508482d6d64, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
@@ -406,6 +418,18 @@ PrefabInstance:
propertyPath: m_SizeDelta.y
value: 80
objectReference: {fileID: 0}
+ - target: {fileID: 1384280946776679044, guid: d8795051068c4f84e84c227a6618e587, type: 3}
+ propertyPath: m_LocalScale.x
+ value: 0.8
+ objectReference: {fileID: 0}
+ - target: {fileID: 1384280946776679044, guid: d8795051068c4f84e84c227a6618e587, type: 3}
+ propertyPath: m_LocalScale.y
+ value: 0.8
+ objectReference: {fileID: 0}
+ - target: {fileID: 1384280946776679044, guid: d8795051068c4f84e84c227a6618e587, type: 3}
+ propertyPath: m_LocalScale.z
+ value: 1
+ objectReference: {fileID: 0}
- target: {fileID: 1384280946776679044, guid: d8795051068c4f84e84c227a6618e587, type: 3}
propertyPath: m_LocalPosition.x
value: 0
diff --git a/Assets/Scripts/Player/PlayerSkillInput.cs b/Assets/Scripts/Player/PlayerSkillInput.cs
index 2272534f..4bdf5164 100644
--- a/Assets/Scripts/Player/PlayerSkillInput.cs
+++ b/Assets/Scripts/Player/PlayerSkillInput.cs
@@ -97,26 +97,73 @@ namespace Colosseum.Player
return;
}
+ // 로컬 체크 (빠른 피드백용)
+ if (skillController.IsExecutingSkill)
+ {
+ Debug.Log($"Already executing skill");
+ return;
+ }
+
+ if (skillController.IsOnCooldown(skill))
+ {
+ Debug.Log($"Skill {skill.SkillName} is on cooldown");
+ return;
+ }
+
// 마나 비용 체크
if (networkController != null && networkController.Mana < skill.ManaCost)
{
- Debug.Log($"Not enough mana for skill: {skill.SkillName} (Required: {skill.ManaCost}, Current: {networkController.Mana})");
+ Debug.Log($"Not enough mana for skill: {skill.SkillName}");
return;
}
- // 논타겟: 타겟 없이 스킬 시전
- bool success = skillController.ExecuteSkill(skill);
- if (!success)
- {
- Debug.Log($"Cannot execute skill: {skill.SkillName}");
- return;
- }
+ // 서버에 스킬 실행 요청
+ RequestSkillExecutionRpc(slotIndex);
+ }
- // 스킬 성공 시 마나 소모
+ ///
+ /// 서버에 스킬 실행 요청
+ ///
+ [Rpc(SendTo.Server)]
+ private void RequestSkillExecutionRpc(int slotIndex)
+ {
+ if (slotIndex < 0 || slotIndex >= skillSlots.Length)
+ return;
+
+ SkillData skill = skillSlots[slotIndex];
+ if (skill == null) return;
+
+ // 서버에서 다시 검증
+ if (skillController.IsExecutingSkill || skillController.IsOnCooldown(skill))
+ return;
+
+ if (networkController != null && networkController.Mana < skill.ManaCost)
+ return;
+
+ // 마나 소모
if (networkController != null && skill.ManaCost > 0)
{
networkController.UseManaRpc(skill.ManaCost);
}
+
+ // 모든 클라이언트에 스킬 실행 전파
+ BroadcastSkillExecutionRpc(slotIndex);
+ }
+
+ ///
+ /// 모든 클라이언트에 스킬 실행 전파
+ ///
+ [Rpc(SendTo.ClientsAndHost)]
+ private void BroadcastSkillExecutionRpc(int slotIndex)
+ {
+ if (slotIndex < 0 || slotIndex >= skillSlots.Length)
+ return;
+
+ SkillData skill = skillSlots[slotIndex];
+ if (skill == null) return;
+
+ // 모든 클라이언트에서 스킬 실행 (애니메이션 포함)
+ skillController.ExecuteSkill(skill);
}
///
diff --git a/Assets/Scripts/Skills/SkillController.cs b/Assets/Scripts/Skills/SkillController.cs
index 75146e10..628f6536 100644
--- a/Assets/Scripts/Skills/SkillController.cs
+++ b/Assets/Scripts/Skills/SkillController.cs
@@ -61,11 +61,6 @@ namespace Colosseum.Skills
var stateInfo = animator.GetCurrentAnimatorStateInfo(0);
- if (debugMode)
- {
- Debug.Log($"[Skill] State: {stateInfo.shortNameHash}, NormalizedTime: {stateInfo.normalizedTime:F2}, IsSkill: {stateInfo.IsName(SKILL_STATE_NAME)}");
- }
-
// EndAnimation 종료 감지
if (waitingForEndAnimation)
{
diff --git a/Assets/UserChoices.choices b/Assets/UserChoices.choices
new file mode 100644
index 00000000..3532d60e
--- /dev/null
+++ b/Assets/UserChoices.choices
@@ -0,0 +1,36 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!114 &1
+MonoBehaviour:
+ m_ObjectHideFlags: 53
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 0}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 18cde282a8d045bf9d245fdcfaa7271b, type: 3}
+ m_Name:
+ m_EditorClassIdentifier: Unity.Multiplayer.Center.Editor::Unity.Multiplayer.Center.Questionnaire.UserChoicesObject
+ QuestionnaireVersion: 1.3
+ UserAnswers:
+ Answers:
+ - QuestionId: Pace
+ Answers:
+ - Fast
+ - QuestionId: Cheating
+ Answers:
+ - CheatingImportant
+ - QuestionId: CostSensitivity
+ Answers:
+ - BestExperience
+ - QuestionId: NetcodeArchitecture
+ Answers:
+ - ClientServer
+ - QuestionId: PlayerCount
+ Answers:
+ - 4
+ Preset: 2
+ SelectedSolutions:
+ SelectedHostingModel: 2
+ SelectedNetcodeSolution: 1
diff --git a/Assets/UserChoices.choices.meta b/Assets/UserChoices.choices.meta
new file mode 100644
index 00000000..d89f3481
--- /dev/null
+++ b/Assets/UserChoices.choices.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 291abe421e975b24d9468acf16de7b2e
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Packages/manifest.json b/Packages/manifest.json
index cd432de1..f7ed6a14 100644
--- a/Packages/manifest.json
+++ b/Packages/manifest.json
@@ -2,13 +2,17 @@
"dependencies": {
"com.unity.ai.navigation": "2.0.10",
"com.unity.collab-proxy": "2.11.3",
+ "com.unity.dedicated-server": "2.0.1",
"com.unity.ide.rider": "3.0.39",
"com.unity.ide.visualstudio": "2.0.26",
"com.unity.inputsystem": "1.18.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.8",
"com.unity.netcode.gameobjects": "2.10.0",
"com.unity.render-pipelines.universal": "17.3.0",
+ "com.unity.services.multiplayer": "2.1.3",
"com.unity.test-framework": "1.6.0",
"com.unity.timeline": "1.8.10",
"com.unity.ugui": "2.0.0",
diff --git a/Packages/packages-lock.json b/Packages/packages-lock.json
index a9234ebc..5d8ba586 100644
--- a/Packages/packages-lock.json
+++ b/Packages/packages-lock.json
@@ -39,6 +39,13 @@
},
"url": "https://packages.unity.com"
},
+ "com.unity.dedicated-server": {
+ "version": "2.0.1",
+ "depth": 0,
+ "source": "registry",
+ "dependencies": {},
+ "url": "https://packages.unity.com"
+ },
"com.unity.ext.nunit": {
"version": "2.0.5",
"depth": 1,
@@ -87,6 +94,25 @@
"com.unity.modules.uielements": "1.0.0"
}
},
+ "com.unity.multiplayer.center.quickstart": {
+ "version": "1.1.1",
+ "depth": 0,
+ "source": "registry",
+ "dependencies": {
+ "com.unity.modules.uielements": "1.0.0",
+ "com.unity.multiplayer.center": "1.0.0"
+ },
+ "url": "https://packages.unity.com"
+ },
+ "com.unity.multiplayer.playmode": {
+ "version": "2.0.1",
+ "depth": 0,
+ "source": "registry",
+ "dependencies": {
+ "com.unity.nuget.newtonsoft-json": "2.0.2"
+ },
+ "url": "https://packages.unity.com"
+ },
"com.unity.multiplayer.tools": {
"version": "2.2.8",
"depth": 0,
@@ -172,6 +198,87 @@
"dependencies": {},
"url": "https://packages.unity.com"
},
+ "com.unity.services.authentication": {
+ "version": "3.6.0",
+ "depth": 1,
+ "source": "registry",
+ "dependencies": {
+ "com.unity.ugui": "1.0.0",
+ "com.unity.services.core": "1.15.1",
+ "com.unity.nuget.newtonsoft-json": "3.2.1",
+ "com.unity.modules.unitywebrequest": "1.0.0"
+ },
+ "url": "https://packages.unity.com"
+ },
+ "com.unity.services.core": {
+ "version": "1.16.0",
+ "depth": 1,
+ "source": "registry",
+ "dependencies": {
+ "com.unity.modules.androidjni": "1.0.0",
+ "com.unity.nuget.newtonsoft-json": "3.2.1",
+ "com.unity.modules.unitywebrequest": "1.0.0"
+ },
+ "url": "https://packages.unity.com"
+ },
+ "com.unity.services.deployment": {
+ "version": "1.7.1",
+ "depth": 1,
+ "source": "registry",
+ "dependencies": {
+ "com.unity.services.core": "1.15.1",
+ "com.unity.services.deployment.api": "1.1.2"
+ },
+ "url": "https://packages.unity.com"
+ },
+ "com.unity.services.deployment.api": {
+ "version": "1.1.3",
+ "depth": 2,
+ "source": "registry",
+ "dependencies": {},
+ "url": "https://packages.unity.com"
+ },
+ "com.unity.services.multiplayer": {
+ "version": "2.1.3",
+ "depth": 0,
+ "source": "registry",
+ "dependencies": {
+ "com.unity.transport": "2.6.0",
+ "com.unity.collections": "2.2.1",
+ "com.unity.services.qos": "1.4.1",
+ "com.unity.services.core": "1.16.0",
+ "com.unity.services.wire": "1.4.1",
+ "com.unity.services.deployment": "1.7.1",
+ "com.unity.nuget.newtonsoft-json": "3.2.2",
+ "com.unity.modules.unitywebrequest": "1.0.0",
+ "com.unity.services.authentication": "3.6.0"
+ },
+ "url": "https://packages.unity.com"
+ },
+ "com.unity.services.qos": {
+ "version": "1.4.1",
+ "depth": 1,
+ "source": "registry",
+ "dependencies": {
+ "com.unity.collections": "1.2.4",
+ "com.unity.services.core": "1.12.5",
+ "com.unity.nuget.newtonsoft-json": "3.0.2",
+ "com.unity.modules.unitywebrequest": "1.0.0",
+ "com.unity.services.authentication": "3.5.2"
+ },
+ "url": "https://packages.unity.com"
+ },
+ "com.unity.services.wire": {
+ "version": "1.4.1",
+ "depth": 1,
+ "source": "registry",
+ "dependencies": {
+ "com.unity.services.core": "1.12.5",
+ "com.unity.nuget.newtonsoft-json": "3.2.1",
+ "com.unity.services.authentication": "2.7.4"
+ },
+ "url": "https://packages.unity.com"
+ },
"com.unity.shadergraph": {
"version": "17.3.0",
"depth": 1,
diff --git a/ProjectSettings/MultiplayerManager.asset b/ProjectSettings/MultiplayerManager.asset
index 2a936644..f9820a8b 100644
--- a/ProjectSettings/MultiplayerManager.asset
+++ b/ProjectSettings/MultiplayerManager.asset
@@ -3,5 +3,9 @@
--- !u!655991488 &1
MultiplayerManager:
m_ObjectHideFlags: 0
- m_EnableMultiplayerRoles: 0
- m_StrippingTypes: {}
+ m_EnableMultiplayerRoles: 1
+ m_EnablePlayModeLocalDeployment: 0
+ m_EnablePlayModeRemoteDeployment: 0
+ m_StrippingTypes:
+ 1: []
+ 2: []
diff --git a/ProjectSettings/Packages/com.unity.dedicated-server/ContentSelectionSettings.asset b/ProjectSettings/Packages/com.unity.dedicated-server/ContentSelectionSettings.asset
new file mode 100644
index 00000000..565a173a
--- /dev/null
+++ b/ProjectSettings/Packages/com.unity.dedicated-server/ContentSelectionSettings.asset
@@ -0,0 +1,22 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!114 &1
+MonoBehaviour:
+ m_ObjectHideFlags: 53
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 0}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: d3c63bcbf0c7c4315b6f985026440942, type: 3}
+ m_Name:
+ m_EditorClassIdentifier: Unity.DedicatedServer.MultiplayerRoles.Editor::Unity.Multiplayer.Editor.ContentSelectionSettings
+ m_EnableSafetyChecks: 1
+ m_AutomaticSelectionOptions:
+ m_StripRenderComponents: 0
+ m_StripUIComponents: 0
+ m_StripAudioComponents: 0
+ m_CustomComponentsList:
+ m_Keys: []
+ m_Values:
diff --git a/ProjectSettings/VirtualProjectsConfig.json b/ProjectSettings/VirtualProjectsConfig.json
new file mode 100644
index 00000000..5dd584d7
--- /dev/null
+++ b/ProjectSettings/VirtualProjectsConfig.json
@@ -0,0 +1,4 @@
+{
+ "PlayerTags": [],
+ "version": "6000.3.10f1"
+}
\ No newline at end of file