Quick Flow
client가 entity state를 해석하려면 먼저 그 entity의 type·ID·초기 state를 알아야 합니다. server는 관심 영역에 새로 들어온 entity에 spawn + baseline을 보내고, client가 그 baseline을 가진 뒤에만 delta를 보냅니다. 관심 영역에서 빠지거나 파괴되면 despawn을 보내고, 늦게 도착한 이전 version update는 버립니다.
replication set에 새 entity 추가
-> spawn(entityId, type, lifecycleVersion, baseline)
-> client가 baseline을 확인 또는 reliable channel로 수신
-> delta(entityId, lifecycleVersion, stateVersion, changed fields)
-> despawn(entityId, lifecycleVersion)
-> 같은 ID 재사용 전 version을 바꾸거나 재사용을 지연| 수신한 메시지 | client 처리 | 필요한 조건 |
|---|---|---|
spawn | entity 생성과 baseline 저장 | 새 lifecycle version |
delta | 알려진 entity state 갱신 | 같은 lifecycle·새 state version |
despawn | entity 제거와 history 정리 | 같은 lifecycle 또는 더 새 종료 상태 |
늦은 이전 delta | 무시 | entity가 없거나 version이 오래됨 |
ID만으로는 부족한 이유
network 지연과 재전송 때문에 entityId=42의 오래된 delta가, 42번 ID를 새 monster에 다시 쓴 뒤 도착할 수 있습니다. ID만 비교하면 새 monster가 이전 monster의 체력·position을 받습니다. entity lifecycle version을 spawn마다 증가시키거나, reuse하지 않는 충분히 긴 ID를 써서 메시지가 어느 생명주기에 속하는지 구분합니다.
state version 또는 server tick은 같은 lifecycle 안의 오래된 delta를 걸러냅니다. client는 마지막으로 적용한 version보다 작거나 같은 update를 무시합니다. unreliable snapshot에서 순서가 뒤집히는 일은 정상일 수 있으므로, 마지막으로 받은 packet이 아니라 entity별로 마지막 적용한 state version을 기억합니다.
entity가 teleport·respawn·form change처럼 상태 공간을 크게 바꾸면 단순 delta보다 새 baseline이 안전할 수 있습니다. 이전 position과 새 position을 보간하면 존재하지 않았던 경로를 그릴 수 있기 때문입니다. 이런 전이는 lifecycle을 새로 열지 않더라도 reset interpolation 같은 명시적 flag로 client history를 비워야 합니다.
spawn과 delta의 순서
reliable spawn을 보냈다고 해도 client가 언제 받았는지 server가 모르면, 다음 unreliable delta가 먼저 도착할 수 있습니다. 방법은 세 가지입니다. spawn과 초기 state를 reliable ordered channel로 보내고 delta를 client acknowledgment 뒤에 허용하거나, snapshot 안에 충분한 self-contained baseline을 반복하거나, client가 모르는 entity의 delta를 짧게 buffer한 뒤 spawn을 기다리는 것입니다.
어느 방법이든 buffer 크기와 만료를 둡니다. 알 수 없는 entity ID의 delta를 무한히 쌓으면 잘못된 protocol이나 악성 packet으로 memory가 늘어납니다. spawn not known 상태가 일정 시간 넘게 이어지면 delta를 버리고 full resync를 요청하거나 다음 snapshot baseline을 기다립니다.
제거도 상태 전파다
despawn을 보내지 않으면 client는 관심 영역에서 이미 빠진 enemy를 계속 그리거나, entity history와 resource를 유지합니다. 관심 영역 때문에 안 보이는 것과 server에서 파괴된 것은 다른 의미일 수 있습니다. 다시 가까워지면 같은 entity를 재spawn할 수 있는지, view에서만 숨길지, 완전히 제거할지를 protocol message로 구분합니다.
server가 match 종료 뒤 instance를 통째로 닫을 때도 client가 아직 command를 보낼 수 있습니다. instance state를 closing으로 바꾸고 새 input·spawn을 막은 뒤, 필요한 종료 event와 despawn을 보내거나 connection을 정리합니다. 종료된 instance ID로 뒤늦게 온 delta는 새 instance의 state에 섞지 않습니다.
spawn 이전 delta를 "다음 packet에서 고쳐지겠지" 하고 무시하면 packet loss에서 entity가 영구히 보이지 않을 수 있습니다. entity 존재·생명주기·state version을 protocol의 명시적 계약으로 두세요.
참고 링크
2 sources