예제 #1
0
        /// <summary>
        /// Ticks the physics entity, doing nothing at all.
        /// </summary>
        public override void Tick()
        {
            if (!TheRegion.IsVisible(GetPosition()))
            {
                if (Body.ActivityInformation.IsActive)
                {
                    wasActive = true;
                    // TODO: Is this needed?
                    if (Body.ActivityInformation.SimulationIsland != null)
                    {
                        Body.ActivityInformation.SimulationIsland.IsActive = false;
                    }
                }
            }
            else if (wasActive)
            {
                wasActive = false;
                Body.ActivityInformation.Activate();
            }
            Vector3i cpos = TheRegion.ChunkLocFor(GetPosition());

            if (CanSave && !TheRegion.LoadedChunks.ContainsKey(cpos))
            {
                TheRegion.LoadChunk(cpos);
            }
        }
예제 #2
0
 public bool ShouldSeePosition(Location pos)
 {
     if (pos.IsNaN())
     {
         return(false);
     }
     return(ShouldSeeChunk(TheRegion.ChunkLocFor(pos)));
 }
예제 #3
0
 public bool ShouldLoadPositionPreviously(Location pos)
 {
     if (pos.IsNaN())
     {
         return(false);
     }
     return(ShouldLoadChunkPreviously(TheRegion.ChunkLocFor(pos)));
 }
예제 #4
0
 public bool ShouldSeeLODPositionOneSecondAgo(Location pos)
 {
     if (pos.IsNaN() || losPos.IsNaN())
     {
         return(false);
     }
     return(ShouldSeeLODChunkOneSecondAgo(TheRegion.ChunkLocFor(pos)));
 }
예제 #5
0
        public bool ShouldLoadChunk(Vector3i cpos)
        {
            Vector3i wpos = TheRegion.ChunkLocFor(LoadRelPos);

            if (Math.Abs(cpos.X - wpos.X) > (ViewRadiusInChunks + ViewRadExtra5) ||
                Math.Abs(cpos.Y - wpos.Y) > (ViewRadiusInChunks + ViewRadExtra5) ||
                Math.Abs(cpos.Z - wpos.Z) > (ViewRadiusInChunks + ViewRadExtra5Height))
            {
                return(false);
            }
            return(true);
        }
예제 #6
0
        public bool ShouldSeeLODChunkOneSecondAgo(Vector3i cpos)
        {
            Vector3i wpos = TheRegion.ChunkLocFor(losPos);

            if (Math.Abs(cpos.X - wpos.X) > (ViewRadiusInChunks + ViewRadExtra5) ||
                Math.Abs(cpos.Y - wpos.Y) > (ViewRadiusInChunks + ViewRadExtra5) ||
                Math.Abs(cpos.Z - wpos.Z) > (ViewRadiusInChunks + ViewRadExtra5Height))
            {
                return(false);
            }
            return(true);
        }
예제 #7
0
        /// <summary>
        /// Ticks the physics entity.
        /// </summary>
        public override void Tick()
        {
            if (!TheRegion.IsVisible(GetPosition()))
            {
                if (Body.ActivityInformation.IsActive)
                {
                    wasActive = true;
                    // TODO: Is this needed?
                    if (Body.ActivityInformation.SimulationIsland != null)
                    {
                        Body.ActivityInformation.SimulationIsland.IsActive = false;
                    }
                }
            }
            else if (wasActive)
            {
                wasActive = false;
                Body.ActivityInformation.Activate();
            }
            Vector3i cpos = TheRegion.ChunkLocFor(GetPosition());

            if (CanSave && !TheRegion.TryFindChunk(cpos, out Chunk _)) // TODO: is this really needed every tick?
            {
                TheRegion.LoadChunk(cpos);
            }
            if (!GenBlockShadow)// TODO: and world config allows trackables
            {
                if (TheRegion.GetEntitiesInRadius(GetPosition(), 1.5f, EntityType.SMASHER_PRIMTIVE).Count == 0)
                {
                    // TODO: 5 * 60 -> world config
                    TheRegion.SpawnEntity(new SmasherPrimitiveEntity(TheRegion, Math.Min((float)GetScaleEstimate(), 2f), TheRegion.TheWorld.GlobalTickTime + (5 * 60))
                    {
                        Position = GetPosition()
                    });
                }
            }
            // TODO: More genericish
            if (TheRegion.Generator is SphereGeneratorCore)
            {
                Location pos   = new Location(Body.Position);
                double   scale = TheRegion.TheWorld.GeneratorScale;
                Location gravDir;
                if (pos.LengthSquared() > scale * scale)
                {
                    gravDir = new Location(scale / pos.X, scale / pos.Y, scale / pos.Z);
                }
                else
                {
                    gravDir = pos / scale;
                }
                SetGravity(gravDir * (-TheRegion.GravityStrength));
            }
        }
예제 #8
0
        public void SetTypingStatus(bool isTyping)
        {
            IsTyping = isTyping;
            // TODO: Generic find-all-players-that-can-see-me method
            Vector3i           ch   = TheRegion.ChunkLocFor(GetPosition());
            SetStatusPacketOut pack = new SetStatusPacketOut(this, ClientStatus.TYPING, (byte)(IsTyping ? 1 : 0));

            foreach (PlayerEntity player in TheRegion.Players)
            {
                if (player.CanSeeChunk(ch))
                {
                    player.Network.SendPacket(pack);
                }
            }
        }
예제 #9
0
        public bool ShouldSeeChunk(Vector3i cpos)
        {
            if (LoadRelPos.IsNaN())
            {
                return(false);
            }
            Vector3i wpos = TheRegion.ChunkLocFor(LoadRelPos);

            if (Math.Abs(cpos.X - wpos.X) > ViewRadiusInChunks ||
                Math.Abs(cpos.Y - wpos.Y) > ViewRadiusInChunks ||
                Math.Abs(cpos.Z - wpos.Z) > ViewRadiusInChunks)
            {
                return(false);
            }
            return(true);
        }
예제 #10
0
        /// <summary>
        /// Ticks the physics entity.
        /// </summary>
        public override void Tick()
        {
            if (!TheRegion.IsVisible(GetPosition()))
            {
                if (Body.ActivityInformation.IsActive)
                {
                    wasActive = true;
                    // TODO: Is this needed?
                    if (Body.ActivityInformation.SimulationIsland != null)
                    {
                        Body.ActivityInformation.SimulationIsland.IsActive = false;
                    }
                }
            }
            else if (wasActive)
            {
                wasActive = false;
                Body.ActivityInformation.Activate();
            }
            Vector3i cpos = TheRegion.ChunkLocFor(GetPosition());

            if (CanSave && !TheRegion.LoadedChunks.ContainsKey(cpos)) // TODO: is this really needed every tick?
            {
                TheRegion.LoadChunk(cpos);
            }
            // TODO: More genericish
            if (TheRegion.Generator is SphereGeneratorCore)
            {
                Location pos   = new Location(Body.Position);
                double   scale = TheRegion.TheWorld.GeneratorScale;
                Location gravDir;
                if (pos.LengthSquared() > scale * scale)
                {
                    gravDir = new Location(scale / pos.X, scale / pos.Y, scale / pos.Z);
                }
                else
                {
                    gravDir = pos / scale;
                }
                SetGravity(gravDir * (-TheRegion.GravityStrength));
            }
        }
예제 #11
0
        void ChunkMarchAndSend()
        {
            // TODO: is this the most efficient it can be?
            int maxChunks   = TheServer.CVars.n_chunkspertick.ValueI;
            int chunksFound = 0;

            if (LoadRelPos.IsNaN() || LoadRelDir.IsNaN() || LoadRelDir.LengthSquared() < 0.1f)
            {
                return;
            }
            Matrix             proj     = Matrix.CreatePerspectiveFieldOfViewRH(Max_FOV * (double)Utilities.PI180, 1, 0.5f, 3000f);
            Matrix             view     = Matrix.CreateLookAtRH((LoadRelPos - LoadRelDir * 8).ToBVector(), (LoadRelPos + LoadRelDir * 8).ToBVector(), new Vector3(0, 0, 1));
            Matrix             combined = view * proj;
            BFrustum           bfs      = new BFrustum(combined);
            Vector3i           start    = TheRegion.ChunkLocFor(LoadRelPos);
            HashSet <Vector3i> seen     = new HashSet <Vector3i>();
            Queue <Vector3i>   toSee    = new Queue <Vector3i>();

            toSee.Enqueue(start);
            while (toSee.Count > 0)
            {
                Vector3i cur = toSee.Dequeue();
                seen.Add(cur);
                if (Math.Abs(cur.X - start.X) > (ViewRadiusInChunks + ViewRadExtra5) ||
                    Math.Abs(cur.Y - start.Y) > (ViewRadiusInChunks + ViewRadExtra5) ||
                    Math.Abs(cur.Z - start.Z) > (ViewRadiusInChunks + ViewRadExtra5Height))
                {
                    continue;
                }
                if (Math.Abs(cur.X - start.X) <= ViewRadiusInChunks &&
                    Math.Abs(cur.Y - start.Y) <= ViewRadiusInChunks &&
                    Math.Abs(cur.Z - start.Z) <= ViewRadiusInChunks)
                {
                    if (TryChunk(cur, 1))
                    {
                        chunksFound++;
                        if (chunksFound > maxChunks)
                        {
                            return;
                        }
                    }
                }
                else if (Math.Abs(cur.X - start.X) <= (ViewRadiusInChunks + ViewRadExtra2) &&
                         Math.Abs(cur.Y - start.Y) <= (ViewRadiusInChunks + ViewRadExtra2) &&
                         Math.Abs(cur.Z - start.Z) <= (ViewRadiusInChunks + ViewRadExtra2Height))
                {
                    if (TryChunk(cur, 2))
                    {
                        chunksFound++;
                        if (chunksFound > maxChunks)
                        {
                            return;
                        }
                    }
                }
                else
                {
                    if (TryChunk(cur, 5))
                    {
                        chunksFound++;
                        if (chunksFound > maxChunks)
                        {
                            return;
                        }
                    }
                }
                for (int i = 0; i < MoveDirs.Length; i++)
                {
                    Vector3i t = cur + MoveDirs[i];
                    if (!seen.Contains(t) && !toSee.Contains(t))
                    {
                        //toSee.Enqueue(t);
                        for (int j = 0; j < MoveDirs.Length; j++)
                        {
                            if (Vector3.Dot(MoveDirs[j].ToVector3(), LoadRelDir.ToBVector()) < -0.8f) // TODO: Wut?
                            {
                                continue;
                            }
                            Vector3i nt = cur + MoveDirs[j];
                            if (!seen.Contains(nt) && !toSee.Contains(nt))
                            {
                                bool  val = false;
                                Chunk ch  = TheRegion.GetChunk(t);
                                if (ch == null)
                                {
                                    val = true;
                                }
                                // TODO: Oh, come on!
                                else if (MoveDirs[i].X == -1)
                                {
                                    if (MoveDirs[j].X == -1)
                                    {
                                        val = ch.Reachability[(int)ChunkReachability.XP_XM];
                                    }
                                    else if (MoveDirs[j].Y == -1)
                                    {
                                        val = ch.Reachability[(int)ChunkReachability.XP_YM];
                                    }
                                    else if (MoveDirs[j].Y == 1)
                                    {
                                        val = ch.Reachability[(int)ChunkReachability.XP_YP];
                                    }
                                    else if (MoveDirs[j].Z == -1)
                                    {
                                        val = ch.Reachability[(int)ChunkReachability.ZM_XP];
                                    }
                                    else if (MoveDirs[j].Z == 1)
                                    {
                                        val = ch.Reachability[(int)ChunkReachability.ZP_XP];
                                    }
                                }
                                else if (MoveDirs[i].X == 1)
                                {
                                    if (MoveDirs[j].X == 1)
                                    {
                                        val = ch.Reachability[(int)ChunkReachability.XP_XM];
                                    }
                                    else if (MoveDirs[j].Y == -1)
                                    {
                                        val = ch.Reachability[(int)ChunkReachability.XM_YM];
                                    }
                                    else if (MoveDirs[j].Y == 1)
                                    {
                                        val = ch.Reachability[(int)ChunkReachability.XM_YP];
                                    }
                                    else if (MoveDirs[j].Z == -1)
                                    {
                                        val = ch.Reachability[(int)ChunkReachability.ZM_XM];
                                    }
                                    else if (MoveDirs[j].Z == 1)
                                    {
                                        val = ch.Reachability[(int)ChunkReachability.ZP_XM];
                                    }
                                }
                                else if (MoveDirs[i].Y == -1)
                                {
                                    if (MoveDirs[j].Y == 1)
                                    {
                                        val = ch.Reachability[(int)ChunkReachability.YP_YM];
                                    }
                                    else if (MoveDirs[j].X == -1)
                                    {
                                        val = ch.Reachability[(int)ChunkReachability.XM_YP];
                                    }
                                    else if (MoveDirs[j].X == 1)
                                    {
                                        val = ch.Reachability[(int)ChunkReachability.XP_YP];
                                    }
                                    else if (MoveDirs[j].Z == -1)
                                    {
                                        val = ch.Reachability[(int)ChunkReachability.ZM_YP];
                                    }
                                    else if (MoveDirs[j].Z == 1)
                                    {
                                        val = ch.Reachability[(int)ChunkReachability.ZP_YP];
                                    }
                                }
                                else if (MoveDirs[i].Y == 1)
                                {
                                    if (MoveDirs[j].Y == -1)
                                    {
                                        val = ch.Reachability[(int)ChunkReachability.YP_YM];
                                    }
                                    else if (MoveDirs[j].X == -1)
                                    {
                                        val = ch.Reachability[(int)ChunkReachability.XM_YP];
                                    }
                                    else if (MoveDirs[j].X == 1)
                                    {
                                        val = ch.Reachability[(int)ChunkReachability.XP_YP];
                                    }
                                    else if (MoveDirs[j].Z == -1)
                                    {
                                        val = ch.Reachability[(int)ChunkReachability.ZM_YP];
                                    }
                                    else if (MoveDirs[j].Z == 1)
                                    {
                                        val = ch.Reachability[(int)ChunkReachability.ZP_YP];
                                    }
                                }
                                else if (MoveDirs[i].Z == -1)
                                {
                                    if (MoveDirs[j].Z == 1)
                                    {
                                        val = ch.Reachability[(int)ChunkReachability.ZP_ZM];
                                    }
                                    else if (MoveDirs[j].X == -1)
                                    {
                                        val = ch.Reachability[(int)ChunkReachability.ZP_XM];
                                    }
                                    else if (MoveDirs[j].X == 1)
                                    {
                                        val = ch.Reachability[(int)ChunkReachability.ZP_XP];
                                    }
                                    else if (MoveDirs[j].Y == -1)
                                    {
                                        val = ch.Reachability[(int)ChunkReachability.ZP_YM];
                                    }
                                    else if (MoveDirs[j].Y == 1)
                                    {
                                        val = ch.Reachability[(int)ChunkReachability.ZP_YP];
                                    }
                                }
                                else if (MoveDirs[i].Z == 1)
                                {
                                    if (MoveDirs[j].Z == -1)
                                    {
                                        val = ch.Reachability[(int)ChunkReachability.ZP_ZM];
                                    }
                                    else if (MoveDirs[j].X == -1)
                                    {
                                        val = ch.Reachability[(int)ChunkReachability.ZM_XM];
                                    }
                                    else if (MoveDirs[j].X == 1)
                                    {
                                        val = ch.Reachability[(int)ChunkReachability.ZM_XP];
                                    }
                                    else if (MoveDirs[j].Y == -1)
                                    {
                                        val = ch.Reachability[(int)ChunkReachability.ZM_YM];
                                    }
                                    else if (MoveDirs[j].Y == 1)
                                    {
                                        val = ch.Reachability[(int)ChunkReachability.ZM_YP];
                                    }
                                }
                                if (val)
                                {
                                    Location min = nt.ToLocation() * Chunk.CHUNK_SIZE;
                                    if (bfs.ContainsBox(min, min + new Location(Chunk.CHUNK_SIZE)))
                                    {
                                        toSee.Enqueue(nt);
                                    }
                                    else
                                    {
                                        seen.Add(nt);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
예제 #12
0
        public override void Tick()
        {
            if (!IsSpawned)
            {
                return;
            }
            if (TheRegion.Delta <= 0)
            {
                return;
            }
            base.Tick();
            opstt += TheRegion.Delta;
            while (opstt > 1.0)
            {
                opstt -= 1.0;
                OncePerSecondTick();
            }
            ItemStack cit = Items.GetItemForSlot(Items.cItem);

            if (GetVelocity().LengthSquared() > 1) // TODO: Move animation to CharacterEntity
            {
                // TODO: Replicate animation automation on client?
                SetAnimation("human/stand/run", 0);
                SetAnimation("human/stand/" + AnimToHold(cit), 1);
                SetAnimation("human/stand/run", 2);
            }
            else
            {
                SetAnimation("human/stand/idle01", 0);
                SetAnimation("human/stand/" + AnimToHold(cit), 1);
                SetAnimation("human/stand/idle01", 2);
            }
            if (Click) // TODO: Move clicking to CharacterEntity
            {
                cit.Info.Click(this, cit);
                LastClick   = TheRegion.GlobalTickTime;
                WasClicking = true;
            }
            else if (WasClicking)
            {
                cit.Info.ReleaseClick(this, cit);
                WasClicking = false;
            }
            if (AltClick)
            {
                cit.Info.AltClick(this, cit);
                LastAltClick   = TheRegion.GlobalTickTime;
                WasAltClicking = true;
            }
            else if (WasAltClicking)
            {
                cit.Info.ReleaseAltClick(this, cit);
                WasAltClicking = false;
            }
            cit.Info.Tick(this, cit);
            WasItemLefting  = ItemLeft;
            WasItemUpping   = ItemUp;
            WasItemRighting = ItemRight;
            Location pos  = LoadRelPos;
            Vector3i cpos = TheRegion.ChunkLocFor(pos);

            if (cpos != pChunkLoc)
            {
                for (int x = -2; x <= 2; x++)
                {
                    for (int y = -2; y <= 2; y++)
                    {
                        for (int z = -2; z <= 2; z++)
                        {
                            TryChunk(cpos + new Vector3i(x, y, z), 1);
                        }
                    }
                }
            }
            ChunkMarchAndSend();
            if (cpos != pChunkLoc)
            {
                /*
                 * // TODO: Better system -> async?
                 * TrySet(pos, 1, 1, 0, 1, false);
                 * TrySet(pos, ViewRadiusInChunks / 2, ViewRadiusInChunks / 2, 0, 1, false);
                 * TrySet(pos, ViewRadiusInChunks, ViewRadiusInChunks, 0, 1, false);
                 * TrySet(pos, ViewRadiusInChunks + 1, ViewRadiusInChunks, 15, 2, true);
                 * TrySet(pos, ViewRadiusInChunks + ViewRadExtra2, ViewRadiusInChunks + ViewRadExtra2Height, 30, 2, true);
                 * TrySet(pos, ViewRadiusInChunks + ViewRadExtra5, ViewRadiusInChunks + ViewRadExtra5Height, 60, 5, true);
                 */
                /*
                 * if (!loadedInitially)
                 * {
                 *  loadedInitially = true;
                 *  ChunkNetwork.SendPacket(new TeleportPacketOut(GetPosition()));
                 *  ChunkNetwork.SendPacket(new OperationStatusPacketOut(StatusOperation.CHUNK_LOAD, 1));
                 * }
                 * else
                 * {
                 *  ChunkNetwork.SendPacket(new OperationStatusPacketOut(StatusOperation.CHUNK_LOAD, 2));
                 * }
                 */
                foreach (ChunkAwarenessInfo ch in ChunksAwareOf.Values)
                {
                    if (!ShouldLoadChunk(ch.ChunkPos))
                    {
                        removes.Add(ch.ChunkPos);
                    }
                    else if (!ShouldSeeChunk(ch.ChunkPos) && ch.LOD <= BestLOD)
                    {
                        ch.LOD = Chunk.CHUNK_SIZE;
                    }
                }
                foreach (Vector3i loc in removes)
                {
                    Chunk ch = TheRegion.GetChunk(loc);
                    if (ch != null)
                    {
                        ForgetChunk(ch, loc);
                    }
                    else
                    {
                        ChunksAwareOf.Remove(loc);
                    }
                }
                removes.Clear();
                pChunkLoc = cpos;
            }
            if (Breadcrumbs.Count > 0)
            {
                double dist = (GetPosition() - Breadcrumbs[Breadcrumbs.Count - 1]).LengthSquared();
                if (dist > BreadcrumbRadius * BreadcrumbRadius)
                {
                    Location one = Breadcrumbs[Breadcrumbs.Count - 1];
                    Location two = GetPosition().GetBlockLocation() + new Location(0.5f, 0.5f, 0.5f);
                    Breadcrumbs.Add((two - one).Normalize() * BreadcrumbRadius + one);
                    // TODO: Effect?
                }
            }
            // TODO: Move use to CharacterEntity
            if (Use)
            {
                Location        forw = ForwardVector();
                CollisionResult cr   = TheRegion.Collision.RayTrace(GetEyePosition(), GetEyePosition() + forw * 5, IgnoreThis);
                if (cr.Hit && cr.HitEnt != null && cr.HitEnt.Tag is EntityUseable)
                {
                    if (UsedNow != (EntityUseable)cr.HitEnt.Tag)
                    {
                        if (UsedNow != null && ((Entity)UsedNow).IsSpawned)
                        {
                            UsedNow.StopUse(this);
                        }
                        UsedNow = (EntityUseable)cr.HitEnt.Tag;
                        UsedNow.StartUse(this);
                    }
                }
                else if (UsedNow != null)
                {
                    if (((Entity)UsedNow).IsSpawned)
                    {
                        UsedNow.StopUse(this);
                    }
                    UsedNow = null;
                }
            }
            else if (UsedNow != null)
            {
                if (((Entity)UsedNow).IsSpawned)
                {
                    UsedNow.StopUse(this);
                }
                UsedNow = null;
            }
            if (!CanReach(GetPosition()))
            {
                Teleport(posClamp(GetPosition()));
            }
        }
예제 #13
0
        public override void Tick()
        {
            if (TheRegion.IsVisible(GetPosition()))
            {
                bool sme = false;
                SetVelocity(GetVelocity() * 0.99f + Gravity * TheRegion.Delta);
                if (GetVelocity().LengthSquared() > 0)
                {
                    CollisionResult cr  = TheRegion.Collision.CuboidLineTrace(Scale, GetPosition(), GetPosition() + GetVelocity() * TheRegion.Delta, FilterHandle);
                    Location        vel = GetVelocity();
                    if (cr.Hit && Collide != null)
                    {
                        Collide(this, new CollisionEventArgs(cr));
                    }
                    if (!IsSpawned || Removed)
                    {
                        return;
                    }
                    if (vel == GetVelocity())
                    {
                        SetVelocity((cr.Position - GetPosition()) / TheRegion.Delta);
                    }
                    SetPosition(cr.Position);
                    // TODO: Timer
                    if (network)
                    {
                        sme = true;
                    }
                    netdeltat = 2;
                }
                else
                {
                    netdeltat += TheRegion.Delta;
                    if (netdeltat > 2.0)
                    {
                        netdeltat -= 2.0;
                        sme        = true;
                    }
                }
                Location pos = GetPosition();
                PrimitiveEntityUpdatePacketOut primupd = sme ? new PrimitiveEntityUpdatePacketOut(this) : null;
                foreach (PlayerEntity player in TheRegion.Players)
                {
                    bool shouldseec = player.ShouldSeePosition(pos);
                    bool shouldseel = player.ShouldSeePositionPreviously(lPos);
                    if (shouldseec && !shouldseel)
                    {
                        player.Network.SendPacket(GetSpawnPacket());
                    }
                    if (shouldseel && !shouldseec)
                    {
                        player.Network.SendPacket(new DespawnEntityPacketOut(EID));
                    }
                    if (sme && shouldseec)
                    {
                        player.Network.SendPacket(primupd);
                    }
                }
            }
            lPos = GetPosition();
            Vector3i cpos = TheRegion.ChunkLocFor(lPos);

            if (CanSave && !TheRegion.TryFindChunk(cpos, out Chunk _))
            {
                TheRegion.LoadChunk(cpos);
            }
        }
예제 #14
0
        public void UpdateForPacketFromServer(double gtt, long ID, Location pos, Location vel, bool _pup)
        {
            ServerLocation = pos;
            if (ServerFlags.HasFlag(YourStatusFlags.INSECURE_MOVEMENT))
            {
                return;
            }
            if (InVehicle)
            {
                return;
            }
            // TODO: big solid entities!
            double now = TheRegion.GlobalTickTimeLocal;

            if (TheClient.CVars.n_movemode.ValueI == 2)
            {
                // TODO: Remove outsider chunks!
                for (int x = -1; x <= 1; x++)
                {
                    for (int y = -1; y <= 1; y++)
                    {
                        for (int z = -1; z <= 1; z++)
                        {
                            Vector3i ch    = TheRegion.ChunkLocFor(pos) + new Vector3i(x, y, z);
                            Chunk    chunk = TheRegion.GetChunk(ch);
                            if (chunk == null)
                            {
                                continue;
                            }
                            if (!NMTWOMeshes.ContainsKey(ch))
                            {
                                if (chunk.FCO != null)
                                {
                                    FullChunkObject im = new FullChunkObject(chunk.FCO.Position, chunk.FCO.ChunkShape);
                                    NMTWOWorld.Add(im);
                                    NMTWOMeshes[ch] = im;
                                }
                            }
                        }
                    }
                }
                AddUIS();
                int    xf       = 0;
                double jumpback = gtt - lGTT;
                if (jumpback < 0)
                {
                    return;
                }
                double       target = TheRegion.GlobalTickTimeLocal - jumpback;
                UserInputSet past   = null;
                while (xf < Input.Length)
                {
                    UserInputSet uis = Input[xf];
                    if (uis.GlobalTimeLocal < target)
                    {
                        past = uis;
                        Input.Pop();
                        continue;
                    }
                    else if (xf == 0)
                    {
                        double mult = Math.Max(Math.Min(jumpback / TheClient.CVars.n_movement_adjustment.ValueD, 1.0), 0.01);
                        NMTWOSetPosition(uis.Position + (pos - uis.Position) * mult);
                        NMTWOSetVelocity(uis.Velocity + (vel - uis.Velocity) * mult);
                    }
                    xf++;
                    double delta;
                    if (xf < 2)
                    {
                        if (past == null)
                        {
                            continue;
                        }
                        delta = uis.GlobalTimeLocal - target;
                        SetBodyMovement(NMTWOCBody, past);
                    }
                    else
                    {
                        UserInputSet prev = Input[xf - 2];
                        delta = uis.GlobalTimeLocal - prev.GlobalTimeLocal;
                        SetBodyMovement(NMTWOCBody, prev);
                    }
                    SetMoveSpeed(NMTWOCBody, uis);
                    if (!_pup)
                    {
                        NMTWOTryToJump(uis);
                    }
                    lPT = uis.GlobalTimeLocal;
                    NMTWOWorld.Update((float)delta);
                    FlyForth(NMTWOCBody, uis, delta); // TODO: Entirely disregard NWTWOWorld if flying?
                }
                AddUIS();
                SetPosition(NMTWOGetPosition());
                SetVelocity(new Location(NMTWOCBody.Body.LinearVelocity));
                pup  = _pup;
                lGTT = gtt;
            }
            else
            {
                double   delta = lPT - now;
                Location dir   = pos - TheClient.Player.GetPosition();
                if (dir.LengthSquared() < TheClient.CVars.n_movement_maxdistance.ValueF * TheClient.CVars.n_movement_maxdistance.ValueF)
                {
                    SetPosition(GetPosition() + dir / Math.Max(TheClient.CVars.n_movement_adjustment.ValueF / delta, 1));
                    Location veldir = vel - GetVelocity();
                    SetVelocity(GetVelocity() + veldir / Math.Max(TheClient.CVars.n_movement_adjustment.ValueF / delta, 1));
                }
                else
                {
                    TheClient.Player.SetPosition(pos);
                    TheClient.Player.SetVelocity(vel);
                }
                lPT = now;
            }
        }