]> git.rm.cloudns.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Experimental port of stats (networked variables) to QC
authorMario <mario.mario@y7mail.com>
Mon, 25 May 2020 10:05:57 +0000 (20:05 +1000)
committerMario <mario.mario@y7mail.com>
Mon, 25 May 2020 10:05:57 +0000 (20:05 +1000)
qcsrc/client/hud/panel/ammo.qc
qcsrc/client/hud/panel/healtharmor.qc
qcsrc/client/hud/panel/weapons.qc
qcsrc/client/view.qc
qcsrc/common/state.qc
qcsrc/common/stats.qh
qcsrc/common/weapons/all.qc
qcsrc/dpdefs/csprogsdefs.qh
qcsrc/lib/stats.qh

index 5abbbf036bc4e2c9b1dae289c8595f83fec6e7d0..8ae792e7f02641336b2d96106aab4220e1c2a092 100644 (file)
@@ -48,7 +48,7 @@ void DrawAmmoItem(vector myPos, vector mySize, int ammoType, bool isCurrent, boo
                ammo = 60;
        }
        else
-               ammo = getstati(GetAmmoStat(ammoType));
+               ammo = GetAmmoStat(ammoType);
 
        if(!isCurrent)
        {
index b1a9311939e33ea9f368f15baef17a441045331f..ecf4d20aa3b8b165e705be0cdbd77e81835b224d 100644 (file)
@@ -229,7 +229,7 @@ void HUD_HealthArmor()
                                HUD_Panel_DrawProgressBar(pos + health_offset, mySize, autocvar_hud_panel_healtharmor_progressbar_health, p_health/maxhealth, is_vertical, health_baralign, autocvar_hud_progressbar_health_color, autocvar_hud_progressbar_alpha * panel_fg_alpha * pain_health_alpha, DRAWFLAG_NORMAL);
                        }
                        if(autocvar_hud_panel_healtharmor_text)
-                               DrawNumIcon(pos + health_offset, mySize, health, "health", is_vertical, health_iconalign, HUD_Get_Num_Color(health, maxhealth), 1);
+                               DrawNumIcon(pos + health_offset, mySize, floor(health), "health", is_vertical, health_iconalign, HUD_Get_Num_Color(health, maxhealth), 1);
                }
 
                //if(armor)
@@ -276,7 +276,7 @@ void HUD_HealthArmor()
                        }
                        if(!autocvar_hud_panel_healtharmor_progressbar || p_armor)
                        if(autocvar_hud_panel_healtharmor_text)
-                               DrawNumIcon(pos + armor_offset, mySize, armor, "armor", is_vertical, armor_iconalign, HUD_Get_Num_Color(armor, maxarmor), 1);
+                               DrawNumIcon(pos + armor_offset, mySize, floor(armor), "armor", is_vertical, armor_iconalign, HUD_Get_Num_Color(armor, maxarmor), 1);
                }
 
                vector cell_size = mySize;
index f7444daaa3572cd063eaa62f454430f8ef353db0..fc8250ee7ca6890e8b08553a62a5631d69f475ac 100644 (file)
@@ -531,7 +531,7 @@ void HUD_Weapons()
                        if(!infinite_ammo && autocvar_hud_panel_weapons_ammo && (it.ammo_type != RES_NONE))
                        {
                                float ammo_full;
-                               a = getstati(GetAmmoStat(it.ammo_type)); // how much ammo do we have?
+                               a = floor(GetAmmoStat(it.ammo_type)); // how much ammo do we have?
 
                                if(a > 0)
                                {
index 57cd15a78bd7fd68cac6454b13232d56a4b1d1c4..5042515ee2720cc286bf39c0643d8cb2b59f049f 100644 (file)
@@ -2300,7 +2300,6 @@ void CSQC_UpdateView(entity this, float w, float h)
 
        ++framecount;
 
-       stats_get();
        hud = STAT(HUD);
 
        ReplicateVars(false);
index 14b22e991cceed2ad0bccdd2222ee899fbcab040..a61047549bb21af2a62ce7a8afcf2d017f1110f3 100644 (file)
@@ -52,6 +52,7 @@ void ClientState_attach(entity this)
        entcs_attach(this);
        anticheat_init(this);
        W_HitPlotOpen(this);
+       Stats_new(this);
 }
 
 void bot_clientdisconnect(entity this);
@@ -72,6 +73,7 @@ void ClientState_detach(entity this)
     entcs_detach(this);
        delete(CS(this));
        this._cs = NULL;
+       Stats_delete(this);
 
     bot_clientdisconnect(this);
 
index c77ca16be2a432043f0d8808fa1506b25b0d3a7d..4489328b3ae92db2b27f103e7dcf9b21e8e812e5 100644 (file)
@@ -19,6 +19,7 @@ const int MAX_CL_STATS = 256;
 // const int STAT_ITEMS = 15; // .items | .items2 << 23 | serverflags << 28
 // const int STAT_VIEWHEIGHT = 16;
 
+#if 0
 #if defined(CSQC)
     #define g_stat_HEALTH getstati(STAT_HEALTH)
     #define g_stat_ARMOR getstati(STAT_ARMOR)
@@ -38,6 +39,16 @@ const int MAX_CL_STATS = 256;
     #define stat_ITEMS items
     #define stat_VIEWHEIGHT view_ofs_z
 #endif
+#endif
+
+REGISTER_STAT(HEALTH, int, this.health)
+REGISTER_STAT(ARMOR, int, this.armorvalue)
+REGISTER_STAT(SHELLS, int, this.ammo_shells)
+REGISTER_STAT(NAILS, int, this.ammo_nails)
+REGISTER_STAT(ROCKETS, int, this.ammo_rockets)
+REGISTER_STAT(CELLS, int, this.ammo_cells)
+REGISTER_STAT(ITEMS, int, this.items)
+REGISTER_STAT(VIEWHEIGHT, int, this.view_ofs_z)
 
 #ifdef SVQC
 /// all the weapons actually spawned in the map, does not include filtered items
index a8d1376d1d86b60781be17f990ff41f835f88996..04cbd6dd614a2f0be4ff30e09c612e33a8cc4fe8 100644 (file)
@@ -258,12 +258,12 @@ int GetAmmoStat(int ammotype)
 {
        switch (ammotype)
        {
-               case RES_SHELLS: return STAT_SHELLS;
-               case RES_BULLETS: return STAT_NAILS;
-               case RES_ROCKETS: return STAT_ROCKETS;
-               case RES_CELLS: return STAT_CELLS;
-               case RES_PLASMA: return STAT_PLASMA.m_id;
-               case RES_FUEL: return STAT_FUEL.m_id;
+               case RES_SHELLS: return STAT(SHELLS);
+               case RES_BULLETS: return STAT(NAILS);
+               case RES_ROCKETS: return STAT(ROCKETS);
+               case RES_CELLS: return STAT(CELLS);
+               case RES_PLASMA: return STAT(PLASMA);
+               case RES_FUEL: return STAT(FUEL);
                default: return -1;
        }
 }
index eaea70f5e9eb33d3fb45377a5d1c6e907aa5d119..9756c074585dff755318a9b59c4745c85ff0027a 100644 (file)
 #define STAT_MOVEVARS_TICRATE _STAT_MOVEVARS_TICRATE
 #define STAT_MOVEVARS_TIMESCALE _STAT_MOVEVARS_TIMESCALE
 #define STAT_MOVEVARS_GRAVITY _STAT_MOVEVARS_GRAVITY
+#define STAT_HEALTH _STAT_HEALTH
+#define STAT_ARMOR _STAT_ARMOR
+#define STAT_SHELLS _STAT_SHELLS
+#define STAT_NAILS _STAT_NAILS
+#define STAT_ROCKETS _STAT_ROCKETS
+#define STAT_CELLS _STAT_CELLS
+#define STAT_ITEMS _STAT_ITEMS
+#define STAT_VIEWHEIGHT _STAT_VIEWHEIGHT
 
 #include "upstream/csprogsdefs.qc"
 
 #undef STAT_MOVEVARS_TICRATE
 #undef STAT_MOVEVARS_TIMESCALE
 #undef STAT_MOVEVARS_GRAVITY
+#undef STAT_HEALTH
+#undef STAT_ARMOR
+#undef STAT_SHELLS
+#undef STAT_NAILS
+#undef STAT_ROCKETS
+#undef STAT_CELLS
+#undef STAT_ITEMS
+#undef STAT_VIEWHEIGHT
 
 #define use use1
 .void(entity this, entity actor, entity trigger) use;
index 5a2b53b69f3796da2c23802c617567d221ddbeb6..3727286197d0be5f7a07e8dc2cb51ea7b1ce8ba9 100644 (file)
 .int m_id;
 USING(vectori, vector);
 
-const int STATS_ENGINE_RESERVE = 32;
-// must be listed in ascending order
-#define MAGIC_STATS(_, x) \
-       _(x, MOVEVARS_AIRACCEL_QW_STRETCHFACTOR, 220) \
-       _(x, MOVEVARS_AIRCONTROL_PENALTY, 221) \
-       _(x, MOVEVARS_AIRSPEEDLIMIT_NONQW, 222) \
-       _(x, MOVEVARS_AIRSTRAFEACCEL_QW, 223) \
-       _(x, MOVEVARS_AIRCONTROL_POWER, 224) \
-       _(x, MOVEFLAGS, 225) \
-       _(x, MOVEVARS_WARSOWBUNNY_AIRFORWARDACCEL, 226) \
-       _(x, MOVEVARS_WARSOWBUNNY_ACCEL, 227) \
-       _(x, MOVEVARS_WARSOWBUNNY_TOPSPEED, 228) \
-       _(x, MOVEVARS_WARSOWBUNNY_TURNACCEL, 229) \
-       _(x, MOVEVARS_WARSOWBUNNY_BACKTOSIDERATIO, 230) \
-       _(x, MOVEVARS_AIRSTOPACCELERATE, 231) \
-       _(x, MOVEVARS_AIRSTRAFEACCELERATE, 232) \
-       _(x, MOVEVARS_MAXAIRSTRAFESPEED, 233) \
-       _(x, MOVEVARS_AIRCONTROL, 234) \
-       _(x, FRAGLIMIT, 235) \
-       _(x, TIMELIMIT, 236) \
-       _(x, MOVEVARS_WALLFRICTION, 237) \
-       _(x, MOVEVARS_FRICTION, 238) \
-       _(x, MOVEVARS_WATERFRICTION, 239) \
-       _(x, MOVEVARS_TICRATE, 240) \
-       _(x, MOVEVARS_TIMESCALE, 241) \
-       _(x, MOVEVARS_GRAVITY, 242) \
-       _(x, MOVEVARS_STOPSPEED, 243) \
-       _(x, MOVEVARS_MAXSPEED, 244) \
-       _(x, MOVEVARS_SPECTATORMAXSPEED, 245) \
-       _(x, MOVEVARS_ACCELERATE, 246) \
-       _(x, MOVEVARS_AIRACCELERATE, 247) \
-       _(x, MOVEVARS_WATERACCELERATE, 248) \
-       _(x, MOVEVARS_ENTGRAVITY, 249) \
-       _(x, MOVEVARS_JUMPVELOCITY, 250) \
-       _(x, MOVEVARS_EDGEFRICTION, 251) \
-       _(x, MOVEVARS_MAXAIRSPEED, 252) \
-       _(x, MOVEVARS_STEPHEIGHT, 253) \
-       _(x, MOVEVARS_AIRACCEL_QW, 254) \
-       _(x, MOVEVARS_AIRACCEL_SIDEWAYS_FRICTION, 255) \
-       /**/
-
-int g_magic_stats_hole = 0;
-
-#define MAGIC_STATS_FIX_MANUAL(it, var, id) \
-       if (it.registered_id == "STAT_" #var) { --g_magic_stats_hole; it.m_id = id; } else
-
-#define MAGIC_STATS_FIX_AUTO(it, var, id) \
-       if (it.m_id == id) { ++g_magic_stats_hole; ++it.m_id; }
-
-#define MAGIC_STATS_FIX(it) \
-       it.m_id += g_magic_stats_hole; \
-       MAGIC_STATS(MAGIC_STATS_FIX_MANUAL, it) { MAGIC_STATS(MAGIC_STATS_FIX_AUTO, it) }
+REGISTRY(Stats, 256)
+#define Stats_from(i) _Stats_from(i, NULL)
+REGISTER_REGISTRY(Stats)
+REGISTRY_SORT(Stats)
+REGISTRY_CHECK(Stats)
+STATIC_INIT(Stats_renumber) { FOREACH(Stats, true, it.m_id = i); }
 
 #define REGISTER_STAT(...) EVAL_REGISTER_STAT(OVERLOAD(REGISTER_STAT, __VA_ARGS__))
 #define EVAL_REGISTER_STAT(...) __VA_ARGS__
+
+#if defined(CSQC)
+       #define stats_get_int() ReadInt24_t()
+       #define stats_get_bool() boolean(ReadByte())
+       #define stats_get_float() ReadFloat()
+       #define stats_get_vector() ReadVector()
+       #define stats_get_vectori() ReadInt72_t()
+
+.void(entity ent) m_receive;
+#elif defined(SVQC)
+       #define stats_write_int(chan,id,ent) WriteInt24_t(chan, STAT(id, ent))
+       #define stats_write_bool(chan,id,ent) WriteByte(chan, STAT(id, ent))
+       #define stats_write_float(chan,id,ent) WriteFloat(chan, STAT(id, ent))
+       #define stats_write_vector(chan,id,ent) WriteVector(chan, STAT(id, ent))
+       #define stats_write_vectori(chan,id,ent) WriteInt72_t(chan, STAT(id, ent))
+
+.bool(entity ent, entity player) m_check;
+.void(entity ent, entity player) m_set;
+.void(int chan, entity ent) m_send;
+#endif
+
 #if defined(CSQC)
-       /** Get all stats and store them as globals, access with `STAT(ID)` */
-       void stats_get() {}
        #define STAT(...) EVAL_STAT(OVERLOAD(STAT, __VA_ARGS__))
        #define EVAL_STAT(...) __VA_ARGS__
     #define STAT_1(id) (RVALUE, _STAT(id))
        #define STAT_2(id, cl) STAT_1(id)
 
-       #define getstat_int(id) getstati(id, 0, 24)
-       #define getstat_bool(id) boolean(getstati(id))
-       #define getstat_float(id) getstatf(id)
-       #define getstat_vector(id) vec3(getstat_float(id + 0), getstat_float(id + 1), getstat_float(id + 2))
-       #define getstat_vectori(id) vec3(getstat_int(id + 0), getstat_int(id + 1), getstat_int(id + 2))
-
        #define _STAT(id) g_stat_##id
        #define REGISTER_STAT_2(id, T) \
                T _STAT(id); \
                /* T CAT(_STAT(id), _prev); */ \
+               void STAT_##id##_receive(entity data) { _STAT(id) = stats_get_##T(); } \
                REGISTER(Stats, STAT_##id, m_id, new_pure(stat)) \
                { \
-                       if (#T == "vector" || #T == "vectori") { \
-                               REGISTRY_RESERVE(Stats, m_id, STAT_##id, y); \
-                               REGISTRY_RESERVE(Stats, m_id, STAT_##id, z); \
-                       } \
-               } \
-               ACCUMULATE void stats_get() \
-               { \
-                       T it = getstat_##T(STAT_##id.m_id); \
-                       /* if (it != CAT(_STAT(id), _prev)) \
-                               CAT(_STAT(id), _prev) = */ _STAT(id) = it; \
+                       this.m_receive = STAT_##id##_receive; \
                }
        #define REGISTER_STAT_3(x, T, expr) REGISTER_STAT_2(x, T)
 #elif defined(SVQC)
     /** Internal use only */
     entity STATS;
        /** Add all registered stats, access with `STAT(ID, player)` or `.type stat = _STAT(ID); player.stat` */
-       void stats_add() {}
        #define STAT(...) EVAL_STAT(OVERLOAD_(STAT, __VA_ARGS__))
     #define EVAL_STAT(...) __VA_ARGS__
     #define STAT_1(id) (RVALUE, STAT_2(id, STATS))
        #define STAT_2(id, cl) (cl)._STAT(id)
 
-       #define addstat_int(id, fld) addstat(id, AS_INT, fld)
-       #define addstat_bool(id, fld) addstat(id, AS_INT, fld)
-       #define addstat_float(id, fld) addstat(id, AS_FLOAT, fld)
-       #define addstat_vector(id, fld) MACRO_BEGIN \
-               addstat_float(id + 0, fld##_x); \
-               addstat_float(id + 1, fld##_y); \
-               addstat_float(id + 2, fld##_z); \
-       MACRO_END
-       #define addstat_vectori(id, fld) MACRO_BEGIN \
-               addstat_int(id + 0, fld##_x); \
-               addstat_int(id + 1, fld##_y); \
-               addstat_int(id + 2, fld##_z); \
-       MACRO_END
-       const int AS_STRING = 1;
-       const int AS_INT = 2;
-       const int AS_FLOAT = 8;
-
-       .int __stat_null;
        STATIC_INIT(stats)
        {
-           STATS = new(stats);
-           // Prevent engine stats being sent
-               int r = STATS_ENGINE_RESERVE;
-               for (int i = 0, n = 256 - r; i < n; ++i) {
-                       #define X(_, name, id) if (i == id) continue;
-                       MAGIC_STATS(X, );
-                       #undef X
-                       addstat(r + i, AS_INT, __stat_null);
-               }
+           STATS = new_pure(stats);
        }
 
        #define _STAT(id) stat_##id
        #define REGISTER_STAT_2(id, T) \
                .T _STAT(id); \
+               bool STAT_##id##_check(entity ent, entity player) { return STAT(id, ent) != STAT(id, player); } \
+               void STAT_##id##_set(entity ent, entity player) { STAT(id, ent) = STAT(id, player); } \
+               void STAT_##id##_send(int chan, entity ent) { stats_write_##T(chan, id, ent); } \
                REGISTER(Stats, STAT_##id, m_id, new_pure(stat)) \
                { \
-                       if (#T == "vector" || #T == "vectori") { \
-                               REGISTRY_RESERVE(Stats, m_id, STAT_##id, y); \
-                               REGISTRY_RESERVE(Stats, m_id, STAT_##id, z); \
-                       } \
-               } \
-               ACCUMULATE void stats_add() \
-               { \
-                       .T fld = _STAT(id); \
-                       addstat_##T(STAT_##id.m_id, fld); \
+                       this.m_check = STAT_##id##_check; \
+                       this.m_set = STAT_##id##_set; \
+                       this.m_send = STAT_##id##_send; \
                }
        void GlobalStats_update(entity this) {}
        void GlobalStats_updateglobal() {}
@@ -164,17 +93,120 @@ int g_magic_stats_hole = 0;
     #define REGISTER_STAT_3(id, T, expr)
 #endif
 
-REGISTRY(Stats, 256 - STATS_ENGINE_RESERVE)
-REGISTER_REGISTRY(Stats)
-REGISTRY_SORT(Stats)
-REGISTRY_CHECK(Stats)
-STATIC_INIT(Stats_renumber)
+#ifdef GAMEQC
+/** Player stats */
+.entity stats;
+
+REGISTER_NET_LINKED(ENT_CLIENT_STATS)
+
+const int Stats_groups_minor = 24; // exactly 1 byte
+const int Stats_groups_major = 11; // ceil(Stats_MAX / Stats_groups_minor)
+
+#define G_MAJOR(id) (floor((id) / Stats_groups_minor))
+#define G_MINOR(id) ((id) % Stats_groups_minor)
+#endif
+
+#ifdef CSQC
+NET_HANDLE(ENT_CLIENT_STATS, bool isnew)
+{
+    make_pure(this);
+    const int majorBits = ReadByte();
+    for (int i = 0; i < Stats_groups_major; ++i) {
+        if (!(majorBits & BIT(i))) {
+            continue;
+        }
+        const int minorBits = ReadInt24_t();
+        for (int j = 0; j < Stats_groups_minor; ++j) {
+            if (!(minorBits & BIT(j))) {
+                continue;
+            }
+            const entity it = Stats_from(Stats_groups_minor * i + j);
+            it.m_receive(it);
+        }
+    }
+    return true;
+}
+#endif
+
+#ifdef SVQC
+int statsminorBitsArr[Stats_groups_major];
+void Stats_Write(entity data)
+{
+    if (!data) {
+        WriteShort(MSG_ENTITY, 0);
+        return;
+    }
+    TC(entity, data);
+
+       for (int i = 0; i < Stats_groups_major; ++i)
+               statsminorBitsArr[i] = 0;
+
+    int majorBits = 0;
+    FOREACH(Stats, true, {
+        const bool changed = it.m_check(data, data.owner);
+        if (changed) {
+               it.m_set(data, data.owner);
+                       int maj = G_MAJOR(it.m_id);
+                       majorBits = BITSET(majorBits, BIT(maj), true);
+                       statsminorBitsArr[maj] = BITSET(statsminorBitsArr[maj], BIT(G_MINOR(it.m_id)), true);
+        }
+    });
+    WriteByte(MSG_ENTITY, majorBits);
+
+       for (int i = 0; i < Stats_groups_major; ++i)
+       {
+               if (!(majorBits & BIT(i)))
+                       continue;
+
+               const int minorBits = statsminorBitsArr[i];
+               WriteInt24_t(MSG_ENTITY, minorBits);
+               for (int j = 0; j < Stats_groups_minor; ++j)
+               {
+                       if (!(minorBits & BIT(j)))
+                               continue;
+
+                       const entity it = Stats_from(Stats_groups_minor * i + j);
+            it.m_send(MSG_ENTITY, data);
+               }
+       }
+}
+#endif
+
+#undef G_MAJOR
+#undef G_MINOR
+
+#ifdef SVQC
+bool Stats_Send(entity this, entity to, int sf)
+{
+    TC(entity, this);
+    WriteHeader(MSG_ENTITY, ENT_CLIENT_STATS);
+    TC(PlayerState, this.owner);
+    Stats_Write(this);
+    return true;
+}
+
+void Stats_update(entity e) { e.stats.SendFlags = 0xFFFFFF; }
+void Stats_checkupdate(entity this)
 {
        FOREACH(Stats, true, {
-               it.m_id = STATS_ENGINE_RESERVE + i;
-               MAGIC_STATS_FIX(it);
+               const bool changed = it.m_check(this, this.owner);
+               if(changed)
+               {
+                       Stats_update(this.owner);
+                       break; // no need to keep looping once we've found a stat that needs updating
+               }
        });
+
+       this.nextthink = time;
 }
-#ifdef SVQC
-STATIC_INIT(stats_add) { stats_add(); }
+
+void Stats_new(entity this)
+{
+    entity ent = new_pure(Stats);
+    setthink(ent, Stats_checkupdate);
+    ent.nextthink = time;
+    ent.drawonlytoclient = this;
+    Net_LinkEntity((ent.owner = this).stats = ent, false, 0, Stats_Send);
+}
+void Stats_delete(entity e) { delete(e.stats); }
 #endif