]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Linked entities: simplify registration
authorTimePath <andrew.hardaker1995@gmail.com>
Mon, 5 Oct 2015 05:44:12 +0000 (16:44 +1100)
committerTimePath <andrew.hardaker1995@gmail.com>
Mon, 5 Oct 2015 05:44:12 +0000 (16:44 +1100)
14 files changed:
qcsrc/client/main.qc
qcsrc/common/constants.qh
qcsrc/common/nades.qc
qcsrc/common/nades.qh
qcsrc/common/util.qc
qcsrc/common/util.qh
qcsrc/lib/_all.inc
qcsrc/lib/net.qh [new file with mode: 0644]
qcsrc/lib/oo.qh
qcsrc/lib/registry.qh
qcsrc/lib/sort.qh [new file with mode: 0644]
qcsrc/server/defs.qh
qcsrc/server/miscfunctions.qc
qcsrc/server/miscfunctions.qh

index ca31f32f71bf7b5afb82bb487a650653d1da108d..898b10e0bc69a1cd2ecba8155cf054a91806567e 100644 (file)
@@ -796,15 +796,13 @@ void Ent_Init();
 void Ent_ScoresInfo();
 void CSQC_Ent_Update(float bIsNewEntity)
 {SELFPARAM();
-       float t;
-       float savetime;
-       t = ReadByte();
+       int t = ReadByte();
 
        if(autocvar_developer_csqcentities)
                LOG_INFOF("CSQC_Ent_Update(%d) with self=%i self.entnum=%d self.enttype=%d t=%d\n", bIsNewEntity, self, self.entnum, self.enttype, t);
 
        // set up the "time" global for received entities to be correct for interpolation purposes
-       savetime = time;
+       float savetime = time;
        if(servertime)
        {
                time = servertime;
@@ -821,7 +819,6 @@ void CSQC_Ent_Update(float bIsNewEntity)
        {
                if(t != self.enttype || bIsNewEntity)
                {
-                       //print("A CSQC entity changed its type!\n");
                        LOG_INFOF("A CSQC entity changed its type! (edict: %d, server: %d, type: %d -> %d)\n", num_for_edict(self), self.entnum, self.enttype, t);
                        Ent_Remove();
                        clearentity(self);
@@ -838,6 +835,13 @@ void CSQC_Ent_Update(float bIsNewEntity)
        }
 #endif
        self.enttype = t;
+       bool done = false;
+       FOREACH(Linked, it.m_id == t, LAMBDA(
+               it.m_read(self, bIsNewEntity);
+               done = true;
+               break;
+       ));
+       if (!done)
        switch(t)
        {
                case ENT_CLIENT_MUTATOR: {
@@ -884,7 +888,6 @@ void CSQC_Ent_Update(float bIsNewEntity)
                case ENT_CLIENT_SPAWNPOINT: Ent_ReadSpawnPoint(bIsNewEntity); break;
                case ENT_CLIENT_SPAWNEVENT: Ent_ReadSpawnEvent(bIsNewEntity); break;
                case ENT_CLIENT_NOTIFICATION: Read_Notification(bIsNewEntity); break;
-               case ENT_CLIENT_HEALING_ORB: ent_healer(); break;
                case ENT_CLIENT_MINIGAME: ent_read_minigame(); break;
                case ENT_CLIENT_VIEWLOC: ent_viewloc(); break;
                case ENT_CLIENT_VIEWLOC_TRIGGER: ent_viewloc_trigger(); break;
index fe04e910cff4782d6e482abb74866eedc083330f..2fcd63c24f34aa6542acdbfd65507dc27c9e1bc7 100644 (file)
@@ -127,7 +127,6 @@ const int ENT_CLIENT_EFFECT = 74;
 const int ENT_CLIENT_MINIGAME = 75;
 const int ENT_CLIENT_VIEWLOC = 78;
 const int ENT_CLIENT_VIEWLOC_TRIGGER = 79;
-const int ENT_CLIENT_HEALING_ORB = 80;
 
 const int ENT_CLIENT_MUTATOR = TE_CSQC_MUTATOR; // 99
 
index f361730ba16b29f5a9fe150e6272586e74afe0b3..f0e72b7ecc99aa0905d604cc1b5894d9c907a002 100644 (file)
 #endif
 
 
-#ifdef SVQC
-float healer_send(entity to, int sf)
-{SELFPARAM();
-       WriteByte(MSG_ENTITY, ENT_CLIENT_HEALING_ORB);
-       WriteByte(MSG_ENTITY, sf);
-
-       if(sf & 1)
-       {
-               WriteCoord(MSG_ENTITY, self.origin.x);
-               WriteCoord(MSG_ENTITY, self.origin.y);
-               WriteCoord(MSG_ENTITY, self.origin.z);
-
-               WriteByte(MSG_ENTITY, self.healer_lifetime);
-               //WriteByte(MSG_ENTITY, self.ltime - time + 1);
-               WriteShort(MSG_ENTITY, self.healer_radius);
-               // round time delta to a 1/10th of a second
-               WriteByte(MSG_ENTITY, (self.ltime - time)*10.0+0.5);
-       }
-
-       return true;
-}
-#endif // SVQC
-
 #ifdef CSQC
 .float ltime;
 void healer_draw()
@@ -49,48 +26,66 @@ void healer_draw()
 
        self.alpha = (self.ltime - time) / self.healer_lifetime;
        self.scale = min((1 - self.alpha)*self.healer_lifetime*4,1)*self.healer_radius;
-
 }
 
-void healer_setup()
-{SELFPARAM();
-       setmodel(self, MDL_NADE_HEAL);
-
-       setorigin(self, self.origin);
-
-       float model_radius = self.maxs.x;
-       vector size = '1 1 1' * self.healer_radius / 2;
-       setsize(self,-size,size);
-       self.healer_radius = self.healer_radius/model_radius*0.6;
-
-       self.draw = healer_draw;
-       self.health = 255;
-       self.movetype = MOVETYPE_NONE;
-       self.solid = SOLID_NOT;
-       self.drawmask = MASK_NORMAL;
-       self.scale = 0.01;
-       self.avelocity = self.move_avelocity = '7 0 11';
-       self.colormod = '1 0 0';
-       self.renderflags |= RF_ADDITIVE;
+void healer_setup(entity e)
+{
+       setmodel(e, MDL_NADE_HEAL);
+
+       setorigin(e, e.origin);
+
+       float model_radius = e.maxs.x;
+       vector size = '1 1 1' * e.healer_radius / 2;
+       setsize(e,-size,size);
+       e.healer_radius = e.healer_radius/model_radius*0.6;
+
+       e.draw = healer_draw;
+       e.health = 255;
+       e.movetype = MOVETYPE_NONE;
+       e.solid = SOLID_NOT;
+       e.drawmask = MASK_NORMAL;
+       e.scale = 0.01;
+       e.avelocity = e.move_avelocity = '7 0 11';
+       e.colormod = '1 0 0';
+       e.renderflags |= RF_ADDITIVE;
 }
+#endif // CSQC
 
-void ent_healer()
-{SELFPARAM();
+REGISTER_LINKED(Nade_Heal, bool isNew)
+#ifdef CSQC
+{
        int sf = ReadByte();
+       if (sf & 1) {
+               this.origin_x = ReadCoord();
+               this.origin_y = ReadCoord();
+               this.origin_z = ReadCoord();
+               setorigin(this, this.origin);
+               this.healer_lifetime = ReadByte();
+               this.healer_radius = ReadShort();
+               this.ltime = time + ReadByte()/10.0;
+               // this.ltime = time + this.healer_lifetime;
+               healer_setup(this);
+       }
+}
+#endif
 
-       if(sf & TNSF_SETUP)
-       {
-               self.origin_x = ReadCoord();
-               self.origin_y = ReadCoord();
-               self.origin_z = ReadCoord();
-               setorigin(self, self.origin);
-
-               self.healer_lifetime = ReadByte();
-               self.healer_radius = ReadShort();
-               self.ltime = time + ReadByte()/10.0;
-               //self.ltime = time + self.healer_lifetime;
-
-               healer_setup();
+#ifdef SVQC
+float healer_send(entity to, int sf)
+{
+       SELFPARAM();
+       WriteByte(MSG_ENTITY, Linked_Nade_Heal.m_id);
+       WriteByte(MSG_ENTITY, sf);
+       if (sf & 1) {
+               WriteCoord(MSG_ENTITY, this.origin.x);
+               WriteCoord(MSG_ENTITY, this.origin.y);
+               WriteCoord(MSG_ENTITY, this.origin.z);
+
+               WriteByte(MSG_ENTITY, this.healer_lifetime);
+               //WriteByte(MSG_ENTITY, this.ltime - time + 1);
+               WriteShort(MSG_ENTITY, this.healer_radius);
+               // round time delta to a 1/10th of a second
+               WriteByte(MSG_ENTITY, (this.ltime - time)*10.0+0.5);
        }
+       return true;
 }
-#endif // CSQC
+#endif // SVQC
index 1ec1b9ec7e3782d4161618204989e0fd6707e117..5a7f5d49dcd67f41f4e02232af4aee3b48048464 100644 (file)
@@ -137,8 +137,4 @@ string Nade_TrailEffect(int proj, float nade_team)
 float healer_send(entity to, int sf);
 #endif
 
-#ifdef CSQC
-// misc functions
-void ent_healer();
-#endif // CSQC
 #endif
index a506a59fcd2808ac26419691fe3c1b5ca7f90b17..4b6a346ff34af56b9766b9088d1b98c9818c01bd 100644 (file)
@@ -1500,26 +1500,6 @@ float isGametypeInFilter(float gt, float tp, float ts, string pattern)
        return 1;
 }
 
-void shuffle(float n, swapfunc_t swap, entity pass)
-{
-       float i, j;
-       for(i = 1; i < n; ++i)
-       {
-               // swap i-th item at a random position from 0 to i
-               // proof for even distribution:
-               //   n = 1: obvious
-               //   n -> n+1:
-               //     item n+1 gets at any position with chance 1/(n+1)
-               //     all others will get their 1/n chance reduced by factor n/(n+1)
-               //     to be on place n+1, their chance will be 1/(n+1)
-               //     1/n * n/(n+1) = 1/(n+1)
-               //     q.e.d.
-               j = floor(random() * (i + 1));
-               if(j != i)
-                       swap(j, i, pass);
-       }
-}
-
 string substring_range(string s, float b, float e)
 {
        return substring(s, b, e - b);
@@ -1750,58 +1730,6 @@ vector decompressShotOrigin(int f)
        return v;
 }
 
-void heapsort(float n, swapfunc_t swap, comparefunc_t cmp, entity pass)
-{
-       float start, end, root, child;
-
-       // heapify
-       start = floor((n - 2) / 2);
-       while(start >= 0)
-       {
-               // siftdown(start, count-1);
-               root = start;
-               while(root * 2 + 1 <= n-1)
-               {
-                       child = root * 2 + 1;
-                       if(child < n-1)
-                               if(cmp(child, child+1, pass) < 0)
-                                       ++child;
-                       if(cmp(root, child, pass) < 0)
-                       {
-                               swap(root, child, pass);
-                               root = child;
-                       }
-                       else
-                               break;
-               }
-               // end of siftdown
-               --start;
-       }
-
-       // extract
-       end = n - 1;
-       while(end > 0)
-       {
-               swap(0, end, pass);
-               --end;
-               // siftdown(0, end);
-               root = 0;
-               while(root * 2 + 1 <= end)
-               {
-                       child = root * 2 + 1;
-                       if(child < end && cmp(child, child+1, pass) < 0)
-                               ++child;
-                       if(cmp(root, child, pass) < 0)
-                       {
-                               swap(root, child, pass);
-                               root = child;
-                       }
-                       else
-                               break;
-               }
-               // end of siftdown
-       }
-}
 
 void RandomSelection_Init()
 {
index d43136c6734d23842a08ab570d926edfa67b1d76..4af16801db6442e473c1ecf07aa250d3d787e31d 100644 (file)
@@ -130,11 +130,6 @@ string getWrappedLineLen(float w, textLengthUpToLength_lenFunction_t tw);
 
 float isGametypeInFilter(float gt, float tp, float ts, string pattern);
 
-typedef void(float i1, float i2, entity pass) swapfunc_t; // is only ever called for i1 < i2
-typedef float(float i1, float i2, entity pass) comparefunc_t; // <0 for <, ==0 for ==, >0 for > (like strcmp)
-void shuffle(float n, swapfunc_t swap, entity pass);
-void heapsort(float n, swapfunc_t swap, comparefunc_t cmp, entity pass);
-
 string swapwords(string str, float i, float j);
 string shufflewords(string str);
 
index e7ee2746f553f5e06dbec8c491ca1982ad0e479c..7dc607405d43d3b68a945ca9e1727d2ccac185f2 100644 (file)
@@ -12,6 +12,7 @@
 #include "lazy.qh"
 #include "log.qh"
 #include "math.qh"
+#include "net.qh"
 #include "nil.qh"
 #include "noise.qc"
 #include "oo.qh"
@@ -21,6 +22,7 @@
 #include "progname.qh"
 #include "registry.qh"
 #include "replicate.qh"
+#include "sort.qh"
 #include "sortlist.qc"
 #include "spawnfunc.qh"
 #include "static.qh"
diff --git a/qcsrc/lib/net.qh b/qcsrc/lib/net.qh
new file mode 100644 (file)
index 0000000..a41fae1
--- /dev/null
@@ -0,0 +1,81 @@
+#ifndef NET_H
+#define NET_H
+
+#ifdef SVQC
+.int SendFlags;
+.bool(entity to, int sendflags) SendEntity;
+
+void Net_LinkEntity(entity e, bool docull, float dt, bool(entity to, int sendflags) sendfunc)
+{
+    if (!e.classname) e.classname = "net_linked";
+
+    if (!e.model || !self.modelindex) {
+        vector mi = e.mins;
+        vector ma = e.maxs;
+        _setmodel(e, "null");
+        setsize(e, mi, ma);
+    }
+
+    e.SendEntity = sendfunc;
+    e.SendFlags = 0xFFFFFF;
+
+    if (!docull) e.effects |= EF_NODEPTHTEST;
+
+    if (dt) {
+        e.nextthink = time + dt;
+        e.think = SUB_Remove;
+    }
+}
+
+.void() uncustomizeentityforclient;
+.float uncustomizeentityforclient_set;
+
+void SetCustomizer(entity e, float(void) customizer, void(void) uncustomizer)
+{
+    e.customizeentityforclient = customizer;
+    e.uncustomizeentityforclient = uncustomizer;
+    e.uncustomizeentityforclient_set = !!uncustomizer;
+}
+
+void UncustomizeEntitiesRun()
+{
+    for (entity e = NULL; (e = findfloat(e, uncustomizeentityforclient_set, 1)); ) {
+        WITH(entity, self, e, e.uncustomizeentityforclient());
+    }
+}
+
+#endif
+
+#include "registry.qh"
+#include "sort.qh"
+
+REGISTRY(Linked, 24)
+
+.string netname;
+.int m_id;
+.void(entity this, bool isNew) m_read;
+
+#ifdef CSQC
+    #define REGISTER_LINKED(id, param) \
+        void Ent_Read##id(entity this, param) { this = self; } \
+        REGISTER(RegisterLinked, Linked, Linked, Linked_COUNT, id, m_id, spawn()) { \
+            this.netname = #id; \
+            this.m_read = Ent_Read##id; \
+        } \
+        [[accumulate]] void Ent_Read##id(entity this, param)
+#else
+    #define REGISTER_LINKED(id, param) \
+        REGISTER(RegisterLinked, Linked, Linked, Linked_COUNT, id, m_id, spawn()) { \
+            this.netname = #id; \
+        }
+#endif
+
+REGISTER_REGISTRY(RegisterLinked)
+REGISTRY_SORT(Linked, netname, 0)
+STATIC_INIT(RegisterLinked_renumber) {
+    for (int i = 0; i < Linked_COUNT; ++i) {
+        Linked[i].m_id = 100 + i;
+    }
+}
+
+#endif
index 88c0ef8a46df4b7890c91923e158c82ba3e7ddbb..fce18cbfddac268702fdedfe33eeab5129f5b111 100644 (file)
@@ -2,7 +2,6 @@
 #define OO_H
 
 #include "nil.qh"
-#include "registry.qh"
 
 #ifdef MENUQC
     #define NULL (null_entity)
index c751fc79346b7fbb5688287cd119693b6bbdc356..b74c4783b9285debdd37b718561ddafaf5287a27 100644 (file)
@@ -6,6 +6,12 @@
 #define REGISTER_INIT(ns, id) [[accumulate]] void Register_##ns##_##id##_init(entity this)
 #define REGISTER_INIT_POST(ns, id) [[accumulate]] void Register_##ns##_##id##_init_post(entity this)
 
+#define REGISTRY(id, max) \
+    void Register##id() {} \
+    const int id##_MAX = max; \
+    noref entity id[id##_MAX], id##_first, id##_last; \
+    int id##_COUNT;
+
 /**
  * Register a new entity with a global constructor.
  * Must be followed by a semicolon or a function body with a `this` parameter.
     ACCUMULATE_FUNCTION(initfunc, Register_##ns##_##id)         \
     REGISTER_INIT(ns, id)
 
+#define REGISTRY_SORT(id, field, skip)                          \
+    void _REGISTRY_SWAP_##id(int i, int j, entity pass) {       \
+        i += skip; j += skip;                                   \
+        entity e = id[i];                                       \
+        id[i] = id[j];                                          \
+        id[j] = e;                                              \
+    }                                                           \
+    float _REGISTRY_CMP_##id(int i, int j, entity pass) {       \
+        i += skip; j += skip;                                   \
+        string a = id[i].field;                                 \
+        string b = id[j].field;                                 \
+        return strcasecmp(a, b);                                \
+    }                                                           \
+    STATIC_INIT(Registry_sort_##id) {                           \
+        heapsort(id##_COUNT, _REGISTRY_SWAP_##id, _REGISTRY_CMP_##id, NULL); \
+    }
+
 #endif
diff --git a/qcsrc/lib/sort.qh b/qcsrc/lib/sort.qh
new file mode 100644 (file)
index 0000000..0d3177a
--- /dev/null
@@ -0,0 +1,75 @@
+#ifndef SORT_H
+#define SORT_H
+
+/** is only ever called for i1 < i2 */
+typedef void(float i1, float i2, entity pass) swapfunc_t;
+/** <0 for <, ==0 for ==, >0 for > (like strcmp) */
+typedef float(float i1, float i2, entity pass) comparefunc_t;
+
+void heapsort(float n, swapfunc_t swap, comparefunc_t cmp, entity pass)
+{
+    int root, child;
+
+    // heapify
+    int start = floor((n - 2) / 2);
+    while (start >= 0) {
+        // siftdown(start, n - 1);
+        root = start;
+        while (root * 2 + 1 <= n - 1) {
+            child = root * 2 + 1;
+            if (child < n - 1 && cmp(child, child + 1, pass) < 0) {
+                child += 1;
+            }
+            if (cmp(root, child, pass) < 0) {
+                swap(root, child, pass);
+                root = child;
+            } else {
+                break;
+            }
+        }
+        // end of siftdown
+        --start;
+    }
+
+    // extract
+    int end = n - 1;
+    while (end > 0) {
+        swap(0, end, pass);
+        end -= 1;
+        // siftdown(0, end);
+        root = 0;
+        while (root * 2 + 1 <= end) {
+            child = root * 2 + 1;
+            if (child < end && cmp(child, child+1, pass) < 0) {
+                child += 1;
+            }
+            if (cmp(root, child, pass) < 0) {
+                swap(root, child, pass);
+                root = child;
+            } else {
+                break;
+            }
+        }
+        // end of siftdown
+    }
+}
+
+void shuffle(float n, swapfunc_t swap, entity pass)
+{
+    for (int i = 1; i < n; ++i) {
+        // swap i-th item at a random position from 0 to i
+        // proof for even distribution:
+        //   n = 1: obvious
+        //   n -> n+1:
+        //     item n+1 gets at any position with chance 1/(n+1)
+        //     all others will get their 1/n chance reduced by factor n/(n+1)
+        //     to be on place n+1, their chance will be 1/(n+1)
+        //     1/n * n/(n+1) = 1/(n+1)
+        //     q.e.d.
+        int j = floor(random() * (i + 1));
+        if (j != i)
+            swap(j, i, pass);
+    }
+}
+
+#endif
index 723b137a1366c54d7480eea6a8ee1523ced2ca1e..c55ae50f3512aff8f12d8dcc3c3d80b42a40cc2e 100644 (file)
@@ -304,8 +304,6 @@ float tracebox_hits_trigger_hurt(vector start, vector mi, vector ma, vector end)
 float next_pingtime;
 
 .float Version;
-.int SendFlags;
-.bool(entity to, int sendflags) SendEntity;
 
 // player sounds, voice messages
 // TODO implemented fall and falling
index a6164747dbdfa8fba56b601c5ea995496c4a35a1..58239a38aa6aba24f219bab60be7761cf30c4c7c 100644 (file)
@@ -1155,49 +1155,6 @@ void InitializeEntitiesRun()
     remove = remove_unsafely;
 }
 
-void UncustomizeEntitiesRun()
-{SELFPARAM();
-    for (entity e = NULL; (e = findfloat(e, uncustomizeentityforclient_set, 1)); )
-    {
-        WITH(entity, self, e, e.uncustomizeentityforclient());
-    }
-}
-void SetCustomizer(entity e, float(void) customizer, void(void) uncustomizer)
-{
-    e.customizeentityforclient = customizer;
-    e.uncustomizeentityforclient = uncustomizer;
-    e.uncustomizeentityforclient_set = !!uncustomizer;
-}
-
-void Net_LinkEntity(entity e, bool docull, float dt, bool(entity, int) sendfunc)
-{SELFPARAM();
-    vector mi, ma;
-
-    if (e.classname == "")
-        e.classname = "net_linked";
-
-    if (e.model == "" || self.modelindex == 0)
-    {
-        mi = e.mins;
-        ma = e.maxs;
-        setmodel(e, MDL_Null);
-        setsize(e, mi, ma);
-    }
-
-    e.SendEntity = sendfunc;
-    e.SendFlags = 0xFFFFFF;
-
-    if (!docull)
-        e.effects |= EF_NODEPTHTEST;
-
-    if (dt)
-    {
-        e.nextthink = time + dt;
-        e.think = SUB_Remove;
-    }
-}
-
-
 .float(entity) isEliminated;
 float EliminatedPlayers_SendEntity(entity to, float sendflags)
 {
index fc3583bb16bc6824dd5c0f4fce6638af8e631c13..bdd6dc6a60fc1c2e5572242b673af9d62e13de11 100644 (file)
@@ -29,8 +29,6 @@ float cvar_normal(string n)
 #define cvar_set_normal builtin_cvar_set
 
 .vector dropped_origin;
-.void(void) uncustomizeentityforclient;
-.float uncustomizeentityforclient_set;
 .float nottargeted;
 
 entity eliminatedPlayers;
@@ -61,9 +59,6 @@ void precache_all_playermodels(string pattern);
 
 void soundat(entity e, vector o, float chan, string samp, float vol, float _atten);
 
-void defer(float fdelay, void() func);
-
-void UncustomizeEntitiesRun();
 void InitializeEntitiesRun();
 
 void stopsoundto(float _dest, entity e, float chan);