From 72694b5bdf60bccad188113f6e45b554edd43e3e Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sat, 29 Oct 2022 20:05:35 +1100 Subject: [PATCH 1/7] WIP on interpolation flags rewrite, breaks network interpolation though --- src/Camera.c | 2 +- src/Chat.c | 2 +- src/Entity.c | 6 +- src/Entity.h | 32 +++++---- src/EntityComponents.c | 154 +++++++++++++++++++++++++++-------------- src/EntityComponents.h | 11 +-- src/Input.c | 4 +- src/Protocol.c | 20 +++--- 8 files changed, 144 insertions(+), 87 deletions(-) diff --git a/src/Camera.c b/src/Camera.c index 26897bc78..9bd233584 100644 --- a/src/Camera.c +++ b/src/Camera.c @@ -84,7 +84,7 @@ static void PerspectiveCamera_UpdateMouseRotation(double delta) { return; } - update.flags = LU_INCLUDES_YAW | LU_INCLUDES_PITCH; + update.flags = LU_HAS_YAW | LU_HAS_PITCH; update.yaw = e->next.yaw + rot.X; update.pitch = e->next.pitch + rot.Y; update.pitch = Math_ClampAngle(update.pitch); diff --git a/src/Chat.c b/src/Chat.c index f6f5238ff..4d5dcea30 100644 --- a/src/Chat.c +++ b/src/Chat.c @@ -631,7 +631,7 @@ static void TeleportCommand_Execute(const cc_string* args, int argsCount) { return; } - update.flags = LU_INCLUDES_POS; + update.flags = LU_HAS_POS; update.pos = v; e->VTABLE->SetLocation(e, &update); } diff --git a/src/Entity.c b/src/Entity.c index 62f5f37be..92a26f3b2 100644 --- a/src/Entity.c +++ b/src/Entity.c @@ -508,7 +508,7 @@ void Entity_LerpAngles(struct Entity* e, float t) { e->Pitch = Math_LerpAngle(prev->pitch, next->pitch, t); e->Yaw = Math_LerpAngle(prev->yaw, next->yaw, t); e->RotX = Math_LerpAngle(prev->rotX, next->rotX, t); - e->RotY = Math_LerpAngle(prev->rotY, next->rotY, t); + e->RotY = Math_LerpAngle(prev->rotY, next->rotY, t); e->RotZ = Math_LerpAngle(prev->rotZ, next->rotZ, t); } @@ -997,7 +997,7 @@ static void LocalPlayer_DoRespawn(void) { /* it's obvious to the player that they are being respawned */ spawn.Y += 2.0f/16.0f; - update.flags = LU_INCLUDES_POS | LU_INCLUDES_YAW | LU_INCLUDES_PITCH; + update.flags = LU_HAS_POS | LU_HAS_YAW | LU_HAS_PITCH; update.pos = spawn; update.yaw = p->SpawnYaw; update.pitch = p->SpawnPitch; @@ -1107,7 +1107,7 @@ void LocalPlayer_MoveToSpawn(void) { struct LocalPlayer* p = &LocalPlayer_Instance; struct LocationUpdate update; - update.flags = LU_INCLUDES_POS | LU_INCLUDES_YAW | LU_INCLUDES_PITCH; + update.flags = LU_HAS_POS | LU_HAS_YAW | LU_HAS_PITCH; update.pos = p->Spawn; update.yaw = p->SpawnYaw; update.pitch = p->SpawnPitch; diff --git a/src/Entity.h b/src/Entity.h index 151763ad0..485bbddcb 100644 --- a/src/Entity.h +++ b/src/Entity.h @@ -32,20 +32,26 @@ extern const char* const ShadowMode_Names[SHADOW_MODE_COUNT]; enum EntityType { ENTITY_TYPE_NONE, ENTITY_TYPE_PLAYER }; /* Which fields are included/valid in a LocationUpdate */ -#define LU_INCLUDES_POS 0x01 -#define LU_INCLUDES_PITCH 0x02 -#define LU_INCLUDES_YAW 0x04 -#define LU_INCLUDES_ROTX 0x08 -#define LU_INCLUDES_ROTZ 0x10 +#define LU_HAS_POS 0x01 +#define LU_HAS_PITCH 0x02 +#define LU_HAS_YAW 0x04 +#define LU_HAS_ROTX 0x08 +#define LU_HAS_ROTZ 0x10 -/* If set, then new position is calculated by adding current position to update->pos */ -/* If not set, then new position is just update->pos */ -#define LU_FLAG_RELATIVEPOS 0x20 -/* TODO fill this in when implemented */ -#define LU_FLAG_X 0x40 -/* If set, then linearly interpolates between current and new state */ -/* If not set, then current state is immediately updated to new state */ -#define LU_FLAG_INTERPOLATE 0x80 +/* How to move the entity when position field is included */ +#define LU_POS_MODEMASK 0x60 +/* Entity is instantly teleported to update->pos */ +#define LU_POS_ABSOLUTE_INSTANT 0x00 +/* Entity is smoothly moved to update->pos */ +#define LU_POS_ABSOLUTE_SMOOTH 0x20 +/* Entity is smoothly moved to current position + update->pos */ +#define LU_POS_RELATIVE_SMOOTH 0x40 +/* Entity is offset/shifted by update->pos */ +#define LU_POS_RELATIVE_SHIFT 0x60 + +/* If set, then linearly interpolates between current and new angles */ +/* If not set, then current angles are immediately updated to new angles */ +#define LU_ORI_INTERPOLATE 0x80 /* Represents a location update for an entity. Can be a relative position, full position, and/or an orientation update. */ struct LocationUpdate { diff --git a/src/EntityComponents.c b/src/EntityComponents.c index 76347c72e..a8d55ee87 100644 --- a/src/EntityComponents.c +++ b/src/EntityComponents.c @@ -313,61 +313,94 @@ static void InterpComp_AdvanceRotY(struct InterpComp* interp, struct Entity* e) /*########################################################################################################################* *----------------------------------------------NetworkInterpolationComponent----------------------------------------------* *#########################################################################################################################*/ -#define NetInterpState_Copy(dst, src) \ -(dst).pos = (src)->Pos;\ +#define NetInterpAngles_Copy(dst, src) \ (dst).pitch = (src)->Pitch;\ (dst).yaw = (src)->Yaw;\ (dst).rotX = (src)->RotX;\ (dst).rotZ = (src)->RotZ; -static void NetInterpComp_RemoveOldestState(struct NetInterpComp* interp) { +static void NetInterpComp_RemoveOldestPosition(struct NetInterpComp* interp) { int i; - for (i = 0; i < Array_Elems(interp->States); i++) { - interp->States[i] = interp->States[i + 1]; + interp->PositionsCount--; + + for (i = 0; i < interp->PositionsCount; i++) { + interp->Positions[i] = interp->Positions[i + 1]; } - interp->StatesCount--; } -static void NetInterpComp_AddState(struct NetInterpComp* interp, struct NetInterpState state) { - if (interp->StatesCount == Array_Elems(interp->States)) { - NetInterpComp_RemoveOldestState(interp); +static void NetInterpComp_AddPosition(struct NetInterpComp* interp, Vec3 pos) { + if (interp->PositionsCount == Array_Elems(interp->Positions)) { + NetInterpComp_RemoveOldestPosition(interp); } - interp->States[interp->StatesCount] = state; interp->StatesCount++; + interp->Positions[interp->PositionsCount++] = pos; +} + +static void NetInterpComp_SetPosition(struct NetInterpComp* interp, struct LocationUpdate* update, struct Entity* e, int mode) { + Vec3 lastPos = interp->CurPos; + Vec3* curPos = &interp->CurPos; + Vec3 midPos; + + if (mode == LU_POS_ABSOLUTE_INSTANT || mode == LU_POS_ABSOLUTE_SMOOTH) { + *curPos = update->pos; + } else { + Vec3_AddBy(curPos, &update->pos); + } + + if (mode == LU_POS_ABSOLUTE_INSTANT) { + e->prev.pos = *curPos; + e->next.pos = *curPos; + interp->PositionsCount = 0; + } else { + /* Smoother interpolation by also adding midpoint */ + Vec3_Lerp(&midPos, &lastPos, curPos, 0.5f); + NetInterpComp_AddPosition(interp, midPos); + NetInterpComp_AddPosition(interp, *curPos); + } +} + +static void NetInterpComp_RemoveOldestAngles(struct NetInterpComp* interp) { + int i; + interp->AnglesCount--; + + for (i = 0; i < interp->AnglesCount; i++) { + interp->Angles[i] = interp->Angles[i + 1]; + } +} + +static void NetInterpComp_AddAngles(struct NetInterpComp* interp, struct NetInterpAngles angles) { + if (interp->AnglesCount == Array_Elems(interp->Angles)) { + NetInterpComp_RemoveOldestAngles(interp); + } + interp->Angles[interp->AnglesCount++] = angles; } void NetInterpComp_SetLocation(struct NetInterpComp* interp, struct LocationUpdate* update, struct Entity* e) { - struct NetInterpState last = interp->Cur; - struct NetInterpState* cur = &interp->Cur; - struct NetInterpState mid; + struct NetInterpAngles last = interp->CurAngles; + struct NetInterpAngles* cur = &interp->CurAngles; + struct NetInterpAngles mid; cc_uint8 flags = update->flags; - cc_bool interpolate = flags & LU_FLAG_INTERPOLATE; + cc_bool interpolate = flags & LU_ORI_INTERPOLATE; - if (flags & LU_INCLUDES_POS) { - if (flags & LU_FLAG_RELATIVEPOS) { - Vec3_AddBy(&cur->Pos, &update->pos); - } else { - cur->Pos = update->pos; - } + if (flags & LU_HAS_POS) { + NetInterpComp_SetPosition(interp, update, e, flags & LU_POS_MODEMASK); } - - if (flags & LU_INCLUDES_ROTX) cur->RotX = Math_ClampAngle(update->rotX); - if (flags & LU_INCLUDES_ROTZ) cur->RotZ = Math_ClampAngle(update->rotZ); - if (flags & LU_INCLUDES_PITCH) cur->Pitch = Math_ClampAngle(update->pitch); - if (flags & LU_INCLUDES_YAW) cur->Yaw = Math_ClampAngle(update->yaw); + if (flags & LU_HAS_ROTX) cur->RotX = Math_ClampAngle(update->rotX); + if (flags & LU_HAS_ROTZ) cur->RotZ = Math_ClampAngle(update->rotZ); + if (flags & LU_HAS_PITCH) cur->Pitch = Math_ClampAngle(update->pitch); + if (flags & LU_HAS_YAW) cur->Yaw = Math_ClampAngle(update->yaw); if (!interpolate) { - NetInterpState_Copy(e->prev, cur); e->prev.rotY = cur->Yaw; - NetInterpState_Copy(e->next, cur); e->next.rotY = cur->Yaw; - interp->RotYCount = 0; interp->StatesCount = 0; + NetInterpAngles_Copy(e->prev, cur); e->prev.rotY = cur->Yaw; + NetInterpAngles_Copy(e->next, cur); e->next.rotY = cur->Yaw; + interp->RotYCount = 0; interp->AnglesCount = 0; } else { - /* Smoother interpolation by also adding midpoint. */ - Vec3_Lerp(&mid.Pos, &last.Pos, &cur->Pos, 0.5f); + /* Smoother interpolation by also adding midpoint */ mid.RotX = Math_LerpAngle(last.RotX, cur->RotX, 0.5f); mid.RotZ = Math_LerpAngle(last.RotZ, cur->RotZ, 0.5f); mid.Pitch = Math_LerpAngle(last.Pitch, cur->Pitch, 0.5f); mid.Yaw = Math_LerpAngle(last.Yaw, cur->Yaw, 0.5f); - NetInterpComp_AddState(interp, mid); - NetInterpComp_AddState(interp, *cur); + NetInterpComp_AddAngles(interp, mid); + NetInterpComp_AddAngles(interp, *cur); /* Body rotation lags behind head a tiny bit */ InterpComp_AddRotY((struct InterpComp*)interp, Math_LerpAngle(last.Yaw, cur->Yaw, 0.33333333f)); @@ -380,9 +413,13 @@ void NetInterpComp_AdvanceState(struct NetInterpComp* interp, struct Entity* e) e->prev = e->next; e->Position = e->prev.pos; - if (interp->StatesCount > 0) { - NetInterpState_Copy(e->next, &interp->States[0]); - NetInterpComp_RemoveOldestState(interp); + if (interp->PositionsCount) { + e->next.pos = interp->Positions[0]; + NetInterpComp_RemoveOldestPosition(interp); + } + if (interp->AnglesCount) { + NetInterpAngles_Copy(e->next, &interp->Angles[0]); + NetInterpComp_RemoveOldestAngles(interp); } InterpComp_AdvanceRotY((struct InterpComp*)interp, e); } @@ -391,6 +428,28 @@ void NetInterpComp_AdvanceState(struct NetInterpComp* interp, struct Entity* e) /*########################################################################################################################* *-----------------------------------------------LocalInterpolationComponent-----------------------------------------------* *#########################################################################################################################*/ +static void LocalInterpComp_SetPosition(struct LocationUpdate* update, int mode) { + struct Entity* e = &LocalPlayer_Instance.Base; + float yOffset; + + if (mode == LU_POS_ABSOLUTE_INSTANT || mode == LU_POS_ABSOLUTE_SMOOTH) { + e->next.pos = update->pos; + } else if (mode == LU_POS_RELATIVE_SMOOTH) { + Vec3_AddBy(&e->next.pos, &update->pos); + } else if (mode == LU_POS_RELATIVE_SHIFT) { + Vec3_AddBy(&e->prev.pos, &update->pos); + Vec3_AddBy(&e->next.pos, &update->pos); + } + + /* If server sets Y position exactly on ground, push up a tiny bit */ + yOffset = e->next.pos.Y - Math_Floor(e->next.pos.Y); + if (yOffset < ENTITY_ADJUSTMENT) e->next.pos.Y += ENTITY_ADJUSTMENT; + + if (mode == LU_POS_ABSOLUTE_INSTANT) { + e->prev.pos = e->next.pos; e->Position = e->next.pos; + } +} + static void LocalInterpComp_Angle(float* prev, float* next, float value, cc_bool interpolate) { value = Math_ClampAngle(value); *next = value; @@ -402,33 +461,22 @@ void LocalInterpComp_SetLocation(struct InterpComp* interp, struct LocationUpdat struct EntityLocation* prev = &e->prev; struct EntityLocation* next = &e->next; cc_uint8 flags = update->flags; - cc_bool interpolate = flags & LU_FLAG_INTERPOLATE; + cc_bool interpolate = flags & LU_ORI_INTERPOLATE; float yOffset; - if (flags & LU_INCLUDES_POS) { - if (flags & LU_FLAG_RELATIVEPOS) { - Vec3_AddBy(&next->pos, &update->pos); - } else { - next->pos = update->pos; - } - - /* If server sets Y position exactly on ground, push up a tiny bit */ - yOffset = next->pos.Y - Math_Floor(next->pos.Y); - - if (yOffset < ENTITY_ADJUSTMENT) next->pos.Y += ENTITY_ADJUSTMENT; - if (!interpolate) { prev->pos = next->pos; e->Position = next->pos; } + if (flags & LU_HAS_POS) { + LocalInterpComp_SetPosition(update, flags & LU_POS_MODEMASK); } - - if (flags & LU_INCLUDES_PITCH) { + if (flags & LU_HAS_PITCH) { LocalInterpComp_Angle(&prev->pitch, &next->pitch, update->pitch, interpolate); } - if (flags & LU_INCLUDES_ROTX) { + if (flags & LU_HAS_ROTX) { LocalInterpComp_Angle(&prev->rotX, &next->rotX, update->rotX, interpolate); } - if (flags & LU_INCLUDES_ROTZ) { + if (flags & LU_HAS_ROTZ) { LocalInterpComp_Angle(&prev->rotZ, &next->rotZ, update->rotZ, interpolate); } - if (flags & LU_INCLUDES_YAW) { + if (flags & LU_HAS_YAW) { LocalInterpComp_Angle(&prev->yaw, &next->yaw, update->yaw, interpolate); if (!interpolate) { diff --git a/src/EntityComponents.h b/src/EntityComponents.h index a2512a564..6f5532b2c 100644 --- a/src/EntityComponents.h +++ b/src/EntityComponents.h @@ -84,16 +84,17 @@ struct InterpComp { InterpComp_Layout }; void LocalInterpComp_SetLocation(struct InterpComp* interp, struct LocationUpdate* update); void LocalInterpComp_AdvanceState(struct InterpComp* interp, struct Entity* e); -/* Represents a network position and orientation state */ -struct NetInterpState { Vec3 Pos; float Pitch, Yaw, RotX, RotZ; }; +/* Represents a network orientation state */ +struct NetInterpAngles { float Pitch, Yaw, RotX, RotZ; }; /* Entity component that performs interpolation for network players */ struct NetInterpComp { InterpComp_Layout /* Last known position and orientation sent by the server */ - struct NetInterpState Cur; - int StatesCount; - struct NetInterpState States[10]; + Vec3 CurPos; struct NetInterpAngles CurAngles; + /* Interpolated position and orientation state */ + int PositionsCount, AnglesCount; + Vec3 Positions[10]; struct NetInterpAngles Angles[10]; }; void NetInterpComp_SetLocation(struct NetInterpComp* interp, struct LocationUpdate* update, struct Entity* e); diff --git a/src/Input.c b/src/Input.c index 01b727cde..6edbb5dbe 100644 --- a/src/Input.c +++ b/src/Input.c @@ -652,7 +652,7 @@ static cc_bool PushbackPlace(struct AABB* blockBB) { return false; } - update.flags = LU_INCLUDES_POS; + update.flags = LU_HAS_POS | LU_POS_ABSOLUTE_INSTANT; update.pos = pos; p->VTABLE->SetLocation(p, &update); return true; @@ -711,7 +711,7 @@ static cc_bool CheckIsFree(BlockID block) { /* Push player upwards when they are jumping and trying to place a block underneath them */ nextPos.Y = pos.Y + Blocks.MaxBB[block].Y + ENTITY_ADJUSTMENT; - update.flags = LU_INCLUDES_POS; + update.flags = LU_HAS_POS | LU_POS_ABSOLUTE_INSTANT; update.pos = nextPos; p->VTABLE->SetLocation(p, &update); return true; diff --git a/src/Protocol.c b/src/Protocol.c index d9247570c..054396006 100644 --- a/src/Protocol.c +++ b/src/Protocol.c @@ -151,7 +151,8 @@ static void AddEntity(cc_uint8* data, EntityID id, const cc_string* name, const Entity_SetName(e, name); if (!readPosition) return; - Classic_ReadAbsoluteLocation(data, id, 0); + Classic_ReadAbsoluteLocation(data, id, + LU_HAS_POS | LU_HAS_YAW | LU_HAS_PITCH | LU_POS_ABSOLUTE_INSTANT); if (id != ENTITIES_SELF_ID) return; p->Spawn = p->Base.Position; @@ -600,14 +601,15 @@ static void Classic_AddEntity(cc_uint8* data) { static void Classic_EntityTeleport(cc_uint8* data) { EntityID id = *data++; - Classic_ReadAbsoluteLocation(data, id, LU_FLAG_INTERPOLATE); + Classic_ReadAbsoluteLocation(data, id, + LU_HAS_POS | LU_HAS_YAW | LU_HAS_PITCH | LU_ORI_INTERPOLATE); } static void Classic_RelPosAndOrientationUpdate(cc_uint8* data) { struct LocationUpdate update; EntityID id = data[0]; - update.flags = LU_INCLUDES_POS | LU_INCLUDES_YAW | LU_INCLUDES_PITCH | LU_FLAG_RELATIVEPOS | LU_FLAG_INTERPOLATE; + update.flags = LU_HAS_POS | LU_HAS_YAW | LU_HAS_PITCH | LU_POS_RELATIVE_SMOOTH | LU_ORI_INTERPOLATE; update.pos.X = (cc_int8)data[1] / 32.0f; update.pos.Y = (cc_int8)data[2] / 32.0f; update.pos.Z = (cc_int8)data[3] / 32.0f; @@ -620,7 +622,7 @@ static void Classic_RelPositionUpdate(cc_uint8* data) { struct LocationUpdate update; EntityID id = data[0]; - update.flags = LU_INCLUDES_POS | LU_FLAG_RELATIVEPOS | LU_FLAG_INTERPOLATE; + update.flags = LU_HAS_POS | LU_POS_RELATIVE_SMOOTH | LU_ORI_INTERPOLATE; update.pos.X = (cc_int8)data[1] / 32.0f; update.pos.Y = (cc_int8)data[2] / 32.0f; update.pos.Z = (cc_int8)data[3] / 32.0f; @@ -631,7 +633,7 @@ static void Classic_OrientationUpdate(cc_uint8* data) { struct LocationUpdate update; EntityID id = data[0]; - update.flags = LU_INCLUDES_YAW | LU_INCLUDES_PITCH| LU_FLAG_INTERPOLATE; + update.flags = LU_HAS_YAW | LU_HAS_PITCH | LU_ORI_INTERPOLATE; update.yaw = Math_Packed2Deg(data[1]); update.pitch = Math_Packed2Deg(data[2]); UpdateLocation(id, &update); @@ -701,7 +703,7 @@ static void Classic_ReadAbsoluteLocation(cc_uint8* data, EntityID id, cc_uint8 f /* so to simplify things, just always add 22 to Y*/ if (id == ENTITIES_SELF_ID) y += 22; - update.flags = LU_INCLUDES_POS | LU_INCLUDES_PITCH | LU_INCLUDES_YAW | flags; + update.flags = flags; update.pos.X = x/32.0f; update.pos.Y = y/32.0f; update.pos.Z = z/32.0f; @@ -1281,13 +1283,13 @@ static void CPE_SetEntityProperty(cc_uint8* data) { switch (type) { case 0: - update.flags = LU_INCLUDES_ROTX | LU_FLAG_INTERPOLATE; + update.flags = LU_HAS_ROTX | LU_ORI_INTERPOLATE; update.rotX = (float)value; break; case 1: - update.flags = LU_INCLUDES_YAW | LU_FLAG_INTERPOLATE; + update.flags = LU_HAS_YAW | LU_ORI_INTERPOLATE; update.yaw = (float)value; break; case 2: - update.flags = LU_INCLUDES_ROTZ | LU_FLAG_INTERPOLATE; + update.flags = LU_HAS_ROTZ | LU_ORI_INTERPOLATE; update.rotZ = (float)value; break; case 3: From d16ecb6b021697231b8935934fa0419e256a2d61 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sat, 29 Oct 2022 20:13:16 +1100 Subject: [PATCH 2/7] Fix network interpolation whoops That took may too much time to spot --- src/Protocol.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Protocol.c b/src/Protocol.c index 054396006..6715fd69d 100644 --- a/src/Protocol.c +++ b/src/Protocol.c @@ -602,7 +602,7 @@ static void Classic_AddEntity(cc_uint8* data) { static void Classic_EntityTeleport(cc_uint8* data) { EntityID id = *data++; Classic_ReadAbsoluteLocation(data, id, - LU_HAS_POS | LU_HAS_YAW | LU_HAS_PITCH | LU_ORI_INTERPOLATE); + LU_HAS_POS | LU_HAS_YAW | LU_HAS_PITCH | LU_POS_ABSOLUTE_SMOOTH | LU_ORI_INTERPOLATE); } static void Classic_RelPosAndOrientationUpdate(cc_uint8* data) { From b3796ca60594d68aa620c401ab704bb7fa1b7a18 Mon Sep 17 00:00:00 2001 From: Goodlyay Date: Sun, 30 Oct 2022 00:03:10 -0700 Subject: [PATCH 3/7] Add entity teleport ext packet --- src/Protocol.c | 24 ++++++++++++++++++++---- src/Protocol.h | 2 +- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/Protocol.c b/src/Protocol.c index 6715fd69d..adfb7132f 100644 --- a/src/Protocol.c +++ b/src/Protocol.c @@ -928,10 +928,11 @@ static void CPE_ExtEntry(cc_uint8* data) { if (version == 1) return; Protocol.Sizes[OPCODE_DEFINE_BLOCK_EXT] += 3; } else if (String_CaselessEqualsConst(&ext, "ExtEntityPositions")) { - Protocol.Sizes[OPCODE_ENTITY_TELEPORT] += 6; - Protocol.Sizes[OPCODE_ADD_ENTITY] += 6; - Protocol.Sizes[OPCODE_EXT_ADD_ENTITY2] += 6; - Protocol.Sizes[OPCODE_SET_SPAWNPOINT] += 6; + Protocol.Sizes[OPCODE_ENTITY_TELEPORT] += 6; + Protocol.Sizes[OPCODE_ADD_ENTITY] += 6; + Protocol.Sizes[OPCODE_EXT_ADD_ENTITY2] += 6; + Protocol.Sizes[OPCODE_SET_SPAWNPOINT] += 6; + Protocol.Sizes[OPCODE_ENTITY_TELEPORT_EXT] += 6; cpe_extEntityPos = true; } else if (String_CaselessEqualsConst(&ext, "TwoWayPing")) { cpe_twoWayPing = true; @@ -1543,6 +1544,20 @@ static void CPE_PluginMessage(cc_uint8* data) { Event_RaisePluginMessage(&NetEvents.PluginMessageReceived, channel, data + 1); } +static void CPE_EntityTeleportExt(cc_uint8* data) { + EntityID id = *data++; + cc_uint8 type = *data++; + cc_uint8 flags = LU_HAS_POS; + if (type > 3) return; /* Invalid type, do nothing. Or should default be assumed and still TP? */ + if (type != 3) flags |= LU_HAS_PITCH | LU_HAS_YAW; + + if (type == 0) flags |= LU_POS_ABSOLUTE_SMOOTH | LU_ORI_INTERPOLATE; /* Same as OPCODE_ENTITY_TELEPORT */ + if (type == 1) flags |= LU_POS_ABSOLUTE_INSTANT; /* Same as OPCODE_ENTITY_TELEPORT, but with no interpolation (instant) */ + if (type == 2) flags |= LU_POS_RELATIVE_SMOOTH | LU_ORI_INTERPOLATE; /* Same as OPCODE_RELPOS_AND_ORI_UPDATE (with bigger location range) */ + if (type == 3) flags |= LU_POS_RELATIVE_SHIFT; /* Instant and seamless TP for local player, same as OPCODE_RELPOS_UPDATE for net player */ + Classic_ReadAbsoluteLocation(data, id, flags); +} + static void CPE_Reset(void) { cpe_serverExtensionsCount = 0; cpe_pingTicks = 0; cpe_sendHeldBlock = false; cpe_useMessageTypes = false; @@ -1589,6 +1604,7 @@ static void CPE_Reset(void) { Net_Set(OPCODE_DEFINE_MODEL_PART, CPE_DefineModelPart, 104); Net_Set(OPCODE_UNDEFINE_MODEL, CPE_UndefineModel, 2); Net_Set(OPCODE_PLUGIN_MESSAGE, CPE_PluginMessage, 66); + Net_Set(OPCODE_ENTITY_TELEPORT_EXT, CPE_EntityTeleportExt, 11); } static void CPE_Tick(void) { diff --git a/src/Protocol.h b/src/Protocol.h index f780de8ac..4d7bd2db9 100644 --- a/src/Protocol.h +++ b/src/Protocol.h @@ -36,7 +36,7 @@ enum OPCODE_ { OPCODE_SET_SPAWNPOINT, OPCODE_VELOCITY_CONTROL, OPCODE_DEFINE_EFFECT, OPCODE_SPAWN_EFFECT, OPCODE_DEFINE_MODEL, OPCODE_DEFINE_MODEL_PART, OPCODE_UNDEFINE_MODEL, - OPCODE_PLUGIN_MESSAGE, + OPCODE_PLUGIN_MESSAGE, OPCODE_ENTITY_TELEPORT_EXT, OPCODE_COUNT }; From b5bba6f276ea9d230014832af68e3620fda6dbc9 Mon Sep 17 00:00:00 2001 From: Goodlyay Date: Sun, 30 Oct 2022 01:45:18 -0700 Subject: [PATCH 4/7] Change 4-mode preset to more dynamic flags --- src/Entity.h | 11 ++++++----- src/Protocol.c | 38 ++++++++++++++++++++++++-------------- 2 files changed, 30 insertions(+), 19 deletions(-) diff --git a/src/Entity.h b/src/Entity.h index 485bbddcb..4bedd46e9 100644 --- a/src/Entity.h +++ b/src/Entity.h @@ -38,15 +38,16 @@ enum EntityType { ENTITY_TYPE_NONE, ENTITY_TYPE_PLAYER }; #define LU_HAS_ROTX 0x08 #define LU_HAS_ROTZ 0x10 -/* How to move the entity when position field is included */ +/* 0-11-00000 How to move the entity when position field is included */ #define LU_POS_MODEMASK 0x60 -/* Entity is instantly teleported to update->pos */ + +/* 0-00-00000 Entity is instantly teleported to update->pos */ #define LU_POS_ABSOLUTE_INSTANT 0x00 -/* Entity is smoothly moved to update->pos */ +/* 0-01-00000 Entity is smoothly moved to update->pos */ #define LU_POS_ABSOLUTE_SMOOTH 0x20 -/* Entity is smoothly moved to current position + update->pos */ +/* 0-10-00000 Entity is smoothly moved to current position + update->pos */ #define LU_POS_RELATIVE_SMOOTH 0x40 -/* Entity is offset/shifted by update->pos */ +/* 0-11-00000 Entity is offset/shifted by update->pos */ #define LU_POS_RELATIVE_SHIFT 0x60 /* If set, then linearly interpolates between current and new angles */ diff --git a/src/Protocol.c b/src/Protocol.c index adfb7132f..ee974f426 100644 --- a/src/Protocol.c +++ b/src/Protocol.c @@ -683,6 +683,7 @@ static void Classic_SetPermission(cc_uint8* data) { static void Classic_ReadAbsoluteLocation(cc_uint8* data, EntityID id, cc_uint8 flags) { struct LocationUpdate update; int x, y, z; + cc_uint8 mode; if (cpe_extEntityPos) { x = (int)Stream_GetU32_BE(&data[0]); @@ -696,12 +697,15 @@ static void Classic_ReadAbsoluteLocation(cc_uint8* data, EntityID id, cc_uint8 f data += 6; } - y -= 51; /* Convert to feet position */ - /* The original classic client behaves strangely in that */ - /* Y+0 is sent back to the server for next client->server position update */ - /* Y+22 is sent back to the server for all subsequent position updates */ - /* so to simplify things, just always add 22 to Y*/ - if (id == ENTITIES_SELF_ID) y += 22; + mode = flags & LU_POS_MODEMASK; + if (mode == LU_POS_ABSOLUTE_SMOOTH || mode == LU_POS_ABSOLUTE_INSTANT) { /* Only perform height shifts on absolute updates */ + y -= 51; /* Convert to feet position */ + /* The original classic client behaves strangely in that */ + /* Y+0 is sent back to the server for next client->server position update */ + /* Y+22 is sent back to the server for all subsequent position updates */ + /* so to simplify things, just always add 22 to Y*/ + if (id == ENTITIES_SELF_ID) y += 22; + } update.flags = flags; update.pos.X = x/32.0f; @@ -1546,15 +1550,21 @@ static void CPE_PluginMessage(cc_uint8* data) { static void CPE_EntityTeleportExt(cc_uint8* data) { EntityID id = *data++; - cc_uint8 type = *data++; - cc_uint8 flags = LU_HAS_POS; - if (type > 3) return; /* Invalid type, do nothing. Or should default be assumed and still TP? */ - if (type != 3) flags |= LU_HAS_PITCH | LU_HAS_YAW; + cc_uint8 packetFlags = *data++; + cc_uint8 flags = 0; + + /* bit 0 includes position */ + /* bits 1-2 position mode(absolute_instant / absolute_smooth / relative_smooth / relative_seamless) */ + /* bit 3 unused */ + /* bit 4 includes orientation */ + /* bit 5 interpolate ori */ + /* bit 6-7 unused */ + + if (packetFlags & 1) flags |= LU_HAS_POS; + flags |= (packetFlags & 6) << 3; /* bit-and with 00000110 to isolate only pos mode, then left shift by 4 to match client mode offset */ + if (packetFlags & 16) flags |= LU_HAS_PITCH | LU_HAS_YAW; + if (packetFlags & 32) flags |= LU_ORI_INTERPOLATE; - if (type == 0) flags |= LU_POS_ABSOLUTE_SMOOTH | LU_ORI_INTERPOLATE; /* Same as OPCODE_ENTITY_TELEPORT */ - if (type == 1) flags |= LU_POS_ABSOLUTE_INSTANT; /* Same as OPCODE_ENTITY_TELEPORT, but with no interpolation (instant) */ - if (type == 2) flags |= LU_POS_RELATIVE_SMOOTH | LU_ORI_INTERPOLATE; /* Same as OPCODE_RELPOS_AND_ORI_UPDATE (with bigger location range) */ - if (type == 3) flags |= LU_POS_RELATIVE_SHIFT; /* Instant and seamless TP for local player, same as OPCODE_RELPOS_UPDATE for net player */ Classic_ReadAbsoluteLocation(data, id, flags); } From 97a71537edc82e3bda609c8604bea00d70268638 Mon Sep 17 00:00:00 2001 From: Goodlyay Date: Sun, 30 Oct 2022 01:46:57 -0700 Subject: [PATCH 5/7] Oops --- src/Protocol.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Protocol.c b/src/Protocol.c index ee974f426..8ef0fc712 100644 --- a/src/Protocol.c +++ b/src/Protocol.c @@ -1561,7 +1561,7 @@ static void CPE_EntityTeleportExt(cc_uint8* data) { /* bit 6-7 unused */ if (packetFlags & 1) flags |= LU_HAS_POS; - flags |= (packetFlags & 6) << 3; /* bit-and with 00000110 to isolate only pos mode, then left shift by 4 to match client mode offset */ + flags |= (packetFlags & 6) << 4; /* bit-and with 00000110 to isolate only pos mode, then left shift by 4 to match client mode offset */ if (packetFlags & 16) flags |= LU_HAS_PITCH | LU_HAS_YAW; if (packetFlags & 32) flags |= LU_ORI_INTERPOLATE; From 5f096be3e5cd1762d4829580cf9763948dc3a1f3 Mon Sep 17 00:00:00 2001 From: Goodlyay Date: Sun, 30 Oct 2022 02:18:47 -0700 Subject: [PATCH 6/7] Add EntityTeleportExt as a cpe extension --- src/Protocol.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Protocol.c b/src/Protocol.c index 8ef0fc712..e5d0355ab 100644 --- a/src/Protocol.c +++ b/src/Protocol.c @@ -760,7 +760,7 @@ static const char* cpe_clientExtensions[] = { "EnvWeatherType", "MessageTypes", "HackControl", "PlayerClick", "FullCP437", "LongerMessages", "BlockDefinitions", "BlockDefinitionsExt", "BulkBlockUpdate", "TextColors", "EnvMapAspect", "EntityProperty", "ExtEntityPositions", "TwoWayPing", "InventoryOrder", "InstantMOTD", "FastMap", "SetHotbar", - "SetSpawnpoint", "VelocityControl", "CustomParticles", "CustomModels", "PluginMessages", + "SetSpawnpoint", "VelocityControl", "CustomParticles", "CustomModels", "PluginMessages", "EntityTeleportExt", /* NOTE: These must be placed last for when EXTENDED_TEXTURES or EXTENDED_BLOCKS are not defined */ "ExtendedTextures", "ExtendedBlocks" }; From 262c6c06109696941cdbc9936d79d546cc067584 Mon Sep 17 00:00:00 2001 From: Goodlyay Date: Sun, 30 Oct 2022 04:49:18 -0700 Subject: [PATCH 7/7] Ext should be prefixed instead of suffixed to extension name --- src/Protocol.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Protocol.c b/src/Protocol.c index e5d0355ab..3b3417673 100644 --- a/src/Protocol.c +++ b/src/Protocol.c @@ -760,7 +760,7 @@ static const char* cpe_clientExtensions[] = { "EnvWeatherType", "MessageTypes", "HackControl", "PlayerClick", "FullCP437", "LongerMessages", "BlockDefinitions", "BlockDefinitionsExt", "BulkBlockUpdate", "TextColors", "EnvMapAspect", "EntityProperty", "ExtEntityPositions", "TwoWayPing", "InventoryOrder", "InstantMOTD", "FastMap", "SetHotbar", - "SetSpawnpoint", "VelocityControl", "CustomParticles", "CustomModels", "PluginMessages", "EntityTeleportExt", + "SetSpawnpoint", "VelocityControl", "CustomParticles", "CustomModels", "PluginMessages", "ExtEntityTeleport", /* NOTE: These must be placed last for when EXTENDED_TEXTURES or EXTENDED_BLOCKS are not defined */ "ExtendedTextures", "ExtendedBlocks" }; @@ -1548,7 +1548,7 @@ static void CPE_PluginMessage(cc_uint8* data) { Event_RaisePluginMessage(&NetEvents.PluginMessageReceived, channel, data + 1); } -static void CPE_EntityTeleportExt(cc_uint8* data) { +static void CPE_ExtEntityTeleport(cc_uint8* data) { EntityID id = *data++; cc_uint8 packetFlags = *data++; cc_uint8 flags = 0; @@ -1614,7 +1614,7 @@ static void CPE_Reset(void) { Net_Set(OPCODE_DEFINE_MODEL_PART, CPE_DefineModelPart, 104); Net_Set(OPCODE_UNDEFINE_MODEL, CPE_UndefineModel, 2); Net_Set(OPCODE_PLUGIN_MESSAGE, CPE_PluginMessage, 66); - Net_Set(OPCODE_ENTITY_TELEPORT_EXT, CPE_EntityTeleportExt, 11); + Net_Set(OPCODE_ENTITY_TELEPORT_EXT, CPE_ExtEntityTeleport, 11); } static void CPE_Tick(void) {