diff --git a/Assembly-CSharp-Editor.csproj b/Assembly-CSharp-Editor.csproj
index 0b04632..e20c515 100644
--- a/Assembly-CSharp-Editor.csproj
+++ b/Assembly-CSharp-Editor.csproj
@@ -49,10 +49,12 @@
+
+
@@ -65,7 +67,9 @@
+
+
diff --git a/Assembly-CSharp.csproj b/Assembly-CSharp.csproj
index 8a7d6b3..8e4cb8b 100644
--- a/Assembly-CSharp.csproj
+++ b/Assembly-CSharp.csproj
@@ -86,6 +86,7 @@
+
@@ -94,6 +95,7 @@
+
@@ -120,6 +122,7 @@
+
diff --git a/Assets/Scripts/AutoHost.cs b/Assets/Scripts/AutoHost.cs
index 8f51ca7..9935fa6 100644
--- a/Assets/Scripts/AutoHost.cs
+++ b/Assets/Scripts/AutoHost.cs
@@ -3,24 +3,38 @@ using Unity.Netcode;
public class AutoHost : MonoBehaviour
{
- // 에디터에서만 작동하도록 설정
- void Start()
+ [Header("Auto Host Settings")]
+ [SerializeField] private bool enableAutoHost = true;
+ [SerializeField] private bool onlyInEditor = true;
+
+ private void Start()
{
-#if UNITY_EDITOR
- // 1. NetworkManager가 씬에 존재하는지 확인
- if (NetworkManager.Singleton != null)
+ if (ShouldAutoStart())
{
- // 2. 이미 서버나 클라이언트가 실행 중이 아닐 때만 실행
- if (!NetworkManager.Singleton.IsServer && !NetworkManager.Singleton.IsClient)
+ if (NetworkManager.Singleton != null)
{
- NetworkManager.Singleton.StartHost();
- Debug.Log("[AutoHost] 에디터 전용 호스트 자동 시작됨");
+ if (!NetworkManager.Singleton.IsServer && !NetworkManager.Singleton.IsClient)
+ {
+ NetworkManager.Singleton.StartHost();
+ Debug.Log("[AutoHost] Auto-host started");
+ }
+ }
+ else
+ {
+ Debug.LogError("[AutoHost] NetworkManager not found!");
}
}
- else
- {
- Debug.LogError("[AutoHost] NetworkManager를 찾을 수 없습니다!");
- }
+ }
+
+ private bool ShouldAutoStart()
+ {
+ if (!enableAutoHost)
+ return false;
+
+#if UNITY_EDITOR
+ return true;
+#else
+ return !onlyInEditor;
#endif
}
}
\ No newline at end of file
diff --git a/Assets/Scripts/Editor/NetworkConnectionHelperEditor.cs b/Assets/Scripts/Editor/NetworkConnectionHelperEditor.cs
new file mode 100644
index 0000000..494aa8d
--- /dev/null
+++ b/Assets/Scripts/Editor/NetworkConnectionHelperEditor.cs
@@ -0,0 +1,176 @@
+using UnityEngine;
+using UnityEditor;
+using Unity.Netcode;
+
+namespace Northbound.Editor
+{
+ [CustomEditor(typeof(NetworkConnectionHelper))]
+ public class NetworkConnectionHelperEditor : UnityEditor.Editor
+ {
+ private NetworkConnectionHelper _helper;
+ private GUIStyle _statusStyle;
+
+ private void OnEnable()
+ {
+ _helper = (NetworkConnectionHelper)target;
+ }
+
+ public override void OnInspectorGUI()
+ {
+ _statusStyle = new GUIStyle(EditorStyles.boldLabel);
+ _statusStyle.alignment = TextAnchor.MiddleCenter;
+ _statusStyle.fontSize = 12;
+
+ DrawDefaultInspector();
+ EditorGUILayout.Space(10);
+
+ DrawConnectionControls();
+ EditorGUILayout.Space(10);
+
+ DrawStatus();
+ EditorGUILayout.Space(10);
+
+ DrawQuickActions();
+ }
+
+ private void DrawConnectionControls()
+ {
+ EditorGUILayout.LabelField("Network Controls", EditorStyles.boldLabel);
+
+ EditorGUI.BeginDisabledGroup(IsConnected());
+
+ if (GUILayout.Button("Start Host", GUILayout.Height(30)))
+ {
+ _helper.StartHost();
+ }
+
+ if (GUILayout.Button("Start Server", GUILayout.Height(30)))
+ {
+ _helper.StartServer();
+ }
+
+ if (GUILayout.Button("Start Client", GUILayout.Height(30)))
+ {
+ _helper.StartClient();
+ }
+
+ EditorGUI.EndDisabledGroup();
+
+ EditorGUI.BeginDisabledGroup(!IsConnected());
+
+ if (GUILayout.Button("Disconnect", GUILayout.Height(30)))
+ {
+ _helper.Disconnect();
+ }
+
+ EditorGUI.EndDisabledGroup();
+ }
+
+ private void DrawStatus()
+ {
+ EditorGUILayout.LabelField("Status", EditorStyles.boldLabel);
+
+ string status = GetDetailedStatus();
+ Color bgColor = GetStatusColor();
+
+ var oldBgColor = GUI.backgroundColor;
+ GUI.backgroundColor = bgColor;
+
+ EditorGUILayout.LabelField(status, _statusStyle, GUILayout.Height(25));
+
+ GUI.backgroundColor = oldBgColor;
+
+ if (NetworkManager.Singleton != null && IsConnected())
+ {
+ DrawNetworkInfo();
+ }
+ }
+
+ private void DrawNetworkInfo()
+ {
+ EditorGUILayout.LabelField("Network Information", EditorStyles.boldLabel);
+
+ using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox))
+ {
+ if (NetworkManager.Singleton.IsHost)
+ {
+ EditorGUILayout.LabelField($"Mode: Host");
+ }
+ else if (NetworkManager.Singleton.IsServer)
+ {
+ EditorGUILayout.LabelField($"Mode: Server");
+ }
+ else if (NetworkManager.Singleton.IsClient)
+ {
+ EditorGUILayout.LabelField($"Mode: Client");
+ }
+
+ EditorGUILayout.LabelField($"Connected Clients: {NetworkManager.Singleton.ConnectedClients.Count}");
+ EditorGUILayout.LabelField($"Local Client ID: {NetworkManager.Singleton.LocalClientId}");
+
+ var transport = NetworkManager.Singleton.GetComponent();
+ if (transport != null)
+ {
+ EditorGUILayout.LabelField($"Address: {transport.ConnectionData.Address}");
+ EditorGUILayout.LabelField($"Port: {transport.ConnectionData.Port}");
+ }
+ }
+ }
+
+ private void DrawQuickActions()
+ {
+ EditorGUILayout.LabelField("Quick Actions", EditorStyles.boldLabel);
+
+ EditorGUILayout.BeginHorizontal();
+
+ if (GUILayout.Button("Open Connection Window"))
+ {
+ NetworkConnectionWindow.ShowWindow();
+ }
+
+ if (GUILayout.Button("Test Connection"))
+ {
+ TestConnection();
+ }
+
+ EditorGUILayout.EndHorizontal();
+ }
+
+ private bool IsConnected()
+ {
+ return NetworkManager.Singleton != null &&
+ (NetworkManager.Singleton.IsClient || NetworkManager.Singleton.IsServer);
+ }
+
+ private string GetDetailedStatus()
+ {
+ if (NetworkManager.Singleton == null)
+ return "NetworkManager Not Found";
+
+ if (NetworkManager.Singleton.IsHost)
+ return "HOSTING";
+ if (NetworkManager.Singleton.IsServer)
+ return "SERVER RUNNING";
+ if (NetworkManager.Singleton.IsClient)
+ return "CONNECTED";
+
+ return "NOT CONNECTED";
+ }
+
+ private Color GetStatusColor()
+ {
+ if (NetworkManager.Singleton == null)
+ return new Color(0.8f, 0.3f, 0.3f);
+
+ if (NetworkManager.Singleton.IsHost || NetworkManager.Singleton.IsClient || NetworkManager.Singleton.IsServer)
+ return new Color(0.3f, 0.8f, 0.3f);
+
+ return new Color(0.8f, 0.6f, 0.3f);
+ }
+
+ private void TestConnection()
+ {
+ Debug.Log($"[NetworkConnectionHelper] Connection test - Status: {_helper.GetStatus()}");
+ }
+ }
+}
diff --git a/Assets/Scripts/Editor/NetworkConnectionHelperEditor.cs.meta b/Assets/Scripts/Editor/NetworkConnectionHelperEditor.cs.meta
new file mode 100644
index 0000000..372367f
--- /dev/null
+++ b/Assets/Scripts/Editor/NetworkConnectionHelperEditor.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 36e75e477fa8d69459450bd36b5c6878
\ No newline at end of file
diff --git a/Assets/Scripts/Editor/NetworkConnectionWindow.cs b/Assets/Scripts/Editor/NetworkConnectionWindow.cs
new file mode 100644
index 0000000..92358bb
--- /dev/null
+++ b/Assets/Scripts/Editor/NetworkConnectionWindow.cs
@@ -0,0 +1,295 @@
+using UnityEngine;
+using UnityEditor;
+using Unity.Netcode;
+using System.IO;
+using UnityEngine.SceneManagement;
+
+namespace Northbound.Editor
+{
+ public class NetworkConnectionWindow : UnityEditor.EditorWindow
+ {
+ private string _serverIP = "127.0.0.1";
+ private string _port = "7777";
+ private bool _isHost = true;
+ private NetworkConnectionMode _connectionMode = NetworkConnectionMode.Host;
+ private string _savedSettingsPath;
+
+ private enum NetworkConnectionMode
+ {
+ Host,
+ Client,
+ Server
+ }
+
+ [MenuItem("Window/Network/Connection Manager %#n")]
+ public static void ShowWindow()
+ {
+ var window = GetWindow("Network Connection");
+ window.minSize = new Vector2(350, 250);
+ }
+
+ private void OnEnable()
+ {
+ _savedSettingsPath = Path.Combine(Application.persistentDataPath, "NetworkConnectionSettings.json");
+ LoadSettings();
+ }
+
+ private void OnGUI()
+ {
+ EditorGUILayout.Space(10);
+
+ GUILayout.Label("Network Connection Manager", EditorStyles.boldLabel);
+ EditorGUILayout.Space(5);
+
+ DrawConnectionModeUI();
+ EditorGUILayout.Space(10);
+
+ DrawConnectionSettings();
+ EditorGUILayout.Space(10);
+
+ DrawStatusDisplay();
+ EditorGUILayout.Space(10);
+
+ DrawActionButtons();
+ EditorGUILayout.Space(10);
+
+ DrawSettingsButtons();
+ }
+
+ private void DrawConnectionModeUI()
+ {
+ EditorGUILayout.LabelField("Connection Mode", EditorStyles.boldLabel);
+ _connectionMode = (NetworkConnectionMode)EditorGUILayout.EnumPopup("Mode", _connectionMode);
+
+ if (_connectionMode == NetworkConnectionMode.Host)
+ {
+ _isHost = true;
+ }
+ }
+
+ private void DrawConnectionSettings()
+ {
+ EditorGUILayout.LabelField("Connection Settings", EditorStyles.boldLabel);
+
+ if (_connectionMode == NetworkConnectionMode.Client)
+ {
+ _serverIP = EditorGUILayout.TextField("Server IP", _serverIP);
+ _port = EditorGUILayout.TextField("Port", _port);
+ }
+ else if (_connectionMode == NetworkConnectionMode.Host || _connectionMode == NetworkConnectionMode.Server)
+ {
+ _port = EditorGUILayout.TextField("Port", _port);
+ }
+
+ if (GUI.changed)
+ {
+ SaveSettings();
+ }
+ }
+
+ private void DrawStatusDisplay()
+ {
+ EditorGUILayout.LabelField("Status", EditorStyles.boldLabel);
+
+ string status = GetNetworkStatus();
+ Color statusColor = GetStatusColor();
+
+ var oldColor = GUI.color;
+ GUI.color = statusColor;
+ EditorGUILayout.LabelField(status, EditorStyles.helpBox);
+ GUI.color = oldColor;
+ }
+
+ private void DrawActionButtons()
+ {
+ EditorGUI.BeginDisabledGroup(IsNetworkActive());
+
+ if (GUILayout.Button(_connectionMode == NetworkConnectionMode.Client ? "Connect" : "Start", GUILayout.Height(30)))
+ {
+ StartConnection();
+ }
+
+ EditorGUI.EndDisabledGroup();
+
+ EditorGUI.BeginDisabledGroup(!IsNetworkActive());
+
+ if (GUILayout.Button("Disconnect", GUILayout.Height(30)))
+ {
+ Disconnect();
+ }
+
+ EditorGUI.EndDisabledGroup();
+ }
+
+ private void DrawSettingsButtons()
+ {
+ EditorGUILayout.BeginHorizontal();
+
+ if (GUILayout.Button("Save Settings"))
+ {
+ SaveSettings();
+ Debug.Log("[NetworkConnectionWindow] Settings saved.");
+ }
+
+ if (GUILayout.Button("Load Settings"))
+ {
+ LoadSettings();
+ Debug.Log("[NetworkConnectionWindow] Settings loaded.");
+ }
+
+ EditorGUILayout.EndHorizontal();
+ }
+
+ private void StartConnection()
+ {
+ if (NetworkManager.Singleton == null)
+ {
+ EditorUtility.DisplayDialog("Error", "NetworkManager not found in the scene!", "OK");
+ return;
+ }
+
+ ushort port;
+ if (!ushort.TryParse(_port, out port))
+ {
+ EditorUtility.DisplayDialog("Error", "Invalid port number!", "OK");
+ return;
+ }
+
+ NetworkManager.Singleton.GetComponent()?.SetConnectionData(
+ _serverIP,
+ port
+ );
+
+ switch (_connectionMode)
+ {
+ case NetworkConnectionMode.Host:
+ NetworkManager.Singleton.StartHost();
+ Debug.Log($"[NetworkConnectionWindow] Started Host on port {port}");
+ break;
+
+ case NetworkConnectionMode.Client:
+ NetworkManager.Singleton.StartClient();
+ Debug.Log($"[NetworkConnectionWindow] Started Client connecting to {_serverIP}:{port}");
+ break;
+
+ case NetworkConnectionMode.Server:
+ NetworkManager.Singleton.StartServer();
+ Debug.Log($"[NetworkConnectionWindow] Started Server on port {port}");
+ break;
+ }
+ }
+
+ private void Disconnect()
+ {
+ if (NetworkManager.Singleton != null)
+ {
+ NetworkManager.Singleton.Shutdown();
+ Debug.Log("[NetworkConnectionWindow] Disconnected");
+ }
+ }
+
+ private bool IsNetworkActive()
+ {
+ return NetworkManager.Singleton != null &&
+ (NetworkManager.Singleton.IsClient || NetworkManager.Singleton.IsServer);
+ }
+
+ private string GetNetworkStatus()
+ {
+ if (NetworkManager.Singleton == null)
+ return "NetworkManager not found";
+
+ if (NetworkManager.Singleton.IsHost)
+ return $"Hosting (Port: {GetActivePort()})";
+ if (NetworkManager.Singleton.IsServer)
+ return $"Server (Port: {GetActivePort()})";
+ if (NetworkManager.Singleton.IsClient)
+ return $"Client connected to {GetActiveIP()}:{GetActivePort()}";
+
+ return "Not connected";
+ }
+
+ private Color GetStatusColor()
+ {
+ if (NetworkManager.Singleton == null)
+ return Color.red;
+
+ if (NetworkManager.Singleton.IsHost || NetworkManager.Singleton.IsClient || NetworkManager.Singleton.IsServer)
+ return new Color(0f, 0.7f, 0f);
+
+ return new Color(1f, 0.7f, 0f);
+ }
+
+ private string GetActiveIP()
+ {
+ if (NetworkManager.Singleton == null) return "N/A";
+
+ var transport = NetworkManager.Singleton.GetComponent();
+ if (transport != null)
+ {
+ return transport.ConnectionData.Address;
+ }
+ return "N/A";
+ }
+
+ private string GetActivePort()
+ {
+ if (NetworkManager.Singleton == null) return "N/A";
+
+ var transport = NetworkManager.Singleton.GetComponent();
+ if (transport != null)
+ {
+ return transport.ConnectionData.Port.ToString();
+ }
+ return "N/A";
+ }
+
+ private void SaveSettings()
+ {
+ try
+ {
+ string json = $"{{\"serverIP\":\"{_serverIP}\",\"port\":\"{_port}\",\"connectionMode\":{_connectionMode}}}";
+ File.WriteAllText(_savedSettingsPath, json);
+ }
+ catch (System.Exception e)
+ {
+ Debug.LogError($"[NetworkConnectionWindow] Failed to save settings: {e.Message}");
+ }
+ }
+
+ private void LoadSettings()
+ {
+ try
+ {
+ if (File.Exists(_savedSettingsPath))
+ {
+ string json = File.ReadAllText(_savedSettingsPath);
+ var settings = JsonUtility.FromJson(json);
+ _serverIP = settings.serverIP;
+ _port = settings.port;
+ _connectionMode = (NetworkConnectionMode)settings.connectionMode;
+ }
+ }
+ catch (System.Exception e)
+ {
+ Debug.LogError($"[NetworkConnectionWindow] Failed to load settings: {e.Message}");
+ }
+ }
+
+ private void Update()
+ {
+ if (IsNetworkActive())
+ {
+ Repaint();
+ }
+ }
+
+ [System.Serializable]
+ private class ConnectionSettings
+ {
+ public string serverIP;
+ public string port;
+ public int connectionMode;
+ }
+ }
+}
diff --git a/Assets/Scripts/Editor/NetworkConnectionWindow.cs.meta b/Assets/Scripts/Editor/NetworkConnectionWindow.cs.meta
new file mode 100644
index 0000000..2bccbae
--- /dev/null
+++ b/Assets/Scripts/Editor/NetworkConnectionWindow.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: b7b2610829b9bba4f801fb9d527963c9
\ No newline at end of file
diff --git a/Assets/Scripts/Editor/NetworkUIBuilder.cs b/Assets/Scripts/Editor/NetworkUIBuilder.cs
new file mode 100644
index 0000000..f1e4677
--- /dev/null
+++ b/Assets/Scripts/Editor/NetworkUIBuilder.cs
@@ -0,0 +1,176 @@
+using UnityEngine;
+using UnityEngine.UI;
+using UnityEditor;
+
+namespace Northbound.Editor
+{
+ public class NetworkUIBuilder
+ {
+ [MenuItem("GameObject/Network/Create Network Join UI")]
+ public static void CreateNetworkJoinUI()
+ {
+ Canvas canvas = FindOrCreateCanvas();
+ GameObject panel = CreatePanel(canvas.transform);
+
+ InputField ipInput = CreateInputField(panel.transform, "IP Input", "127.0.0.1", 150);
+ InputField portInput = CreateInputField(panel.transform, "Port Input", "7777", 100);
+
+ Button joinButton = CreateButton(panel.transform, "Join", new Vector2(0, -80));
+ Button hostButton = CreateButton(panel.transform, "Host", new Vector2(-60, -80));
+ Button disconnectButton = CreateButton(panel.transform, "Disconnect", new Vector2(60, -80));
+
+ Text statusText = CreateStatusText(panel.transform);
+
+ NetworkJoinUI networkJoinUI = panel.AddComponent();
+ networkJoinUI.SetUIReferences(panel, ipInput, portInput, joinButton, hostButton, disconnectButton, statusText);
+
+ Selection.activeGameObject = panel;
+ Debug.Log("[NetworkUIBuilder] Network Join UI created!");
+ }
+
+ private static Canvas FindOrCreateCanvas()
+ {
+ Canvas[] canvases = Object.FindObjectsByType