1904: Add tune zone prediction r=heinrich5991 a=trml

Is enabled with cl_predict_ddrace 1.

This will predict tunings loaded from the map the first time tunezones are entered, but will also update the tunes after you receive new tunes while in a tunezone, since it's possible to change them in rcon.

Co-authored-by: trml <trml@users.noreply.github.com>
This commit is contained in:
bors[bot] 2019-09-17 13:50:18 +00:00 committed by GitHub
commit 1bf178614f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 142 additions and 28 deletions

View file

@ -331,7 +331,7 @@ MACRO_CONFIG_STR(SvConnLoggingServer, sv_conn_logging_server, 128, "", CFGFLAG_S
#endif
MACRO_CONFIG_INT(ClUnpredictedShadow, cl_unpredicted_shadow, 0, 0, 1, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Show unpredicted shadow tee to estimate your delay")
MACRO_CONFIG_INT(ClPredictDDRace, cl_predict_ddrace, 1, 0, 1, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Predict some DDRace tiles")
MACRO_CONFIG_INT(ClPredictDDRace, cl_predict_ddrace, 1, 0, 1, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Predict DDRace tiles and tunezones")
MACRO_CONFIG_INT(ClPredictFreeze, cl_predict_freeze, 1, 0, 2, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Predict freeze tiles (0 = off, 1 = on, 2 = partial (allow a small amount of movement in freeze)")
MACRO_CONFIG_INT(ClShowNinja, cl_show_ninja, 1, 0, 1, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Show ninja skin")
MACRO_CONFIG_INT(ClShowHookCollOther, cl_show_hook_coll_other, 1, 0, 1, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Show other players' hook collision line")

View file

@ -239,6 +239,8 @@ void CGameClient::OnConsoleInit()
Console()->Register("swap_teams", "", CFGFLAG_SERVER, 0, 0, "Swap the current teams");
Console()->Register("shuffle_teams", "", CFGFLAG_SERVER, 0, 0, "Shuffle the current teams");
// register tune zone command to allow the client prediction to load tunezones from the map
Console()->Register("tune_zone", "i[zone] s[tuning] i[value]", CFGFLAG_CLIENT|CFGFLAG_GAME, ConTuneZone, this, "Tune in zone a variable to value");
for(int i = 0; i < m_All.m_Num; i++)
m_All.m_paComponents[i]->m_pClient = this;
@ -350,6 +352,7 @@ void CGameClient::OnInit()
m_GameWorld.m_GameTickSpeed = SERVER_TICK_SPEED;
m_GameWorld.m_pCollision = Collision();
m_GameWorld.m_pTuningList = m_aTuningList;
m_pMapimages->SetTextureScale(g_Config.m_ClTextEntitiesSize);
}
@ -488,6 +491,7 @@ void CGameClient::OnConnected()
m_GameWorld.m_WorldConfig.m_InfiniteAmmo = true;
for(int i = 0; i < MAX_CLIENTS; i++)
m_aLastWorldCharacters[i].m_Alive = false;
LoadMapSettings();
}
void CGameClient::OnReset()
@ -2003,7 +2007,12 @@ void CGameClient::UpdatePrediction()
m_GameWorld.m_WorldConfig.m_InfiniteAmmo = false;
m_GameWorld.m_WorldConfig.m_IsSolo = !m_Snap.m_aCharacters[m_Snap.m_LocalClientID].m_HasExtendedData && !m_Tuning[g_Config.m_ClDummy].m_PlayerCollision && !m_Tuning[g_Config.m_ClDummy].m_PlayerHooking;
m_GameWorld.m_Core.m_Tuning[g_Config.m_ClDummy] = m_Tuning[g_Config.m_ClDummy];
// update the tuning/tunezone at the local character position with the latest tunings received before the new snapshot
int TuneZone = Collision()->IsTune(Collision()->GetMapIndex(vec2(m_Snap.m_pLocalCharacter->m_X, m_Snap.m_pLocalCharacter->m_Y)));
if(!TuneZone || !m_GameWorld.m_WorldConfig.m_PredictTiles)
m_GameWorld.m_Tuning[g_Config.m_ClDummy] = m_Tuning[g_Config.m_ClDummy];
else
m_GameWorld.TuningList()[TuneZone] = m_GameWorld.m_Core.m_Tuning[g_Config.m_ClDummy] = m_Tuning[g_Config.m_ClDummy];
// restore characters from previously saved ones if they temporarily left the snapshot
for(int i = 0; i < MAX_CLIENTS; i++)
@ -2303,3 +2312,60 @@ bool CGameClient::IsOtherTeam(int ClientID)
return m_Teams.Team(ClientID) != m_Teams.Team(m_Snap.m_LocalClientID);
}
void CGameClient::LoadMapSettings()
{
// Reset Tunezones
CTuningParams TuningParams;
for(int i = 0; i < NUM_TUNEZONES; i++)
{
TuningList()[i] = TuningParams;
TuningList()[i].Set("gun_curvature", 0);
TuningList()[i].Set("gun_speed", 1400);
TuningList()[i].Set("shotgun_curvature", 0);
TuningList()[i].Set("shotgun_speed", 500);
TuningList()[i].Set("shotgun_speeddiff", 0);
}
// Load map tunings
IMap *pMap = Kernel()->RequestInterface<IMap>();
int Start, Num;
pMap->GetType(MAPITEMTYPE_INFO, &Start, &Num);
for(int i = Start; i < Start + Num; i++)
{
int ItemID;
CMapItemInfoSettings *pItem = (CMapItemInfoSettings *)pMap->GetItem(i, 0, &ItemID);
int ItemSize = pMap->GetItemSize(i);
if(!pItem || ItemID != 0)
continue;
if(ItemSize < (int)sizeof(CMapItemInfoSettings))
break;
if(!(pItem->m_Settings > -1))
break;
int Size = pMap->GetDataSize(pItem->m_Settings);
char *pSettings = (char *)pMap->GetData(pItem->m_Settings);
char *pNext = pSettings;
dbg_msg("New tune ","%s", pNext);
while(pNext < pSettings + Size)
{
int StrSize = str_length(pNext) + 1;
Console()->ExecuteLine(pNext, IConsole::CLIENT_ID_GAME);
pNext += StrSize;
}
pMap->UnloadData(pItem->m_Settings);
break;
}
}
void CGameClient::ConTuneZone(IConsole::IResult *pResult, void *pUserData)
{
CGameClient *pSelf = (CGameClient *)pUserData;
int List = pResult->GetInteger(0);
const char *pParamName = pResult->GetString(1);
float NewValue = pResult->GetFloat(2);
if(List >= 0 && List < NUM_TUNEZONES)
pSelf->TuningList()[List].Set(pParamName, NewValue);
}

View file

@ -154,6 +154,8 @@ class CGameClient : public IGameClient
static void ConchainSpecialDummy(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
static void ConchainClTextEntitiesSize(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
static void ConTuneZone(IConsole::IResult *pResult, void *pUserData);
public:
IKernel *Kernel() { return IInterface::Kernel(); }
IEngine *Engine() const { return m_pEngine; }
@ -467,6 +469,14 @@ private:
CCharOrder m_CharOrder;
class CCharacter m_aLastWorldCharacters[MAX_CLIENTS];
enum
{
NUM_TUNEZONES = 256
};
void LoadMapSettings();
CTuningParams m_aTuningList[NUM_TUNEZONES];
CTuningParams *TuningList() { return &m_aTuningList[0]; }
};
ColorRGBA CalculateNameColor(ColorHSLA TextColorHSL);

View file

@ -87,7 +87,9 @@ void CCharacter::HandleJetpack()
{
if (m_Jetpack)
{
float Strength = m_LastJetpackStrength;
float Strength = GetTuning(m_TuneZone)->m_JetpackStrength;
if(!m_TuneZone)
Strength = m_LastJetpackStrength;
TakeDamage(Direction * -1.0f * (Strength / 100.0f / 6.11f), g_pData->m_Weapons.m_Hammer.m_pBase->m_Damage, GetCID(), m_Core.m_ActiveWeapon);
}
}
@ -324,7 +326,7 @@ void CCharacter::FireWeapon()
else
Dir = vec2(0.f, -1.f);
float Strength = Tuning()->m_HammerStrength;
float Strength = GetTuning(m_TuneZone)->m_HammerStrength;
vec2 Temp = pTarget->m_Core.m_Vel + normalize(Dir + vec2(0.f, -1.1f)) * 10.0f;
pTarget->Core()->LimitForce(&Temp);
@ -365,8 +367,8 @@ void CCharacter::FireWeapon()
{
if (!m_Jetpack)
{
int Lifetime;
Lifetime = (int)(GameWorld()->GameTickSpeed()*Tuning()->m_GunLifetime);
int Lifetime = (int)(GameWorld()->GameTickSpeed()*GetTuning(m_TuneZone)->m_GunLifetime);
new CProjectile
(
GameWorld(),
@ -388,7 +390,6 @@ void CCharacter::FireWeapon()
{
if(GameWorld()->m_WorldConfig.m_IsVanilla)
{
int ShotSpread = 2;
for(int i = -ShotSpread; i <= ShotSpread; ++i)
{
@ -396,7 +397,7 @@ void CCharacter::FireWeapon()
float a = GetAngle(Direction);
a += Spreading[i+2];
float v = 1-(absolute(i)/(float)ShotSpread);
float Speed = mix((float)GameWorld()->Tuning()->m_ShotgunSpeeddiff, 1.0f, v);
float Speed = mix((float)Tuning()->m_ShotgunSpeeddiff, 1.0f, v);
new CProjectile
(
GameWorld(),
@ -404,7 +405,7 @@ void CCharacter::FireWeapon()
GetCID(),//Owner
ProjStartPos,//Pos
vec2(cosf(a), sinf(a))*Speed,//Dir
(int)(GameWorld()->GameTickSpeed()*GameWorld()->Tuning()->m_ShotgunLifetime),//Span
(int)(GameWorld()->GameTickSpeed()*Tuning()->m_ShotgunLifetime),//Span
0,//Freeze
0,//Explosive
0,//Force
@ -415,14 +416,16 @@ void CCharacter::FireWeapon()
}
else if(GameWorld()->m_WorldConfig.m_IsDDRace)
{
float LaserReach = Tuning()->m_LaserReach;
float LaserReach = GetTuning(m_TuneZone)->m_LaserReach;
new CLaser(GameWorld(), m_Pos, Direction, LaserReach, GetCID(), WEAPON_SHOTGUN);
}
} break;
case WEAPON_GRENADE:
{
int Lifetime = (int)(GameWorld()->GameTickSpeed()*Tuning()->m_GrenadeLifetime);
int Lifetime = (int)(GameWorld()->GameTickSpeed()*GetTuning(m_TuneZone)->m_GrenadeLifetime);
new CProjectile
(
GameWorld(),
@ -441,7 +444,8 @@ void CCharacter::FireWeapon()
case WEAPON_RIFLE:
{
float LaserReach = Tuning()->m_LaserReach;
float LaserReach = GetTuning(m_TuneZone)->m_LaserReach;
new CLaser(GameWorld(), m_Pos, Direction, LaserReach, GetCID(), WEAPON_RIFLE);
} break;
@ -462,7 +466,8 @@ void CCharacter::FireWeapon()
if(!m_ReloadTimer)
{
float FireDelay;
Tuning()->Get(38 + m_Core.m_ActiveWeapon, &FireDelay);
GetTuning(m_TuneZone)->Get(38 + m_Core.m_ActiveWeapon, &FireDelay);
m_ReloadTimer = FireDelay * GameWorld()->GameTickSpeed() / 1000;
}
}
@ -886,6 +891,14 @@ void CCharacter::HandleTiles(int Index)
}
}
void CCharacter::HandleTuneLayer()
{
int CurrentIndex = Collision()->GetMapIndex(m_Pos);
m_TuneZone = GameWorld()->m_WorldConfig.m_PredictTiles ? Collision()->IsTune(CurrentIndex) : 0;
m_Core.m_pWorld->m_Tuning[g_Config.m_ClDummy] = *GetTuning(m_TuneZone); // throw tunings (from specific zone if in a tunezone) into gamecore
}
void CCharacter::DDRaceTick()
{
mem_copy(&m_Input, &m_SavedInput, sizeof(m_Input));
@ -904,6 +917,8 @@ void CCharacter::DDRaceTick()
if (m_FreezeTime == 1)
UnFreeze();
}
HandleTuneLayer();
}
void CCharacter::DDRacePostCoreTick()
@ -1185,6 +1200,8 @@ void CCharacter::Read(CNetObj_Character *pChar, CNetObj_DDNetCharacter *pExtende
m_LastSnapWeapon = pChar->m_Weapon;
m_Alive = true;
m_TuneZone = GameWorld()->m_WorldConfig.m_PredictTiles ? Collision()->IsTune(Collision()->GetMapIndex(m_Pos)) : 0;
// set the current weapon
if(pChar->m_Weapon != WEAPON_NINJA)
{

View file

@ -88,6 +88,7 @@ public:
DISABLE_HIT_RIFLE=8
};
int m_Hit;
int m_TuneZone;
vec2 m_PrevPos;
vec2 m_PrevPrevPos;
int m_TeleCheckpoint;
@ -207,6 +208,7 @@ private:
void HandleSkippableTiles(int Index);
void DDRaceTick();
void DDRacePostCoreTick();
void HandleTuneLayer();
int m_StrongWeakID;
};

View file

@ -20,6 +20,7 @@ CLaser::CLaser(CGameWorld *pGameWorld, vec2 Pos, vec2 Direction, float StartEner
m_TelePos = vec2(0,0);
m_WasTele = false;
m_Type = Type;
m_TuneZone = GameWorld()->m_WorldConfig.m_PredictTiles ? Collision()->IsTune(Collision()->GetMapIndex(m_Pos)) : 0;
GameWorld()->InsertEntity(this);
DoBounce();
}
@ -45,7 +46,7 @@ bool CLaser::HitCharacter(vec2 From, vec2 To)
{
vec2 Temp;
float Strength = GameWorld()->Tuning()->m_ShotgunStrength;;
float Strength = GetTuning(m_TuneZone)->m_ShotgunStrength;
if(!g_Config.m_SvOldLaser)
Temp = pHit->Core()->m_Vel + normalize(m_PrevPos - pHit->Core()->m_Pos) * Strength;
@ -119,12 +120,12 @@ void CLaser::DoBounce()
m_Pos = TempPos;
m_Dir = normalize(TempDir);
m_Energy -= distance(m_From, m_Pos) + GameWorld()->Tuning()->m_LaserBounceCost;
m_Energy -= distance(m_From, m_Pos) + GetTuning(m_TuneZone)->m_LaserBounceCost;
m_Bounces++;
m_WasTele = false;
int BounceNum = GameWorld()->Tuning()->m_LaserBounceNum;
int BounceNum = GetTuning(m_TuneZone)->m_LaserBounceNum;
if(m_Bounces > BounceNum)
m_Energy = -1;
@ -143,7 +144,7 @@ void CLaser::DoBounce()
void CLaser::Tick()
{
float Delay = GameWorld()->Tuning()->m_LaserBounceDelay;
float Delay = GetTuning(m_TuneZone)->m_LaserBounceDelay;
if(GameWorld()->m_WorldConfig.m_IsVanilla) // predict old physics on vanilla 0.6 servers
{
@ -165,8 +166,9 @@ CLaser::CLaser(CGameWorld *pGameWorld, int ID, CNetObj_Laser *pLaser)
m_From.x = pLaser->m_FromX;
m_From.y = pLaser->m_FromY;
m_EvalTick = pLaser->m_StartTick;
m_TuneZone = GameWorld()->m_WorldConfig.m_PredictTiles ? Collision()->IsTune(Collision()->GetMapIndex(m_Pos)) : 0;
m_Owner = -2;
m_Energy = pGameWorld->Tuning()->m_LaserReach;
m_Energy = GetTuning(m_TuneZone)->m_LaserReach;
if(pGameWorld->m_WorldConfig.m_IsFNG && m_Energy < 10.f)
m_Energy = 800.0f;

View file

@ -38,6 +38,7 @@ private:
vec2 m_PrevPos;
int m_Type;
int m_TuneZone;
};
#endif

View file

@ -38,6 +38,8 @@ CProjectile::CProjectile
m_Number = Number;
m_Freeze = Freeze;
m_TuneZone = GameWorld()->m_WorldConfig.m_PredictTiles ? Collision()->IsTune(Collision()->GetMapIndex(m_Pos)) : 0;
GameWorld()->InsertEntity(this);
}
@ -45,22 +47,23 @@ vec2 CProjectile::GetPos(float Time)
{
float Curvature = 0;
float Speed = 0;
CTuningParams *pTuning = GetTuning(m_TuneZone);
switch(m_Type)
{
case WEAPON_GRENADE:
Curvature = Tuning()->m_GrenadeCurvature;
Speed = Tuning()->m_GrenadeSpeed;
Curvature = pTuning->m_GrenadeCurvature;
Speed = pTuning->m_GrenadeSpeed;
break;
case WEAPON_SHOTGUN:
Curvature = Tuning()->m_ShotgunCurvature;
Speed = Tuning()->m_ShotgunSpeed;
Curvature = pTuning->m_ShotgunCurvature;
Speed = pTuning->m_ShotgunSpeed;
break;
case WEAPON_GUN:
Curvature = Tuning()->m_GunCurvature;
Speed = Tuning()->m_GunSpeed;
Curvature = pTuning->m_GunCurvature;
Speed = pTuning->m_GunSpeed;
break;
}
@ -169,18 +172,19 @@ CProjectile::CProjectile(CGameWorld *pGameWorld, int ID, CNetObj_Projectile *pPr
}
m_Type = m_Weapon = pProj->m_Type;
m_StartTick = pProj->m_StartTick;
m_TuneZone = GameWorld()->m_WorldConfig.m_PredictTiles ? Collision()->IsTune(Collision()->GetMapIndex(m_Pos)) : 0;
int Lifetime = 20 * GameWorld()->GameTickSpeed();
m_SoundImpact = -1;
if(m_Weapon == WEAPON_GRENADE)
{
Lifetime = pGameWorld->Tuning()->m_GrenadeLifetime * GameWorld()->GameTickSpeed();
Lifetime = GetTuning(m_TuneZone)->m_GrenadeLifetime * GameWorld()->GameTickSpeed();
m_SoundImpact = SOUND_GRENADE_EXPLODE;
}
else if(m_Weapon == WEAPON_GUN)
Lifetime = pGameWorld->Tuning()->m_GunLifetime * GameWorld()->GameTickSpeed();
Lifetime = GetTuning(m_TuneZone)->m_GunLifetime * GameWorld()->GameTickSpeed();
else if(m_Weapon == WEAPON_SHOTGUN && !GameWorld()->m_WorldConfig.m_IsDDRace)
Lifetime = pGameWorld->Tuning()->m_ShotgunLifetime * GameWorld()->GameTickSpeed();
Lifetime = GetTuning(m_TuneZone)->m_ShotgunLifetime * GameWorld()->GameTickSpeed();
m_LifeSpan = Lifetime - (pGameWorld->GameTick() - m_StartTick);
m_ID = ID;
}

View file

@ -59,6 +59,7 @@ private:
int m_Bouncing;
bool m_Freeze;
int m_TuneZone;
};
#endif

View file

@ -40,6 +40,8 @@ public:
class CGameWorld *GameWorld() { return m_pGameWorld; }
CTuningParams *Tuning() { return GameWorld()->Tuning(); }
CTuningParams *TuningList() { return GameWorld()->TuningList(); }
CTuningParams *GetTuning(int i) { return GameWorld()->GetTuning(i); }
class CCollision *Collision() { return GameWorld()->Collision(); }
CEntity *TypeNext() { return m_pNextTypeEntity; }
CEntity *TypePrev() { return m_pPrevTypeEntity; }

View file

@ -281,7 +281,7 @@ void CGameWorld::ReleaseHooked(int ClientID)
CTuningParams *CGameWorld::Tuning()
{
return &m_Core.m_Tuning[g_Config.m_ClDummy];
return &m_Tuning[g_Config.m_ClDummy];
}
CEntity *CGameWorld::GetEntity(int ID, int EntType)
@ -518,7 +518,11 @@ void CGameWorld::CopyWorld(CGameWorld *pFrom)
m_pCollision = pFrom->m_pCollision;
m_WorldConfig = pFrom->m_WorldConfig;
for(int i = 0; i < 2; i++)
{
m_Core.m_Tuning[i] = pFrom->m_Core.m_Tuning[i];
m_Tuning[i] = pFrom->m_Tuning[i];
}
m_pTuningList = pFrom->m_pTuningList;
m_Teams = pFrom->m_Teams;
// delete the previous entities
for(int i = 0; i < NUM_ENTTYPES; i++)

View file

@ -88,6 +88,11 @@ public:
CEntity *FindMatch(int ObjID, int ObjType, const void *pObjData);
void Clear();
CTuningParams m_Tuning[2];
CTuningParams *m_pTuningList;
CTuningParams *TuningList() { return m_pTuningList; }
CTuningParams *GetTuning(int i) { return i == 0 ? Tuning() : &TuningList()[i]; }
private:
void RemoveEntities();