Abstract
게임이 바깥 세상과 주고받는 통로는 네 가지입니다. 무엇을 주고받느냐에 따라 고르면 됩니다. 넷 다 "요청을 넣으면 번호(serialId)를 돌려주고, 결과는 나중에 이벤트로 온다"는 같은 모양이라 하나를 익히면 나머지도 같은 방식으로 씁니다.
무엇을 쓸지 고르기
하고 싶은 일 | 모듈 | 예 |
서버 API 를 한 번 호출하고 응답 받기 | WebRequest | 랭킹 등록, 로그인, 공지 가져오기 |
파일을 내려받아 디스크에 저장 | Download | 추가 콘텐츠, 리플레이 파일 |
서버와 연결을 유지하며 계속 주고받기 | Network | 실시간 멀티플레이, 채팅 |
여러 파일을 하나로 묶어 읽고 쓰기 | FileSystem | 수천 개의 작은 파일을 한 덩어리로 배포 |
싱글플레이 게임에 온라인 기능을 얹는다면 십중팔구 WebRequest 하나면 충분합니다.
직접 해 보기 — 최고 점수를 서버에 올리기
public class ScoreUploader
{
private int mRequestId;
public void Upload(string playerName, int score)
{
EventComponent events = GameEntry.GetComponent<EventComponent>();
events.Subscribe(WebRequestSuccessEventArgs.EventId, OnSuccess);
events.Subscribe(WebRequestFailureEventArgs.EventId, OnFailure);
WWWForm form = new WWWForm();
form.AddField("name", playerName);
form.AddField("score", score);
// 요청을 넣으면 번호가 돌아온다. 이 번호로 "내 요청의 응답"을 가려낸다
mRequestId = GameEntry.GetComponent<WebRequestComponent>().AddWebRequest("https://example.com/api/scores", form);
}
private void OnSuccess(object sender, GameEventArgs e)
{
WebRequestSuccessEventArgs ne = (WebRequestSuccessEventArgs)e;
if (ne.SerialId != mRequestId)
return;
string body = Utility.Converter.GetString(ne.GetWebResponseBytes());
Log.Info("등록 완료: {0}", body);
}
private void OnFailure(object sender, GameEventArgs e)
{
WebRequestFailureEventArgs ne = (WebRequestFailureEventArgs)e;
if (ne.SerialId != mRequestId)
return;
Log.Warning("등록 실패: {0}", ne.ErrorMessage);
}
}
C#
복사
이벤트는 전역으로 발행됩니다. 다른 코드가 넣은 요청의 응답도 같은 핸들러로 들어오므로, SerialId 비교를 빼면 남의 응답을 자기 것으로 처리하게 됩니다. 다 쓴 뒤에는 Unsubscribe 로 구독을 풀어야 합니다.
ToyboxNightmare 에서는
네 모듈 모두 쓰지 않습니다. 싱글플레이 오프라인 게임이기 때문입니다. GameFramework.prefab 에 컴포넌트는 붙어 있지만 요청이 없으면 아무 일도 하지 않습니다.
이 에디션에서 다른 점 · 본문을 읽을 때 주의할 점
•
결과는 downloadComponent.DownloadSuccess += ... 같은 C# 이벤트가 아니라 EventComponent 구독으로 받습니다. 본문 예제도 그렇게 고쳐 두었습니다.
•
AddDownload 의 인자 순서는 (저장 경로, 주소) 입니다. 반대로 쓰기 쉽습니다.
•
Network 는 TCP 만 지원합니다(ServiceType.Tcp, TcpWithSyncReceive). UDP 는 없습니다. 또 패킷을 어떻게 자르고 직렬화할지는 프레임워크가 정해 주지 않습니다 — INetworkChannelHelper 를 직접 구현해야 연결할 수 있습니다.
•
FileSystem 은 일반적인 "파일 읽기/쓰기 유틸"이 아니라 가상 파일 시스템입니다. 여러 파일을 하나의 큰 파일 안에 넣어 관리합니다. 세이브 파일 하나를 쓰는 용도라면 File.WriteAllText 나 Setting 모듈이 맞습니다.
•
5절의 DefaultLoadResourceAgentHelper / DefaultResourceHelper 는 원작의 AssetBundle 로더입니다. 이 에디션에는 없고 Addressables 가 그 일을 합니다.
•
WebGL 빌드에서는 브라우저 제약으로 TCP 소켓을 쓸 수 없어 Network 모듈이 동작하지 않습니다.
Networking and I/O (네트워킹 & 입출력)
1. 아키텍처 개요
•
Component-Helper 구조
→ Unity 컴포넌트가 매니저 기능을 노출, 실제 구현은 Helper 클래스가 담당
•
주요 구성:
◦
NetworkComponent : 네트워크 채널 관리 (TCP)
◦
DownloadComponent : 파일 다운로드 관리
◦
WebRequestComponent : HTTP/HTTPS 요청 처리
◦
ResourceHelper : 원격/로컬 리소스 로드
◦
FileSystem : 파일 읽기/쓰기
2. Network System
•
특징
◦
TCP 소켓 통신
◦
다중 채널(NetworkChannel) 구조
◦
하트비트(heartbeat) 내장
◦
패킷 직렬화/역직렬화 가능
◦
연결 상태 및 에러 이벤트 지원
•
핵심 API
◦
CreateNetworkChannel(name, serviceType, helper)
◦
GetNetworkChannel(name)
◦
DestroyNetworkChannel(name)
•
이벤트
◦
NetworkConnected
◦
NetworkClosed
◦
NetworkMissHeartBeat
◦
NetworkError
•
디버깅
◦
런타임 Debugger 창의 Network 탭 : 연결 상태, 송수신 패킷 수, 하트비트 상태 표시 (원작의 NetworkComponentInspector 는 이 에디션에 없음)
3. Download System
•
특징
◦
파일 다운로드 (전체, 부분, 범위 지정 지원)
◦
진행 상황 & 오류 이벤트 제공
•
Agent Helpers
◦
UnityWebRequestDownloadAgentHelper (최신 Unity API)
◦
WWWDownloadAgentHelper (Unity 2018.3 미만 전용. 현재 Unity 에서는 컴파일에서 제외됨)
•
주요 이벤트
◦
UpdateBytes, UpdateLength, Complete, Error
4. Web Request System
•
특징
◦
GET, POST 지원
◦
JSON, FormData, RawData 전송 가능
◦
이벤트 기반 완료/에러 처리
•
구현체
◦
UnityWebRequestAgentHelper
5. Resource Loading with Network I/O
•
DefaultLoadResourceAgentHelper
◦
AssetBundle 로드 (로컬/원격)
◦
바이트 스트림 처리
◦
에셋 추출
•
DefaultResourceHelper
◦
URL에서 바이트 읽기
◦
씬 언로드, 리소스 해제 기능 포함
6. File System
•
기능
◦
파일 읽기/쓰기
◦
디렉토리 관리
◦
커스텀 파일 시스템 확장 가능
•
통합
◦
리소스 시스템과 연결
◦
데이터 테이블 로딩 가능
7. 프레임워크 통합
•
Resource System : 원격 에셋 다운로드 활용
•
Event System : 모든 네트워크/IO 결과를 이벤트로 발행
•
Data Tables : 원격 데이터 테이블 로드 가능
8. 코드 예시
네트워크 연결var networkComponent = GameEntry.GetComponent<NetworkComponent>();
var channel = networkComponent.CreateNetworkChannel("GameServer", ServiceType.Tcp, new GameNetworkChannelHelper());
channel.Connect(IPAddress.Parse("192.168.1.1"), 8888);
channel.Send(gamePacket);
channel.Close();
C#
복사
파일 다운로드var downloadComponent = GameEntry.GetComponent<DownloadComponent>();
var events = GameEntry.GetComponent<EventComponent>();
// 결과는 C# 이벤트가 아니라 EventComponent 로 온다
events.Subscribe(DownloadSuccessEventArgs.EventId, OnDownloadSuccess);
events.Subscribe(DownloadFailureEventArgs.EventId, OnDownloadFailure);
// 인자 순서 주의: (저장할 경로, 내려받을 주소)
string savePath = Path.Combine(Application.persistentDataPath, "bundle.dat");
mDownloadId = downloadComponent.AddDownload(savePath, "https://example.com/assets/bundle.dat");
private void OnDownloadSuccess(object sender, GameEventArgs e)
{
DownloadSuccessEventArgs ne = (DownloadSuccessEventArgs)e;
if (ne.SerialId != mDownloadId)
return;
Debug.Log("Download completed: " + ne.DownloadPath);
}
C#
복사
웹 요청var webRequestComponent = GameEntry.GetComponent<WebRequestComponent>();
WWWForm form = new WWWForm();
form.AddField("username", "player");
form.AddField("score", 100);
GameEntry.GetComponent<EventComponent>().Subscribe(WebRequestSuccessEventArgs.EventId, OnWebRequestSuccess);
mRequestId = webRequestComponent.AddWebRequest("https://example.com/api/scores", form);
private void OnWebRequestSuccess(object sender, GameEventArgs e)
{
WebRequestSuccessEventArgs ne = (WebRequestSuccessEventArgs)e;
if (ne.SerialId != mRequestId)
return;
string response = Utility.Converter.GetString(ne.GetWebResponseBytes());
Debug.Log("Response: " + response);
}
C#
복사
요약하자면:•
네트워크 (TCP) : 채널 기반 소켓 통신
•
다운로드 : 파일 전송 및 범위 요청
•
웹 요청 : GET/POST API 호출
•
리소스 시스템 : (원작) AssetBundle + 네트워크 연동 — 이 에디션은 Addressables 가 담당
•
파일 시스템 : 기본 파일 I/O + 커스텀 확장








