Пример #1
0
        public void UpdateTerrain()
        {
            if (RendererMap == null)
            {
                //Start() not called yet.
                return;
            }
            Stopwatch stopwatch = new Stopwatch();

            stopwatch.Start();

            TryRemap();

            for (int x = 0; x < mapAreaSize / chunksize; x++)
            {
                for (int y = 0; y < mapAreaSize / chunksize; y++)
                {
                    for (int z = 0; z < MapSizeZ / chunksize; z++)
                    {
                        int pos = MapUtil.Index3d(x, y, z, mapAreaSize / chunksize, mapAreaSize / chunksize);
                        if (RendererMap[pos].dirty)
                        {
                            if (RendererMap[pos].ids != null)
                            {
                                foreach (int loadedSubmesh in RendererMap[pos].ids)
                                {
                                    d_Batcher.Remove(loadedSubmesh);
                                }
                            }
                            RendererMap[pos].dirty = false;
                            List <int> ids = new List <int>();
                            var        a   = d_TerrainChunkTesselator.MakeChunk(CurrentRendererMapPositionG.x / chunksize + x,
                                                                                CurrentRendererMapPositionG.y / chunksize + y, z);
                            foreach (var submesh in a)
                            {
                                if (submesh.indices.Length != 0)
                                {
                                    Vector3 center = new Vector3(submesh.position.X + chunksize / 2, submesh.position.Z + chunksize / 2, submesh.position.Y + chunksize / 2);
                                    float   radius = chunksize;
                                    ids.Add(d_Batcher.Add(submesh.indices, submesh.indicesCount, submesh.vertices, submesh.verticesCount, submesh.transparent, submesh.texture, center, radius));
                                }
                            }
                            RendererMap[pos].ids = ids.ToArray();
                            if (stopwatch.ElapsedMilliseconds > 2)
                            {
                                goto exit;
                            }
                        }
                    }
                }
            }
exit:
            ;
        }
Пример #2
0
        public void TryRemap()
        {
            var p = MapUtil.PlayerArea(mapAreaSize, centerAreaSize, PlayerBlockPosition());
            var newMapPosition = new Vector3i(p.X, p.Y, 0);

            if (CurrentRendererMapPositionG != newMapPosition)
            {
                //todo: check if complete terrain in new area is already downloaded.
                Remap(newMapPosition);
                CurrentRendererMapPositionG = newMapPosition;
            }
        }
Пример #3
0
        public void ClearChunk(int x, int y, int z)
        {
            if (!MapUtil.IsValidPos(d_Map, x, y, z))
            {
                return;
            }
            int cx = x / chunksize;
            int cy = y / chunksize;
            int cz = z / chunksize;

            chunks[cx, cy, cz] = new byte[chunksize, chunksize, chunksize];
        }
Пример #4
0
 public void RedrawBlock(int x, int y, int z)
 {
     foreach (var a in MapUtil.BlocksAround(new Vector3(x, y, z)))
     {
         int xx = (int)a.X - CurrentRendererMapPositionG.x;
         int yy = (int)a.Y - CurrentRendererMapPositionG.y;
         int zz = (int)a.Z - CurrentRendererMapPositionG.z;
         if (xx < 0 || yy < 0 || zz < 0 || xx >= mapAreaSize || yy >= mapAreaSize || zz >= MapSizeZ)
         {
             return;
         }
         RendererMap[MapUtil.Index3d(xx / chunksize, yy / chunksize, zz / chunksize, mapAreaSize / chunksize, mapAreaSize / chunksize)].dirty = true;
     }
 }
Пример #5
0
        public void StartTerrain()
        {
            //Toggle fog.
            var p = MapUtil.PlayerArea(mapAreaSize, centerAreaSize, PlayerBlockPosition());

            CurrentRendererMapPositionG = new Vector3i(p.X, p.Y, 0);
            if (RendererMap != null)
            {
                throw new NotImplementedException();
            }
            RendererMap = new RenderedChunk[(mapAreaSize / chunksize) * (mapAreaSize / chunksize) * (MapSizeZ / chunksize)];
            for (int i = 0; i < RendererMap.Length; i++)
            {
                RendererMap[i] = new RenderedChunk();
            }
        }
Пример #6
0
 bool IsSpongeNear(int x, int y, int z)
 {
     for (int xx = x - spongerange; xx <= x + spongerange; xx++)
     {
         for (int yy = y - spongerange; yy <= y + spongerange; yy++)
         {
             for (int zz = z - spongerange; zz <= z + spongerange; zz++)
             {
                 if (MapUtil.IsValidPos(map, xx, yy, zz) && map.GetBlock(xx, yy, zz) == data.BlockIdSponge)
                 {
                     return(true);
                 }
             }
         }
     }
     return(false);
 }
Пример #7
0
 public void GetMapPortion(byte[] outPortion, int x, int y, int z, int portionsizex, int portionsizey, int portionsizez)
 {
     Array.Clear(outPortion, 0, outPortion.Length);
     for (int xx = 0; xx < portionsizex; xx++)
     {
         for (int yy = 0; yy < portionsizey; yy++)
         {
             for (int zz = 0; zz < portionsizez; zz++)
             {
                 if (MapUtil.IsValidPos(this, x + xx, y + yy, z + zz))
                 {
                     int pos = MapUtil.Index3d(xx, yy, zz, portionsizex, portionsizey);
                     outPortion[pos] = map[x + xx, y + yy, z + zz];
                 }
             }
         }
     }
 }
Пример #8
0
        UpDown GetUpDownMove(Vector3 railblock, TileEnterDirection dir)
        {
            if (!MapUtil.IsValidPos(d_Map, (int)railblock.X, (int)railblock.Y, (int)railblock.Z))
            {
                return(UpDown.None);
            }
            //going up
            RailSlope slope = d_RailMapUtil.GetRailSlope((int)railblock.X, (int)railblock.Y, (int)railblock.Z);

            if (slope == RailSlope.TwoDownRaised && dir == TileEnterDirection.Up)
            {
                return(UpDown.Up);
            }
            if (slope == RailSlope.TwoUpRaised && dir == TileEnterDirection.Down)
            {
                return(UpDown.Up);
            }
            if (slope == RailSlope.TwoLeftRaised && dir == TileEnterDirection.Right)
            {
                return(UpDown.Up);
            }
            if (slope == RailSlope.TwoRightRaised && dir == TileEnterDirection.Left)
            {
                return(UpDown.Up);
            }
            //going down
            if (slope == RailSlope.TwoDownRaised && dir == TileEnterDirection.Down)
            {
                return(UpDown.Down);
            }
            if (slope == RailSlope.TwoUpRaised && dir == TileEnterDirection.Up)
            {
                return(UpDown.Down);
            }
            if (slope == RailSlope.TwoLeftRaised && dir == TileEnterDirection.Left)
            {
                return(UpDown.Down);
            }
            if (slope == RailSlope.TwoRightRaised && dir == TileEnterDirection.Right)
            {
                return(UpDown.Down);
            }
            return(UpDown.None);
        }
Пример #9
0
        void SetChunkDirty(int cx, int cy, int cz, bool dirty)
        {
            int x = cx * chunksize;
            int y = cy * chunksize;
            int z = cz * chunksize;

            if (x >= CurrentRendererMapPositionG.x &&
                y >= CurrentRendererMapPositionG.y &&
                z >= CurrentRendererMapPositionG.z &&
                x < CurrentRendererMapPositionG.x + mapAreaSize &&
                y < CurrentRendererMapPositionG.y + mapAreaSize &&
                z < MapSizeZ)
            {
                int xx = x - CurrentRendererMapPositionG.x;
                int yy = y - CurrentRendererMapPositionG.y;
                int zz = z - CurrentRendererMapPositionG.z;
                RendererMap[MapUtil.Index3d(xx / chunksize, yy / chunksize, zz / chunksize, mapAreaSize / chunksize, mapAreaSize / chunksize)].dirty = dirty;
            }
        }
Пример #10
0
 void BlockChangeFlood(IMapStorage map, int x, int y, int z)
 {
     //water here
     if (MapUtil.IsValidPos(map, x, y, z) &&
         data.IsWater[map.GetBlock(x, y, z)])
     {
         Flood(new Vector3(x, y, z));
         return;
     }
     //water around
     foreach (var vv in BlocksAround(new Vector3(x, y, z)))
     {
         if (MapUtil.IsValidPos(map, (int)vv.X, (int)vv.Y, (int)vv.Z) &&
             data.IsWater[map.GetBlock((int)vv.X, (int)vv.Y, (int)vv.Z)])
         {
             Flood(vv);
             return;
         }
     }
 }
Пример #11
0
        public void BlockChange(IMapStorage map, int x, int y, int z)
        {
            this.flooded = new Dictionary <Vector3, Vector3>();
            this.map     = map;
            //sponge just built.
            if (MapUtil.IsValidPos(map, x, y, z) && map.GetBlock(x, y, z) == data.BlockIdSponge)
            {
                for (int xx = x - spongerange; xx <= x + spongerange; xx++)
                {
                    for (int yy = y - spongerange; yy <= y + spongerange; yy++)
                    {
                        for (int zz = z - spongerange; zz <= z + spongerange; zz++)
                        {
                            if (MapUtil.IsValidPos(map, xx, yy, zz) && data.IsWater[map.GetBlock(xx, yy, zz)])
                            {
                                tosetempty.Add(new Vector3(xx, yy, zz));
                            }
                        }
                    }
                }
            }
            //maybe sponge destroyed. todo faster test.
            for (int xx = x - spongerange; xx <= x + spongerange; xx++)
            {
                for (int yy = y - spongerange; yy <= y + spongerange; yy++)
                {
                    for (int zz = z - spongerange; zz <= z + spongerange; zz++)
                    {
                        if (MapUtil.IsValidPos(map, xx, yy, zz) && map.GetBlock(xx, yy, zz) == 0)
                        {
                            BlockChangeFlood(map, xx, yy, zz);
                        }
                    }
                }
            }
            BlockChangeFlood(map, x, y, z);
            var v = new Vector3(x, y, z);

            tosetwater.Sort((a, b) => (v - a).Length.CompareTo((v - b).Length));
        }
Пример #12
0
        public VehicleDirection12Flags PossibleRails(TileEnterData enter)
        {
            Vector3 new_position = enter.BlockPosition;
            VehicleDirection12Flags possible_rails = VehicleDirection12Flags.None;

            if (MapUtil.IsValidPos(d_Map, (int)enter.BlockPosition.X, (int)enter.BlockPosition.Y, (int)enter.BlockPosition.Z))
            {
                RailDirectionFlags newpositionrail = d_Data.Rail[
                    d_Map.GetBlock((int)enter.BlockPosition.X, (int)enter.BlockPosition.Y, (int)enter.BlockPosition.Z)];
                List <VehicleDirection12> all_possible_rails = new List <VehicleDirection12>();
                foreach (var z in DirectionUtils.PossibleNewRails(enter.EnterDirection))
                {
                    if ((newpositionrail & DirectionUtils.ToRailDirectionFlags(DirectionUtils.ToRailDirection(z)))
                        != RailDirectionFlags.None)
                    {
                        all_possible_rails.Add(z);
                    }
                }
                possible_rails = DirectionUtils.ToVehicleDirection12Flags(all_possible_rails);
            }
            return(possible_rails);
        }
Пример #13
0
 public bool IsValidPos(int x, int y, int z)
 {
     return(MapUtil.IsValidPos(server.d_Map, x, y, z));
 }
Пример #14
0
        public Vector3 WallSlide(CharacterPhysicsState state, Vector3 oldposition, Vector3 newposition)
        {
            reachedceiling = false;
            reachedwall    = false;
            //Math.Floor() is needed because casting negative values to integer is not floor.
            Vector3i oldpositioni = new Vector3i((int)Math.Floor(oldposition.X), (int)Math.Floor(oldposition.Z),
                                                 (int)Math.Floor(oldposition.Y));
            bool wasonstairs = false;

            if (MapUtil.IsValidPos(d_Map, oldpositioni.x, oldpositioni.y, oldpositioni.z))
            {
                wasonstairs = d_Map.GetBlock(oldpositioni.x, oldpositioni.y, oldpositioni.z) == d_Data.BlockIdSingleStairs;
            }
            Vector3 playerposition = newposition;

            //left
            {
                var  qnewposition = newposition + new Vector3(0, 0, walldistance);
                bool newempty     = IsTileEmptyForPhysics((int)Math.Floor(qnewposition.X), (int)Math.Floor(qnewposition.Z), (int)Math.Floor(qnewposition.Y)) &&
                                    IsTileEmptyForPhysics((int)Math.Floor(qnewposition.X), (int)Math.Floor(qnewposition.Z), (int)Math.Floor(qnewposition.Y) + 1);
                if (newposition.Z - oldposition.Z > 0)
                {
                    if (!wasonstairs)
                    {
                        if (!newempty)
                        {
                            reachedwall      = true;
                            playerposition.Z = oldposition.Z;
                        }
                    }
                    else
                    {
                        bool aboveempty = IsTileEmptyForPhysics((int)Math.Floor(qnewposition.X), (int)Math.Floor(qnewposition.Z), (int)Math.Floor(qnewposition.Y) + 1) &&
                                          IsTileEmptyForPhysics((int)Math.Floor(qnewposition.X), (int)Math.Floor(qnewposition.Z), (int)Math.Floor(qnewposition.Y) + 2);
                        // if the new coord isnt passable stop the player from moving
                        if (aboveempty && !IsTileEmptyForPhysics((int)Math.Floor(qnewposition.X), (int)Math.Floor(qnewposition.Z), (int)Math.Floor(qnewposition.Y)))
                        {
                            playerposition.Y += 0.5f;
                            goto ok;
                        }
                        if (!aboveempty)
                        {
                            reachedwall      = true;
                            playerposition.Z = oldposition.Z;
                        }
                    }
                }
            }
            //front
            {
                var  qnewposition = newposition + new Vector3(walldistance, 0, 0);
                bool newempty     = IsTileEmptyForPhysics((int)Math.Floor(qnewposition.X), (int)Math.Floor(qnewposition.Z), (int)Math.Floor(qnewposition.Y)) &&
                                    IsTileEmptyForPhysics((int)Math.Floor(qnewposition.X), (int)Math.Floor(qnewposition.Z), (int)Math.Floor(qnewposition.Y) + 1);
                if (newposition.X - oldposition.X > 0)
                {
                    if (!wasonstairs)
                    {
                        if (!newempty)
                        {
                            reachedwall      = true;
                            playerposition.X = oldposition.X;
                        }
                    }
                    else
                    {
                        bool aboveempty = IsTileEmptyForPhysics((int)Math.Floor(qnewposition.X), (int)Math.Floor(qnewposition.Z), (int)Math.Floor(qnewposition.Y) + 1) &&
                                          IsTileEmptyForPhysics((int)Math.Floor(qnewposition.X), (int)Math.Floor(qnewposition.Z), (int)Math.Floor(qnewposition.Y) + 2);
                        // if the new coord isnt passable stop the player from moving
                        if (aboveempty && !IsTileEmptyForPhysics((int)Math.Floor(qnewposition.X), (int)Math.Floor(qnewposition.Z), (int)Math.Floor(qnewposition.Y)))
                        {
                            playerposition.Y += 0.5f;
                            goto ok;
                        }
                        if (!aboveempty)
                        {
                            reachedwall      = true;
                            playerposition.X = oldposition.X;
                        }
                    }
                }
            }
            //top
            {
                var   qnewposition = newposition + new Vector3(0, -walldistance, 0);
                int   x            = (int)Math.Floor(qnewposition.X);
                int   y            = (int)Math.Floor(qnewposition.Z);
                int   z            = (int)Math.Floor(qnewposition.Y);
                float a            = walldistance;
                bool  newfull      = (!IsTileEmptyForPhysics(x, y, z)) ||
                                     (qnewposition.X - Math.Floor(qnewposition.X) <= a && (!IsTileEmptyForPhysics(x - 1, y, z)) && (IsTileEmptyForPhysics(x - 1, y, z + 1))) ||
                                     (qnewposition.X - Math.Floor(qnewposition.X) >= (1 - a) && (!IsTileEmptyForPhysics(x + 1, y, z)) && (IsTileEmptyForPhysics(x + 1, y, z + 1))) ||
                                     (qnewposition.Z - Math.Floor(qnewposition.Z) <= a && (!IsTileEmptyForPhysics(x, y - 1, z)) && (IsTileEmptyForPhysics(x, y - 1, z + 1))) ||
                                     (qnewposition.Z - Math.Floor(qnewposition.Z) >= (1 - a) && (!IsTileEmptyForPhysics(x, y + 1, z)) && (IsTileEmptyForPhysics(x, y + 1, z + 1)));
                if (newposition.Y - oldposition.Y < 0)
                {
                    if (newfull)
                    {
                        playerposition.Y = oldposition.Y;
                    }
                }
            }
            //right
            {
                var  qnewposition = newposition + new Vector3(0, 0, -walldistance);
                bool newempty     = IsTileEmptyForPhysics((int)Math.Floor(qnewposition.X), (int)Math.Floor(qnewposition.Z), (int)Math.Floor(qnewposition.Y)) &&
                                    IsTileEmptyForPhysics((int)Math.Floor(qnewposition.X), (int)Math.Floor(qnewposition.Z), (int)Math.Floor(qnewposition.Y) + 1);
                if (newposition.Z - oldposition.Z < 0)
                {
                    if (!wasonstairs)
                    {
                        if (!newempty)
                        {
                            reachedwall      = true;
                            playerposition.Z = oldposition.Z;
                        }
                    }
                    else
                    {
                        bool aboveempty = IsTileEmptyForPhysics((int)Math.Floor(qnewposition.X), (int)Math.Floor(qnewposition.Z), (int)Math.Floor(qnewposition.Y) + 1) &&
                                          IsTileEmptyForPhysics((int)Math.Floor(qnewposition.X), (int)Math.Floor(qnewposition.Z), (int)Math.Floor(qnewposition.Y) + 2);
                        // if the new coord isnt passable stop the player from moving
                        if (aboveempty && !IsTileEmptyForPhysics((int)Math.Floor(qnewposition.X), (int)Math.Floor(qnewposition.Z), (int)Math.Floor(qnewposition.Y)))
                        {
                            playerposition.Y += 0.5f;
                            goto ok;
                        }
                        if (!aboveempty)
                        {
                            reachedwall      = true;
                            playerposition.Z = oldposition.Z;
                        }
                    }
                }
            }
            //back
            {
                var  qnewposition = newposition + new Vector3(-walldistance, 0, 0);
                bool newempty     = IsTileEmptyForPhysics((int)Math.Floor(qnewposition.X), (int)Math.Floor(qnewposition.Z), (int)Math.Floor(qnewposition.Y)) &&
                                    IsTileEmptyForPhysics((int)Math.Floor(qnewposition.X), (int)Math.Floor(qnewposition.Z), (int)Math.Floor(qnewposition.Y) + 1);
                if (newposition.X - oldposition.X < 0)
                {
                    if (!wasonstairs)
                    {
                        if (!newempty)
                        {
                            reachedwall      = true;
                            playerposition.X = oldposition.X;
                        }
                    }
                    else
                    {
                        bool aboveempty = IsTileEmptyForPhysics((int)Math.Floor(qnewposition.X), (int)Math.Floor(qnewposition.Z), (int)Math.Floor(qnewposition.Y) + 1) &&
                                          IsTileEmptyForPhysics((int)Math.Floor(qnewposition.X), (int)Math.Floor(qnewposition.Z), (int)Math.Floor(qnewposition.Y) + 2);
                        // if the new coord isnt passable stop the player from moving
                        if (aboveempty && !IsTileEmptyForPhysics((int)Math.Floor(qnewposition.X), (int)Math.Floor(qnewposition.Z), (int)Math.Floor(qnewposition.Y)))
                        {
                            playerposition.Y += 0.5f;
                            goto ok;
                        }
                        if (!aboveempty)
                        {
                            reachedwall      = true;
                            playerposition.X = oldposition.X;
                        }
                    }
                }
            }
            //bottom
            {
                var  qnewposition = newposition + new Vector3(0, +walldistance + characterheight, 0);
                bool newempty     = IsTileEmptyForPhysics((int)Math.Floor(qnewposition.X), (int)Math.Floor(qnewposition.Z), (int)Math.Floor(qnewposition.Y));
                if (newposition.Y - oldposition.Y > 0)
                {
                    if (!newempty)
                    {
                        playerposition.Y = oldposition.Y;
                        reachedceiling   = true;
                    }
                }
            }
ok:
            bool isonstairs = false;
            Vector3i playerpositioni = new Vector3i((int)Math.Floor(playerposition.X), (int)Math.Floor(playerposition.Z),
                                                    (int)Math.Floor(playerposition.Y));

            if (MapUtil.IsValidPos(d_Map, playerpositioni.x, playerpositioni.y, playerpositioni.z))
            {
                isonstairs = d_Map.GetBlock(playerpositioni.x, playerpositioni.y, playerpositioni.z) == d_Data.BlockIdSingleStairs;
            }

            if (isonstairs && state.jumpacceleration == 0)
            {
                playerposition.Y = ((int)Math.Floor(playerposition.Y)) + 0.5f + walldistance;
            }
            return(playerposition);
        }
Пример #15
0
        //todo: use this for chunk byte[], not just for terrain renderer meshes.
        public void Remap(Vector3i newMapPosition)
        {
            //make a list of old chunks
            var newRendererMap = new RenderedChunk[RendererMap.Length];
            Dictionary <Vector3i, RenderedChunk> oldChunks = new Dictionary <Vector3i, RenderedChunk>();

            for (int x = 0; x < mapAreaSize / chunksize; x++)
            {
                for (int y = 0; y < mapAreaSize / chunksize; y++)
                {
                    for (int z = 0; z < MapSizeZ / chunksize; z++)
                    {
                        int      pos    = MapUtil.Index3d(x, y, z, mapAreaSize / chunksize, mapAreaSize / chunksize);
                        int      chunkx = x + CurrentRendererMapPositionG.x / chunksize;
                        int      chunky = y + CurrentRendererMapPositionG.y / chunksize;
                        int      chunkz = z + CurrentRendererMapPositionG.z / chunksize;
                        Vector3i pos2   = new Vector3i(chunkx, chunky, chunkz);
                        oldChunks[pos2] = RendererMap[pos];
                    }
                }
            }
            for (int x = 0; x < mapAreaSize / chunksize; x++)
            {
                for (int y = 0; y < mapAreaSize / chunksize; y++)
                {
                    for (int z = 0; z < MapSizeZ / chunksize; z++)
                    {
                        int      pos       = MapUtil.Index3d(x, y, z, mapAreaSize / chunksize, mapAreaSize / chunksize);
                        int      newchunkx = x + newMapPosition.x / chunksize;
                        int      newchunky = y + newMapPosition.y / chunksize;
                        int      newchunkz = z + newMapPosition.z / chunksize;
                        Vector3i pos2      = new Vector3i(newchunkx, newchunky, newchunkz);
                        if (oldChunks.ContainsKey(pos2))
                        {
                            //if already loaded
                            newRendererMap[pos] = oldChunks[pos2];
                            oldChunks[pos2]     = null;
                        }
                        else
                        {
                            //if needs loading
                            newRendererMap[pos] = new RenderedChunk();
                        }
                    }
                }
            }
            foreach (var k in oldChunks)
            {
                //wasn't used in new area.
                if (k.Value != null && k.Value.ids != null)
                {
                    foreach (var subMeshId in k.Value.ids)
                    {
                        d_Batcher.Remove(subMeshId);
                    }
                }
                //todo: save to disk
            }
            for (int i = 0; i < newRendererMap.Length; i++)
            {
                RendererMap[i] = newRendererMap[i];
            }
        }
Пример #16
0
        void RailOnNewFrame(float dt)
        {
            LocalPlayerAnimationHint.InVehicle = railriding;
            LocalPlayerAnimationHint.DrawFix   = railriding ? new Vector3(0, -0.7f, 0) : new Vector3();

            bool turnright = keyboardstate[GetKey(OpenTK.Input.Key.D)];
            bool turnleft  = keyboardstate[GetKey(OpenTK.Input.Key.A)];

            RailSound();
            if (railriding)
            {
                ENABLE_FREEMOVE           = true;
                ENABLE_MOVE               = false;
                LocalPlayerPosition       = CurrentRailPos();
                currentrailblockprogress += currentvehiclespeed * (float)dt;
                if (currentrailblockprogress >= 1)
                {
                    lastdirection            = currentdirection;
                    currentrailblockprogress = 0;
                    var newenter = new TileEnterData();
                    newenter.BlockPosition = NextTile(currentdirection, currentrailblock);
                    //slope
                    if (GetUpDownMove(currentrailblock,
                                      DirectionUtils.ResultEnter(DirectionUtils.ResultExit(currentdirection))) == UpDown.Up)
                    {
                        newenter.BlockPosition.Z++;
                    }
                    if (GetUpDownMove(newenter.BlockPosition + new Vector3(0, 0, -1),
                                      DirectionUtils.ResultEnter(DirectionUtils.ResultExit(currentdirection))) == UpDown.Down)
                    {
                        newenter.BlockPosition.Z--;
                    }

                    newenter.EnterDirection = DirectionUtils.ResultEnter(DirectionUtils.ResultExit(currentdirection));
                    var newdir = BestNewDirection(PossibleRails(newenter), turnleft, turnright);
                    if (newdir == null)
                    {
                        //end of rail
                        currentdirection = DirectionUtils.Reverse(currentdirection);
                    }
                    else
                    {
                        currentdirection = newdir.Value;
                        currentrailblock = newenter.BlockPosition;
                    }
                }
            }
            if (keyboardstate[GetKey(OpenTK.Input.Key.W)] && GuiTyping != TypingState.Typing)
            {
                currentvehiclespeed += 1f * (float)dt;
            }
            if (keyboardstate[GetKey(OpenTK.Input.Key.S)] && GuiTyping != TypingState.Typing)
            {
                currentvehiclespeed -= 5f * (float)dt;
            }
            if (currentvehiclespeed < 0)
            {
                currentvehiclespeed = 0;
            }
            //todo fix
            //if (viewport.keypressed != null && viewport.keypressed.Key == OpenTK.Input.Key.Q)
            if (!wasqpressed && keyboardstate[GetKey(OpenTK.Input.Key.Q)] && GuiTyping != TypingState.Typing)
            {
                Reverse();
            }

            if (!wasepressed && keyboardstate[GetKey(OpenTK.Input.Key.E)] && !railriding && !ENABLE_FREEMOVE && GuiTyping != TypingState.Typing)
            {
                currentrailblock = new Vector3((int)LocalPlayerPosition.X,
                                               (int)LocalPlayerPosition.Z, (int)LocalPlayerPosition.Y - 1);
                if (!MapUtil.IsValidPos(d_Map, (int)currentrailblock.X, (int)currentrailblock.Y, (int)currentrailblock.Z))
                {
                    ExitVehicle();
                }
                else
                {
                    var railunderplayer = d_Data.Rail[d_Map.GetBlock((int)currentrailblock.X, (int)currentrailblock.Y, (int)currentrailblock.Z)];
                    railriding          = true;
                    CharacterHeight     = minecartheight;
                    currentvehiclespeed = 0;
                    if ((railunderplayer & RailDirectionFlags.Horizontal) != 0)
                    {
                        currentdirection = VehicleDirection12.HorizontalRight;
                    }
                    else if ((railunderplayer & RailDirectionFlags.Vertical) != 0)
                    {
                        currentdirection = VehicleDirection12.VerticalUp;
                    }
                    else if ((railunderplayer & RailDirectionFlags.UpLeft) != 0)
                    {
                        currentdirection = VehicleDirection12.UpLeftUp;
                    }
                    else if ((railunderplayer & RailDirectionFlags.UpRight) != 0)
                    {
                        currentdirection = VehicleDirection12.UpRightUp;
                    }
                    else if ((railunderplayer & RailDirectionFlags.DownLeft) != 0)
                    {
                        currentdirection = VehicleDirection12.DownLeftLeft;
                    }
                    else if ((railunderplayer & RailDirectionFlags.DownRight) != 0)
                    {
                        currentdirection = VehicleDirection12.DownRightRight;
                    }
                    else
                    {
                        ExitVehicle();
                    }
                    lastdirection = currentdirection;
                }
            }
            else if (!wasepressed && keyboardstate[GetKey(OpenTK.Input.Key.E)] && railriding && GuiTyping != TypingState.Typing)
            {
                ExitVehicle();
                LocalPlayerPosition += new Vector3(0, 0.7f, 0);
            }
            wasqpressed = keyboardstate[GetKey(OpenTK.Input.Key.Q)] && GuiTyping != TypingState.Typing;
            wasepressed = keyboardstate[GetKey(OpenTK.Input.Key.E)] && GuiTyping != TypingState.Typing;
        }