]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Viewmodels: smooth switch with high latency
authorTimePath <andrew.hardaker1995@gmail.com>
Mon, 30 Nov 2015 01:25:28 +0000 (12:25 +1100)
committerTimePath <andrew.hardaker1995@gmail.com>
Mon, 30 Nov 2015 01:25:28 +0000 (12:25 +1100)
qcsrc/client/view.qc
qcsrc/common/weapons/all.qc
qcsrc/lib/net.qh
qcsrc/server/defs.qh
qcsrc/server/weapons/weaponsystem.qc

index 07fa43eddd18a6a032405fa363e4e05f592523dd..df4a6d335552a1520fd6eac509fb221718ff692a 100644 (file)
@@ -264,6 +264,8 @@ void viewmodel_animate(entity this)
 }
 
 .vector viewmodel_origin, viewmodel_angles;
+.float weapon_nextthink;
+.float weapon_eta_last;
 
 void viewmodel_draw(entity this)
 {
@@ -300,9 +302,10 @@ void viewmodel_draw(entity this)
                if (!this.animstate_override)
                        anim_set(this, this.anim_idle, true, false, false);
        }
-       float eta = (STAT(WEAPON_NEXTTHINK) - time); // TODO: / W_WeaponRateFactor();
        float f = 0; // 0..1; 0: fully active
-       switch (this.state)
+       float eta = (this.weapon_nextthink - time); // TODO: / W_WeaponRateFactor();
+       if (eta <= 0) f = this.weapon_eta_last;
+       else switch (this.state)
        {
                case WS_RAISE:
                {
@@ -324,6 +327,7 @@ void viewmodel_draw(entity this)
                        break;
                }
        }
+       this.weapon_eta_last = f;
        this.origin = this.viewmodel_origin;
        this.angles = this.viewmodel_angles;
        this.angles_x = (-90 * f * f);
index f0b606e8b1b9ddc6437ae514ccc8deb62fe351de..ab613bb940195a257af28f5b758464d7a671d827 100644 (file)
@@ -561,6 +561,7 @@ NET_HANDLE(wframe, bool isNew)
        bool restartanim = ReadByte();
        anim_set(viewmodel, a, !restartanim, restartanim, restartanim);
        viewmodel.state = ReadByte();
+       viewmodel.weapon_nextthink = ReadFloat();
        viewmodel.alpha = ReadByte() / 255;
        return true;
 }
@@ -578,6 +579,7 @@ void wframe_send(entity actor, entity weaponentity, vector a, bool restartanim)
        WriteCoord(channel, a.z);
        WriteByte(channel, restartanim);
        WriteByte(channel, weaponentity.state);
+       WriteFloat(channel, weaponentity.weapon_nextthink);
        WriteByte(channel, weaponentity.alpha * 255);
 }
 #endif
index 50461945722cbbf250b3b1f667be1e97f4ee1556..bd1c5e14ad8c94f3b69c8429d662a07300c32c94 100644 (file)
@@ -187,7 +187,7 @@ STATIC_INIT(RegisterTempEntities_renumber)
                }
 
                #define ReadFloat() ReadCoord()
-        vector ReadVector() { vector v; v.x = ReadFloat(); v_y = ReadFloat(); v.z = ReadFloat(); return v; }
+        vector ReadVector() { vector v; v.x = ReadFloat(); v.y = ReadFloat(); v.z = ReadFloat(); return v; }
                vector ReadVector2D() { vector v; v.x = ReadFloat(); v.y = ReadFloat(); v.z = 0; return v; }
 
                float ReadApproxPastTime()
index a18dd3c43029e6d27c0c164fbc788d79738da5e7..62fec55feee4890ecd8b100eaa9b51ebb38ff5af 100644 (file)
@@ -148,7 +148,7 @@ float client_hasweapon(entity cl, float wpn, float andammo, float complain);
 void w_clear(Weapon thiswep, entity actor, .entity weaponentity, int fire);
 void w_ready(Weapon thiswep, entity actor, .entity weaponentity, int fire);
 // VorteX: standalone think for weapons, so normal think on weaponentity can be reserved by weaponflashes (which needs update even player dies)
-.float weapon_nextthink = _STAT(WEAPON_NEXTTHINK);
+.float weapon_nextthink;
 .void(Weapon thiswep, entity actor, .entity weaponentity, int fire) weapon_think;
 
 
index 54bc2c9a5f2dba2336a7b7a47ed73d9f9d9fe891..d8706b26e7993dd4c81f4aba88187a3b9d068329 100644 (file)
@@ -335,18 +335,16 @@ void weapon_thinkf(entity actor, .entity weaponentity, WFRAME fr, float t, void(
        vector or = v_right;
        vector ou = v_up;
 
+       vector a = '0 0 0';
        if (this)
        {
                this.wframe = fr;
-               vector a = '0 0 0';
                if (fr == WFRAME_IDLE) a = this.anim_idle;
                else if (fr == WFRAME_FIRE1) a = this.anim_fire1;
                else if (fr == WFRAME_FIRE2) a = this.anim_fire2;
                else  // if (fr == WFRAME_RELOAD)
                        a = this.anim_reload;
                a.z *= g_weaponratefactor;
-               entity e;
-               FOR_EACH_CLIENT(e) if (e == actor || (IS_SPEC(e) && e.enemy == actor)) wframe_send(e, this, a, restartanim);
        }
 
        v_forward = of;
@@ -371,20 +369,27 @@ void weapon_thinkf(entity actor, .entity weaponentity, WFRAME fr, float t, void(
                // dprint("reset weapon animation timer at ", ftos(time), "\n");
        }
        this.weapon_nextthink += t;
-       if (weaponentity == weaponentities[0]) actor.weapon_nextthink = this.weapon_nextthink;
+       if (weaponentity == weaponentities[0]) STAT(WEAPON_NEXTTHINK, actor) = this.weapon_nextthink;
        this.weapon_think = func;
        // dprint("next ", ftos(this.weapon_nextthink), "\n");
 
+       if (this)
+       {
+               entity e;
+               FOR_EACH_CLIENT(e) if (e == actor || (IS_SPEC(e) && e.enemy == actor)) wframe_send(e, this, a, restartanim);
+       }
+
        if ((fr == WFRAME_FIRE1 || fr == WFRAME_FIRE2) && t)
        {
-               if ((actor.weapon == WEP_SHOCKWAVE.m_id || actor.weapon == WEP_SHOTGUN.m_id)
-                   && fr == WFRAME_FIRE2) animdecide_setaction(actor, ANIMACTION_MELEE, restartanim);
-               else animdecide_setaction(actor, ANIMACTION_SHOOT, restartanim);
+               int act = (fr == WFRAME_FIRE2 && (actor.weapon == WEP_SHOCKWAVE.m_id || actor.weapon == WEP_SHOTGUN.m_id))
+                       ? ANIMACTION_MELEE
+                       : ANIMACTION_SHOOT
+                       ;
+               animdecide_setaction(actor, act, restartanim);
        }
-       else
+       else if (actor.anim_upper_action == ANIMACTION_SHOOT || actor.anim_upper_action == ANIMACTION_MELEE)
        {
-               if (actor.anim_upper_action == ANIMACTION_SHOOT
-                   || actor.anim_upper_action == ANIMACTION_MELEE) actor.anim_upper_action = 0;
+               actor.anim_upper_action = 0;
        }
 }
 
@@ -486,13 +491,7 @@ void W_WeaponFrame(entity actor)
                                entity oldwep = Weapons_from(actor.weapon);
 
                                // set up weapon switch think in the future, and start drop anim
-                               if (
-#if INDEPENDENT_ATTACK_FINISHED
-                                           true
-#else
-                                           ATTACK_FINISHED(actor, slot) <= time + actor.weapon_frametime * 0.5
-#endif
-                                  )
+                               if (INDEPENDENT_ATTACK_FINISHED || ATTACK_FINISHED(actor, weaponslot(weaponentity)) <= time + actor.weapon_frametime * 0.5)
                                {
                                        sound(actor, CH_WEAPON_SINGLE, SND_WEAPON_SWITCH, VOL_BASE, ATTN_NORM);
                                        this.state = WS_DROP;