Quick Reference
interest management가 "이 client가 알 수 있는 entity는 무엇인가"를 고르면, byte budget은 "이번 snapshot에 그중 무엇을 먼저 실을 것인가"를 고릅니다. entity를 전부 보내지 못하는 순간이 정상이라는 전제에서, lifecycle과 가까운 위험 요소를 먼저 보내고 먼 배경 object는 다음 update로 미룹니다.
| 우선순위 신호 | 먼저 보내는 이유 | 낮추면 생기는 일 |
|---|---|---|
| spawn·despawn·ownership 변경 | client의 entity graph가 달라짐 | 없는 entity를 갱신하거나 참조가 끊김 |
| client와의 거리·화면 관련성 | 즉시 체감되는 변화 | 가까운 적이 순간이동처럼 보임 |
| 마지막 전송 뒤 경과 | 오래 기다린 entity의 굶주림 방지 | 멀리 있는 object가 영원히 멈춤 |
| 변화량·gameplay 중요도 | 충돌, 투사체, 목표물의 판정 영향 | 중요한 event가 늦음 |
| 예상 byte 수 | packet 한도 안에서 선택 | 한 entity가 나머지를 모두 밀어냄 |
packet size, snapshot rate, client별 최대 bytes/tick을 먼저 고정합니다. 이 수치는 network 환경과 게임 요구에 맞춘 budget이지, serializer가 우연히 만든 길이가 아닙니다. control message와 reliable lifecycle message를 위한 예약 공간도 별도로 둡니다.
예약 흐름
function buildSnapshot(client: Client, candidates: Entity[]) {
let remaining = client.snapshotByteBudget;
const selected = sortByPriority(candidates, client);
const updates = [];
for (const entity of selected) {
const update = encodeDelta(entity, client.baseline);
if (update.byteLength > remaining) continue;
updates.push(update);
remaining -= update.byteLength;
client.lastSent.set(entity.id, now());
}
return { baselineId: client.baseline.id, updates };
}실제 scheduler는 lifecycle을 일반 delta보다 앞에 고정하고, entity 하나가 budget을 모두 쓰는 경우의 정책을 둡니다. 예를 들어 큰 inventory 변경은 chunk로 나누거나 reliable stream으로 분리합니다. snapshot에 억지로 넣어 한 packet을 크게 만들면 packet loss와 burst가 동시에 커집니다.
priority score를 한 숫자로만 숨기기보다 mustSend, nearby, changed, starved처럼 이유를 분리해 로그로 남기면 tuning이 쉬워집니다. 같은 거리라도 client가 조종하는 entity와 관전자에게만 보이는 장식은 우선순위가 다릅니다.
baseline과 손실을 함께 보기
delta는 client가 가진 baseline을 기준으로만 해석할 수 있습니다. 아직 spawn을 받지 않은 entity의 delta를 보내지 않고, ack된 snapshot 또는 명시적인 revision을 기준으로 encode합니다. UDP처럼 snapshot 유실이 가능한 경로에서는 sender가 client가 실제로 받았다고 아는 baseline을 써야 합니다. ack가 없는 최신 snapshot을 기준으로 delta를 만들면 client는 없는 state를 전제로 decode합니다.
매 update를 못 보냈다고 reliable queue에 무한 적재하지 않습니다. 위치처럼 최신값만 의미 있는 data는 다음 snapshot에서 최신 state로 대체합니다. 반대로 despawn, ownership transfer, match phase 같은 lifecycle 전환은 별도 신뢰성 계약이 필요합니다. 자세한 entity 경계는 entity 생성·제거와 상태 버전에서 다룹니다.
자주 틀리는 부분
"가까운 것부터"만 쓰면 멀리 있는 문, 목표물, 팀원의 state가 영원히 갱신되지 않을 수 있습니다. 마지막 전송 시각을 score에 반영하거나 최대 침묵 시간을 두어 starvation을 끊습니다.
또한 모든 client에 같은 entity 순서를 보내면, 한 client의 camera와 역할에 중요하지 않은 data가 budget을 차지합니다. priority는 connection별로 계산하고, 실제 평균·상위 percentile의 snapshot bytes와 제외된 entity 수를 관찰하며 조정합니다.
참고 링크
2 sources