묻고 답해요
160만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
실무에서는 어떠한 코드 스타일을 사용하는지 궁금합니다
물론 회사마다 다르고 각 회사의 기존 스타일을 따라야 하는게 맞지만 독학하는 입장에서는 clang-format이 제공해주는 힌트들, 구글 스타일 가이드 혹은 인터넷에서 나오는 여러 c++ 스타일 가이드를 보면서 어떠한 스타일을 채택해 사용할지 고민이 됩니다미리 손에 익혀두며 학습하고 싶어 질문드려 봅니다
-
미해결[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part9: MMO 컨텐츠 구현 (DB연동 + 대형 구조 + 라이브 준비)
모바일 데이터 환경에서의 렉 현상 문의 드립니다.
안녕하세요 루키스님, 잘 지내고 계시는지요? 프로젝트를 하러 떠나간다라고 글을 남긴게 2월24일 쯤인 것 같은데, 어느 덧 출시를 앞두고 있네요. 어찌저찌 구글 비공개 테스트까지 진행중에 있습니다 하하.. 다름이 아니라 최근에 예상치 못한 이슈가 하나 발생하였는데, 어찌 해결해야 될 지 도저히 방법을 찾지 못해서 문의 드립니다. 실시간 사냥터에서의 캐릭터 움직임|전투 로직이 와이파이 환경에서는 꽤 원활하게 잘 이루어지는데, 와이파이를 끄고 모바일 데이터(네트워크) 환경으로 게임을 진행하면 캐릭터가 너무 '뚝 , 뚝' 거리면서 움직이더라구요. 뭔가 모바일 데이터 환경에서는 네트워크 통신 환경이 공유기 와이파이 잡아서 하는것보다는 불안정하고 속도도 느리니까 이런 현상이 발생하나 싶어서 GPT + 인터넷 자료들을 찾아보았습니다.서버와 클라 양 쪽의 소켓 옵션에서 socket.NoDelay = true; 을 켜주기도 하고, 서버 쪽에서 패킷 모아 보내기 Flush 틱도 10ms 정도로 줄여도 보고 했는데 끊김 현상이 크게 나아지지는 않더라구요ㅠㅠ. 사냥터에서 이루어지는 이동/스킬 패킷 같은 경우에는 UDP 프로토콜로 진행하고, 그외에 실시간성이 과하게 요구되지 않거나 신뢰성이 더 커야 되는 것들(채팅,아이템 구매, 판매 등)은 TCP로 진행하라라는 조언도 있기는 한데 정말 이게 유일한 방법인가 싶습니다.. 의외로 간단한 건데 제가 제대로 못 찾고 있는 것인지, 아니면 정말 UDP / TCP 두 프로토콜을 같이 써가면서 네트워크 통신을 하여야 이 문제를 해결할 수 있는 건지,, 왠만하면 선생님께 문의 드리지 않고 혼자 해결해 보려고 했는데 도저히 그럴싸한 답들을 찾지 못해서 부득이 문의 드려봅니다! 감사합니다. (아 참고로 서버는 OCI -> 오라클 리눅스에서 실행하고 있습니다.)
-
미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
Stomp Allocator의 Release함수에 대한 질문입니다.
예들 들어서, 할당된 메모리 주소가 0x1000~0x3000이고, 실제 사용하려는 메모리 위치를 0x2008로 반환받았다고 가정할 때,const int64 address = reinterpret_cast<int64>(ptr);const int64 baseAddress = address - (address % PAGE_SIZE);이 계산으로 전체 메모리 해제가 가능한가요? 메모리 해제 부분이 이해가 잘 안되네요..
-
미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
공부법 관련해서
루키스님 강의 잘 듣고 있습니다. 서버 강의 재밌게 듣고 있는데 제가 공부 하는 방법이 시간이 많이 드는데 시간을 많이 쓰는 거에 비해 학습에 크게 도움이 되는 것 같지 않아서 질문 드립니다.저는 강의를 듣고 복습 차원에서 노트에 그날 들었던 강의들의 내용을 정리하고 코드에 대해 이해해보려고 검색 하면서 공부하고 있는데 노트에 필기 하는데도 시간이 많이 들고 필기에 투자 하는 시간 대비 외우는 게 잘 안되는 거 같아서 이 방식이 잘못되었다고 느껴지네요...루키스님은 어떤 식으로 공부 했는지 궁금합니다!! 진로는 서버 쪽으로 밀고 가려고 하고 있습니다.
-
미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
MakeShared 함수 관련
52강 ServerService 수강 중 13:54 때에 MakeShared함수를 이용해서 shared_ptr을 생성해주는 부분이 있는데, 똑같이 따라하던 중 제 프로젝트에서 컴파일 에러가 발생했습니다.첨부해주신 프로젝트와 비교해보니 MakeShared함수가 변경되어 있더라구요기존에 Memory 관련 강의 이후에는 변경된점이 없어서 어느 시점에 변경된건지 궁금합니다.
-
미해결[켠김에 출시까지] 유니티 캐주얼 모바일 MMORPG (M2)
MMO 3D 게임 서버의 스킬 판정을 어떻게 하면 좋을까요?
3D MMO 중에서 소수점 단위로 이동하고 모든 방향을 바라볼 수 있는 게임은 스킬 판정을 어떻게 하면 좋을까요?어려운 점은 모든 방향을 볼 수 있는 캐릭가 스킬을 사용하면 스킬 범위는 float 형태로 나와야 한다는 것 인데요.기존 강의에서 배운 맵 좌표는 int로 관리할텐데, 3D 게임은 오브젝트 위치 정보를 float 형태로 관리하기 때문에 이 둘을 동기화 하는 방법을 떠올리는게 어려웠습니다. 루키스님 질의응답과 상상을 통해서 두 가지 방법을 생각해봤습니다.(맵에 높이는 없이 x, y 축만 생각하겠습니다.)첫 번째 방법서버의 맵은 2D 타일 맵(int 좌표)으로 관리하면서 캐릭터는 정밀한 위치(float 좌표)를 가지고 있어, 스킬 히트 판단 시 정밀 판단 로직을 추가한다.아래 그림처럼 회색 캐릭터의 정확한 위치는 캐릭터가 가지고 있으며, 점유하고 있는 셀(분홍색 박스 4개)은 서버 맵에 저장합니다.현재 서버 맵에 (0,0), (1,0), (0,1), (1,1)에는 회색 캐릭터가 (3,2)에는 빨간색 캐릭터가 있습니다. 빨간 캐릭터가 방사형 or 투사체를 발사했을 때 서버는 서버는 서버 맵에서 스킬 효과 범위에 들어갈 것 같은 예상 후보가 있는지 탐색합니다.투사체가 닿는 범위인 (1,0), (2,0), (3,0), (2,1), (3,1) 을 대상으로 예상 후보 탐색예상 후보 셀에 포함된 캐릭터가 있는지 확인하고 해당 캐릭터가 실제 효과 범위에 들어가는지 판단합니다.(1,0) 셀에 회색 캐릭터가 있을 수 있으니 스킬 효과 범위 min < 캐릭터 중심점 기반 히트박스 < 스킬 효과 범위 max 인지 판단두 번째 방법캐릭터가 점유하는 셀을 더 작게 쪼개서 캐릭터 히트 박스나 조이스틱 처럼 살짝 이동할 수도 있고, 전방향 이동에 위화감이 없도록 구현 현업에서는 어떻게 구현하는지 궁금합니다!
-
미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
지금까지 서버코어에서 만든 내용에 대해 궁금한 점이 있어서 질문 드립니다.
지금까지 개발한 서버코어는 IOCP기반의 비동기 논블로킹 방식이라 생각됨니다.Send에서는 SendBuffer를 sendEvent에 등록한 다음 Scatter-Gather로 모아서 ::WSASend로 송신을 수행하는 것으로 이해했습니다.Recv에서는 ::WSARecv에서 수신을 받기 전에 버퍼에 패킷 데이터를 조립한 다음에 바로 함수를 실행하고 있습니다.이벤트 데이터는 사실상 비어있고 callback함수도 없으니 ::WSARecv는 수신완료를 CP에 보내는 것 밖에 없다고 봅니다.제가 볼때 수신부는 제가 이해한 비동기 방식과는 다르게 돌아가는 것 같습니다.어떻게 이해해야 할까요?
-
미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
운영체제관련 질문입니다
운영체제도 같이 공부를 하고싶어 소위 공룡책이라는 운영체제책을 사서 공부를 하고있습니다 운영체제를 처음부터 만들어보는 실습 책들을 따라해보면 이라고 하셨는데 어떤책을 추천해주시는지 알수있을까요?
-
미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
send하려는 데이터 크기가 크면 memcpy에서 문제가 발생할 것 같습니다.
여기서 만약 복사 시작지점 + len 이 array 범위 밖이면 sendBuffer->Close(len) 안에서ASSERT_CRASH(_allocSize >= len); 으로 체크하기 전에 array 정적배열에 memcpy를 하니까 이 부분에서 문제가 생길 것 같습니다.OnRecv로 들어온 buffer가 6001바이트짜리 라면 Open(4096)이 성공하고, 6000크기의 배열에 6001크기를 memcpy 하니 오버플로우가 일어날 것 같습니다.아니면 Open(4096)으로 chunk로부터 사용할 수 있는 공간을 할당 받을 때 len이 4096보다 반드시 작을거라는 확신이 있기 때문에 memcpy 전에 확인하지 않는건가요?
-
미해결[켠김에 출시까지] 유니티 캐주얼 모바일 MMORPG (M2)
코드 머지와 관련하여.
안녕하세요.코드가 업데이트되는 부분이 풀버전이 아니고 변경된 부분들이 폴더 단위로 자료가 올라오는것 같습니다. 이에 따라 코드를 병합할때,Merge tool을 사용해야되는 것인지?아니면 동일 폴더별로 복사 갱신을 하는 것인지 궁금하여 질문드립니다.
-
미해결[켠김에 출시까지] 유니티 캐주얼 모바일 MMORPG (M2)
퀘스트 처리 시 궁금한게 있습니다.
서버에서 브로드캐스트 이벤트 발생 시 퀘스트 클리어 확인 후 보상을 지급하고 DB 갱신을 하는 부분까지 이해했습니다. DB쪽에서 보상처리 라던지 퀘스트 상태저장 시 실패할 가능성도 있을 듯한데 만약 실패했다면 서버의 메모리를 이전상태로 롤백해줘야할듯한데 서버 메모리를 이전상태로 변경하려니 코드가 많이 지저분해지는듯한데실패가능성은 없나요?
-
해결됨[켠김에 출시까지] 유니티 캐주얼 모바일 MMORPG (M2)
Nagle Algorithm
Is there a reason why its not switch off in socket? Isnt it a problem with mmo servers and we hold packets on our own?
-
미해결[켠김에 출시까지] 유니티 캐주얼 모바일 MMORPG (M2)
현재 강의를 이용하여 3D 게임을 만들 경우 변경되야 될 사항들에 대해 궁금합니다.
안녕하세요. 루키스님 강의를 열심히 듣고 있는 초보개발자입니다. 현재 강의는 2D기반의 게임인데, 맵 및 몬스터, 캐릭터를 3D 케릭터로 변경되면, 현재 개발하신 코드들에서 어떤 부분들이 변경되는지.. 그리고 변경될 사항들이 많은지 궁금증이 생겨 문의드립니다.
-
미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
메모리 풀 질문있습니다.
우선 좋은강의 만들어주셔서 감사합니다.제가 질문드릴건 메모리풀을 1024까지는 32바이트단위로 만드는데, 그러면 32바이트전용 풀 64바이트 전용 풀 이렇게 만들어질거고근데 이제 요청하는데 16바이트 요청을 1000번하면,32바이트 풀안에 메모리헤더 큐가 1000개가 생기는거죠?? 해제안했다는 가정하에
-
미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
메모리 풀 질문있습니다.
우선 좋은강의 만들어주셔서 감사합니다.제가 질문드릴건 메모리풀을 1024까지는 32바이트단위로 만드는데, 그러면 32바이트전용 풀 64바이트 전용 풀 이렇게 만들어질거고근데 이제 요청하는데 16바이트 요청을 1000번하면,32바이트 풀안에 메모리헤더 큐가 1000개가 생기는거죠?? 해제안했다는 가정하에
-
해결됨[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
JobQueue의 Push Execute쪽 코드 질문
해결 ++아래 질문 내용을 글로벌 큐에서 추가로 처리해 주는 거였습니다.삭제가 안되서 최상단에 남깁니다.이것저것 건들면서 연습하다 보니 제 환경에서 글로벌 큐 호출을 안해서 문제였습니다. 안녕하세요?루키스님 강의를 참고하여 더미 프로젝트 하는 중에 문제가 식별 되어제가 분석한게 맞다면 강의 코드에 문제가 있어 제보 드려봅니다.문제라고 생각되는 부분은 JobQueue 클래스인데요, 문제 상황은부하가 있는 상황에서 '워커스레드를 2개 이상 돌릴 때, Execute()함수가 실행되지 않는'점을 확인하였습니다.jobCount 관련 변수의 조건이 어디서 안 맞는 것 같아서 생각해보건데,아래와 같은 경우라고 생각됩니다.// JobQueue.cpp void JobQueue::Execute() { ... if (_jobCount.fetch_sub(jobCount) == jobCount) { // 여기서 다른 워커 스레드의 _jobCount.fetch_add 발생?! LCurrentJobQueue = nullptr; return; } ... } } 그렇기 때문의 이후의 잡들이 처리되지 못하고 해당 부분에서 prevCount가 계속 쌓이고 있었습니다.// JobQueue.cpp void JobQueue::Push(JobRef job, bool pushOnly) { const int32 prevCount = _jobCount.fetch_add(1); _jobs.Push(job); // WRITE_LOCK // 여기서 prevCount가 계속 쌓여 0이 아님 if (prevCount == 0) { //그러므로 이 부분의 Excute()도 실행되지 않음 ... } 아래는 해당 클래스 cpp 전문입니다.귀한 시간 내시어 확인해주시면 감사하겠습니다!#include "pch.h" #include "JobQueue.h" #include "GlobalQueue.h" /*-------------- JobQueue ---------------*/ void JobQueue::Push(JobRef job, bool pushOnly) { const int32 prevCount = _jobCount.fetch_add(1); _jobs.Push(job); // WRITE_LOCK // 첫번째 Job을 넣은 쓰레드가 실행까지 담당 if (prevCount == 0) { // 이미 실행중인 JobQueue가 없으면 실행 if (LCurrentJobQueue == nullptr && pushOnly == false) { Execute(); } else { // 여유 있는 다른 쓰레드가 실행하도록 GlobalQueue에 넘긴다 GGlobalQueue->Push(shared_from_this()); } } } // 1) 일감이 너~무 몰리면? void JobQueue::Execute() { LCurrentJobQueue = this; while (true) { vector<JobRef> jobs; _jobs.PopAll(OUT jobs); const int32 jobCount = static_cast<int32>(jobs.size()); for (int32 i = 0; i < jobCount; i++) jobs[i]->Execute(); // 남은 일감이 0개라면 종료 if (_jobCount.fetch_sub(jobCount) == jobCount) { LCurrentJobQueue = nullptr; return; } const uint64 now = ::GetTickCount64(); if (now >= LEndTickCount) { LCurrentJobQueue = nullptr; // 여유 있는 다른 쓰레드가 실행하도록 GlobalQueue에 넘긴다 GGlobalQueue->Push(shared_from_this()); break; } } }
-
미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
JobQueue의 Push Execute쪽 코드에 문제가 있는 것 같아 말씀 드려봅니다
안녕하세요? 루키스님 강의를 참고하여 더미 프로젝트 하는 중에 문제가 식별 되어제가 분석한게 맞다면 강의 코드에 문제가 있어 제보 드려봅니다.문제라고 생각되는 부분은 JobQueue 클래스인데요, 문제 상황은'워커스레드를 2개 이상 돌릴 때, Execute()함수가 실행되지 않는'점을 확인하였습니다.jobCount 관련 변수의 조건이 어디서 안 맞는 것 같아서 생각해보건데,아래와 같은 경우라고 생각됩니다.// JobQueue.cpp void JobQueue::Execute() { ... if (_jobCount.fetch_sub(jobCount) == jobCount) { // 여기서 다른 워커 스레드의 _jobCount.fetch_add 발생?! LCurrentJobQueue = nullptr; return; } ... } } 그렇기 때문의 이후의 잡들이 처리되지 못하고 해당 부분에서 prevCount가 계속 쌓이고 있었습니다.// JobQueue.cpp void JobQueue::Push(JobRef job, bool pushOnly) { const int32 prevCount = _jobCount.fetch_add(1); _jobs.Push(job); // WRITE_LOCK // 여기서 prevCount가 계속 쌓여 0이 아님 if (prevCount == 0) { //그러므로 이 부분의 Excute()도 실행되지 않음 ... } 아래는 해당 클래스 cpp 전문입니다.귀한 시간 내시어 확인해주시면 감사하겠습니다!#include "pch.h" #include "JobQueue.h" #include "GlobalQueue.h" /*-------------- JobQueue ---------------*/ void JobQueue::Push(JobRef job, bool pushOnly) { const int32 prevCount = _jobCount.fetch_add(1); _jobs.Push(job); // WRITE_LOCK // 첫번째 Job을 넣은 쓰레드가 실행까지 담당 if (prevCount == 0) { // 이미 실행중인 JobQueue가 없으면 실행 if (LCurrentJobQueue == nullptr && pushOnly == false) { Execute(); } else { // 여유 있는 다른 쓰레드가 실행하도록 GlobalQueue에 넘긴다 GGlobalQueue->Push(shared_from_this()); } } } // 1) 일감이 너~무 몰리면? void JobQueue::Execute() { LCurrentJobQueue = this; while (true) { vector<JobRef> jobs; _jobs.PopAll(OUT jobs); const int32 jobCount = static_cast<int32>(jobs.size()); for (int32 i = 0; i < jobCount; i++) jobs[i]->Execute(); // 남은 일감이 0개라면 종료 if (_jobCount.fetch_sub(jobCount) == jobCount) { LCurrentJobQueue = nullptr; return; } const uint64 now = ::GetTickCount64(); if (now >= LEndTickCount) { LCurrentJobQueue = nullptr; // 여유 있는 다른 쓰레드가 실행하도록 GlobalQueue에 넘긴다 GGlobalQueue->Push(shared_from_this()); break; } } }
-
해결됨[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
Protobuff is it sufficient for mmorpg?
I mean that protobuff need serialization, and its not zero copy so it introduce latency to communication. Is it suitable for game servers with 1-5k players? Or its better to use instead https://flatbuffers.dev/quick_start/ ?
-
미해결[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버
void IocpEvent::Init() is correct?
void IocpEvent::Init(){OVERLAPPED::hEvent = 0;(...)} Isnt this a mistake? hEvent isnt static field and when compiled with gcc its error: 'hEvent' is not a static member of 'OVERLAPPED'. With msvc its compiled but its interpreted as 2 different instruction wich could lead to unexpected behaviour?
-
해결됨[켠김에 출시까지] 유니티 방치형 키우기 게임 (M1 + C1)
UI 자동화 관련 문의입니다.
UI_TitleScene.csStartImage 에 클릭 기능 추가에 관한 문의입니다. GetObject((int)GameObjects.StartImage).BindEvent((evt) =>{ Debug.Log("ChageScene"); Managers.Scene.LoadScene(EScene.GameScene);},Define.EUIEvent.Click); 에서StartImage 의 경우 enum GameObjects 소속에 타입도 GameObject 라서 Extension에 의해서 BindEvent를 바로 사용할 수 있는 것으로 보이는데, 만약 Image라 하더라도 Click등의 액션을 이용하려면 무조건 GameObject로 설정해야 하는 것인가요? 아님 extension에서 뭔가를 설정하면 Image(Object)도 GameObject 같이 사용가능한가요? 이것 저것 해봐도 붉은색 투성이라 문의 드립니다.