]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
ent_cs: rewrite
authorTimePath <andrew.hardaker1995@gmail.com>
Mon, 16 Nov 2015 09:58:02 +0000 (20:58 +1100)
committerTimePath <andrew.hardaker1995@gmail.com>
Mon, 16 Nov 2015 09:58:02 +0000 (20:58 +1100)
18 files changed:
qcsrc/client/hud/panel/radar.qc
qcsrc/client/main.qc
qcsrc/client/main.qh
qcsrc/client/miscfunctions.qc
qcsrc/client/miscfunctions.qh
qcsrc/client/progs.inc
qcsrc/client/shownames.qc
qcsrc/client/view.qc
qcsrc/common/constants.qh
qcsrc/common/effects/qc/globalsound.qc
qcsrc/common/ent_cs.qc [new file with mode: 0644]
qcsrc/common/ent_cs.qh [new file with mode: 0644]
qcsrc/common/weapons/weapon/arc.qc
qcsrc/lib/warpzone/common.qc
qcsrc/server/cl_client.qc
qcsrc/server/ent_cs.qc [deleted file]
qcsrc/server/ent_cs.qh [deleted file]
qcsrc/server/progs.inc

index ad3e79ce53467b8b13c170fcdbe4d073e216ee1b..c06fcdbfe218e87ad282ac0fbec2093ec6d96ce7 100644 (file)
@@ -359,6 +359,8 @@ void HUD_Radar()
        }
        for(tm = world; (tm = find(tm, classname, "entcs_receiver")); )
        {
+               if (!tm.m_entcs_private) continue;
+               if (entcs_is_self(tm)) continue;
                color2 = GetPlayerColor(tm.sv_entnum);
                //if(color == NUM_SPECTATOR || color == color2)
                        draw_teamradar_player(tm.origin, tm.angles, Team_ColorRGB(color2));
index 985489b81e37118cd05c011c26788173529ea884..4b4f5a68b9f77e35ee5be552708cf7ecec9271a3 100644 (file)
@@ -327,47 +327,6 @@ float CSQC_InputEvent(float bInputType, float nPrimary, float nSecondary)
 // --------------------------------------------------------------------------
 // BEGIN OPTIONAL CSQC FUNCTIONS
 
-void Ent_RemoveEntCS()
-{
-       SELFPARAM();
-       entcs_receiver[this.sv_entnum] = NULL;
-}
-
-NET_HANDLE(ENT_CLIENT_ENTCS, bool isnew)
-{
-       make_pure(this);
-       this.classname = "entcs_receiver";
-       InterpolateOrigin_Undo();
-       int sf = ReadByte();
-
-       if(sf & BIT(0))
-               this.sv_entnum = ReadByte();
-       if (sf & BIT(1))
-       {
-               this.origin_x = ReadShort();
-               this.origin_y = ReadShort();
-               this.origin_z = ReadShort();
-               setorigin(this, this.origin);
-       }
-       if (sf & BIT(2))
-       {
-               this.angles_y = ReadByte() * 360.0 / 256;
-               this.angles_x = this.angles_z = 0;
-       }
-       if (sf & BIT(3))
-               this.healthvalue = ReadByte() * 10;
-       if (sf & BIT(4))
-               this.armorvalue = ReadByte() * 10;
-
-       return = true;
-
-       entcs_receiver[this.sv_entnum] = this;
-       this.entremove = Ent_RemoveEntCS;
-       this.iflags |= IFLAG_ORIGIN;
-
-       InterpolateOrigin_Note();
-}
-
 void Ent_Remove();
 
 void Ent_RemovePlayerScore()
@@ -795,7 +754,7 @@ void CSQC_Ent_Update(float bIsNewEntity)
        this.enttype = t;
        bool done = false;
        FOREACH(LinkedEntities, it.m_id == t, LAMBDA(
-               this.classname = it.netname;
+               if (bIsNewEntity) this.classname = it.netname;
                if (autocvar_developer_csqcentities)
             LOG_INFOF("CSQC_Ent_Update(%d) with this=%i {.entnum=%d, .enttype=%d} t=%s (%d)\n", bIsNewEntity, this, this.entnum, this.enttype, it.netname, t);
                done = it.m_read(this, bIsNewEntity);
index 48f7621879e63ace51b83a5904b4db03aebfdede..9229b718a5dbe33b5a27e059e7f7feb2745f7f10 100644 (file)
@@ -141,8 +141,6 @@ float g_balance_electro_secondary_bouncefactor;
 float g_balance_electro_secondary_bouncestop;
 float g_trueaim_minrange;
 
-entity entcs_receiver[255]; // 255 is the engine limit on maxclients
-
 float hud;
 float view_quality;
 int framecount;
index ab4cb1f15673c6c952872e83e22f2048c3b15237..bbe0722fd7dad9464b9a8df5a3d1ceb7537d3059 100644 (file)
@@ -482,55 +482,25 @@ void DrawCircleClippedPic(vector centre, float radi, string pic, float f, vector
        }
 }
 
-vector getplayerorigin(int pl)
+// TODO: entcs
+float getplayeralpha(int pl)
 {
-       entity e;
-
-       e = CSQCModel_server2csqc(pl + 1);
-       if(e)
-               return e.origin;
-
-       e = entcs_receiver[pl];
-       if(e)
-               return e.origin;
-
-       return GETPLAYERORIGIN_ERROR;
-}
-
-float getplayeralpha(float pl)
-{
-       entity e;
-
-       e = CSQCModel_server2csqc(pl + 1);
-       if(e)
-               return e.alpha;
-
-       return 1;
+       entity e = CSQCModel_server2csqc(pl + 1);
+       return (e) ? e.alpha : 1;
 }
 
-vector getcsqcplayercolor(float pl)
+// TODO: entcs
+vector getcsqcplayercolor(int pl)
 {
-       entity e;
-
-       e = CSQCModel_server2csqc(pl);
-       if(e)
-       {
-               if(e.colormap > 0)
-                       return colormapPaletteColor(((e.colormap >= 1024) ? e.colormap : stof(getplayerkeyvalue(e.colormap - 1, "colors"))) & 0x0F, true);
-       }
-
-       return '1 1 1';
+       entity e = CSQCModel_server2csqc(pl);
+       return (e && e.colormap > 0) ? colormapPaletteColor(((e.colormap >= 1024) ? e.colormap : stof(getplayerkeyvalue(e.colormap - 1, "colors"))) & 0x0F, true) : '1 1 1';
 }
 
-float getplayerisdead(float pl)
+// TODO: entcs
+bool getplayerisdead(int pl)
 {
-       entity e;
-
-       e = CSQCModel_server2csqc(pl + 1);
-       if(e)
-               return e.csqcmodel_isdead;
-
-       return false;
+       entity e = CSQCModel_server2csqc(pl + 1);
+       return e ? e.csqcmodel_isdead : false;
 }
 
 /** engine callback */
index 60048d0497bdd65279c9ec7f1e57c0551031bab2..520b5e47de7196597d7bae4a198d7b7b741de665 100644 (file)
@@ -143,9 +143,6 @@ void PolyDrawModel(entity e);
 
 void DrawCircleClippedPic(vector centre, float radi, string pic, float f, vector rgb, float a, float drawflag);
 
-const vector GETPLAYERORIGIN_ERROR = '1123581321 2357111317 3141592653'; // way out of bounds for anything on the map
-vector getplayerorigin(int pl);
-
 float getplayeralpha(float pl);
 
 vector getcsqcplayercolor(float pl);
index 1e939b77035169aa0fd727d954155c9a4ccb1d45..4a6b587882c744ae15e9c16036025acbbca336d6 100644 (file)
@@ -27,6 +27,7 @@
 
 #include "../common/animdecide.qc"
 #include "../common/effects/effectinfo.qc"
+#include "../common/ent_cs.qc"
 #include "../common/mapinfo.qc"
 #include "../common/movetypes/include.qc"
 #include "../common/net_notice.qc"
index 300521545354cad1a34efbca961a6193b8e8c9a5..0dbffb8747fdda70a032fc4a5797df509ea0d63a 100644 (file)
@@ -8,8 +8,10 @@
 
 #include "../lib/csqcmodel/cl_model.qh"
 
+entity shownames_ent[255];
+
 // self.isactive = player is in range and coordinates/status (health and armor) are up to date
-// self.origin = player origin TODO: should maybe move this so it's the origin of the shownames tag already in SSQC for culling?
+// self.origin = player origin
 // self.healthvalue
 // self.armorvalue
 // self.sameteam = player is on same team as local client
 
 const float SHOWNAMES_FADESPEED = 4;
 const float SHOWNAMES_FADEDELAY = 0.4;
-void Draw_ShowNames(entity ent)
+void Draw_ShowNames(entity this)
 {
-       if(!autocvar_hud_shownames)
-               return;
-
-       if(ent.sv_entnum == player_localentnum) // ent is me or person i'm spectating
-               if(!(autocvar_hud_shownames_self && autocvar_chase_active))
-                       return;
-
-       if(ent.sameteam || (!ent.sameteam && autocvar_hud_shownames_enemies))
+       if (!autocvar_hud_shownames) return;
+       if (this.sv_entnum == player_localentnum)  // self or spectatee
+               if (!(autocvar_hud_shownames_self && autocvar_chase_active)) return;
+       if (!this.sameteam && !autocvar_hud_shownames_enemies) return;
+       bool hit;
+       if (!autocvar_hud_shownames_crosshairdistance && this.sameteam)
        {
-               ent.origin_z += autocvar_hud_shownames_offset;
-
-               float hit;
-               if(ent.sameteam && !autocvar_hud_shownames_crosshairdistance)
-               {
-                       hit = 1;
-               }
-               else
-               {
-                       traceline(view_origin, ent.origin, MOVE_NORMAL, ent);
-                       if(trace_fraction < 1 && (trace_networkentity != ent.sv_entnum && trace_ent.entnum != ent.sv_entnum))
-                               hit = 0;
-                       else
-                               hit = 1;
-               }
-
-               // handle tag fading
-               float overlap = false, onscreen, crosshairdistance;
-               vector o, eo;
-
-               o = project_3d_to_2d(ent.origin);
-
-               if(autocvar_hud_shownames_antioverlap)
+               hit = true;
+       }
+       else
+       {
+               traceline(view_origin, this.origin, MOVE_NORMAL, this);
+               hit = !(trace_fraction < 1 && (trace_networkentity != this.sv_entnum && trace_ent.entnum != this.sv_entnum));
+       }
+       // handle tag fading
+       bool overlap = false;
+       vector o = project_3d_to_2d(this.origin + eZ * autocvar_hud_shownames_offset);
+       float dist = vlen(this.origin - view_origin);
+       if (autocvar_hud_shownames_antioverlap)
+       {
+               // fade tag out if another tag that is closer to you overlaps
+               for (entity e = world; (e = find(e, classname, "shownames_tag")); )
                {
-                       // fade tag out if another tag that is closer to you overlaps
-                       entity e;
-                       for(e = world; (e = find(e, classname, "shownames_tag")); )
+                       if (e == this) continue;
+                       vector eo = project_3d_to_2d(e.origin);
+                       if (eo.z < 0 || eo.x < 0 || eo.y < 0 || eo.x > vid_conwidth || eo.y > vid_conheight) continue;
+                       eo.z = 0;
+                       if (vlen((eX * o.x + eY * o.y) - eo) < autocvar_hud_shownames_antioverlap_distance
+                           && dist > vlen(e.origin - view_origin))
                        {
-                               if(e == ent)
-                                       continue;
-                               eo = project_3d_to_2d(e.origin);
-                               if (!(eo.z < 0 || eo.x < 0 || eo.y < 0 || eo.x > vid_conwidth || eo.y > vid_conheight))
-                               {
-                                       eo.z = 0;
-                                       if(vlen((eX * o.x + eY * o.y) - eo) < autocvar_hud_shownames_antioverlap_distance && vlen(ent.origin - view_origin) > vlen(e.origin - view_origin))
-                                       {
-                                               overlap = true;
-                                               break;
-                                       }
-                               }
-                       }
-               }
-
-               onscreen = (o.z >= 0 && o.x >= 0 && o.y >= 0 && o.x <= vid_conwidth && o.y <= vid_conheight);
-               crosshairdistance = sqrt( pow(o.x - vid_conwidth/2, 2) + pow(o.y - vid_conheight/2, 2) );
-
-               if(autocvar_hud_shownames_crosshairdistance)
-               {
-                       if(autocvar_hud_shownames_crosshairdistance > crosshairdistance)
-                               ent.pointtime = time;
-
-                       if (ent.pointtime + autocvar_hud_shownames_crosshairdistance_time <= time)
                                overlap = true;
-                       else
-                               overlap = (autocvar_hud_shownames_crosshairdistance_antioverlap ? overlap : false); // override what antioverlap says unless allowed by cvar.
-               }
-
-               if(!ent.fadedelay)
-                       ent.fadedelay = time + SHOWNAMES_FADEDELAY;
-
-               if(!ent.sameteam && (!onscreen || !hit)) // out of view, fade out
-               {
-                       ent.alpha = max(0, ent.alpha - SHOWNAMES_FADESPEED * frametime);
-                       ent.fadedelay = 0; // reset fade in delay, enemy has left the view
-               }
-               else if(ent.csqcmodel_isdead) // dead player, fade out slowly
-                       ent.alpha = max(0, ent.alpha - SHOWNAMES_FADESPEED * 0.25 * frametime);
-               else if(overlap) // tag overlap detected, fade out
-                       ent.alpha = max(0, ent.alpha - SHOWNAMES_FADESPEED * frametime);
-               else if(ent.sameteam) // fade in for team mates
-                       ent.alpha = min(1, ent.alpha + SHOWNAMES_FADESPEED * frametime);
-               else if(time > ent.fadedelay) // fade in for enemies
-                       ent.alpha = min(1, ent.alpha + SHOWNAMES_FADESPEED * frametime);
-
-               // multiply by player alpha
-               if(!ent.sameteam || (ent.sv_entnum == player_localentnum))
-                       ent.alpha *= getplayeralpha(ent.sv_entnum-1);
-
-               if(ent.alpha < ALPHA_MIN_VISIBLE && gametype != MAPINFO_TYPE_CTS)
-                       return;
-
-               float dist;
-               dist = vlen(ent.origin - view_origin);
-
-               float a;
-               a = autocvar_hud_shownames_alpha;
-               a *= ent.alpha;
-               if(autocvar_hud_shownames_maxdistance)
-               {
-                       if(dist >= autocvar_hud_shownames_maxdistance)
-                               return;
-                       a *= ((autocvar_hud_shownames_maxdistance - autocvar_hud_shownames_mindistance) - max(0, dist - autocvar_hud_shownames_mindistance)) / (autocvar_hud_shownames_maxdistance - autocvar_hud_shownames_mindistance);
+                               break;
+                       }
                }
-
-               if(!a)
-                       return;
-
-               float resize;
-               resize = 1;
-               if(autocvar_hud_shownames_resize) // limit resize so its never smaller than 0.5... gets unreadable
-                       resize = 0.5 + 0.5 * ((autocvar_hud_shownames_maxdistance - autocvar_hud_shownames_mindistance) - max(0, dist - autocvar_hud_shownames_mindistance)) / (autocvar_hud_shownames_maxdistance - autocvar_hud_shownames_mindistance);
-
-               // draw the sprite image
-               if(o.z >= 0)
+       }
+       bool onscreen = (o.z >= 0 && o.x >= 0 && o.y >= 0 && o.x <= vid_conwidth && o.y <= vid_conheight);
+       float crosshairdistance = sqrt(pow(o.x - vid_conwidth / 2, 2) + pow(o.y - vid_conheight / 2, 2));
+       if (autocvar_hud_shownames_crosshairdistance)
+       {
+               if (autocvar_hud_shownames_crosshairdistance > crosshairdistance) this.pointtime = time;
+               if (this.pointtime + autocvar_hud_shownames_crosshairdistance_time <= time) overlap = true;
+               else overlap = (autocvar_hud_shownames_crosshairdistance_antioverlap ? overlap : false); // override what antioverlap says unless allowed by cvar.
+       }
+       if (!this.fadedelay) this.fadedelay = time + SHOWNAMES_FADEDELAY;
+       if (this.csqcmodel_isdead)                                                                   // dead player, fade out slowly
+       {
+               this.alpha = max(0, this.alpha - SHOWNAMES_FADESPEED * 0.25 * frametime);
+       }
+       else if (!this.sameteam && (!onscreen || !hit)) // out of view, fade out
+       {
+               this.alpha = max(0, this.alpha - SHOWNAMES_FADESPEED * frametime);
+               this.fadedelay = 0;                         // reset fade in delay, enemy has left the view
+       }
+       else if (overlap)                               // tag overlap detected, fade out
+       {
+               this.alpha = max(0, this.alpha - SHOWNAMES_FADESPEED * frametime);
+       }
+       else if (this.sameteam)  // fade in for team mates
+       {
+               this.alpha = min(1, this.alpha + SHOWNAMES_FADESPEED * frametime);
+       }
+       else if (time > this.fadedelay)  // fade in for enemies
+       {
+               this.alpha = min(1, this.alpha + SHOWNAMES_FADESPEED * frametime);
+       }
+       float a = autocvar_hud_shownames_alpha * this.alpha;
+       // multiply by player alpha
+       if (!this.sameteam || (this.sv_entnum == player_localentnum))
+       {
+               float f = getplayeralpha(this.sv_entnum - 1);
+               if (f == 0) f = 1;
+               if (f < 0) f = 0;
+               // FIXME: alpha is negative when dead, breaking death fade
+               if (!this.csqcmodel_isdead) a *= f;
+       }
+       if (a < ALPHA_MIN_VISIBLE && gametype != MAPINFO_TYPE_CTS) return;
+       if (autocvar_hud_shownames_maxdistance)
+       {
+               if (dist >= autocvar_hud_shownames_maxdistance) return;
+               float f = autocvar_hud_shownames_maxdistance - autocvar_hud_shownames_mindistance;
+               a *= (f - max(0, dist - autocvar_hud_shownames_mindistance)) / f;
+       }
+       if (!a) return;
+       float resize = 1;
+       if (autocvar_hud_shownames_resize)  // limit resize so its never smaller than 0.5... gets unreadable
+       {
+               float f = autocvar_hud_shownames_maxdistance - autocvar_hud_shownames_mindistance;
+               resize = 0.5 + 0.5 * (f - max(0, dist - autocvar_hud_shownames_mindistance)) / f;
+       }
+       // draw the sprite image
+       if (o.z >= 0)
+       {
+               o.z = 0;
+               vector mySize = (eX * autocvar_hud_shownames_aspect + eY) * autocvar_hud_shownames_fontsize;
+               vector myPos = o - '0.5 0 0' * mySize.x - '0 1 0' * mySize.y;
+               // size scaling
+               mySize.x *= resize;
+               mySize.y *= resize;
+               myPos.x += 0.5 * (mySize.x / resize - mySize.x);
+               myPos.y += (mySize.y / resize - mySize.y);
+               // this is where the origin of the string
+               vector namepos = myPos;
+               float namewidth = mySize.x;
+               if (autocvar_hud_shownames_status && this.sameteam)
                {
-                       o.z = 0;
-
-                       vector myPos, mySize;
-                       mySize = (eX * autocvar_hud_shownames_aspect + eY) * autocvar_hud_shownames_fontsize;
-                       myPos = o - '0.5 0 0' * mySize.x - '0 1 0' * mySize.y;
-
-                       // size scaling
-                       mySize.x *= resize;
-                       mySize.y *= resize;
-
-                       myPos.x += 0.5 * (mySize.x / resize - mySize.x);
-                       myPos.y += (mySize.y / resize - mySize.y);
-
-                       vector namepos; // this is where the origin of the string
-                       float namewidth;
-
-                       namepos = myPos;
-                       namewidth = mySize.x;
-
-                       if(autocvar_hud_shownames_status && teamplay)
+                       vector v = namepos + '0 1 0' * autocvar_hud_shownames_fontsize * resize;
+                       vector s = eX * 0.5 * mySize.x + eY * resize * autocvar_hud_shownames_statusbar_height;
+                       if (this.healthvalue > 0)
                        {
-                               if(ent.sameteam)
-                               {
-                                       if(ent.healthvalue > 0)
-                                       {
-                                               HUD_Panel_DrawProgressBar(namepos + '0 1 0' * autocvar_hud_shownames_fontsize * resize, eX * 0.5 * mySize.x + eY * resize * autocvar_hud_shownames_statusbar_height, "nametag_statusbar", ent.healthvalue/autocvar_hud_panel_healtharmor_maxhealth, 0, 1, '1 0 0', a, DRAWFLAG_NORMAL);
-
-                                               if(ent.armorvalue > 0)
-                                                       HUD_Panel_DrawProgressBar(namepos + '0 1 0' * autocvar_hud_shownames_fontsize * resize + eX * 0.5 * mySize.x, eX * 0.5 * mySize.x + eY * resize * autocvar_hud_shownames_statusbar_height, "nametag_statusbar", ent.armorvalue/autocvar_hud_panel_healtharmor_maxarmor, 0, 0, '0 1 0', a, DRAWFLAG_NORMAL);
-                                       }
-                               }
+                               HUD_Panel_DrawProgressBar(v, s, "nametag_statusbar",
+                                       this.healthvalue / autocvar_hud_panel_healtharmor_maxhealth, false, 1, '1 0 0', a,
+                                       DRAWFLAG_NORMAL);
+                       }
+                       if (this.armorvalue > 0)
+                       {
+                               HUD_Panel_DrawProgressBar(v + eX * 0.5 * mySize.x, s, "nametag_statusbar",
+                                       this.armorvalue / autocvar_hud_panel_healtharmor_maxarmor, false, 0, '0 1 0', a,
+                                       DRAWFLAG_NORMAL);
                        }
-
-                       string s;
-                       s = GetPlayerName(ent.sv_entnum-1);
-                       if((autocvar_hud_shownames_decolorize == 1 && teamplay) || autocvar_hud_shownames_decolorize == 2)
-                               s = playername(s, GetPlayerColor(ent.sv_entnum-1));
-
-                       drawfontscale = '1 1 0' * resize;
-                       s = textShortenToWidth(s, namewidth, '1 1 0' * autocvar_hud_shownames_fontsize, stringwidth_colors);
-
-                       float width;
-                       width = stringwidth(s, true, '1 1 0' * autocvar_hud_shownames_fontsize);
-
-                       if (width != namewidth)
-                               namepos.x += (namewidth - width) / 2;
-                       drawcolorcodedstring(namepos, s, '1 1 0' * autocvar_hud_shownames_fontsize, a, DRAWFLAG_NORMAL);
-                       drawfontscale = '1 1 0';
                }
+               string s = GetPlayerName(this.sv_entnum - 1);
+               if ((autocvar_hud_shownames_decolorize == 1 && teamplay)
+                   || autocvar_hud_shownames_decolorize == 2) s = playername(s, GetPlayerColor(this.sv_entnum - 1));
+               drawfontscale = '1 1 0' * resize;
+               s = textShortenToWidth(s, namewidth, '1 1 0' * autocvar_hud_shownames_fontsize, stringwidth_colors);
+               float width = stringwidth(s, true, '1 1 0' * autocvar_hud_shownames_fontsize);
+               if (width != namewidth) namepos.x += (namewidth - width) / 2;
+               drawcolorcodedstring(namepos, s, '1 1 0' * autocvar_hud_shownames_fontsize, a, DRAWFLAG_NORMAL);
+               drawfontscale = '1 1 0';
        }
 }
 
-entity shownames_ent[255];
 void Draw_ShowNames_All()
 {
-       int i;
-       for(i = 0; i < maxclients; ++i)
+       for (int i = 0; i < maxclients; ++i)
        {
-               float t;
-               t = GetPlayerColor(i);
-               if(t == NUM_SPECTATOR)
-                       continue;
-
-               entity e;
-               e = shownames_ent[i];
-               if(!e)
+               entity e = shownames_ent[i];
+               if (!e)
                {
-                       e = new(shownames_tag);
-                       e.sv_entnum = i+1;
-                       shownames_ent[i] = e;
+                       e = shownames_ent[i] = new(shownames_tag);
+                       e.sv_entnum = i + 1;
                }
-
-               entity entcs;
-               entcs = entcs_receiver[i];
-               if(entcs)
+               entity entcs = entcs_receiver[i];
+               if (entcs.m_entcs_private)
                {
                        e.healthvalue = entcs.healthvalue;
                        e.armorvalue = entcs.armorvalue;
-                       e.sameteam = 1; /* (teamplay && (t == myteam)); */
+                       e.sameteam = true;
                }
                else
                {
-                       e.healthvalue = 2342;
+                       e.healthvalue = 0;
                        e.armorvalue = 0;
-                       e.sameteam = 0;
+                       e.sameteam = false;
                }
-
-               setorigin(e, getplayerorigin(i));
-               if(e.origin == GETPLAYERORIGIN_ERROR)
-                       continue;
-
-               e.csqcmodel_isdead = getplayerisdead(i);
-
+               bool dead = getplayerisdead(i);
+               if (!e.csqcmodel_isdead && entcs.has_origin) setorigin(e, entcs.origin);
+               e.csqcmodel_isdead = dead;
                Draw_ShowNames(e);
        }
 }
index 699e2d8ade41b81b6da5922980f2aa4449849009..11c8f431fd81780fe8a0aa9b3cc47305701a0103 100644 (file)
@@ -359,7 +359,7 @@ float TrueAimCheck()
                        break;
        }
 
-       vector traceorigin = getplayerorigin(player_localentnum-1) + (eZ * getstati(STAT_VIEWHEIGHT));
+       vector traceorigin = entcs_receiver[player_localentnum - 1].origin + (eZ * getstati(STAT_VIEWHEIGHT));
 
        vecs = decompressShotOrigin(getstati(STAT_SHOTORG));
 
index 8d8e8df19fecc4965ebf3242946f04282d972d47..1ea5a8bff56aa213d54992e529f7030bc0a65efc 100644 (file)
@@ -55,7 +55,6 @@ NET_HANDLE(_ENT_CLIENT_INIT, bool isnew) { return true; }
 /** Sent as a temp entity from a persistent linked entity */
 REGISTER_NET_TEMP(ENT_CLIENT_INIT)
 
-REGISTER_NET_LINKED(ENT_CLIENT_ENTCS)
 REGISTER_NET_LINKED(ENT_CLIENT_SCORES_INFO)
 REGISTER_NET_LINKED(ENT_CLIENT_SCORES)
 REGISTER_NET_LINKED(ENT_CLIENT_TEAMSCORES)
index 301b0215b4c3dcb4f8a8f350dbe1617b450bdc2b..413df981fda771b968c9fbcc1ae28336954451c7 100644 (file)
@@ -1,4 +1,7 @@
 #include "globalsound.qh"
+
+#include "../common/ent_cs.qh"
+
 #ifdef IMPLEMENTATION
        #include "../../animdecide.qh"
 
@@ -46,6 +49,7 @@
                        WriteByte(channel, fabs(chan));
                        WriteByte(channel, floor(vol * 255));
                        WriteByte(channel, floor(atten * 64));
+                       entcs_force_origin(from);
                        vector o = from.origin + 0.5 * (from.mins + from.maxs);
                        WriteCoord(channel, o.x);
                        WriteCoord(channel, o.y);
 
                NET_HANDLE(playersound, bool isnew)
                {
-                       entity ps;
-                       ps = PlayerSounds_from(ReadByte());
+                       entity ps = PlayerSounds_from(ReadByte());
                        float r = ReadByte() / 255;
                        int who = ReadByte();
-                       entity e = findfloat(world, entnum, who);
-                       if (autocvar_cl_forceplayermodels)
-                       {
-                               entity me = findfloat(world, entnum, player_currententnum);
-                               if (me.model != "null") e = me;
-                       }
+                       entity e = entcs_receiver[who - 1];
                        UpdatePlayerSounds(e);
                        string s = e.(ps.m_playersoundfld);
                        string sample = GlobalSound_sample(s, r);
                        o.x = ReadCoord();
                        o.y = ReadCoord();
                        o.z = ReadCoord();
-                       if (who == player_currententnum)
+                       if (e)
                        {
-                               // client knows better, play at current position to unlag
+                               // TODO: for non-visible players, origin should probably continue to be updated as long as the sound is playing
+                               e.origin = o;
                                sound7(e, chan, sample, vol, atten, 0, 0);
                        }
                        else
                        {
+                           LOG_WARNINGF("Missing entcs data for player %i\n", e);
+                // Can this happen?
                                entity e = new(playersound);
                                e.origin = o;
                                sound8(e, o, chan, sample, vol, atten, 0, 0);
                        return true;
                }
 
-               .int modelindex_for_playersound;
+               .string model_for_playersound;
                .int skin_for_playersound;
 
                bool autocvar_g_debug_defaultsounds;
 
                void UpdatePlayerSounds(entity this)
                {
-                       if (this.modelindex == this.modelindex_for_playersound && this.skin == this.skin_for_playersound) return;
-                       this.modelindex_for_playersound = this.modelindex;
+                       if (this.model == this.model_for_playersound && this.skin == this.skin_for_playersound) return;
+                       if (this.model_for_playersound) strunzone(this.model_for_playersound);
+                       this.model_for_playersound = strzone(this.model);
                        this.skin_for_playersound = this.skin;
                        ClearPlayerSounds(this);
                        LoadPlayerSounds(this, "sound/player/default.sounds", true);
diff --git a/qcsrc/common/ent_cs.qc b/qcsrc/common/ent_cs.qc
new file mode 100644 (file)
index 0000000..e016dd3
--- /dev/null
@@ -0,0 +1,165 @@
+#include "ent_cs.qh"
+
+// #define PROP(public, fld, sv, cl)
+#define ENTCS_NETPROPS(PROP) \
+       PROP(true, sv_entnum, \
+       { WriteByte(MSG_ENTITY, etof(player) - 1); }, \
+       { this.sv_entnum = ReadByte(); }) \
+    \
+       PROP(false, origin, \
+       { WriteShort(MSG_ENTITY, this.origin.x);  WriteShort(MSG_ENTITY, this.origin.y); \
+         WriteShort(MSG_ENTITY, this.origin.z); }, \
+       { this.has_origin = true; vector v; v.x = ReadShort(); v.y = ReadShort(); v.z = ReadShort(); setorigin(this, v); }) \
+    \
+       PROP(false, angles_y, \
+       { WriteByte(MSG_ENTITY, this.angles.y / 360 * 256); }, \
+       { vector v = '0 0 0'; v.y = ReadByte() / 256 * 360; this.angles = v; }) \
+    \
+       PROP(false, health, \
+       { WriteByte(MSG_ENTITY, this.health / 10);  /* FIXME: use a better scale? */ }, \
+       { this.healthvalue = ReadByte() * 10; }) \
+    \
+       PROP(false, armorvalue, \
+       { WriteByte(MSG_ENTITY, this.armorvalue / 10);  /* FIXME: use a better scale? */ }, \
+       { this.armorvalue = ReadByte() * 10; }) \
+    \
+       PROP(true, netname, \
+       { WriteString(MSG_ENTITY, this.netname); }, \
+       { if (this.netname) strunzone(this.netname); this.netname = strzone(ReadString()); }) \
+    \
+       PROP(true, model, \
+       { WriteString(MSG_ENTITY, this.model); }, \
+       { if (this.model) strunzone(this.model); this.model = strzone(ReadString()); }) \
+    \
+       PROP(true, skin, \
+       { WriteByte(MSG_ENTITY, this.skin); }, \
+       { this.skin = ReadByte(); }) \
+    \
+       /**/
+
+#ifdef SVQC
+
+       int ENTCS_PUBLICMASK = 0;
+       STATIC_INIT(ENTCS_PUBLICMASK)
+       {
+               int i = 1;
+               #define X(public, fld, sv, cl) { if (public) ENTCS_PUBLICMASK |= BIT(i); } i += 1;
+               ENTCS_NETPROPS(X);
+       #undef X
+               if (i >= BITS(16 - 1)) LOG_FATAL("Exceeded ENTCS_NETPROPS limit");
+       }
+
+       bool entcs_customize()
+       {
+               SELFPARAM();
+               entity player = this.owner;
+               return IS_PLAYER(player)             // player must be active
+                      && player.deadflag == DEAD_NO // player must be alive
+               ;
+       }
+
+       bool entcs_send(entity this, entity to, int sf)
+       {
+               entity player = this.owner;
+               sf |= 1;
+               if (IS_PLAYER(to) || to.caplayer)                                  // unless spectating,
+               {
+                       bool same_team = (to == player) || (teamplay && player.team == to.team);
+                       if (!same_team && !radar_showennemies) sf &= ENTCS_PUBLICMASK; // no private updates
+               }
+               sf |= this.m_forceupdate;
+               this.m_forceupdate = 0;
+               WriteHeader(MSG_ENTITY, ENT_CLIENT_ENTCS);
+               WriteShort(MSG_ENTITY, sf);
+               int i = 1;
+               #define X(public, fld, sv, cl) { if (sf & BIT(i)) sv; } i += 1;
+               ENTCS_NETPROPS(X);
+       #undef X
+               return true;
+       }
+
+       void entcs_think()
+       {
+               SELFPARAM();
+               this.nextthink = time + 0.033333333333;  // TODO: increase this to like 0.15 once the client can do smoothing
+               entity o = this.owner;
+               int i = 1;
+               #define X(public, fld, sv, cl) \
+                       if (o.fld != this.fld) \
+                       { \
+                               this.fld = o.fld; \
+                               this.SendFlags |= BIT(i); \
+                       } \
+                       i += 1;
+               ENTCS_NETPROPS(X);
+       #undef X
+       }
+
+       void entcs_attach(entity player)
+       {
+               entity e = player.entcs = new(entcs_sender);
+               make_pure(e);
+               e.owner = player;
+               e.think = entcs_think;
+               e.nextthink = time;
+               Net_LinkEntity(e, false, 0, entcs_send);
+               e.customizeentityforclient = entcs_customize;
+       }
+
+       void entcs_detach(entity player)
+       {
+               if (!player.entcs) return;
+               remove(player.entcs);
+               player.entcs = NULL;
+       }
+
+#endif
+
+#ifdef CSQC
+
+       void Ent_RemoveEntCS()
+       {
+               SELFPARAM();
+               entcs_receiver[this.sv_entnum] = NULL;
+       }
+
+       void entcs_think()
+       {
+               SELFPARAM();
+               this.nextthink = time;
+               entity e = CSQCModel_server2csqc(this.sv_entnum + 1);
+               bool exists = !!e;
+               if (exists)
+               {
+                       this.has_origin = true;
+                       this.origin = e.origin;
+                       // `cl_forceplayermodels 1` sounds will be wrong until the player has been in the PVS, but so be it
+                       this.model = e.model;
+               }
+       }
+
+       NET_HANDLE(ENT_CLIENT_ENTCS, bool isnew)
+       {
+               if (isnew)
+               {
+                       make_pure(this);
+                       this.classname = "entcs_receiver";
+                       this.entremove = Ent_RemoveEntCS;
+                       this.think = entcs_think;
+                       this.nextthink = time;
+               }
+               InterpolateOrigin_Undo();
+               int sf = ReadShort();
+               this.has_origin = false;
+               this.m_entcs_private = boolean(sf & 1);
+               int i = 1;
+               #define X(public, fld, sv, cl) { if (sf & BIT(i)) cl; } i += 1;
+               ENTCS_NETPROPS(X);
+       #undef X
+               entcs_receiver[this.sv_entnum] = this;
+               this.iflags |= IFLAG_ORIGIN;
+               InterpolateOrigin_Note();
+               return true;
+       }
+
+#endif
diff --git a/qcsrc/common/ent_cs.qh b/qcsrc/common/ent_cs.qh
new file mode 100644 (file)
index 0000000..598ff05
--- /dev/null
@@ -0,0 +1,49 @@
+#ifndef ENT_CS_H
+#define ENT_CS_H
+
+REGISTER_NET_LINKED(ENT_CLIENT_ENTCS)
+
+/** True when private information such as origin is available */
+.bool m_entcs_private;
+
+/** True when a recent origin is available */
+.bool has_origin;
+
+#ifdef SVQC
+/**
+ * The point of these entities is to avoid the problems
+ * with clientprediction.
+ * If you add SendEntity to players, the engine will not
+ * do any prediction anymore, and you'd have to write the whole
+ * prediction code in CSQC, you want that? :P
+ * Data can depend on gamemode. For now, it serves as GPS entities
+ * in onslaught... YAY ;)
+ */
+
+.entity entcs;
+
+bool entcs_customize();
+
+bool entcs_send(entity this, entity to, int sf);
+
+void entcs_think();
+
+void entcs_attach(entity e);
+
+void entcs_detach(entity e);
+
+.int m_forceupdate;
+
+/** Force an origin update, for player sounds */
+#define entcs_force_origin(e) ((e).entcs.m_forceupdate = BIT(2))
+
+#endif
+
+#ifdef CSQC
+
+entity entcs_receiver[255]; // 255 is the engine limit on maxclients
+#define entcs_is_self(e) ((e).sv_entnum + 1 == player_localentnum)
+
+#endif
+
+#endif
index b873e62388d1c5f19755a9d3c6f5b0da5cdc63a0..749237fa311b9c70c6c6e97714d946e908536926 100644 (file)
@@ -1227,7 +1227,7 @@ NET_HANDLE(ENT_CLIENT_ARC_BEAM, bool isnew)
                else
                {
                        // use player origin so that third person display still works
-                       self.origin = getplayerorigin(player_localnum) + ('0 0 1' * getstati(STAT_VIEWHEIGHT));
+                       self.origin = entcs_receiver[player_localnum].origin + ('0 0 1' * getstati(STAT_VIEWHEIGHT));
                }
        }
 
index 50339a73038121a5b8541200be0aede37db6bd1a..0f898c3401b1b41df7b15ad1bcc717600f4a8002 100644 (file)
@@ -576,8 +576,6 @@ bool WarpZoneLib_BadEntity(entity e)
        if (is_pure(e)) return true;
        switch (s)
        {
-               case "entcs_sender":
-               case "entcs_receiver":
                // case "net_linked": // actually some real entities are linked without classname, fail
                case "":
                        return true;
index 454ddc9030e6a0d6ad6475ce959bc11dba5c0974..26d089245f4822a15966f7505dc68bc3a54ccf74 100644 (file)
@@ -3,7 +3,6 @@
 #include "anticheat.qh"
 #include "cl_impulse.qh"
 #include "cl_player.qh"
-#include "ent_cs.qh"
 #include "ipban.qh"
 #include "miscfunctions.qh"
 #include "portals.qh"
@@ -23,6 +22,7 @@
 #include "bot/bot.qh"
 #include "bot/navigation.qh"
 
+#include "../common/ent_cs.qh"
 #include "../common/vehicles/all.qh"
 #include "../common/triggers/teleporters.qh"
 
@@ -1178,7 +1178,7 @@ void ClientConnect ()
        else
                stuffcmd(self, "set _teams_available 0\n");
 
-       attach_entcs(self);
+       entcs_attach(self);
 
        bot_relinkplayerlist();
 
@@ -1264,7 +1264,7 @@ void ClientDisconnect ()
 
        bot_clientdisconnect();
 
-       detach_entcs(self);
+       entcs_detach(self);
 
        if(autocvar_sv_eventlog)
                GameLogEcho(strcat(":part:", ftos(self.playerid)));
diff --git a/qcsrc/server/ent_cs.qc b/qcsrc/server/ent_cs.qc
deleted file mode 100644 (file)
index 9c98e7d..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-#include "ent_cs.qh"
-
-float entcs_customize()
-{
-       SELFPARAM();
-       entity o = self.owner;
-       if(o.deadflag != DEAD_NO)
-               return false;
-       if (!IS_PLAYER(o))
-               return false;
-       if(other == o)
-               return false;
-       if((IS_PLAYER(other)) || other.caplayer)
-               if(!teamplay || o.team != other.team)
-                       if (!radar_showennemies)
-                               return false;
-       return true;
-}
-
-bool entcs_send(entity this, entity to, int sf)
-{
-       WriteHeader(MSG_ENTITY, ENT_CLIENT_ENTCS);
-       WriteByte(MSG_ENTITY, sf);
-       if(sf & BIT(0))
-               WriteByte(MSG_ENTITY, num_for_edict(self.owner) - 1);
-       if(sf & BIT(1))
-       {
-               WriteShort(MSG_ENTITY, self.origin.x);
-               WriteShort(MSG_ENTITY, self.origin.y);
-               WriteShort(MSG_ENTITY, self.origin.z);
-       }
-       if(sf & BIT(2))
-               WriteByte(MSG_ENTITY, self.angles.y * 256.0 / 360);
-       if(sf & BIT(3))
-               WriteByte(MSG_ENTITY, self.health / 10); // FIXME use a better scale?
-       if(sf & BIT(4))
-               WriteByte(MSG_ENTITY, self.armorvalue / 10); // FIXME use a better scale?
-       return true;
-}
-
-void entcs_think()
-{
-       SELFPARAM();
-       self.nextthink = time + 0.033333333333; // increase this to like 0.15 once the client can do smoothing
-       entity o = self.owner;
-       if (o.origin != self.origin)
-       {
-               setorigin(self, o.origin);
-               self.SendFlags |= BIT(1);
-       }
-       if (o.angles.y != self.angles.y)
-       {
-               self.angles = o.angles;
-               self.SendFlags |= BIT(2);
-       }
-       if (o.health != self.health)
-       {
-               self.health = o.health;
-               self.SendFlags |= BIT(3);
-       }
-       if (o.armorvalue != self.armorvalue)
-       {
-               self.armorvalue = o.armorvalue;
-               self.SendFlags |= BIT(4);
-       }
-}
-
-entity attach_entcs(entity e)
-{
-       entity ent = e.entcs = new(entcs_sender);
-       make_pure(ent);
-       ent.owner = e;
-       ent.think = entcs_think;
-       ent.nextthink = time;
-
-       Net_LinkEntity(ent, false, 0, entcs_send);
-       ent.customizeentityforclient = entcs_customize;
-
-       return ent;
-}
-
-void detach_entcs(entity e)
-{
-       if (!e.entcs) return;
-       remove(e.entcs);
-       e.entcs = NULL;
-}
diff --git a/qcsrc/server/ent_cs.qh b/qcsrc/server/ent_cs.qh
deleted file mode 100644 (file)
index 1cfc854..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-#ifndef ENT_CS_H
-#define ENT_CS_H
-
-/**
- * The point of these entities is to avoid the problems
- * with clientprediction.
- * If you add SendEntity to players, the engine will not
- * do any prediction anymore, and you'd have to write the whole
- * prediction code in CSQC, you want that? :P
- * Data can depend on gamemode. For now, it serves as GPS entities
- * in onslaught... YAY ;)
- */
-
-.entity entcs;
-
-float entcs_customize();
-
-bool entcs_send(entity this, entity to, int sf);
-
-void entcs_think();
-
-entity attach_entcs(entity e);
-
-void detach_entcs(entity e);
-
-#endif
index 08a9d4d22b14f1ff50540d4f2e64ee7862f03f40..e23909812d27dd6494ace3e26b6a9aa42ce49d7a 100644 (file)
@@ -10,7 +10,6 @@
 #include "cl_client.qc"
 #include "cl_impulse.qc"
 #include "cl_player.qc"
-#include "ent_cs.qc"
 #include "g_damage.qc"
 #include "g_hook.qc"
 // #include "g_lights.qc" // TODO: was never used
@@ -58,6 +57,7 @@
 #include "../common/campaign_file.qc"
 #include "../common/campaign_setup.qc"
 #include "../common/effects/effectinfo.qc"
+#include "../common/ent_cs.qc"
 #include "../common/mapinfo.qc"
 #include "../common/minigames/minigames.qc"
 #include "../common/minigames/sv_minigames.qc"