Inheritance: INetworkInterpolation
 private void DrawPlayers(float dt)
 {
     totaltime += dt;
     foreach (var k in clients.Players)
     {
         if (!playerdrawinfo.ContainsKey(k.Key))
         {
             playerdrawinfo[k.Key] = new PlayerDrawInfo();
             NetworkInterpolation n = new NetworkInterpolation();
             n.req = new PlayerInterpolate();
             n.DELAY = 0.5f;
             n.EXTRAPOLATE = true;
             n.EXTRAPOLATION_TIME = 0.3f;
             playerdrawinfo[k.Key].interpolation = n;
         }
         PlayerDrawInfo info = playerdrawinfo[k.Key];
         Vector3 realpos = k.Value.Position;
         if (realpos != info.lastrealpos
             || k.Value.Heading != info.lastrealheading
             || k.Value.Pitch != info.lastrealpitch)
         {
             info.interpolation.AddNetworkPacket(
                 new PlayerInterpolationState()
                 {
                     position = realpos,
                     heading = k.Value.Heading,
                     pitch = k.Value.Pitch,
                 },
                 totaltime);
         }
         var curstate = ((PlayerInterpolationState)info.interpolation.InterpolatedState(totaltime));
         if (curstate == null)
         {
             curstate = new PlayerInterpolationState();
         }
         //do not interpolate player position if player is controlled by game world
         if (network.EnablePlayerUpdatePosition.ContainsKey(k.Key) && !network.EnablePlayerUpdatePosition[k.Key])
         {
             curstate.position = k.Value.Position;
         }
         Vector3 curpos = curstate.position;
         bool moves = curpos != info.lastcurpos;
         DrawCharacter(info.anim, curpos + new Vector3(0, -CharacterPhysics.characterheight, 0)
             + new Vector3(0, -CharacterPhysics.walldistance, 0),
             curstate.heading, curstate.pitch, moves, dt, GetPlayerTexture(k.Key),
             clients.Players[k.Key].AnimationHint);
         info.lastcurpos = curpos;
         info.lastrealpos = realpos;
         info.lastrealheading = k.Value.Heading;
         info.lastrealpitch = k.Value.Pitch;
     }
     if (ENABLE_TPP_VIEW)
     {
         DrawCharacter(localplayeranim, LocalPlayerPosition + new Vector3(0, -CharacterPhysics.walldistance, 0),
             NetworkHelper.HeadingByte(LocalPlayerOrientation),
             NetworkHelper.PitchByte(LocalPlayerOrientation),
             lastlocalplayerpos != LocalPlayerPosition, dt, GetPlayerTexture(255), localplayeranimationhint);
         lastlocalplayerpos = LocalPlayerPosition;
     }
 }
 private void DrawPlayers(float dt)
 {
     totaltime += dt;
     foreach (var k in d_Clients.Players)
     {
         if (k.Key == 255)
         {
             continue;
         }
         if (!playerdrawinfo.ContainsKey(k.Key))
         {
             playerdrawinfo[k.Key] = new PlayerDrawInfo();
             NetworkInterpolation n = new NetworkInterpolation();
             n.req = new PlayerInterpolate();
             n.DELAY = 0.5f;
             n.EXTRAPOLATE = true;
             n.EXTRAPOLATION_TIME = 0.3f;
             playerdrawinfo[k.Key].interpolation = n;
         }
         PlayerDrawInfo info = playerdrawinfo[k.Key];
         Vector3 realpos = k.Value.Position;
         if (realpos != info.lastrealpos
             || k.Value.Heading != info.lastrealheading
             || k.Value.Pitch != info.lastrealpitch)
         {
             info.interpolation.AddNetworkPacket(
                 new PlayerInterpolationState()
                 {
                     position = realpos,
                     heading = k.Value.Heading,
                     pitch = k.Value.Pitch,
                 },
                 totaltime);
         }
         var curstate = ((PlayerInterpolationState)info.interpolation.InterpolatedState(totaltime));
         if (curstate == null)
         {
             curstate = new PlayerInterpolationState();
         }
         //do not interpolate player position if player is controlled by game world
         if (EnablePlayerUpdatePosition.ContainsKey(k.Key) && !EnablePlayerUpdatePosition[k.Key])
         {
             curstate.position = k.Value.Position;
         }
         Vector3 curpos = curstate.position;
         bool moves = curpos != info.lastcurpos;
         info.lastcurpos = curpos;
         info.lastrealpos = realpos;
         info.lastrealheading = k.Value.Heading;
         info.lastrealpitch = k.Value.Pitch;
         if (!d_FrustumCulling.SphereInFrustum(curpos.X, curpos.Y, curpos.Z, 3))
         {
             continue;
         }
         float shadow = (float)d_Shadows.MaybeGetLight((int)curpos.X, (int)curpos.Z, (int)curpos.Y) / d_Shadows.maxlight;
         GL.Color3(shadow, shadow, shadow);
         Vector3 FeetPos = curpos + new Vector3(0, -CharacterPhysics.characterheight, 0)
                 + new Vector3(0, -CharacterPhysics.walldistance, 0);
         var animHint = d_Clients.Players[k.Key].AnimationHint;
         if (k.Value.Type == PlayerType.Player)
         {
             DrawCharacter(info.anim, FeetPos,
                 curstate.heading, curstate.pitch, moves, dt, GetPlayerTexture(k.Key), animHint);
         }
         else
         {
             int type = k.Value.MonsterType;
             if (!MonsterRenderers.ContainsKey(type))
             {
                 var r = new CharacterRendererMonsterCode();
                 r.Load(new List<string>(d_DataMonsters.MonsterCode[type]));
                 MonsterRenderers[type] = r;
             }
             MonsterRenderers[type].SetAnimation("walk");
             //curpos += new Vector3(0, -CharacterPhysics.walldistance, 0); //todos
             MonsterRenderers[type].DrawCharacter(info.anim, curpos,
                 (byte)(-curstate.heading - 256 / 4), curstate.pitch,
                 moves, dt, GetPlayerTexture(k.Key), animHint);
         }
         GL.Color3(1f, 1f, 1f);
     }
     if (ENABLE_TPP_VIEW)
     {
         float shadow = (float)d_Shadows.MaybeGetLight(
             (int)LocalPlayerPosition.X,
             (int)LocalPlayerPosition.Z,
             (int)LocalPlayerPosition.Y)
             / d_Shadows.maxlight;
         GL.Color3(shadow, shadow, shadow);
         DrawCharacter(localplayeranim, LocalPlayerPosition + new Vector3(0, -CharacterPhysics.walldistance, 0),
             NetworkHelper.HeadingByte(LocalPlayerOrientation),
             NetworkHelper.PitchByte(LocalPlayerOrientation),
             lastlocalplayerpos != LocalPlayerPosition, dt, GetPlayerTexture(255), localplayeranimationhint);
         lastlocalplayerpos = LocalPlayerPosition;
         GL.Color3(1f, 1f, 1f);
     }
 }