#pragma once /** * Purpose: common player state, usable on client and server * Client: singleton representing the viewed player * Server: instance per client, clients decoupled from players */ CLASS(PlayerState, Object) ATTRIB(PlayerState, m_client, entity, NULL) CONSTRUCTOR(PlayerState, entity client) { CONSTRUCT(PlayerState); this.m_client = client; } ATTRIB(PlayerState, m_switchingweapon, Weapon, Weapons_from(-1)) ATTRIB(PlayerState, m_switchweapon, Weapon, Weapons_from(-1)) ATTRIB(PlayerState, m_weapon, Weapon, Weapons_from(-1)) METHOD(PlayerState, ps_push, void(PlayerState this, entity cl)) { STAT(ACTIVEWEAPON, cl) = this.m_weapon.m_id; STAT(SWITCHINGWEAPON, cl) = this.m_switchingweapon.m_id; STAT(SWITCHWEAPON, cl) = this.m_switchweapon.m_id; } ENDCLASS(PlayerState) .PlayerState _ps; #if NDEBUG #define PS(this) (this._ps) #else PlayerState PS(entity this) { assert(IS_CLIENT(this)); return this._ps; } #endif void Inventory_new(entity this); void Inventory_delete(entity this); // TODO: renew on death void PlayerState_attach(entity this) { this._ps = NEW(PlayerState, this); Inventory_new(this); } void PlayerState_detach(entity this) { if (!PS(this)) return; // initial connect remove(PS(this)); this._ps = NULL; Inventory_delete(self); } /** * Purpose: common client state, usable on client and server * Client: singleton representing the viewed player * Server: instance per client */ CLASS(ClientState, Object) ATTRIB(ClientState, m_client, entity, NULL) CONSTRUCTOR(ClientState, entity client) { CONSTRUCT(ClientState); this.m_client = client; } ENDCLASS(ClientState) .ClientState _cs; #if NDEBUG #define CS(this) (this._cs) #else ClientState CS(entity this) { assert(IS_CLIENT(this)); assert(this._cs); return this._cs; } #endif void GetCvars(int); void DecodeLevelParms(entity this); void PlayerScore_Attach(entity this); void ClientData_Attach(entity this); void accuracy_init(entity this); void entcs_attach(entity this); void playerdemo_init(entity this); void anticheat_init(entity this); void W_HitPlotOpen(entity this); void bot_clientconnect(entity this); void ClientState_attach(entity this) { this._cs = NEW(ClientState, this); GetCvars(0); // get other cvars from player // TODO: xonstat elo.txt support, until then just 404s if (false && IS_REAL_CLIENT(this)) { PlayerStats_PlayerBasic_CheckUpdate(this); } // TODO: fold all of these into ClientState DecodeLevelParms(this); PlayerScore_Attach(this); ClientData_Attach(this); accuracy_init(this); entcs_attach(this); playerdemo_init(this); anticheat_init(this); W_HitPlotOpen(this); bot_clientconnect(this); } void bot_clientdisconnect(); void W_HitPlotClose(entity this); void anticheat_report(); void playerdemo_shutdown(); void entcs_detach(entity this); void accuracy_free(entity this); void ClientData_Detach(entity this); void PlayerScore_Detach(entity this); void ClientState_detach(entity this) { remove(CS(this)); this._cs = NULL; GetCvars(-1); // free cvars bot_clientdisconnect(); W_HitPlotClose(this); anticheat_report(); playerdemo_shutdown(); entcs_detach(this); accuracy_free(self); ClientData_Detach(this); PlayerScore_Detach(self); }