티스토리 뷰
어제 중간에 쓰래드 관련해서 문제가 터져서 더 진행을 못했다. 정황상 유니티가 메인 스레드에서만 작업을 하고 다른 쓰레드에서 작업을 하는 결과를 메인쓰레드에 바로 넣을 수 없기 때문인듯 싶다. 즉 서버로 입력을 받는 대기하는 시스템이 다른 쓰레드에서 동작하고 있다는 이야기 이다.
익숙하지 않지만 해결할수 있을듯 싶긴 하다. 아에 메인쓰레드에서 동작하게 하거나 아니면 메인쓰레드에서 대기 타고 있는 시스템을 만들어서 받으면 실행을 하게 하면 될듯 싶다.
Failed to parse playerSet data: get_gameObject can only be called from the main thread.
Constructors and field initializers will be executed from the loading thread when loading a scene.
Don't use this function in the constructor or field initializers, instead move initialization code to the Awake or Start function.
UnityEngine.Debug:LogError (object)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using UnityEngine;
namespace Main
{
public class SocketManager : MonoBehaviour
{
SocketIOUnity _socket;
int Port => 3000;
string _thisID;
public List<PlayerMove> playerMoveList;
Transform _playerManager;
Dictionary<string, float> _clientList;
string _key;
float _value;
void Awake()
{
_playerManager = GameObject.Find("PlayerManager").transform;
playerMoveList = _playerManager.GetComponentsInChildren<PlayerMove>().ToList();
foreach (var player in playerMoveList)
{
player.gameObject.SetActive(false);
}
}
async void Start()
{
MainThreadRun();
SocketThreadRun();
}
async void MainThreadRun()
{
while (_clientList == null) await Task.Yield();
int index = 0;
if (_clientList == null) return;
foreach (var client in _clientList)
{
if (index >= playerMoveList.Count)
{
print("We need more players!");
index += 1;
continue;
}
print($"{client.Key} is positionX {client.Value}");
playerMoveList[index].gameObject.SetActive(true);
playerMoveList[index].name = client.Key;
playerMoveList[index].transform.position = new Vector3(client.Value, -1.25f, -1);
index += 1;
}
}
async void SocketThreadRun()
{
_socket = new SocketIOUnity($"http://localhost:{Port}");
_socket.OnConnected += async (sender, eventArgs) =>
{
_thisID = _socket.Id;
print($"{_thisID} is connected!");
};
_socket.On("playerSet", response =>
{
try
{
_clientList = response.GetValue<Dictionary<string, float>>();
}
catch (Exception exception)
{
Debug.LogError("Failed to parse playerSet data: " + exception.Message);
}
});
_socket.OnDisconnected += async (sender, eventArgs) =>
{
print($"{_thisID} is disconnected!");
};
_socket.Connect();
}
}
}
이런식으로 짜면 구지 작업을 소켓작업을 메인쓰레드에 할당을 안해도 되긴 하다.
하나 더 키면 어떻게 되는지 확인해 봐야 할듯 싶다.
하나 더 키면 한놈이 더 나오기는 하는데 문제는 조작을 서버가 아니라 여기서 해놓게 해놓으니까 둘다 같이 움직인다.
일단 그건 나중에 해결하기로 하고 디스커넥트 하면 나가게 하고 커넥트 하면 새로 뜨게 하고 이런거 좀 만들어 볼 필요가 있다. 밥좀 먹고 오자.
하면서 느끼는 거지만 이거 영상으로 다루기에는 너무 어렵고 복잡한거 같다는 생각이 문득 든다. 특히 멀티스래드 개념이 들어가면 만만치가 않다.
void MainThreadRun()
{
PlayerSet();
}
async void PlayerSet()
{
while (!_playerSet) await Task.Yield();
if (_clientList == null)
{
_playerSet = false;
PlayerSet();
}
int index = 0;
foreach (var client in _clientList!)
{
if (index >= playerMoveList.Count)
{
print("We need more players!");
index += 1;
continue;
}
print($"{client.Key} is positionX {client.Value}");
playerMoveList[index].gameObject.SetActive(true);
playerMoveList[index].name = client.Key;
playerMoveList[index].transform.position = new Vector3(client.Value, -1.25f, -1);
index += 1;
}
_playerSet = false;
if (!_playerSet) PlayerSet();
}
이걸 강의로 만들면 이해를 할수 있을지 모르겠다. 이게 회사에서 이런식으로 Update를 안쓰고 코드를 짜는걸 시연을 했을때 처음에 다들 혼돈에 빠지더라. 근데 이건 나중에 서버사이드를 작업하려면 꼭 필요하다며 가급적 이렇게 짜도록 습관을 들여라고 권고를 했었다. 사실 인스탄시에트도 안쓰고 public으로 드래그 앤 드롭도 안하는거 보고 신기해 하더라.
여튼 이런식으로 둘이 나오는 코드를 만들었으니 하나가 연결이 끊어지면 알려주도록 하는 코드를 만들자.
서버쪽에서 이렇게 하면 될꺼 같긴 하다.
아니다 이렇게 해주자. 어차피 2명 이상 테스트를 안하니 여기까지면 충분할듯 싶다.
종료했는데 연결이 안끊어 진다. 아마 유니티 동작과 별개로 C#에서 쓰래드가 돌고 있기 때문인거 같다. 먼가 인위적으로 연결을 끝어야 할꺼 같긴 하다.
void OnApplicationQuit()
{
_socket.Disconnect();
}
이런거는 GPT에게 물어보면 잘 대답해준다.
잘 작동한다.
서버랑 디스커넥티드 되면 죄다 사라지게 하는 거만 만들면 될듯 싶다.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using UnityEngine;
namespace Main
{
public class SocketManager : MonoBehaviour
{
SocketIOUnity _socket;
int Port => 3000;
string _thisID;
public List<PlayerMove> playerMoveList;
Transform _playerManager;
Dictionary<string, float> _clientList;
bool _playerSet;
void Awake()
{
_playerManager = GameObject.Find("PlayerManager").transform;
playerMoveList = _playerManager.GetComponentsInChildren<PlayerMove>().ToList();
foreach (var player in playerMoveList)
{
player.gameObject.SetActive(false);
}
}
void Start()
{
MainThreadRun();
SocketThreadRun();
}
void MainThreadRun()
{
PlayerSet();
}
async void PlayerSet()
{
while (!_playerSet) await Task.Yield();
if (_clientList == null)
{
_playerSet = false;
PlayerSet();
}
PlayerInit();
int index = 0;
foreach (var client in _clientList!)
{
if (index >= playerMoveList.Count)
{
print("We need more players!");
index += 1;
continue;
}
print($"{client.Key} is positionX {client.Value}");
playerMoveList[index].gameObject.SetActive(true);
playerMoveList[index].name = client.Key;
playerMoveList[index].transform.position = new Vector3(client.Value, -1.25f, -1f);
index += 1;
}
_playerSet = false;
if (!_playerSet) PlayerSet();
}
void PlayerInit()
{
foreach (var player in playerMoveList)
{
player.gameObject.SetActive(false);
player.name = "Player";
player.transform.position = new Vector3(0f, 0f, 0f);
}
}
void SocketThreadRun()
{
_socket = new SocketIOUnity($"http://localhost:{Port}");
_socket.Connect();
_socket.OnConnected += async (sender, eventArgs) =>
{
_thisID = _socket.Id;
print($"{_thisID} is connected!");
};
_socket.On("playerSet", response =>
{
try {
_playerSet = true;
_clientList = response.GetValue<Dictionary<string, float>>();
}
catch (Exception exception)
{
Debug.LogError(exception.Message);
}
});
_socket.OnDisconnected += async (sender, eventArgs) =>
{
print($"{_thisID} is disconnected!");
PlayerInit();
};
}
void OnApplicationQuit()
{
PlayerInit();
_socket.Disconnect();
}
}
}
잘 작동하는지 보자. 강의로 만들기엔 코드가 너무 복잡하고 어렵긴 하다.
쉬었다가 이동 관련해서 코드를 넘겨주면 될꺼 같긴 하다. 포지션 뿐만 아니라 플립여부까지 넘겨줄 필요가 있다.
'학습 > AWS' 카테고리의 다른 글
전회사가 잘되는 꿈을 꾸다니 (0) | 2024.08.27 |
---|---|
꼼수일수도 있는데 (0) | 2024.08.27 |
영상으로 만들어야지 (0) | 2024.08.25 |
게임 서버 개발의 경우 (0) | 2024.08.25 |
어디까지 했더라 (0) | 2024.08.24 |