move DDNetCharacterDisplayInfo to DDNetCharacter

- add default value option to NetworkValues
- rename m_FreezeTick to m_FreezeStart
This commit is contained in:
c0d3d3v 2022-05-24 17:26:49 +02:00
parent 3e54b35955
commit df52df9d4a
No known key found for this signature in database
GPG key ID: 068AF680530DFF31
17 changed files with 129 additions and 127 deletions

View file

@ -225,17 +225,22 @@ class NetObject:
def emit_validate(self, base_item): def emit_validate(self, base_item):
lines = ["case %s:" % self.enum_name] lines = ["case %s:" % self.enum_name]
lines += ["{"] lines += ["{"]
if self.validate_size:
lines += ["\t%s *pObj = (%s *)pData;"%(self.struct_name, self.struct_name)]
lines += ["\tif((int)sizeof(*pObj) > Size) return -1;"]
prev_len = len(lines)
variables = self.variables variables = self.variables
if base_item: if base_item:
variables += base_item.variables variables += base_item.variables
validate_variables_lines = []
for v in variables: for v in variables:
lines += ["\t"+line for line in v.emit_validate()] validate_variable_lines = ["\t"+line for line in v.emit_validate()]
if not self.validate_size and prev_len != len(lines): if not self.validate_size and len(validate_variable_lines) > 0 and v.default is None:
raise ValueError("Can't use members that need validation in a struct whose size isn't validated") raise ValueError("Members that require validation and do not have a default value cannot be used in a structure whose size is not validated")
validate_variables_lines += validate_variable_lines
if self.validate_size or validate_variables_lines:
lines += ["\t%s *pObj = (%s *)pData;"%(self.struct_name, self.struct_name)]
if self.validate_size:
lines += ["\tif((int)sizeof(*pObj) > Size) return -1;"]
lines += validate_variables_lines
lines += ["\treturn 0;"] lines += ["\treturn 0;"]
lines += ["}"] lines += ["}"]
return lines return lines
@ -297,8 +302,9 @@ class NetMessageEx(NetMessage):
class NetVariable: class NetVariable:
def __init__(self, name): def __init__(self, name, default=None):
self.name = name self.name = name
self.default = None if default is None else str(default)
def emit_declaration(self): def emit_declaration(self):
return [] return []
def emit_validate(self): def emit_validate(self):
@ -338,13 +344,15 @@ class NetIntAny(NetVariable):
def emit_declaration(self): def emit_declaration(self):
return ["int %s;"%self.name] return ["int %s;"%self.name]
def emit_unpack(self): def emit_unpack(self):
if self.default is None:
return ["pMsg->%s = pUnpacker->GetInt();" % self.name] return ["pMsg->%s = pUnpacker->GetInt();" % self.name]
return ["pMsg->%s = pUnpacker->GetIntOrDefault(%s);" % (self.name, self.default)]
def emit_pack(self): def emit_pack(self):
return ["pPacker->AddInt(%s);" % self.name] return ["pPacker->AddInt(%s);" % self.name]
class NetIntRange(NetIntAny): class NetIntRange(NetIntAny):
def __init__(self, name, min_val, max_val): def __init__(self, name, min_val, max_val, default=None):
NetIntAny.__init__(self,name) NetIntAny.__init__(self,name,default=default)
self.min = str(min_val) self.min = str(min_val)
self.max = str(max_val) self.max = str(max_val)
def emit_validate(self): def emit_validate(self):
@ -353,12 +361,13 @@ class NetIntRange(NetIntAny):
return ["if(pMsg->%s < %s || pMsg->%s > %s) { m_pMsgFailedOn = \"%s\"; break; }" % (self.name, self.min, self.name, self.max, self.name)] return ["if(pMsg->%s < %s || pMsg->%s > %s) { m_pMsgFailedOn = \"%s\"; break; }" % (self.name, self.min, self.name, self.max, self.name)]
class NetBool(NetIntRange): class NetBool(NetIntRange):
def __init__(self, name): def __init__(self, name, default=None):
NetIntRange.__init__(self,name,0,1) default = None if default is None else int(default)
NetIntRange.__init__(self,name,0,1,default=default)
class NetTick(NetIntAny): class NetTick(NetIntAny):
def __init__(self, name): def __init__(self, name, default=None):
NetIntAny.__init__(self,name) NetIntAny.__init__(self,name,default=default)
class NetArray(NetVariable): class NetArray(NetVariable):
def __init__(self, var, size): def __init__(self, var, size):

View file

@ -11,7 +11,7 @@ CharacterFlags = ["SOLO", "JETPACK", "NO_COLLISION", "ENDLESS_HOOK", "ENDLESS_JU
"NO_HAMMER_HIT", "NO_SHOTGUN_HIT", "NO_GRENADE_HIT", "NO_LASER_HIT", "NO_HOOK", "NO_HAMMER_HIT", "NO_SHOTGUN_HIT", "NO_GRENADE_HIT", "NO_LASER_HIT", "NO_HOOK",
"TELEGUN_GUN", "TELEGUN_GRENADE", "TELEGUN_LASER", "TELEGUN_GUN", "TELEGUN_GRENADE", "TELEGUN_LASER",
"WEAPON_HAMMER", "WEAPON_GUN", "WEAPON_SHOTGUN", "WEAPON_GRENADE", "WEAPON_LASER", "WEAPON_NINJA", "WEAPON_HAMMER", "WEAPON_GUN", "WEAPON_SHOTGUN", "WEAPON_GRENADE", "WEAPON_LASER", "WEAPON_NINJA",
"NO_MOVEMENTS"] "NO_MOVEMENTS", "IN_FREEZE", "PRACTICE_MODE"]
GameInfoFlags = [ GameInfoFlags = [
"TIMESCORE", "GAMETYPE_RACE", "GAMETYPE_FASTCAP", "GAMETYPE_FNG", "TIMESCORE", "GAMETYPE_RACE", "GAMETYPE_FASTCAP", "GAMETYPE_FNG",
"GAMETYPE_DDRACE", "GAMETYPE_DDNET", "GAMETYPE_BLOCK_WORLDS", "GAMETYPE_DDRACE", "GAMETYPE_DDNET", "GAMETYPE_BLOCK_WORLDS",
@ -237,21 +237,20 @@ Objects = [
NetObjectEx("DDNetCharacter", "character@netobj.ddnet.tw", [ NetObjectEx("DDNetCharacter", "character@netobj.ddnet.tw", [
NetIntAny("m_Flags"), NetIntAny("m_Flags"),
NetTick("m_FreezeEnd"), NetTick("m_FreezeEnd"),
NetIntRange("m_Jumps", -1, 255), NetIntRange("m_Jumps", -1, 255, 2),
NetIntAny("m_TeleCheckpoint"), NetIntAny("m_TeleCheckpoint"),
NetIntRange("m_StrongWeakID", 0, 'MAX_CLIENTS-1'), NetIntRange("m_StrongWeakID", 0, 'MAX_CLIENTS-1', 0),
]),
NetObjectEx("DDNetCharacterDisplayInfo", "character-display-info@netobj.ddnet.tw", [ # New data fields for jump display, freeze bar and ninja bar
NetIntRange("m_JumpedTotal", 0, 255), # Default values indicate that these values should not be used
NetTick("m_NinjaActivationTick"), NetIntRange("m_JumpedTotal", -1, 255, -1),
NetTick("m_FreezeTick"), NetTick("m_NinjaActivationTick", -1),
NetBool("m_IsInFreeze"), NetTick("m_FreezeStart", -1),
NetBool("m_IsInPracticeMode"), # New data fields for improved target accuracy and speed display
NetIntAny("m_TargetX"), NetIntAny("m_TargetX", 0),
NetIntAny("m_TargetY"), NetIntAny("m_TargetY", 0),
NetIntAny("m_RampValue"), NetIntAny("m_RampValue", 1),
]), ], validate_size=False),
NetObjectEx("DDNetPlayer", "player@netobj.ddnet.tw", [ NetObjectEx("DDNetPlayer", "player@netobj.ddnet.tw", [
NetIntAny("m_Flags"), NetIntAny("m_Flags"),

View file

@ -974,11 +974,11 @@ void CServer::DoSnapshot()
int Crc = pData->Crc(); int Crc = pData->Crc();
// remove old snapshos // remove old snapshots
// keep 3 seconds worth of snapshots // keep 3 seconds worth of snapshots
m_aClients[i].m_Snapshots.PurgeUntil(m_CurrentGameTick - SERVER_TICK_SPEED * 3); m_aClients[i].m_Snapshots.PurgeUntil(m_CurrentGameTick - SERVER_TICK_SPEED * 3);
// save it the snapshot // save the snapshot
m_aClients[i].m_Snapshots.Add(m_CurrentGameTick, time_get(), SnapshotSize, pData, 0); m_aClients[i].m_Snapshots.Add(m_CurrentGameTick, time_get(), SnapshotSize, pData, 0);
// find snapshot that we can perform delta against // find snapshot that we can perform delta against

View file

@ -10,13 +10,14 @@ void CFreezeBars::RenderFreezeBar(const int ClientID)
// pCharacter contains the predicted character for local players or the last snap for players who are spectated // pCharacter contains the predicted character for local players or the last snap for players who are spectated
CCharacterCore *pCharacter = &m_pClient->m_aClients[ClientID].m_Predicted; CCharacterCore *pCharacter = &m_pClient->m_aClients[ClientID].m_Predicted;
if(pCharacter->m_FreezeEnd <= 0.0f || pCharacter->m_FreezeTick == 0 || !m_pClient->m_Snap.m_aCharacters[ClientID].m_HasExtendedDisplayInfo || (pCharacter->m_IsInFreeze && g_Config.m_ClFreezeBarsAlphaInsideFreeze == 0))
if(pCharacter->m_FreezeEnd <= 0.0f || pCharacter->m_FreezeStart == 0 || !m_pClient->m_Snap.m_aCharacters[ClientID].m_HasExtendedDisplayInfo || (pCharacter->m_IsInFreeze && g_Config.m_ClFreezeBarsAlphaInsideFreeze == 0))
{ {
return; return;
} }
const int Max = pCharacter->m_FreezeEnd - pCharacter->m_FreezeTick; const int Max = pCharacter->m_FreezeEnd - pCharacter->m_FreezeStart;
float FreezeProgress = clamp(Max - (Client()->GameTick(g_Config.m_ClDummy) - pCharacter->m_FreezeTick), 0, Max) / (float)Max; float FreezeProgress = clamp(Max - (Client()->GameTick(g_Config.m_ClDummy) - pCharacter->m_FreezeStart), 0, Max) / (float)Max;
if(FreezeProgress <= 0.0f) if(FreezeProgress <= 0.0f)
{ {
return; return;

View file

@ -1126,7 +1126,7 @@ void CHud::RenderPlayerState(const int ClientID)
{ {
y += 12; y += 12;
} }
if(m_pClient->m_Snap.m_aCharacters[ClientID].m_HasExtendedDisplayInfo && m_pClient->m_Snap.m_aCharacters[ClientID].m_ExtendedDisplayInfo.m_IsInPracticeMode) if(m_pClient->m_Snap.m_aCharacters[ClientID].m_HasExtendedDisplayInfo && m_pClient->m_Snap.m_aCharacters[ClientID].m_ExtendedData.m_Flags & CHARACTERFLAG_PRACTICE_MODE)
{ {
Graphics()->TextureSet(m_pClient->m_HudSkin.m_SpriteHudPracticeMode); Graphics()->TextureSet(m_pClient->m_HudSkin.m_SpriteHudPracticeMode);
Graphics()->RenderQuadContainerAsSprite(m_HudQuadContainerIndex, m_PracticeModeOffset, x, y); Graphics()->RenderQuadContainerAsSprite(m_HudQuadContainerIndex, m_PracticeModeOffset, x, y);
@ -1424,15 +1424,15 @@ void CHud::RenderMovementInformation(const int ClientID)
if(m_pClient->m_Snap.m_aCharacters[ClientID].m_HasExtendedDisplayInfo) if(m_pClient->m_Snap.m_aCharacters[ClientID].m_HasExtendedDisplayInfo)
{ {
// On DDNet servers the actual speed on X axis is displayed, i.e. VelspeedX * Ramp // On DDNet servers the actual speed on X axis is displayed, i.e. VelspeedX * Ramp
DisplaySpeedX *= (m_pClient->m_Snap.m_aCharacters[ClientID].m_ExtendedDisplayInfo.m_RampValue / 1000.0f); DisplaySpeedX *= (m_pClient->m_Snap.m_aCharacters[ClientID].m_ExtendedData.m_RampValue / 1000.0f);
} }
float Angle = 0.0f; float Angle = 0.0f;
if(m_pClient->m_Snap.m_aCharacters[ClientID].m_HasExtendedDisplayInfo) if(m_pClient->m_Snap.m_aCharacters[ClientID].m_HasExtendedDisplayInfo)
{ {
// On DDNet servers the more accurate angle is displayed, calculated from the target coordinates // On DDNet servers the more accurate angle is displayed, calculated from the target coordinates
CNetObj_DDNetCharacterDisplayInfo *CharacterDisplayInfo = &m_pClient->m_Snap.m_aCharacters[ClientID].m_ExtendedDisplayInfo; CNetObj_DDNetCharacter *ExtendedData = &m_pClient->m_Snap.m_aCharacters[ClientID].m_ExtendedData;
Angle = atan2f(CharacterDisplayInfo->m_TargetY, CharacterDisplayInfo->m_TargetX); Angle = atan2f(ExtendedData->m_TargetY, ExtendedData->m_TargetX);
} }
else else
{ {

View file

@ -84,19 +84,19 @@ float CPlayers::GetPlayerTargetAngle(
AngleIntraTick = Client()->IntraGameTick(g_Config.m_ClDummy); AngleIntraTick = Client()->IntraGameTick(g_Config.m_ClDummy);
if(ClientID >= 0 && m_pClient->m_Snap.m_aCharacters[ClientID].m_HasExtendedDisplayInfo) if(ClientID >= 0 && m_pClient->m_Snap.m_aCharacters[ClientID].m_HasExtendedDisplayInfo)
{ {
CNetObj_DDNetCharacterDisplayInfo *CharacterDisplayInfo = &m_pClient->m_Snap.m_aCharacters[ClientID].m_ExtendedDisplayInfo; CNetObj_DDNetCharacter *ExtendedData = &m_pClient->m_Snap.m_aCharacters[ClientID].m_ExtendedData;
if(m_pClient->m_Snap.m_aCharacters[ClientID].m_PrevExtendedDisplayInfo) if(m_pClient->m_Snap.m_aCharacters[ClientID].m_PrevExtendedData)
{ {
const CNetObj_DDNetCharacterDisplayInfo *PrevCharacterDisplayInfo = m_pClient->m_Snap.m_aCharacters[ClientID].m_PrevExtendedDisplayInfo; const CNetObj_DDNetCharacter *PrevExtendedData = m_pClient->m_Snap.m_aCharacters[ClientID].m_PrevExtendedData;
float MixX = mix((float)PrevCharacterDisplayInfo->m_TargetX, (float)CharacterDisplayInfo->m_TargetX, AngleIntraTick); float MixX = mix((float)PrevExtendedData->m_TargetX, (float)ExtendedData->m_TargetX, AngleIntraTick);
float MixY = mix((float)PrevCharacterDisplayInfo->m_TargetY, (float)CharacterDisplayInfo->m_TargetY, AngleIntraTick); float MixY = mix((float)PrevExtendedData->m_TargetY, (float)ExtendedData->m_TargetY, AngleIntraTick);
return angle(vec2(MixX, MixY)); return angle(vec2(MixX, MixY));
} }
else else
{ {
return angle(vec2(CharacterDisplayInfo->m_TargetX, CharacterDisplayInfo->m_TargetY)); return angle(vec2(ExtendedData->m_TargetX, ExtendedData->m_TargetY));
} }
} }
else else

View file

@ -1321,8 +1321,13 @@ void CGameClient::OnNewSnapshot()
if(Item.m_ID < MAX_CLIENTS) if(Item.m_ID < MAX_CLIENTS)
{ {
m_Snap.m_aCharacters[Item.m_ID].m_ExtendedData = *pCharacterData; m_Snap.m_aCharacters[Item.m_ID].m_ExtendedData = *pCharacterData;
m_Snap.m_aCharacters[Item.m_ID].m_PrevExtendedData = (const CNetObj_DDNetCharacter *)Client()->SnapFindItem(IClient::SNAP_PREV, NETOBJTYPE_DDNETCHARACTER, Item.m_ID);
m_Snap.m_aCharacters[Item.m_ID].m_HasExtendedData = true; m_Snap.m_aCharacters[Item.m_ID].m_HasExtendedData = true;
m_Snap.m_aCharacters[Item.m_ID].m_HasExtendedDisplayInfo = false;
if(Item.m_DataSize >= 44)
{
m_Snap.m_aCharacters[Item.m_ID].m_HasExtendedDisplayInfo = true;
}
CClientData *pClient = &m_aClients[Item.m_ID]; CClientData *pClient = &m_aClients[Item.m_ID];
// Collision // Collision
pClient->m_Solo = pCharacterData->m_Flags & CHARACTERFLAG_SOLO; pClient->m_Solo = pCharacterData->m_Flags & CHARACTERFLAG_SOLO;
@ -1352,20 +1357,6 @@ void CGameClient::OnNewSnapshot()
pClient->m_Predicted.ReadDDNet(pCharacterData); pClient->m_Predicted.ReadDDNet(pCharacterData);
} }
} }
else if(Item.m_Type == NETOBJTYPE_DDNETCHARACTERDISPLAYINFO)
{
const CNetObj_DDNetCharacterDisplayInfo *pCharacterDisplayInfo = (const CNetObj_DDNetCharacterDisplayInfo *)pData;
if(Item.m_ID < MAX_CLIENTS)
{
m_Snap.m_aCharacters[Item.m_ID].m_ExtendedDisplayInfo = *pCharacterDisplayInfo;
m_Snap.m_aCharacters[Item.m_ID].m_PrevExtendedDisplayInfo = (const CNetObj_DDNetCharacterDisplayInfo *)Client()->SnapFindItem(IClient::SNAP_PREV, NETOBJTYPE_DDNETCHARACTERDISPLAYINFO, Item.m_ID);
m_Snap.m_aCharacters[Item.m_ID].m_HasExtendedDisplayInfo = true;
CClientData *pClient = &m_aClients[Item.m_ID];
pClient->m_Predicted.ReadDDNetDisplayInfo(pCharacterDisplayInfo);
}
}
else if(Item.m_Type == NETOBJTYPE_SPECCHAR) else if(Item.m_Type == NETOBJTYPE_SPECCHAR)
{ {
const CNetObj_SpecChar *pSpecCharData = (const CNetObj_SpecChar *)pData; const CNetObj_SpecChar *pSpecCharData = (const CNetObj_SpecChar *)pData;
@ -2432,7 +2423,6 @@ void CGameClient::UpdatePrediction()
int GameTeam = (m_Snap.m_pGameInfoObj->m_GameFlags & GAMEFLAG_TEAMS) ? m_aClients[i].m_Team : i; int GameTeam = (m_Snap.m_pGameInfoObj->m_GameFlags & GAMEFLAG_TEAMS) ? m_aClients[i].m_Team : i;
m_GameWorld.NetCharAdd(i, &m_Snap.m_aCharacters[i].m_Cur, m_GameWorld.NetCharAdd(i, &m_Snap.m_aCharacters[i].m_Cur,
m_Snap.m_aCharacters[i].m_HasExtendedData ? &m_Snap.m_aCharacters[i].m_ExtendedData : 0, m_Snap.m_aCharacters[i].m_HasExtendedData ? &m_Snap.m_aCharacters[i].m_ExtendedData : 0,
m_Snap.m_aCharacters[i].m_HasExtendedDisplayInfo ? &m_Snap.m_aCharacters[i].m_ExtendedDisplayInfo : 0,
GameTeam, IsLocal); GameTeam, IsLocal);
} }

View file

@ -305,10 +305,8 @@ public:
CNetObj_Character m_Cur; CNetObj_Character m_Cur;
CNetObj_DDNetCharacter m_ExtendedData; CNetObj_DDNetCharacter m_ExtendedData;
const CNetObj_DDNetCharacter *m_PrevExtendedData;
bool m_HasExtendedData; bool m_HasExtendedData;
const CNetObj_DDNetCharacterDisplayInfo *m_PrevExtendedDisplayInfo;
CNetObj_DDNetCharacterDisplayInfo m_ExtendedDisplayInfo;
bool m_HasExtendedDisplayInfo; bool m_HasExtendedDisplayInfo;
// interpolated position // interpolated position

View file

@ -1050,10 +1050,10 @@ bool CCharacter::Freeze(int Seconds)
return false; return false;
if((Seconds <= 0 || m_Super || m_FreezeTime == -1 || m_FreezeTime > Seconds * GameWorld()->GameTickSpeed()) && Seconds != -1) if((Seconds <= 0 || m_Super || m_FreezeTime == -1 || m_FreezeTime > Seconds * GameWorld()->GameTickSpeed()) && Seconds != -1)
return false; return false;
if(m_Core.m_FreezeTick < GameWorld()->GameTick() - GameWorld()->GameTickSpeed() || Seconds == -1) if(m_Core.m_FreezeStart < GameWorld()->GameTick() - GameWorld()->GameTickSpeed() || Seconds == -1)
{ {
m_FreezeTime = Seconds == -1 ? Seconds : Seconds * GameWorld()->GameTickSpeed(); m_FreezeTime = Seconds == -1 ? Seconds : Seconds * GameWorld()->GameTickSpeed();
m_Core.m_FreezeTick = GameWorld()->GameTick(); m_Core.m_FreezeStart = GameWorld()->GameTick();
return true; return true;
} }
return false; return false;
@ -1071,7 +1071,7 @@ bool CCharacter::UnFreeze()
if(!m_Core.m_aWeapons[m_Core.m_ActiveWeapon].m_Got) if(!m_Core.m_aWeapons[m_Core.m_ActiveWeapon].m_Got)
m_Core.m_ActiveWeapon = WEAPON_GUN; m_Core.m_ActiveWeapon = WEAPON_GUN;
m_FreezeTime = 0; m_FreezeTime = 0;
m_Core.m_FreezeTick = 0; m_Core.m_FreezeStart = 0;
m_FrozenLastTick = true; m_FrozenLastTick = true;
return true; return true;
} }
@ -1115,7 +1115,7 @@ CTeamsCore *CCharacter::TeamsCore()
return m_Core.m_pTeams; return m_Core.m_pTeams;
} }
CCharacter::CCharacter(CGameWorld *pGameWorld, int ID, CNetObj_Character *pChar, CNetObj_DDNetCharacter *pExtended, CNetObj_DDNetCharacterDisplayInfo *pExtendedDisplayInfo) : CCharacter::CCharacter(CGameWorld *pGameWorld, int ID, CNetObj_Character *pChar, CNetObj_DDNetCharacter *pExtended) :
CEntity(pGameWorld, CGameWorld::ENTTYPE_CHARACTER, vec2(0, 0), CCharacterCore::PhysicalSize()) CEntity(pGameWorld, CGameWorld::ENTTYPE_CHARACTER, vec2(0, 0), CCharacterCore::PhysicalSize())
{ {
m_ID = ID; m_ID = ID;
@ -1148,7 +1148,7 @@ CCharacter::CCharacter(CGameWorld *pGameWorld, int ID, CNetObj_Character *pChar,
m_LatestPrevInput = m_LatestInput = m_PrevInput = m_SavedInput = m_Input; m_LatestPrevInput = m_LatestInput = m_PrevInput = m_SavedInput = m_Input;
ResetPrediction(); ResetPrediction();
Read(pChar, pExtended, pExtendedDisplayInfo, false); Read(pChar, pExtended, false);
} }
void CCharacter::ResetPrediction() void CCharacter::ResetPrediction()
@ -1164,7 +1164,7 @@ void CCharacter::ResetPrediction()
m_Core.m_NoCollision = false; m_Core.m_NoCollision = false;
m_NumInputs = 0; m_NumInputs = 0;
m_FreezeTime = 0; m_FreezeTime = 0;
m_Core.m_FreezeTick = 0; m_Core.m_FreezeStart = 0;
m_Core.m_IsInFreeze = false; m_Core.m_IsInFreeze = false;
m_DeepFreeze = false; m_DeepFreeze = false;
m_LiveFreeze = false; m_LiveFreeze = false;
@ -1184,15 +1184,13 @@ void CCharacter::ResetPrediction()
m_LastTuneZoneTick = 0; m_LastTuneZoneTick = 0;
} }
void CCharacter::Read(CNetObj_Character *pChar, CNetObj_DDNetCharacter *pExtended, CNetObj_DDNetCharacterDisplayInfo *pExtendedDisplayInfo, bool IsLocal) void CCharacter::Read(CNetObj_Character *pChar, CNetObj_DDNetCharacter *pExtended, bool IsLocal)
{ {
m_Core.ReadCharacterCore((const CNetObj_CharacterCore *)pChar); m_Core.ReadCharacterCore((const CNetObj_CharacterCore *)pChar);
m_IsLocal = IsLocal; m_IsLocal = IsLocal;
if(pExtended) if(pExtended)
{ {
m_Core.ReadDDNet(pExtended);
SetSolo(pExtended->m_Flags & CHARACTERFLAG_SOLO); SetSolo(pExtended->m_Flags & CHARACTERFLAG_SOLO);
m_Super = pExtended->m_Flags & CHARACTERFLAG_SUPER; m_Super = pExtended->m_Flags & CHARACTERFLAG_SUPER;
if(m_Super) if(m_Super)
@ -1235,6 +1233,8 @@ void CCharacter::Read(CNetObj_Character *pChar, CNetObj_DDNetCharacter *pExtende
} }
else else
UnFreeze(); UnFreeze();
m_Core.ReadDDNet(pExtended);
} }
else else
{ {
@ -1306,7 +1306,7 @@ void CCharacter::Read(CNetObj_Character *pChar, CNetObj_DDNetCharacter *pExtende
// detect unfreeze (in case the player was frozen in the tile prediction and not correctly unfrozen) // detect unfreeze (in case the player was frozen in the tile prediction and not correctly unfrozen)
if(pChar->m_Emote != EMOTE_PAIN && pChar->m_Emote != EMOTE_NORMAL) if(pChar->m_Emote != EMOTE_PAIN && pChar->m_Emote != EMOTE_NORMAL)
m_DeepFreeze = false; m_DeepFreeze = false;
if(pChar->m_Weapon != WEAPON_NINJA || pChar->m_AttackTick > m_Core.m_FreezeTick || absolute(pChar->m_VelX) == 256 * 10 || !GameWorld()->m_WorldConfig.m_PredictFreeze) if(pChar->m_Weapon != WEAPON_NINJA || pChar->m_AttackTick > m_Core.m_FreezeStart || absolute(pChar->m_VelX) == 256 * 10 || !GameWorld()->m_WorldConfig.m_PredictFreeze)
{ {
m_DeepFreeze = false; m_DeepFreeze = false;
UnFreeze(); UnFreeze();
@ -1344,9 +1344,18 @@ void CCharacter::Read(CNetObj_Character *pChar, CNetObj_DDNetCharacter *pExtende
mem_zero(&m_SavedInput, sizeof(m_SavedInput)); mem_zero(&m_SavedInput, sizeof(m_SavedInput));
m_Input.m_Direction = m_SavedInput.m_Direction = m_Core.m_Direction; m_Input.m_Direction = m_SavedInput.m_Direction = m_Core.m_Direction;
m_Input.m_Hook = m_SavedInput.m_Hook = (m_Core.m_HookState != HOOK_IDLE); m_Input.m_Hook = m_SavedInput.m_Hook = (m_Core.m_HookState != HOOK_IDLE);
if(pExtended)
{
m_Input.m_TargetX = m_SavedInput.m_TargetX = pExtended->m_TargetX;
m_Input.m_TargetY = m_SavedInput.m_TargetY = pExtended->m_TargetY;
}
else
{
m_Input.m_TargetX = m_SavedInput.m_TargetX = cosf(pChar->m_Angle / 256.0f) * 256.0f; m_Input.m_TargetX = m_SavedInput.m_TargetX = cosf(pChar->m_Angle / 256.0f) * 256.0f;
m_Input.m_TargetY = m_SavedInput.m_TargetY = sinf(pChar->m_Angle / 256.0f) * 256.0f; m_Input.m_TargetY = m_SavedInput.m_TargetY = sinf(pChar->m_Angle / 256.0f) * 256.0f;
} }
}
// in most cases the reload timer can be determined from the last attack tick // in most cases the reload timer can be determined from the last attack tick
// (this is only needed for autofire weapons to prevent the predicted reload timer from desyncing) // (this is only needed for autofire weapons to prevent the predicted reload timer from desyncing)
@ -1360,22 +1369,6 @@ void CCharacter::Read(CNetObj_Character *pChar, CNetObj_DDNetCharacter *pExtende
m_ReloadTimer = maximum(0, m_AttackTick + FireDelayTicks - GameWorld()->GameTick()); m_ReloadTimer = maximum(0, m_AttackTick + FireDelayTicks - GameWorld()->GameTick());
} }
} }
if(pExtendedDisplayInfo)
{
if(GameWorld()->m_WorldConfig.m_PredictFreeze)
{
m_Core.m_FreezeTick = pExtendedDisplayInfo->m_FreezeTick;
}
m_Core.m_IsInFreeze = pExtendedDisplayInfo->m_IsInFreeze;
m_Core.m_Ninja.m_ActivationTick = pExtendedDisplayInfo->m_NinjaActivationTick;
m_Core.m_JumpedTotal = pExtendedDisplayInfo->m_JumpedTotal;
if(!IsLocal)
{
m_Input.m_TargetX = pExtendedDisplayInfo->m_TargetX;
m_Input.m_TargetY = pExtendedDisplayInfo->m_TargetY;
}
}
} }
void CCharacter::SetCoreWorld(CGameWorld *pGameWorld) void CCharacter::SetCoreWorld(CGameWorld *pGameWorld)

View file

@ -129,8 +129,8 @@ public:
int GetAttackTick() { return m_AttackTick; } int GetAttackTick() { return m_AttackTick; }
int GetStrongWeakID() { return m_StrongWeakID; } int GetStrongWeakID() { return m_StrongWeakID; }
CCharacter(CGameWorld *pGameWorld, int ID, CNetObj_Character *pChar, CNetObj_DDNetCharacter *pExtended = 0, CNetObj_DDNetCharacterDisplayInfo *pExtendedDisplayInfo = 0); CCharacter(CGameWorld *pGameWorld, int ID, CNetObj_Character *pChar, CNetObj_DDNetCharacter *pExtended = 0);
void Read(CNetObj_Character *pChar, CNetObj_DDNetCharacter *pExtended, CNetObj_DDNetCharacterDisplayInfo *pExtendedDisplayInfo, bool IsLocal); void Read(CNetObj_Character *pChar, CNetObj_DDNetCharacter *pExtended, bool IsLocal);
void SetCoreWorld(CGameWorld *pGameWorld); void SetCoreWorld(CGameWorld *pGameWorld);
int m_LastSnapWeapon; int m_LastSnapWeapon;

View file

@ -371,17 +371,17 @@ void CGameWorld::NetObjBegin()
OnModified(); OnModified();
} }
void CGameWorld::NetCharAdd(int ObjID, CNetObj_Character *pCharObj, CNetObj_DDNetCharacter *pExtended, CNetObj_DDNetCharacterDisplayInfo *pExtendedDisplayInfo, int GameTeam, bool IsLocal) void CGameWorld::NetCharAdd(int ObjID, CNetObj_Character *pCharObj, CNetObj_DDNetCharacter *pExtended, int GameTeam, bool IsLocal)
{ {
CCharacter *pChar; CCharacter *pChar;
if((pChar = (CCharacter *)GetEntity(ObjID, ENTTYPE_CHARACTER))) if((pChar = (CCharacter *)GetEntity(ObjID, ENTTYPE_CHARACTER)))
{ {
pChar->Read(pCharObj, pExtended, pExtendedDisplayInfo, IsLocal); pChar->Read(pCharObj, pExtended, IsLocal);
pChar->Keep(); pChar->Keep();
} }
else else
{ {
pChar = new CCharacter(this, ObjID, pCharObj, pExtended, pExtendedDisplayInfo); pChar = new CCharacter(this, ObjID, pCharObj, pExtended);
InsertEntity(pChar); InsertEntity(pChar);
} }

View file

@ -85,7 +85,7 @@ public:
void OnModified(); void OnModified();
void NetObjBegin(); void NetObjBegin();
void NetCharAdd(int ObjID, CNetObj_Character *pChar, CNetObj_DDNetCharacter *pExtended, CNetObj_DDNetCharacterDisplayInfo *pExtendedDisplayInfo, int GameTeam, bool IsLocal); void NetCharAdd(int ObjID, CNetObj_Character *pChar, CNetObj_DDNetCharacter *pExtended, int GameTeam, bool IsLocal);
void NetObjAdd(int ObjID, int ObjType, const void *pObjData, const CNetObj_EntityEx *pDataEx); void NetObjAdd(int ObjID, int ObjType, const void *pObjData, const CNetObj_EntityEx *pDataEx);
void NetObjEnd(int LocalID); void NetObjEnd(int LocalID);
void CopyWorld(CGameWorld *pFrom); void CopyWorld(CGameWorld *pFrom);

View file

@ -105,7 +105,7 @@ void CCharacterCore::Reset()
m_HasTelegunGun = false; m_HasTelegunGun = false;
m_HasTelegunGrenade = false; m_HasTelegunGrenade = false;
m_HasTelegunLaser = false; m_HasTelegunLaser = false;
m_FreezeTick = 0; m_FreezeStart = 0;
m_FreezeEnd = 0; m_FreezeEnd = 0;
m_IsInFreeze = false; m_IsInFreeze = false;
m_DeepFrozen = false; m_DeepFrozen = false;
@ -599,14 +599,22 @@ void CCharacterCore::ReadDDNet(const CNetObj_DDNetCharacter *pObjDDNet)
// Available jumps // Available jumps
m_Jumps = pObjDDNet->m_Jumps; m_Jumps = pObjDDNet->m_Jumps;
}
void CCharacterCore::ReadDDNetDisplayInfo(const CNetObj_DDNetCharacterDisplayInfo *pObjDDNet) // Display Information
// We only accept the display information when it is received, which means it is not -1 in each case.
if(pObjDDNet->m_JumpedTotal != -1)
{ {
m_JumpedTotal = pObjDDNet->m_JumpedTotal; m_JumpedTotal = pObjDDNet->m_JumpedTotal;
}
if(pObjDDNet->m_NinjaActivationTick != -1)
{
m_Ninja.m_ActivationTick = pObjDDNet->m_NinjaActivationTick; m_Ninja.m_ActivationTick = pObjDDNet->m_NinjaActivationTick;
m_FreezeTick = pObjDDNet->m_FreezeTick; }
m_IsInFreeze = pObjDDNet->m_IsInFreeze; if(pObjDDNet->m_FreezeStart != -1)
{
m_FreezeStart = pObjDDNet->m_FreezeStart;
m_IsInFreeze = pObjDDNet->m_Flags & CHARACTERFLAG_IN_FREEZE;
}
} }
void CCharacterCore::Quantize() void CCharacterCore::Quantize()

View file

@ -291,7 +291,6 @@ public:
void SetTeamsCore(CTeamsCore *pTeams); void SetTeamsCore(CTeamsCore *pTeams);
void SetTeleOuts(std::map<int, std::vector<vec2>> *pTeleOuts); void SetTeleOuts(std::map<int, std::vector<vec2>> *pTeleOuts);
void ReadDDNet(const CNetObj_DDNetCharacter *pObjDDNet); void ReadDDNet(const CNetObj_DDNetCharacter *pObjDDNet);
void ReadDDNetDisplayInfo(const CNetObj_DDNetCharacterDisplayInfo *pObjDDNet);
bool m_Solo; bool m_Solo;
bool m_Jetpack; bool m_Jetpack;
bool m_NoCollision; bool m_NoCollision;
@ -306,7 +305,7 @@ public:
bool m_HasTelegunGun; bool m_HasTelegunGun;
bool m_HasTelegunGrenade; bool m_HasTelegunGrenade;
bool m_HasTelegunLaser; bool m_HasTelegunLaser;
int m_FreezeTick; int m_FreezeStart;
int m_FreezeEnd; int m_FreezeEnd;
bool m_IsInFreeze; bool m_IsInFreeze;
bool m_DeepFrozen; bool m_DeepFrozen;

View file

@ -12,6 +12,7 @@
#include <game/server/player.h> #include <game/server/player.h>
#include "character.h" #include "character.h"
#include "game/generated/protocol.h"
#include "laser.h" #include "laser.h"
#include "projectile.h" #include "projectile.h"
@ -1045,7 +1046,7 @@ void CCharacter::SnapCharacter(int SnappingClient, int ID)
pCharacter->m_AmmoCount = AmmoCount; pCharacter->m_AmmoCount = AmmoCount;
if(m_FreezeTime > 0 || m_FreezeTime == -1 || m_DeepFreeze) if(m_FreezeTime > 0 || m_FreezeTime == -1 || m_DeepFreeze)
pCharacter->m_AmmoCount = m_Core.m_FreezeTick + g_Config.m_SvFreezeDelay * Server()->TickSpeed(); pCharacter->m_AmmoCount = m_Core.m_FreezeStart + g_Config.m_SvFreezeDelay * Server()->TickSpeed();
else if(Weapon == WEAPON_NINJA) else if(Weapon == WEAPON_NINJA)
pCharacter->m_AmmoCount = m_Core.m_Ninja.m_ActivationTick + g_pData->m_Weapons.m_Ninja.m_Duration * Server()->TickSpeed() / 1000; pCharacter->m_AmmoCount = m_Core.m_Ninja.m_ActivationTick + g_pData->m_Weapons.m_Ninja.m_Duration * Server()->TickSpeed() / 1000;
@ -1166,17 +1167,21 @@ void CCharacter::Snap(int SnappingClient)
pDDNetCharacter->m_TeleCheckpoint = m_TeleCheckpoint; pDDNetCharacter->m_TeleCheckpoint = m_TeleCheckpoint;
pDDNetCharacter->m_StrongWeakID = m_StrongWeakID; pDDNetCharacter->m_StrongWeakID = m_StrongWeakID;
CNetObj_DDNetCharacterDisplayInfo *pDDNetCharacterDisplayInfo = static_cast<CNetObj_DDNetCharacterDisplayInfo *>(Server()->SnapNewItem(NETOBJTYPE_DDNETCHARACTERDISPLAYINFO, ID, sizeof(CNetObj_DDNetCharacterDisplayInfo))); // Display Informations
if(!pDDNetCharacterDisplayInfo) pDDNetCharacter->m_JumpedTotal = m_Core.m_JumpedTotal;
return; pDDNetCharacter->m_NinjaActivationTick = m_Core.m_Ninja.m_ActivationTick;
pDDNetCharacterDisplayInfo->m_JumpedTotal = m_Core.m_JumpedTotal; pDDNetCharacter->m_FreezeStart = m_Core.m_FreezeStart;
pDDNetCharacterDisplayInfo->m_NinjaActivationTick = m_Core.m_Ninja.m_ActivationTick; if(m_Core.m_IsInFreeze)
pDDNetCharacterDisplayInfo->m_FreezeTick = m_Core.m_FreezeTick; {
pDDNetCharacterDisplayInfo->m_IsInFreeze = m_Core.m_IsInFreeze; pDDNetCharacter->m_Flags |= CHARACTERFLAG_IN_FREEZE;
pDDNetCharacterDisplayInfo->m_IsInPracticeMode = Teams()->IsPractice(Team()); }
pDDNetCharacterDisplayInfo->m_TargetX = m_Core.m_Input.m_TargetX; if(Teams()->IsPractice(Team()))
pDDNetCharacterDisplayInfo->m_TargetY = m_Core.m_Input.m_TargetY; {
pDDNetCharacterDisplayInfo->m_RampValue = round_to_int(VelocityRamp(length(m_Core.m_Vel) * 50, m_Core.m_Tuning.m_VelrampStart, m_Core.m_Tuning.m_VelrampRange, m_Core.m_Tuning.m_VelrampCurvature) * 1000.0f); pDDNetCharacter->m_Flags |= CHARACTERFLAG_PRACTICE_MODE;
}
pDDNetCharacter->m_TargetX = m_Core.m_Input.m_TargetX;
pDDNetCharacter->m_TargetY = m_Core.m_Input.m_TargetY;
pDDNetCharacter->m_RampValue = round_to_int(VelocityRamp(length(m_Core.m_Vel) * 50, m_Core.m_Tuning.m_VelrampStart, m_Core.m_Tuning.m_VelrampRange, m_Core.m_Tuning.m_VelrampCurvature) * 1000.0f);
} }
// DDRace // DDRace
@ -2207,11 +2212,11 @@ bool CCharacter::Freeze(int Seconds)
{ {
if((Seconds <= 0 || m_Super || m_FreezeTime == -1 || m_FreezeTime > Seconds * Server()->TickSpeed()) && Seconds != -1) if((Seconds <= 0 || m_Super || m_FreezeTime == -1 || m_FreezeTime > Seconds * Server()->TickSpeed()) && Seconds != -1)
return false; return false;
if(m_Core.m_FreezeTick < Server()->Tick() - Server()->TickSpeed() || Seconds == -1) if(m_Core.m_FreezeStart < Server()->Tick() - Server()->TickSpeed() || Seconds == -1)
{ {
m_Armor = 0; m_Armor = 0;
m_FreezeTime = Seconds == -1 ? Seconds : Seconds * Server()->TickSpeed(); m_FreezeTime = Seconds == -1 ? Seconds : Seconds * Server()->TickSpeed();
m_Core.m_FreezeTick = Server()->Tick(); m_Core.m_FreezeStart = Server()->Tick();
return true; return true;
} }
return false; return false;
@ -2230,7 +2235,7 @@ bool CCharacter::UnFreeze()
if(!m_Core.m_aWeapons[m_Core.m_ActiveWeapon].m_Got) if(!m_Core.m_aWeapons[m_Core.m_ActiveWeapon].m_Got)
m_Core.m_ActiveWeapon = WEAPON_GUN; m_Core.m_ActiveWeapon = WEAPON_GUN;
m_FreezeTime = 0; m_FreezeTime = 0;
m_Core.m_FreezeTick = 0; m_Core.m_FreezeStart = 0;
m_FrozenLastTick = true; m_FrozenLastTick = true;
return true; return true;
} }

View file

@ -38,7 +38,7 @@ void CSaveTee::Save(CCharacter *pChr)
m_Jetpack = pChr->m_Jetpack; m_Jetpack = pChr->m_Jetpack;
m_NinjaJetpack = pChr->m_NinjaJetpack; m_NinjaJetpack = pChr->m_NinjaJetpack;
m_FreezeTime = pChr->m_FreezeTime; m_FreezeTime = pChr->m_FreezeTime;
m_FreezeTick = pChr->Server()->Tick() - pChr->m_Core.m_FreezeTick; m_FreezeStart = pChr->Server()->Tick() - pChr->m_Core.m_FreezeStart;
m_DeepFreeze = pChr->m_DeepFreeze; m_DeepFreeze = pChr->m_DeepFreeze;
m_LiveFreeze = pChr->m_LiveFreeze; m_LiveFreeze = pChr->m_LiveFreeze;
@ -133,7 +133,7 @@ void CSaveTee::Load(CCharacter *pChr, int Team, bool IsSwap)
pChr->m_Jetpack = m_Jetpack; pChr->m_Jetpack = m_Jetpack;
pChr->m_NinjaJetpack = m_NinjaJetpack; pChr->m_NinjaJetpack = m_NinjaJetpack;
pChr->m_FreezeTime = m_FreezeTime; pChr->m_FreezeTime = m_FreezeTime;
pChr->m_Core.m_FreezeTick = pChr->Server()->Tick() - m_FreezeTick; pChr->m_Core.m_FreezeStart = pChr->Server()->Tick() - m_FreezeStart;
pChr->m_DeepFreeze = m_DeepFreeze; pChr->m_DeepFreeze = m_DeepFreeze;
pChr->m_LiveFreeze = m_LiveFreeze; pChr->m_LiveFreeze = m_LiveFreeze;
@ -269,7 +269,7 @@ char *CSaveTee::GetString(const CSaveTeam *pTeam)
m_aWeapons[5].m_AmmoRegenStart, m_aWeapons[5].m_Ammo, m_aWeapons[5].m_Ammocost, m_aWeapons[5].m_Got, m_aWeapons[5].m_AmmoRegenStart, m_aWeapons[5].m_Ammo, m_aWeapons[5].m_Ammocost, m_aWeapons[5].m_Got,
m_LastWeapon, m_QueuedWeapon, m_LastWeapon, m_QueuedWeapon,
// tee states // tee states
m_SuperJump, m_Jetpack, m_NinjaJetpack, m_FreezeTime, m_FreezeTick, m_DeepFreeze, m_EndlessHook, m_SuperJump, m_Jetpack, m_NinjaJetpack, m_FreezeTime, m_FreezeStart, m_DeepFreeze, m_EndlessHook,
m_DDRaceState, m_Hit, m_Collision, m_TuneZone, m_TuneZoneOld, m_Hook, m_Time, m_DDRaceState, m_Hit, m_Collision, m_TuneZone, m_TuneZoneOld, m_Hook, m_Time,
(int)m_Pos.x, (int)m_Pos.y, (int)m_PrevPos.x, (int)m_PrevPos.y, (int)m_Pos.x, (int)m_Pos.y, (int)m_PrevPos.x, (int)m_PrevPos.y,
m_TeleCheckpoint, m_LastPenalty, m_TeleCheckpoint, m_LastPenalty,
@ -342,7 +342,7 @@ int CSaveTee::FromString(const char *String)
&m_aWeapons[5].m_AmmoRegenStart, &m_aWeapons[5].m_Ammo, &m_aWeapons[5].m_Ammocost, &m_aWeapons[5].m_Got, &m_aWeapons[5].m_AmmoRegenStart, &m_aWeapons[5].m_Ammo, &m_aWeapons[5].m_Ammocost, &m_aWeapons[5].m_Got,
&m_LastWeapon, &m_QueuedWeapon, &m_LastWeapon, &m_QueuedWeapon,
// tee states // tee states
&m_SuperJump, &m_Jetpack, &m_NinjaJetpack, &m_FreezeTime, &m_FreezeTick, &m_DeepFreeze, &m_EndlessHook, &m_SuperJump, &m_Jetpack, &m_NinjaJetpack, &m_FreezeTime, &m_FreezeStart, &m_DeepFreeze, &m_EndlessHook,
&m_DDRaceState, &m_Hit, &m_Collision, &m_TuneZone, &m_TuneZoneOld, &m_Hook, &m_Time, &m_DDRaceState, &m_Hit, &m_Collision, &m_TuneZone, &m_TuneZoneOld, &m_Hook, &m_Time,
&m_Pos.x, &m_Pos.y, &m_PrevPos.x, &m_PrevPos.y, &m_Pos.x, &m_Pos.y, &m_PrevPos.x, &m_PrevPos.y,
&m_TeleCheckpoint, &m_LastPenalty, &m_TeleCheckpoint, &m_LastPenalty,

View file

@ -57,7 +57,7 @@ private:
int m_Jetpack; int m_Jetpack;
int m_NinjaJetpack; int m_NinjaJetpack;
int m_FreezeTime; int m_FreezeTime;
int m_FreezeTick; int m_FreezeStart;
int m_DeepFreeze; int m_DeepFreeze;
int m_LiveFreeze; int m_LiveFreeze;
int m_EndlessHook; int m_EndlessHook;