묻고 답해요
145만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
SendBuffer 마지막부분 이해가 안됩니다.
질문 1. TLS로 SendBuffer를 스레드별 전역변수로 지정했으면, SendBuffer 멤버필드인 buffer도 스레드별 전역변수가 아닌가요?그런데 왜 _buffer는 공유자원처럼 다수의 스레드가 참조하는 건가요?(28:39 부분) 질문 2. 만약 _buffer는 TLS 여도 다수의 스레드가 볼 수 있다고 쳐도, 어차피 Send하는 부분은 그 스레드가 넣은 부분만(handler에서 close로 보내준 segment영역) 보내주기때문에 상관없는 것 아닌가요? (하지만 애초에 질문 1이 이해가 안됩니다.) 질문 3.이전에 Session#2 강의 시작부분에 설명해주신 내용에서,SEssion의 receive는 OnRecvCompleted()메서드에 여러 스레드가 동시다발적으로 들어가는 경우는 없다. 라고 하셨는데, 해당 강의에서는 어떤 이유로 멀티스레드를 생각해야 하는 상황이 된건지 궁금합니다.질문 4.Session 객체는 connect되는 client당 하나씩이니까 client와 연결 될 때 마다 새로운 session객체가 생성되어 다 따로 만들어지는 것이기 때문에 애초에 _sendQueue도 스레드별로 따로 아닌가요? 질문 5. _buffer는에서 읽기만 하는거니까..(30:03) 라고 하셨는데 읽는 부분이 어느부분인지, deq하는것을 읽는것이라고 표현하신건가요? 어떤 경우들을 말슴하시는건지 이해가 안되어 헷갈리는게 많습니다. 일단 질문은 더 있지만, 대표적인 질문들로 올려봅니다
-
미해결[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
segmeng 범위 지정시에 질문
안녕하세요, RecvBuffer 강의중에서//읽을 수 있는 유효한 데이터의 범위 public ArraySegment<byte> ReadSegment { get { return new ArraySegment<byte>(_buffer.Array, _buffer.Offset + _readPos, DataSize);} } //사용가능한, 비어있는 범위 public ArraySegment<byte> WriteSegment { get { return new ArraySegment<byte>(_buffer.Array, _buffer.Offset + _writePos, FreeSize); } }위와 같이 segment 프로퍼티를 설정하였는데, 중간 인자로 그냥 readPos를 넣지 않고 buffer.Offset + readPos 로 계산한 이유를 모르겠습니다. 현재 저의 생각으로는 buffer.Offset은 결국 언제나 0이지 않나? 입니다. 코드를 보았을 때 offset을 조작하거나 건드리는 코드는 아직 현재강의(RecvBuffer)까지는 없고, 나중에라도 _readPos와 DataSize가 결국 segment범위를 바꿔주니 이 offset을 건들일 필요는 없다고 생각이 드는 상태입니다. 또한, 만약 offset을 변경시키는 경우가 있더라도 offset+readpos 하면 offset이 0이 아닌경우 readpos에 맞지않는곳이 시작위치가 될텐데 왜 offset을 더하는건지 이해가 되지 않습니다.따라서 offset을 더한 이유가 궁금합니다!
-
미해결[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
RecvBuffer clean함수 이렇게 작성하면 어떻게 되나요?
안녕하세요, RecvBuffer 클래스를 작성하는 강의에서, clean()함수를 작성하실 때 강사님께서는이렇게 작성하셨는데,혹시 아래와 같이Array.Copy(ReadSegment.Array, 0, _buffer.Array, 0, DataSize);이렇게 작성해도 똑같은 결과가 나오려나요? 혹은 나중에 다른상황에서 이렇게 작성하면 다르게 동작한다던지 그런 문제가 있을까요?위에 적용된 ReadSegment범위를 사용하지 않는 이유가 뭔지 궁금합니다.public void Clean() { int dataSize = DataSize; if (dataSize == 0) { _readPos = 0; _writePos = 0; } else { Array.Copy(ReadSegment.Array, 0, _buffer.Array, 0, DataSize); _readPos = 0; _writePos = dataSize; } }
-
미해결[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
RegisterRecv()에서 args초기화 구문 사라진 이유
안녕하세요, 현재 RecvBuffer 강의를 시청중입니다.강의를 듣다가 RegisterRecv 를 봤는데 강사님께서void RegisterRecv(SocketAsyncEventArgs args) { args.AcceptSocket = null; bool pending = _socket.ReceiveAsync(args); //바로 성공했으면 if(pending == false) { OnRecvCompleted(null, args); } } 위와 같이 원래 있었는데void RegisterRecv(SocketAsyncEventArgs args) { bool pending = _socket.ReceiveAsync(args); //바로 성공했으면 if(pending == false) { OnRecvCompleted(null, args); } } 위처럼 args.AcceptSocket = null; 를 언제인지는 모르겠지만 삭제를 하셨던거같은데,언제, 왜 삭제하신건지 이유가 궁금합니다.
-
미해결[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part3: 유니티 엔진
manager들 사이의 호출순서가 궁금해요
manager public class Managers : MonoBehaviour{static Managers s_Instance; //유일성이 보장된다public static Managers instance { get { Init(); return s_Instance; } } // 유일한 매니저를 갖고온다InputManager _input = new InputManager();public static InputManager input { get { return instance._input; } }// Start is called before the first frame updatevoid Start(){Init();}// Update is called once per framevoid Update(){_input.OnUpdate();}static void Init(){if (s_Instance == null){GameObject go = GameObject.Find("@Managers");if (go == null){go = new GameObject { name = "@Managers" };go.AddComponent<Managers>();}DontDestroyOnLoad(go);s_Instance = go.GetComponent<Managers>();}}}==================================playercontroller.cs public class PlayerController : MonoBehaviour{[SerializeField]float _speed = 10.0f;// Start is called before the first frame updatevoid Start(){Managers.input.KeyAction -= OnKeyboard; //실수 방지용으로 미리 한번 -함Managers.input.KeyAction += OnKeyboard;}// Update is called once per framevoid Update(){ } void OnKeyboard(){if (Input.GetKey(KeyCode.W)){transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(Vector3.forward), 0.2f);transform.position += Vector3.forward Time.deltaTime _speed;}if (Input.GetKey(KeyCode.S)){transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(Vector3.back), 0.2f);transform.position += Vector3.back Time.deltaTime _speed;}if (Input.GetKey(KeyCode.A)){transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(Vector3.left), 0.2f);transform.position += Vector3.left Time.deltaTime _speed;}if (Input.GetKey(KeyCode.D)){transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(Vector3.right), 0.2f);transform.position += Vector3.right Time.deltaTime _speed;}}}==================================public class InputManager{public Action KeyAction = null; public void OnUpdate(){if (Input.anyKey == false)return;if (KeyAction != null)KeyAction.Invoke();}}==================================player.cs public class Player : MonoBehaviour{ // Start is called before the first frame updatevoid Start(){Managers mg = Managers.instance;}// Update is called once per framevoid Update(){ }} 지금 unitychan 오브잭트에 playercontroller 컴포넌트를 inspector창에다 추가한뒤에 실행을 하는데 input값을 입력받을떄마다 어떤식으로 작동이되는지 순서가 이해가 안가요playercontroller 에 update()에 아무것도 없는데 지속적으로 어떻게 key값을 받는지 궁금해요start()는 1회실행되는 함수인데 player.cs도 지금 존재 이유가 유일한 manager 컴포넌트를 쓰게하기 위해서 만들었는데[ 점점 갈수록 어렵네요
-
미해결[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
listener, connector static 차이 이유
안녕하세요, connector와 listener변수에서 static 차이가 일어나는 이유에 대해 질문드리고자 합니다. server 코드의 listener는 아래와 같이 static으로 정의하셨는데, (그리고 저 _obj는 왜 있는건지, 그냥 지워도 되는걸까요?) static object _obj = new object(); static Listener _listener = new Listener(); client코드의 connector는 그냥 static없이 Connector connector = new Connector();이렇게 그냥 변수로 지정하신 이유가 궁금합니다.
-
미해결따라하면서 배우는 고박사의 유니티 하이퍼캐주얼게임 시리즈 01
여기서 래디안을 구하는 이유가 이해가 안갑니다.
안녕하세요 고박사님.제가 이 강의에서 모든 부분 다 이해가 갑니다. 근데 제가 게임수학 부분은 안해봐서 그런지, 삼각함수 쪽에서 좀 막혀서 따로 공부했는데, 타겟에 핀 배치할 때 왜 굳이 래디안을 구해야하는 지 이해가 잘 안가서 여쭤봅니다.실험으로 래디안 식 없이 돌려보니 핀 머리는 잘 배치가 되는데 막대기 부분의 위치와 로테이션이 잘못 배치돼더군요. 꼭 있어야하는 식인 것 같은데, 왜 그런지 이해가 안갑니다.이 부분만 설명 한번만 부탁드려도 될까요?
-
미해결[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
ArraySegment<byte>
public ArraySegment<byte> ReadSegment { get { return null; } } public ArraySegment<byte> WriteSegment { get { return null; } } 심각도 코드 설명 프로젝트 파일 줄 비표시 오류(Suppression) 상태오류 CS0037 'ArraySegment<byte>'은(는) null을 허용하지 않는 값 형식이므로 null을 이 형식으로 변환할 수 없습니다. ServerCore 저는 null을 넣을때 오류가 뜨는데 무슨 이유일까요?
-
해결됨[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part3: 유니티 엔진
LayerMask를 사용하면 왜 최적화가 되는지 잘 이해가 되지 않습니다.
LayerMask를 통해 RayCasting을 하면 하지 않았을 때보다 최적화가 된다고 하셨는데 왜 그런지 잘 이해가 되지 않습니다. 혹시 더 자세하게 알려주실 수 있나요?
-
미해결유니티 Addressable 을 이용한 패치 시스템 구현
구매한 아이템을 로드할 때
게임 내에서 아이템 세트를 구매하면 어드레서블로 다운로드 받고 에셋을 로드하는데요. 껐다 켰을 때 영수증 검증 되면서 구매한 아이템들을 또 Load Asset Async로 불러와야 하나요?
-
미해결따라하면서 배우는 고박사의 유니티 하이퍼캐주얼게임 시리즈 01
2020.3.0f1 Unity Package Manager Error
2020.3.0f1 버전을 설치 후 프로젝트를 실행하면 위와같은 사진이 나오면서 프로젝트가 열리지 않습니다. 혹시 해결 방안이 있을까요 ??
-
미해결유니티 Addressable 을 이용한 패치 시스템 구현
sprite atlas를 로드하는데
다운로드는 메인 popup에서 하잖아요 로드를 하려는데로드를 하면 꼭 release를 해줘야 하나요? 게임 켤때 로드 -> 게임 꺼질때 release게임 꺼서 release 해줬으면 다음에 게임 켤때 또 로드 이렇게 해줘야 하나요?
-
미해결[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part3: 유니티 엔진
게임을 만들기 전에 서버공부부터 해야할까요?
안녕하세요! 캐쥬얼 싱글 게임을 만드려고 하는 뉴비입니다. 강의수강중에 서버에 관련한 질문을 보다가 저도 비슷한 궁금증이 있어서 댓글 남깁니다. 싱글 게임에는 굳이 서버가 필요 없다고 하셨는데요 그래도 플레이팹이나 파이어베이스같은 서버를 붙히고 싶습니다!1. 유저 데이터를 서버에서 받아서 여러 기기에서 플레이해도 설정값 등등을 불러올수 있도록2. 주기적으로 클라이언트의 데이터 값과 서버의 데이터값을 비교해서 동기화3. 인게임 재화를 이용한 상자에서 나오는 아이템들을 처리하는 함수등등 중요한 데이터를 서버에서 호출4. 우편함 시스템 등등위와 같은 기능들을 서버로 구현해서 보안도 향상시키고 일부 편의 기능들도 추가하고싶어요. 그런데 제가 서버에 대한 지식이 전무하다는게 문제입니다 : (그래서 지금 당장 서버공부 부터 시작을 해야할까요? 게임을 만들다가 추후에 서버를 붙히려고 하면 기존의 코드를 전부 수정해야한다던지 하는 일이 일어나지는 않을까요..? (이부분이 제일 궁금합니다) 배움의 순서가 어느것이 맞는 것인지 게임을 만들면서 추후에 서버를 고려해도 괜찮은지 루키스님의 의견 부탁드립니다!
-
미해결[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
Session #2 내용중 왜 스레드가 동시다발적으로 접근 불가능한지 질문
Session#2 강의 시작부분에 설명해주신 내용에서, SEssion의 receive는 OnRecvCompleted()메서드에 여러 스레드가 동시다발적으로 들어가는 경우는 없다. 라고 하셨는데, 왜 그런지 이해를 못했습니다. ServerCore의 OnAcceptHandler는 콜백함수라서 콜백함수는 다른 스레드가 생겨나서 실행이 된다고 들었던 것 같은데, 그렇다면 두 스레드가 OnAcceptHandler에서 Session.Start()를 해버리면 OnRecvCompleted()메서드를 두 스레드가 동시에 실행할 경우가 생기지 않나요?
-
미해결[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
listener, session 간의 차이
안녕하세요, listener, session 코드간 차이점에 대해서 질문이 있습니다. 1, listener에서는 OnRecvCompleted()와같은 메서드에서 socketerror가 발생했을 때, disconnect를 하지 않았는데, session에서는 왜 disconnect를 하는 건가요? 2.listener 에서는 registerRecv() 와같은 함수를 OnRecvCompleted의 if, else와 상관없이 실행한거같은데, 왜 session에서는 if(args.Bytes.Transferred > 0 && ~~~) 을 만족해야 OnRecvCompleted를 실행하는건가요? using System; using System.Collections.Generic; using System.Net.Sockets; using System.Text; namespace ServerCore { class Session { Socket _socket; public void init(Socket socket) { _socket = socket; SocketAsyncEventArgs recvArgs = new SocketAsyncEventArgs(); recvArgs.Completed += new EventHandler<SocketAsyncEventArgs>(OnRecvCompleted); //userTocken으로 추가적인 정보를 아무거나넘겨줄 수 있다(object를 받기 때문) recvArgs.SetBuffer(new byte[1024],0,1024); RegisterRecv(recvArgs); } void RegisterRecv(SocketAsyncEventArgs args) { args.AcceptSocket = null; bool pending = _socket.ReceiveAsync(args); //바로 성공했으면 if(pending == false) { OnRecvCompleted(null, args); } } void OnRecvCompleted(object obj, SocketAsyncEventArgs args) { //BytesTransferred == 몇바이트 받았는지 if (args.BytesTransferred>0 && args.SocketError == SocketError.Success) { try { string recvData = Encoding.UTF8.GetString(args.Buffer, args.Offset, args.BytesTransferred); Console.WriteLine($"[from client] : {recvData}"); RegisterRecv(args); } catch(Exception e) { Console.WriteLine($"onrecvcompleted failed {e}"); } } else { //TODO Disconnect } } } }
-
해결됨[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
Listener, Session 에서의 콜백메서드 질문
안녕하세요, listener, session 클래스를 구현할 때, 콜백메서드에 대해 질문이 있습니다. 아래와 같은 코드에서, using System; using System.Collections.Generic; using System.Net.Sockets; using System.Text; namespace ServerCore { class Session { Socket _socket; public void init(Socket socket) { _socket = socket; SocketAsyncEventArgs recvArgs = new SocketAsyncEventArgs(); recvArgs.Completed += new EventHandler<SocketAsyncEventArgs>(OnRecvCompleted); //userTocken으로 추가적인 정보를 아무거나넘겨줄 수 있다(object를 받기 때문) recvArgs.SetBuffer(new byte[1024],0,1024); RegisterRecv(recvArgs); } void RegisterRecv(SocketAsyncEventArgs args) { args.AcceptSocket = null; bool pending = _socket.ReceiveAsync(args); //바로 성공했으면 if(pending == false) { OnRecvCompleted(null, args); } } void OnRecvCompleted(object obj, SocketAsyncEventArgs args) { if (args.SocketError == SocketError.Success) { string recvData = Encoding.UTF8.GetString(args.Buffer, 0, args.Buffer.Length); Console.WriteLine($"[from client] : {recvData}"); } else { Console.WriteLine(args.SocketError.ToString()); } RegisterRecv(args); } } } 해당 RegisterRecv()메서드에서 pending이 false인 경우 바로 OnRecvCompleted()를 호출해주는거고, true인 경우 콜백메서드로 OnRecvCompleted가 호출되는 형식이라고 이해를 했는데, void RegisterRecv(SocketAsyncEventArgs args) { args.AcceptSocket = null; bool pending = _socket.ReceiveAsync(args); //바로 성공했으면 if(pending == false) { OnRecvCompleted(null, args); } }그렇다면, pending이 false인 경우에는 if(pending == false) { OnRecvCompleted(null, args); }여기서 OnRecvCompleted() 호출되고 또 콜백메서드에서 또 한번 호출되는 것 아닌가요? 콜백메서드가 false인 경우에 2번호출되지 않는다는 것을 어떻게 이해하면 될까요?
-
미해결[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part3: 유니티 엔진
제네릭 타입 질문
학습중에 클래스를 제네릭으로 받으면 어떻게 될까 궁금해 한번 받아봤습니다!우선 필요한 정보를 받아올때 json 파일마다 역직렬화 & 직렬화 용도의 클래스가 다르기 때문에해당 부분을 public IEnumerator CoDownLoadJsonData<T>(string URL) where T : class { UnityWebRequest request = UnityWebRequest.Get(URL); yield return request.SendWebRequest(); // 에러 발생 시 if (request.result == UnityWebRequest.Result.ConnectionError || request.result == UnityWebRequest.Result.ProtocolError) { Debug.Log(request.error); } // 에러 없을 시 else { // S3의 JSON 파일 읽어와서 넣어주기 T[] jsonDatas = JsonConvert.DeserializeObject<T[]>(request.downloadHandler.text); // 그 뒤 값 처리 해주는 부분 foreach (T jsonData in jsonDatas) { // TEMP Debug.Log(무슨 값을 넣어야 할까요); } } }이렇게 짜봤습니다. 위의 함수를 실행 할 때 넣은 T 값은 public class JsonData{ public string name; public int coin; public int ruby;}JsonData라는 클래스 입니다.그리고 다운로드 받은 json 데이터의 name 값을 보기위해 '무슨 값을 넣어야 할까요'부분에 jsonData.name을 쳐보았지만 타입이 제네릭이라 받기전까지 name이 있나 없나를 알 수 없기 때문에 당연히 해당 코드는 에러가 났습니다. 이러면 파싱 받을 json 데이터 마다의 클래스를 따로 분기해서 처리해줘야 한다는 말인데 제네릭 타입을 이용하여 루키스님 처럼 우아?하게 코드를 짜보고 싶은 생각이 드네요. 방법을 못 찼겠어서 질문드립니다!!현재 저의 머리로는 제네릭으로 만든후 안에 조건문을 추가해서 as 로 파싱되면 그쪽으로 처리하는 분기문을 만드는게 한계인거 같네요 ㅠㅠ값은 정상적으로 받아와집니다만 브레이크 포인트를 통해서 값을 확인하는 것이 아니면 확인이 안되네요 ㅠㅠ
-
미해결[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
환경설정 질문입니다
안녕하세요 선생님, 제가 새 프로젝트를 만들면서 이름과 위치를 정하고 다음으로 넘어갔더니 대상 프레임워크에 .NET Core 3.1 (지원하지 않음) 이라고 나옵니다.visualstudio installer에서 제가 보기에 c#에 관련된 것은 다 설치한 상태인데 더 설치해야 하는 것이 있는걸까요?
-
미해결[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
ConnectionReset
DummyClient의 접속을 끊었을때 ServerCore에 ConnectionReset이란 로그가 뜨는데 따로 로그가 뜨도록 작성하지 않았는데 무엇 때문에 어디서 뜨는건가요?
-
미해결[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
정말 감사히 듣고 있습니다..!! 질문이 몇가지 있습니다..!
강의 너무 잘 듣고 있습니다. MMO RPG를 너무 만들어보고 싶었는데.. 이런 귀한 내용들을 자세히 설명해주시는 분이 있다니.. 정말 큰 도움이 됩니다 다름아니라 해당 강의를 듣다가 문득 궁금해지는 점이 있어 실례안된다면 간략하게라도 의견을 듣고싶어 여쭙게 되었습니다...! 질문은 2개 입니다..!(현재 저는 4챕터까지만 듣고 질문을 드리는 상태임을 미리 말씀드립니다)MMO RPG 서버는 scale out 을 어떻게 할까?? 에 대한 궁금증 입니다.스케일 아웃의 방법을 보통 어떻게 하게 되는지 궁금해져서 여쭤봅니다(제가 부족한지 검색을해도 구체적인 방법들이 잘 안나오는 것 같아서.. 간단하게라도 보통 어떻게하는지 궁금하네요..) 만약 1,2,3,4,5,6,7... 100 맵이 있다고 가정하고, 1번맵에만 유저들이 정말 많아서 하나의 서버로 감당이 부담스럽다고 했을때, 1번 맵을 위해 2개 3개의 서버를 투입하는것이 가능할까요..?왠지 강의를 들었을땐 1번맵의 서비스를 1개의 서버로 밖에 못하지 않을까.. 싶은데.. 우선 제가 생각해본 방식은.. 아래와 같습니다- 1번맵의 경우에는 send할 내용들을 한 서버의 메모리에 두는게 아니라 레디스라는 메모리DB에 저장을 한다- 3개 혹은 4개정도 되는서버가 이 레디스를 바라보고 데이터를 가져와서 연결된 클라이언트들에게 데이터를 전송흠.. 그런데 이렇게하면 속도가 충분히(?) 빠를지에 대한 의문이 들어서 보통의 MMO RPG 서버들에서 이런식으로 scale out을 하는게 맞는방식인지 감이 오지않아 질문 드립니다.MMO RPG 서버는 만약 로직을 수정한다고 한다면 서버점검같은걸 하지 않고 해당로직을 수정해서 배포가 가능할까요??강의내용에서는 서버의 메모리에 유저들의 정보를 다 갖고있어야할 것 같고... 그렇게 되면 중간에 로직을 수정해서 새로운 서버를 띄우고 기존서버를 죽이게되면.. 해당 서버에 접속해있던 유저들이 다 튕기게 되지 않을까 싶어서요. 유저들이 인지하지 않게 편안하게 서버내용을 바꾸는것이 MMO RPG 서버에서 가능할까요..? 끝까지 읽어주셔서 감사드립니다. 강의 정말 잘 듣고 있습니다!!