From aa3e381de9834f9ae1fcf1585ab65dc6fa22d89e Mon Sep 17 00:00:00 2001 From: TimePath Date: Fri, 25 Mar 2016 15:05:27 +1100 Subject: [PATCH] Fix PlayerState ownership Closes #1712 Closes #1715 --- qcsrc/common/items/inventory.qh | 20 +++++++++++++------- qcsrc/common/state.qc | 14 ++++++++------ qcsrc/lib/_all.inc | 23 ++++++++++++++++------- qcsrc/lib/oo.qh | 1 + qcsrc/server/_all.qh | 5 ++++- qcsrc/server/sv_main.qc | 6 +++--- 6 files changed, 45 insertions(+), 24 deletions(-) diff --git a/qcsrc/common/items/inventory.qh b/qcsrc/common/items/inventory.qh index 7780a0054..96c7319b7 100644 --- a/qcsrc/common/items/inventory.qh +++ b/qcsrc/common/items/inventory.qh @@ -4,11 +4,14 @@ #include "all.qh" #include "item/pickup.qh" -entityclass(Inventory); -/** Stores counts of items, the id being the index */ -class(Inventory) .int inv_items[Items_MAX]; +CLASS(Inventory, Object) + /** Stores counts of items, the id being the index */ + ATTRIBARRAY(Inventory, inv_items, int, Items_MAX) + /** Previous state */ + ATTRIB(Inventory, inventory, Inventory, NULL) +ENDCLASS(Inventory) -/** Player inventory; Inventories also have one inventory for storing the previous state */ +/** Player inventory */ .Inventory inventory; REGISTER_NET_LINKED(ENT_CLIENT_INVENTORY) @@ -31,6 +34,7 @@ NET_HANDLE(ENT_CLIENT_INVENTORY, bool isnew) #ifdef SVQC void Inventory_Write(Inventory data) { + TC(Inventory, data); int bits = 0; FOREACH(Items, true, { .int fld = inv_items[it.m_id]; @@ -44,11 +48,13 @@ void Inventory_Write(Inventory data) #endif #ifdef SVQC -bool Inventory_Send(entity this, entity to, int sf) +bool Inventory_Send(Inventory this, Client to, int sf) { + TC(Inventory, this); WriteHeader(MSG_ENTITY, ENT_CLIENT_INVENTORY); - entity e = self.owner; + entity e = this.owner; if (IS_SPEC(e)) e = e.enemy; + TC(Player, e); Inventory data = e.inventory; Inventory_Write(data); return true; @@ -56,7 +62,7 @@ bool Inventory_Send(entity this, entity to, int sf) void Inventory_new(entity e) { - Inventory inv = new_pure(Inventory), bak = new_pure(Inventory); + Inventory inv = NEW(Inventory), bak = NEW(Inventory); inv.inventory = bak; inv.drawonlytoclient = e; Net_LinkEntity((inv.owner = e).inventory = inv, false, 0, Inventory_Send); diff --git a/qcsrc/common/state.qc b/qcsrc/common/state.qc index 21e009022..d75e08027 100644 --- a/qcsrc/common/state.qc +++ b/qcsrc/common/state.qc @@ -12,12 +12,14 @@ void PlayerState_attach(entity this) void PlayerState_detach(entity this) { - if (!PS(this)) return; // initial connect - FOREACH_CLIENT(PS(it) == PS(this), { PS(it) = NULL; }); - remove(PS(this)); - this._ps = NULL; - - Inventory_delete(self); + PlayerState ps = PS(this); + if (!ps) return; // initial connect + PS(this) = NULL; + if (ps.m_client != this) return; // don't own state, spectator + FOREACH_CLIENT(PS(it) == ps, { PS(it) = NULL; }); + remove(ps); + + Inventory_delete(this); } void GetCvars(entity this, int); diff --git a/qcsrc/lib/_all.inc b/qcsrc/lib/_all.inc index 6f88d9067..0fee57ec1 100644 --- a/qcsrc/lib/_all.inc +++ b/qcsrc/lib/_all.inc @@ -36,16 +36,25 @@ #define TC(T, sym) MACRO_BEGIN MACRO_END #else #define TC(T, sym) MACRO_BEGIN \ - if (!is_##T(sym)) LOG_WARNINGF("Type check failed: " #sym " :: " #T); \ + if (!is_##T(sym)) { \ + LOG_WARNINGF("Type check failed: " #sym " :: " #T); \ + isnt_##T(sym); \ + } \ MACRO_END #endif -bool is_float (float this) { return true; } -bool is_vector(vector this) { return true; } -bool is_string(string this) { return true; } -bool is_entity(entity this) { return true; } -bool is_int (float this) { return this == floor(this); } -bool is_bool (float this) { return this == true || this == false; } +#define is_float( this) (true || ftoe(this)) +#define isnt_float( this) +#define is_vector( this) (true || vtos(this)) +#define isnt_vector( this) +#define is_string( this) (true || stof(this)) +#define isnt_string( this) +#define is_entity( this) (true || etof(this)) +#define isnt_entity( this) +bool is_int( float this) { return this == floor(this); } +void isnt_int( float this) { print(ftos(this)); } +bool is_bool( float this) { return this == true || this == false; } +void isnt_bool( float this) { print(ftos(this)); } #include "warpzone/mathlib.qc" diff --git a/qcsrc/lib/oo.qh b/qcsrc/lib/oo.qh index b2b1419ab..e1e319330 100644 --- a/qcsrc/lib/oo.qh +++ b/qcsrc/lib/oo.qh @@ -175,6 +175,7 @@ STATIC_INIT(RegisterClasses) entityclass(cname, base); \ class(cname).bool instanceOf##cname; \ bool is_##cname(entity e) { return e.instanceOf##cname; } \ + void isnt_##cname(entity e) { eprint(e); } \ VTBL(cname, base) \ _INIT_STATIC(cname) \ { \ diff --git a/qcsrc/server/_all.qh b/qcsrc/server/_all.qh index c43605435..a32f8b583 100644 --- a/qcsrc/server/_all.qh +++ b/qcsrc/server/_all.qh @@ -11,9 +11,12 @@ const string STR_OBSERVER = "observer"; #define IS_OBSERVER(v) ((v).classname == STR_OBSERVER) #define IS_CLIENT(v) (v.flags & FL_CLIENT) +/** want: (IS_CLIENT(v) && !IS_REAL_CLIENT(v)) */ #define IS_BOT_CLIENT(v) (clienttype(v) == CLIENTTYPE_BOT) +#define IS_FAKE_CLIENT(v) (clienttype(v) == CLIENTTYPE_NOTACLIENT) #define IS_REAL_CLIENT(v) (clienttype(v) == CLIENTTYPE_REAL) -#define IS_NOT_A_CLIENT(v) (clienttype(v) == CLIENTTYPE_NOTACLIENT) +/** was: (clienttype(v) == CLIENTTYPE_NOTACLIENT) */ +#define IS_NOT_A_CLIENT(v) (!IS_CLIENT(v)) #define IS_MONSTER(v) (v.flags & FL_MONSTER) #define IS_VEHICLE(v) (v.vehicle_flags & VHF_ISVEHICLE) diff --git a/qcsrc/server/sv_main.qc b/qcsrc/server/sv_main.qc index 792885070..df1e1e612 100644 --- a/qcsrc/server/sv_main.qc +++ b/qcsrc/server/sv_main.qc @@ -158,8 +158,8 @@ void PM_Main(Client this); void StartFrame() { // TODO: if move is more than 50ms, split it into two moves (this matches QWSV behavior and the client prediction) - FOREACH_ENTITY_CLASS(STR_PLAYER, IS_NOT_A_CLIENT(it), PM_Main(it)); - FOREACH_ENTITY_CLASS(STR_PLAYER, IS_NOT_A_CLIENT(it), WITH(entity, self, it, PlayerPreThink())); + FOREACH_ENTITY_CLASS(STR_PLAYER, IS_FAKE_CLIENT(it), PM_Main(it)); + FOREACH_ENTITY_CLASS(STR_PLAYER, IS_FAKE_CLIENT(it), WITH(entity, self, it, PlayerPreThink())); execute_next_frame(); if (autocvar_sv_autopause && !server_is_dedicated) Pause_TryPause(true); @@ -231,7 +231,7 @@ void StartFrame() MUTATOR_CALLHOOK(SV_StartFrame); FOREACH_CLIENT(true, LAMBDA(GlobalStats_update(it))); - FOREACH_ENTITY_CLASS(STR_PLAYER, IS_NOT_A_CLIENT(it), WITH(entity, self, it, PlayerPostThink())); + FOREACH_ENTITY_CLASS(STR_PLAYER, IS_FAKE_CLIENT(it), WITH(entity, self, it, PlayerPostThink())); } .vector originjitter; -- 2.39.2