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: ; }
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; } }
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]; }
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; } }
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(); } }
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); }
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]; } } } } }
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); }
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; } }
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; } } }
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)); }
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); }
public bool IsValidPos(int x, int y, int z) { return(MapUtil.IsValidPos(server.d_Map, x, y, z)); }
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); }
//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]; } }
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; }