public class GameLogic : MonoBehaviour{ public int m_PlayerSeed = 1000; public List<PlayerData> m_ConnectedPlayers = new List<PlayerData>(); void Start() { NetworkServerProcessing.SetGameLogic(this); } public PlayerData Add(int clientConnectionID); public PlayerData Remove(int clientConnectionID); public PlayerData Search(int playerSeed);}
public PlayerData Add(int clientConnectionID){ PlayerData playerData = new PlayerData(clientConnectionID, m_PlayerSeed++); m_ConnectedPlayers.Add(playerData); return playerData;}
public PlayerData Remove(int clientConnectionID){ PlayerData removedPlayerData = null; foreach (PlayerData playerData in m_ConnectedPlayers) { if (playerData.m_ClientConnectionID == clientConnectionID) { removedPlayerData = playerData; m_ConnectedPlayers.Remove(removedPlayerData); break; } } return removedPlayerData;}
public PlayerData Search(int playerSeed){ PlayerData foundPlayerData = null; foreach (PlayerData playData in m_ConnectedPlayers) { if (playData.m_Seed == playerSeed) { foundPlayerData = playData; break; } } return foundPlayerData;}
NetworkServerProcessing.cs
static public class NetworkServerProcessing{ static public void ReceivedMessageFromClient(string msg, int clientConnectionID, TransportPipeline pipeline); static public void SendMessageToClient(string msg, int clientConnectionID, TransportPipeline pipeline); static public void ConnectionEvent(int clientConnectionID); static public void DisconnectionEvent(int clientConnectionID);}
Eng
static public void ReceivedMessageFromClient(string msg, int clientConnectionID, TransportPipeline pipeline){ string[] csv = msg.Split(','); int signifier = int.Parse(csv[0]); switch (signifier) { case ClientToServerSignifiers.PTC_PLAYER_MOVE: { string seed = csv[1]; string posX = csv[2], posY = csv[3], posZ = csv[4]; // Update server-side position data gameLogic.Search(int.Parse(seed))?.SetData(posX, posY, posZ); // Forward updated position to all connected clients string msgOut = $"{ServerToClientSignifiers.PTS_PLAYER_MOVE},{seed},{posX},{posY},{posZ}"; foreach (PlayerData data in gameLogic.m_ConnectedPlayers) SendMessageToClient(msgOut, data.m_ClientConnectionID, TransportPipeline.ReliableAndInOrder); } break; case ClientToServerSignifiers.PTC_PLAYER_MOVE2: // [Omitted] Input-based version of the above break; }}
Kor
static public void ReceivedMessageFromClient(string msg, int clientConnectionID, TransportPipeline pipeline){ string[] csv = msg.Split(','); int signifier = int.Parse(csv[0]); switch (signifier) { case ClientToServerSignifiers.PTC_PLAYER_MOVE: { string seed = csv[1]; string posX = csv[2], posY = csv[3], posZ = csv[4]; // 서버 측 위치 데이터 업데이트 gameLogic.Search(int.Parse(seed))?.SetData(posX, posY, posZ); // 업데이트된 위치를 모든 연결된 클라이언트에 전달 string msgOut = $"{ServerToClientSignifiers.PTS_PLAYER_MOVE},{seed},{posX},{posY},{posZ}"; foreach (PlayerData data in gameLogic.m_ConnectedPlayers) SendMessageToClient(msgOut, data.m_ClientConnectionID, TransportPipeline.ReliableAndInOrder); } break; case ClientToServerSignifiers.PTC_PLAYER_MOVE2: // [생략] 위의 입력 기반 버전 break; }}
Client Side
GameLogic.cs
public class GameLogic : MonoBehaviour{ public Player m_prefabPlayer; public Player m_prefabOthers; public List<Player> m_ConnectedPlayers = new List<Player>(); void Start() { NetworkClientProcessing.SetGameLogic(this); } public void SpawnMySelf(int mySeed, Vector3 position); public void SpawnOthers(int otherSeed, Vector3 position); public void MovePlayer(int movedPlayerSeed, Vector3 targetPos); public void MovePlayer(int movedPlayerSeed, Vector3 targetPos, Vector2 inputKeys); public void OtherPlayerLeft(int leftPlayerSeed);}
public void SpawnMySelf(int mySeed, Vector3 position){ Player mySelf = Instantiate(m_prefabPlayer, position, Quaternion.identity); PlayerData myData = new PlayerData(mySelf, mySeed, true); mySelf.InitData(myData); m_ConnectedPlayers.Add(mySelf);}
public void SpawnOthers(int otherSeed, Vector3 position){ Player other = Instantiate(m_prefabOthers, position, Quaternion.identity); PlayerData otherData = new PlayerData(other, otherSeed, false); other.InitData(otherData); m_ConnectedPlayers.Add(other);}
public void MovePlayer(int movedPlayerSeed, Vector3 targetPos){ foreach (Player player in m_ConnectedPlayers) { if (player.m_PlayerData.m_IsMe) continue; if (player.m_PlayerData.m_Seed == movedPlayerSeed) { player.SetMovePosition(targetPos); } }}
public void MovePlayer(int movedPlayerSeed, Vector3 targetPos, Vector2 inputKeys){ foreach (Player player in m_ConnectedPlayers) { if (player.m_PlayerData.m_IsMe) continue; if (player.m_PlayerData.m_Seed == movedPlayerSeed) { player.SetMovePosition(targetPos, inputKeys); } }}
public void OtherPlayerLeft(int leftPlayerSeed){ foreach (Player player in m_ConnectedPlayers) { if (player.m_PlayerData.m_Seed == leftPlayerSeed) { m_ConnectedPlayers.Remove(player); player.RemoveData(); break; } }}
NetworkClientProcessing.cs
static public class NetworkClientProcessing{ static public void ReceivedMessageFromServer(string msg, TransportPipeline pipeline); static public void SendMessageToServer(string msg, TransportPipeline pipeline); static public void ConnectionEvent(); static public void DisconnectionEvent();}
Eng
static public void ReceivedMessageFromServer(string msg, TransportPipeline pipeline){ string[] csv = msg.Split(','); int signifier = int.Parse(csv[0]); switch (signifier) { case ServerToClientSignifiers.PTS_CONNECTED_NEW_PLAYER: // [Omitted] Initialize and spawn the local player break; case ServerToClientSignifiers.PTS_CONNECTED_NEW_PLAYER_RECEIVE_DATA: // [Omitted] Receive and spawn existing players from server break; case ServerToClientSignifiers.PTS_CONNECTED_PLAYERS_RECEIVE_NEW_PLAYER_DATA: // [Omitted] Spawn newly joined remote player on other clients break; case ServerToClientSignifiers.PTS_PLAYER_MOVE: // [Omitted] Update remote player's position (Type A) break; case ServerToClientSignifiers.PTS_PLAYER_MOVE2: // [Omitted] Update remote player's position & input (Type B) break; case ServerToClientSignifiers.PTS_PLAYER_LEFT: // [Omitted] Remove disconnected player from scene break; }}
Kor
static public void ReceivedMessageFromServer(string msg, TransportPipeline pipeline){ string[] csv = msg.Split(','); int signifier = int.Parse(csv[0]); switch (signifier) { case ServerToClientSignifiers.PTS_CONNECTED_NEW_PLAYER: // [생략] 로컬 플레이어 초기화 및 생성 break; case ServerToClientSignifiers.PTS_CONNECTED_NEW_PLAYER_RECEIVE_DATA: // [생략] 서버에서 기존 플레이어 데이터를 받아 생성 break; case ServerToClientSignifiers.PTS_CONNECTED_PLAYERS_RECEIVE_NEW_PLAYER_DATA: // [생략] 다른 클라이언트에 새로 접속한 원격 플레이어 생성 break; case ServerToClientSignifiers.PTS_PLAYER_MOVE: // [생략] 원격 플레이어 위치 업데이트 (Type A) break; case ServerToClientSignifiers.PTS_PLAYER_MOVE2: // [생략] 원격 플레이어 위치 및 입력 업데이트 (Type B) break; case ServerToClientSignifiers.PTS_PLAYER_LEFT: // [생략] 연결이 끊긴 플레이어를 씬에서 제거 break; }}