public void UnloadEntities(ChunkCoordinates coordinates) { foreach (var entity in Entities.ToArray()) { if (new ChunkCoordinates(entity.Value.KnownPosition).Equals(coordinates)) { Remove(entity.Value.UUID); } } }
public ChunkData(ChunkCoordinates coordinates) { Coordinates = coordinates; var availableStages = Enum.GetValues(typeof(RenderStage)); _stages = new ChunkRenderStage[availableStages.Length]; Interlocked.Increment(ref _instances); }
public IChunkColumn GenerateChunkColumn(ChunkCoordinates chunkCoordinates) { IChunkColumn c = new ChunkColumn() { X = chunkCoordinates.X, Z = chunkCoordinates.Z }; for (int x = 0; x < ChunkColumn.ChunkWidth; x++) { for (int z = 0; z < ChunkColumn.ChunkDepth; z++) { for (int y = 0; y < ChunkColumn.ChunkHeight; y++) { if (c.X == 0 && c.Z == 0) { IBlockState block; switch (y >> 4) { case 0: block = _dirt; break; case 1: block = _stone; break; case 2: block = _cobble; break; case 3: block = _grass; break; //case 4: // break; default: continue; } c.SetBlockState(x, y, z, block); } else { //c.SetBlockState(x, y, z, _air); } c.SetSkyLight(x, y, z, 15); } c.SetHeight(x, z, 0); } } return(c); }
public virtual ChunkColumn GenerateChunkColumn(ChunkCoordinates chunkCoordinates, bool cacheOnly = false) { var chunk = WorldProvider.GenerateChunkColumn(chunkCoordinates, cacheOnly); if (chunk != null) { Level.EventDispatcher.DispatchEvent(new ChunkGeneratedEvent(chunkCoordinates, chunk, Level)); } return(chunk); }
internal void SetChunkData(ChunkCoordinates coords, AnvilRegionHeaderChunkData data) { //if (_chunkLocations.ContainsKey(coords)) //{ _chunkLocations[coords] = data; //} //else //{ // _chunkLocations.Add(coords, data); //} }
public ChunkColumn GenerateChunkColumn(ChunkCoordinates chunkCoordinates) { ChunkColumn chunk = new ChunkColumn(); chunk.x = chunkCoordinates.X; chunk.z = chunkCoordinates.Z; PopulateChunk(chunk); return(chunk); }
public ChunkManager(IServiceProvider serviceProvider, GraphicsDevice graphics, World world) { Graphics = graphics; World = world; Options = serviceProvider.GetRequiredService <IOptionsProvider>().AlexOptions; Resources = serviceProvider.GetRequiredService <ResourceManager>(); var stillAtlas = Resources.Atlas.GetStillAtlas(); var fogStart = 0; Shaders = new RenderingShaders(Graphics); Shaders.SetTextures(stillAtlas); Shaders.SetAnimatedTextures(Resources.Atlas.GetAtlas(0)); RenderDistance = Options.VideoOptions.RenderDistance; Options.VideoOptions.RenderDistance.Bind( (value, newValue) => { RenderDistance = newValue; }); Chunks = new ConcurrentDictionary <ChunkCoordinates, ChunkColumn>(); CancellationToken = new CancellationTokenSource(); BlockLightCalculations = new BlockLightCalculations((World)world); SkyLightCalculator = new SkyLightCalculations(); Func <ChunkCoordinates, ChunkCoordinates, int> orderingTool = (a, b) => { var pos = new ChunkCoordinates(World.Camera.Position); var aDistance = a.DistanceTo(pos); var bDistance = b.DistanceTo(pos); if (aDistance < bDistance) { return(-1); } if (bDistance > aDistance) { return(1); } return(0); }; UpdateQueue = new FancyQueue <ChunkCoordinates>(); UpdateBorderQueue = new FancyQueue <ChunkCoordinates>(); FastUpdateQueue = new FancyQueue <ChunkCoordinates>(); }
public ChunkColumn GenerateChunkColumn(ChunkCoordinates chunkCoordinates, bool cacheOnly = false) { if (Locked || cacheOnly) { _chunkCache.TryGetValue(chunkCoordinates, out ChunkColumn chunk); return(chunk); } // Warning: The following code MAY execute the GetChunk 2 times for the same coordinate // if called in rapid succession. However, for the scenario of the provider, this is highly unlikely. return(_chunkCache.GetOrAdd(chunkCoordinates, coordinates => GetChunk(coordinates, MissingChunkProvider))); }
private void GenerateChunks(Level level, int r) { var cX = (int)level.SpawnPoint.X >> 4; var cZ = (int)level.SpawnPoint.Z >> 4; var x = 0; var y = 0; var t = r; var dx = 0; var dy = -1; for (var i = 0; i < (r * r); i++) { if ((-r / 2 <= x) && (x <= r / 2) && (-r / 2 <= y) && (y <= r / 2)) { //Log.InfoFormat("Generating Chunk {0},{1}", x, y); var coords = new ChunkCoordinates(cX + x, cZ + y); //ThreadPool.QueueUserWorkItem(c => level.GetChunk((ChunkCoordinates) c), coords); var chunk = level.GetChunk(coords); RenderChunk(chunk); (level.WorldProvider as ICachingWorldProvider)?.ClearCachedChunks(); //Thread.Sleep(50); } if ((x == y) || ((x < 0) && (x == -y)) || ((x > 0) && (x == 1 - y))) { t = dx; dx = -dy; dy = t; } x += dx; y += dy; } /* * for (int dx = -r; dx <= r; dx++) * { * for (int dz = -r; dz <= r; dz++) * { * * var coords = new ChunkCoordinates(dx, dz); * //ThreadPool.QueueUserWorkItem(c => level.GetChunk((ChunkCoordinates) c), coords); * * var chunk = level.GetChunk(coords); * RenderChunk(chunk); * (level.WorldProvider as ICachingWorldProvider)?.ClearCachedChunks(); * * } * }*/ }
public ChunkColumn GenerateChunkColumn(ChunkCoordinates chunkCoordinates) { // Stopwatch sw = Stopwatch.StartNew(); ChunkColumn chunk = new ChunkColumn { x = chunkCoordinates.X, z = chunkCoordinates.Z }; Decorators.ChunkDecorator[] chunkDecorators = new ChunkDecorator[] { new WaterDecorator(), //new OreDecorator(), new FoliageDecorator(), }; var biomes = CalculateBiomes(chunk.x, chunk.z); foreach (var i in chunkDecorators) { i.SetSeed(Seed); } var heightMap = GenerateHeightMap(biomes, chunk.x, chunk.z); var thresholdMap = GetThresholdMap(chunk.x, chunk.z, biomes); CreateTerrainShape(chunk, heightMap, thresholdMap, biomes); DecorateChunk(chunk, heightMap, thresholdMap, biomes, chunkDecorators); //chunk.isDirty = true; //chunk.NeedSave = true; /*for (int x = 0; x < 16; x++) * { * for (int z = 0; z < 16; z++) * { * for (int y = 0; y < 256; y++) * { * chunk.SetSkyLight(x, y, z, 255); * } * } * }*/ // sw.Stop(); // if (sw.ElapsedMilliseconds > previousTime) //{ // Debug.WriteLine("Chunk gen took " + sw.ElapsedMilliseconds + " ms"); //previousTime = sw.ElapsedMilliseconds; //} return(chunk); }
public int MakeAirChunksAroundWorldToCompensateForBadRendering() { int createdChunks = 0; Stopwatch sw = new Stopwatch(); sw.Start(); foreach (KeyValuePair <ChunkCoordinates, ChunkColumn> valuePair in _chunkCache) { ChunkCoordinates chunkCoordinates = valuePair.Key; ChunkColumn chunkColumn = valuePair.Value; if (chunkColumn != null && !chunkColumn.isAllAir) { for (int startX = chunkCoordinates.X - 1; startX <= chunkCoordinates.X + 1; startX++) { for (int startZ = chunkCoordinates.Z - 1; startZ <= chunkCoordinates.Z + 1; startZ++) { ChunkCoordinates surroundingChunkCoordinates = new ChunkCoordinates(startX, startZ); if (surroundingChunkCoordinates.Equals(chunkCoordinates)) { continue; } ChunkColumn surroundingChunkColumn; _chunkCache.TryGetValue(surroundingChunkCoordinates, out surroundingChunkColumn); if (surroundingChunkColumn == null) { ChunkColumn airColumn = new ChunkColumn { x = startX, z = startZ, isAllAir = true }; airColumn.GetBatch(); _chunkCache[surroundingChunkCoordinates] = airColumn; createdChunks++; } } } } } sw.Stop(); Log.Info("Created " + createdChunks + " air chunks in " + sw.ElapsedMilliseconds + "ms"); return(createdChunks); }
private async Task <ChunkColumn> GenerateChunk(ChunkCoordinates chunkCoordinates) { ChunkColumn chunk = new ChunkColumn(); chunk.X = chunkCoordinates.X; chunk.Z = chunkCoordinates.Z; Decorators.ChunkDecorator[] chunkDecorators = new ChunkDecorator[] { new WaterDecorator(), //new OreDecorator(), new FoliageDecorator(), }; foreach (var i in chunkDecorators) { i.SetSeed(Seed); } var res = await GenerateNeeded(chunkCoordinates); var heightMap = res.heightMap; var thresholdMap = res.thresholdMap; var biomes = res.biomes; var blocks = await CreateTerrainShape(heightMap, thresholdMap); int[] metadata = new int[16 * 16 * 256]; DecorateChunk(chunk.X, chunk.Z, blocks, metadata, heightMap, thresholdMap, biomes, chunkDecorators); for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { var height = heightMap[(x << 4) + z]; var biome = biomes[(x << 4) + z]; chunk.biomeId[(x << 4) + z] = (byte)biome.Id; chunk.height[(x << 4) + z] = (short)height; for (int y = 0; y < 256; y++) { var idx = GetIndex(x, y, z); chunk.SetBlock(x, y, z, blocks[idx]); // chunk.SetMetadata(x,y,z, (byte) metadata[idx]); } } } return(chunk); }
private AnvilRegion GenerateRegion(ChunkCoordinates coords) { int x = coords.X >> 5; int z = coords.Z >> 5; var regionCoords = new ChunkCoordinates(x, z); //Debug.WriteLine($"Generating AnvilRegion {x},{z}"); var region = new AnvilRegion(this, x, z); _regionCache[regionCoords] = region; return(region); }
private void GenerateChunks(int rX, int rZ) { var tot = rX * rZ; ThreadPool.QueueUserWorkItem(delegate { Monitor.Enter(_busy); try { Busy(); _cancelProgress = false; ShowProgress(tot); var i = 0; var hX = (int)Math.Floor(rX / 2f); var hZ = (int)Math.Floor(rZ / 2f); var chunks = _validChunks.ToArray(); for (int x = -hX; x <= hX; x++) { for (int z = -hZ; z <= hZ; z++) { if (_cancelProgress) { HideProgress(); return; } var co = new ChunkCoordinates(x, z); if (!chunks.Contains(co)) { UpdateProgress(i, "Generating Chunks"); _level.GenerateChunk(co); } i++; } } } finally { Monitor.Exit(_busy); HideProgress(); Busy(false); } }); }
public ChunkColumn GenerateChunkColumn(ChunkCoordinates chunkCoordinates) { ChunkColumn c = new ChunkColumn() { X = chunkCoordinates.X, Z = chunkCoordinates.Z }; /* for (int x = 0; x < ChunkColumn.ChunkWidth; x++) * { * for (int z = 0; z < ChunkColumn.ChunkDepth; z++) * { * for (int y = 0; y < ChunkColumn.ChunkHeight; y++) * { * if (c.X == 0 && c.Z == 0) * { * IBlockState block; * switch (y >> 4) * { * case 0: * block = _dirt; * break; * case 1: * block = _stone; * break; * case 2: * block = _cobble; * break; * case 3: * block = _grass; * break; * //case 4: * // break; * default: * continue; * } * * c.SetBlock(x, y, z, block); * } * else * { * //c.SetBlockState(x, y, z, _air); * } * * c.SetSkyLight(x,y,z, 15); * } * c.SetHeight(x,z, 0); * } * }*/ return(c); }
private void LevelManagerOnLevelCreated(object sender, LevelEventArgs e) { ThreadPool.QueueUserWorkItem(o => { var level = e.Level; var maxPoints = ChunkRadius * ChunkRadius; int di = 1; int dj = 0; int segment_length = 1; int i = 0; int j = 0; int segment_passed = 0; for (int k = 0; k < maxPoints; ++k) { i += di; j += dj; ++segment_passed; { var coords = new ChunkCoordinates(i, j); //ThreadPool.QueueUserWorkItem(c => level.GetChunk((ChunkCoordinates) c), coords); level.GetChunk(coords); if (k % ChunkSaveInterval == 0) { level.WorldProvider.SaveChunks(); Log.InfoFormat("Saving Level... {2:F1}% ({0}/{1})", k, maxPoints, (k / (float)maxPoints) * 100); } } if (segment_passed == segment_length) { segment_passed = 0; int buffer = di; di -= dj; dj = buffer; if (dj == 0) { ++segment_length; } } } }); }
private bool IsWithinView(ChunkCoordinates chunk, ICamera camera) { var frustum = camera.BoundingFrustum; var chunkPos = new Vector3(chunk.X * ChunkColumn.ChunkWidth, 0, chunk.Z * ChunkColumn.ChunkDepth); if (chunk.DistanceTo(new ChunkCoordinates(camera.Position)) > RenderDistance) { return(false); } return(frustum.Intersects(new Microsoft.Xna.Framework.BoundingBox(chunkPos, chunkPos + new Vector3(ChunkColumn.ChunkWidth, MathF.Max(camera.Position.Y + 10f, 256f), ChunkColumn.ChunkDepth)))); }
private IEnumerable <ChunkColumn> GenerateChunks(ChunkCoordinates center, int renderDistance) { var oldChunks = _loadedChunks.ToArray(); double radiusSquared = Math.Pow(renderDistance, 2); List <ChunkCoordinates> newChunkCoordinates = new List <ChunkCoordinates>(); List <ChunkCoordinates> results = new List <ChunkCoordinates>(); for (int y = center.Z - renderDistance; y <= center.Z + renderDistance; y++) { for (int x = center.X - renderDistance; x <= center.X + renderDistance; x++) { var cc = new ChunkCoordinates(x, y); newChunkCoordinates.Add(cc); if (!_loadedChunks.Contains(cc)) { ChunkColumn chunk = _generator.GenerateChunkColumn(cc); if (chunk == null) { continue; } _loadedChunks.Add(cc); yield return(chunk); } } } foreach (var chunk in oldChunks) { if (!newChunkCoordinates.Contains(chunk) && chunk != center) { //UnloadChunk(chunk.X, chunk.Z); ChunkUnloadEvent unloadEvent = new ChunkUnloadEvent(chunk); EventDispatcher.DispatchEvent(unloadEvent); if (!unloadEvent.IsCancelled) { _loadedChunks.Remove(chunk); } } } }
public Chunk AllocateChunk(int X, int Y) { ChunkCoordinates chunkCoords = new ChunkCoordinates(X, Y); byte[] blocks = new byte[32768]; Chunk chunk = new Chunk(blocks, X, Y); for (int i = 0; i < chunk.SkylightMap.data.Length; i++) { chunk.SkylightMap.data[i] = 255; } Chunks.Add(chunkCoords, chunk); return(chunk); }
public int PruneAir() { int prunedChunks = 0; Stopwatch sw = new Stopwatch(); sw.Start(); foreach (KeyValuePair <ChunkCoordinates, ChunkColumn> valuePair in _chunkCache) { ChunkCoordinates chunkCoordinates = valuePair.Key; ChunkColumn chunkColumn = valuePair.Value; if (chunkColumn != null && chunkColumn.isAllAir) { bool surroundingIsAir = true; for (int startX = chunkCoordinates.X - 1; startX <= chunkCoordinates.X + 1; startX++) { for (int startZ = chunkCoordinates.Z - 1; startZ <= chunkCoordinates.Z + 1; startZ++) { ChunkCoordinates surroundingChunkCoordinates = new ChunkCoordinates(startX, startZ); if (!surroundingChunkCoordinates.Equals(chunkCoordinates)) { ChunkColumn surroundingChunkColumn; _chunkCache.TryGetValue(surroundingChunkCoordinates, out surroundingChunkColumn); if (surroundingChunkColumn != null && !surroundingChunkColumn.isAllAir) { surroundingIsAir = false; break; } } } } if (surroundingIsAir) { _chunkCache[chunkCoordinates] = null; prunedChunks++; } } } sw.Stop(); Log.Info("Pruned " + prunedChunks + " in " + sw.ElapsedMilliseconds + "ms"); return(prunedChunks); }
private IEnumerable <ChunkColumn> GenerateChunks(ChunkCoordinates center, int renderDistance) { var oldChunks = _loadedChunks.ToArray(); List <ChunkCoordinates> newChunkCoordinates = new List <ChunkCoordinates>(); int minZ = Math.Min(center.Z - renderDistance, center.Z + renderDistance); int maxZ = Math.Max(center.Z - renderDistance, center.Z + renderDistance); int minX = Math.Min(center.X - renderDistance, center.X + renderDistance); int maxX = Math.Max(center.X - renderDistance, center.X + renderDistance); for (int x = minX; x <= maxX; x++) { for (int z = minZ; z <= maxZ; z++) { var cc = new ChunkCoordinates(x, z); newChunkCoordinates.Add(cc); if (!_loadedChunks.Contains(cc)) { _loadedChunks.Add(cc); ChunkColumn chunk = _generator.GenerateChunkColumn(cc); if (chunk == null) { continue; } base.World.ChunkManager.AddChunk(chunk, cc, false); LoadEntities(chunk); yield return(chunk); } } } foreach (var chunk in oldChunks) { if (!newChunkCoordinates.Contains(chunk) && chunk != center) { //World.UnloadChunk(chunk); World.ChunkManager.RemoveChunk(chunk, false); _loadedChunks.Remove(chunk); } } }
public override void HandleMcpeClientCacheMissResponse(McpeClientCacheMissResponse message) { foreach (KeyValuePair <ulong, byte[]> kv in message.blobs) { ulong hash = kv.Key; byte[] data = kv.Value; Client.BlobCache.TryAdd(hash, data); var chunks = _futureChunks.Where(c => c.Key.SubChunks.Contains(hash) || c.Key.Biome == hash); foreach (KeyValuePair <CachedChunk, object> kvp in chunks) { CachedChunk chunk = kvp.Key; if (chunk.Biome == hash) { chunk.Chunk.biomeId = data; chunk.Biome = 0; } else { for (int i = 0; i < chunk.SubChunks.Length; i++) { ulong subChunkHash = chunk.SubChunks[i]; if (subChunkHash == hash) { // parse data chunk.Chunk[i] = ClientUtils.DecodeChunkColumn(1, data, BlockPalette, _internalStates)[0]; chunk.SubChunks[i] = 0; } } } if (chunk.Biome == 0 && chunk.SubChunks.All(c => c == 0)) { _futureChunks.TryRemove(chunk, out _); var coordinates = new ChunkCoordinates(chunk.Chunk.X, chunk.Chunk.Z); foreach (KeyValuePair <BlockCoordinates, NbtCompound> bePair in _futureBlockEntities.Where(be => (ChunkCoordinates)be.Key == coordinates)) { chunk.Chunk.BlockEntities.Add(bePair); _futureBlockEntities.TryRemove(bePair.Key, out _); } chunk.Chunk.RecalcHeight(); Client.Chunks[coordinates] = chunk.Chunk; } } } }
public ChunkColumn GenerateChunkColumn(ChunkCoordinates chunkCoordinates) { ChunkColumn cachedChunk; if (_chunkCache.TryGetValue(chunkCoordinates, out cachedChunk)) return cachedChunk; ChunkColumn chunk = new ChunkColumn(); chunk.x = chunkCoordinates.X; chunk.z = chunkCoordinates.Z; PopulateChunk(chunk); _chunkCache[chunkCoordinates] = chunk; return chunk; }
public bool isSameChunk(ChunkCoordinates otherChunkCoordinates) { if (otherChunkCoordinates == null) { return(false); } else if (otherChunkCoordinates.x == x && otherChunkCoordinates.z == z) { return(true); } else { return(false); } }
internal void DeleteChunk(ChunkCoordinates coords) { lock (_cacheSync) { AnvilChunk chunk; if (_chunkCache.TryRemove(coords, out chunk)) { } NbtFile nbtFile; if (_containingChunks.TryRemove(coords, out nbtFile)) { } } }
public void LoadAnvilChunkLoadTest() { int width = 32; int depth = 32; string basePath = @"D:\Development\Worlds\KingsLanding"; int regionX = 4; int regionZ = 25; //string basePath = @"D:\Temp\TestSave130"; //int regionX = 0; //int regionZ = 0; int cx = (width * regionX) + 3; int cz = (depth * regionZ) + 0; ChunkCoordinates coordinates = new ChunkCoordinates(cx, cz); int rx = coordinates.X >> 5; int rz = coordinates.Z >> 5; Assert.AreEqual(regionX, rx); Assert.AreEqual(regionZ, rz); //IWorldGenerator generator = new AirWorldGenerator(); IWorldGenerator generator = null; Stopwatch sw = new Stopwatch(); sw.Start(); AnvilWorldProvider wp = new AnvilWorldProvider(basePath); int iterations = 1000; ChunkColumn chunk = null; for (int i = 0; i < iterations; i++) { chunk = wp.GetChunk(coordinates, basePath, generator); } long ticks = sw.ElapsedTicks; long ms = sw.ElapsedMilliseconds; Console.WriteLine($"Read {iterations} chunk-columns in {ticks}ns ({ms}ms) at a rate of {ticks/iterations}ticks/col. 1ms={TimeSpan.TicksPerMillisecond}"); Assert.NotNull(chunk); Assert.Less(ticks / iterations, 100); }
public void SaveAnvilChunkTest() { int width = 32; int depth = 32; int regionX = 5; int regionZ = 24; AnvilWorldProvider anvil = new AnvilWorldProvider(@"D:\Development\Worlds\KingsLanding\"); anvil.Initialize(); Stopwatch sw = new Stopwatch(); sw.Start(); for (int x = 0; x < 32; x++) { for (int z = 0; z < 32; z++) { int cx = (width * regionX) + x; int cz = (depth * regionZ) + z; ChunkCoordinates coordinates = new ChunkCoordinates(cx, cz); ChunkColumn chunk = anvil.GenerateChunkColumn(coordinates, false); Assert.NotNull(chunk); } } Console.WriteLine("Read {0} chunks in {1}ms", anvil.NumberOfCachedChunks(), sw.ElapsedMilliseconds); sw.Restart(); anvil.SaveChunks(); Console.WriteLine("Saved {0} chunks in {1}ms", anvil.NumberOfCachedChunks(), sw.ElapsedMilliseconds); for (int x = 0; x < 32; x++) { for (int z = 0; z < 32; z++) { int cx = (width * regionX) + x; int cz = (depth * regionZ) + z; ChunkCoordinates coordinates = new ChunkCoordinates(cx, cz); anvil.GenerateChunkColumn(coordinates, false); } } }
private void Test(World level, BlockCoordinates sourceBlock, BlockCoordinates target, ConcurrentQueue <BlockCoordinates> lightBfsQueue, int lightLevel) { var chunkCoord = new ChunkCoordinates(sourceBlock); //Interlocked.Add(ref touches, 1); bool isOtherChunk = false; var newChunkCoord = (ChunkCoordinates)target; if (chunkCoord.X != newChunkCoord.X || chunkCoord.Z != newChunkCoord.Z) { //chunk = GetChunk(level, newCoord); lightBfsQueue = ChunkQueues.GetOrAdd(newChunkCoord, coordinates => new ConcurrentQueue <BlockCoordinates>()); isOtherChunk = true; } if (isOtherChunk && !World.TryGetBlockLight(target, out _)) { lightBfsQueue.Enqueue(target); /*Queue.Enqueue((newCoord, () => * { * if (ChunkQueues.TryGetValue((ChunkCoordinates) newCoord, out var queue)) * { * if (!level.TryGetBlockLight(coord, out var ll)) * { * return false; * } * //var cc = GetChunk(level, newCoord); * //if (cc == null) * // return false; * //var ll = level.GetBlockLight(coord); * * DoPass(level, newCoord, queue, ll); * * Enqueue(coord); * Enqueue(newCoord); * return true; * } * return false; * }));*/ return; } DoPass(level, target, lightBfsQueue, lightLevel); }
public ChunkColumn GenerateChunkColumn(ChunkCoordinates chunkCoordinates, bool cacheOnly = false) { ChunkColumn cachedChunk; if (_chunkCache.TryGetValue(chunkCoordinates, out cachedChunk)) return cachedChunk; if (cacheOnly) { return null; } ChunkColumn chunk = Generator.GenerateChunkColumn(chunkCoordinates); _chunkCache[chunkCoordinates] = chunk; return chunk; }
public ChunkColumn GetChunk(ChunkCoordinates coordinates, bool cacheOnly = false) { if (coordinates == _coord) { return(_chunk); } if (_coord != ChunkCoordinates.None) { if (coordinates != _coord) { if (coordinates != _coord + ChunkCoordinates.Backward) { if (coordinates != _coord + ChunkCoordinates.Forward) { if (coordinates != _coord + ChunkCoordinates.Left) { if (coordinates != _coord + ChunkCoordinates.Right) { if (coordinates != _coord + ChunkCoordinates.Backward + ChunkCoordinates.Left) { if (coordinates != _coord + ChunkCoordinates.Backward + ChunkCoordinates.Right) { if (coordinates != _coord + ChunkCoordinates.Forward + ChunkCoordinates.Left) { if (coordinates != _coord + ChunkCoordinates.Forward + ChunkCoordinates.Right) { return(null); } } } } } } } } } } if (_worldProvider.TryGetChunk(coordinates, out ChunkColumn column)) { return((ChunkColumn)column); } return(null); //return _worldProvider.GenerateChunkColumn(coordinates, true); }
public ChunkColumn GenerateChunkColumn(ChunkCoordinates chunkCoordinates) { ChunkColumn column = new ChunkColumn(); column.X = chunkCoordinates.X; column.Z = chunkCoordinates.Z; for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { column.SetBlockState(x, 0, z, Bedrock); if (column.X == 1 && column.Z == 1) { for (int y = 1; y < 2; y++) { column.SetBlockState(x, y, z, Water.WithProperty("level", "8")); } column.SetBlockState(x, 3, z, Water.WithProperty("level", "3")); } else { column.SetBlockState(x, 1, z, Dirt); column.SetBlockState(x, 2, z, Dirt); column.SetBlockState(x, 3, z, Grass); if (x == 8 && z == 8) { column.SetBlockState(x, 5, z, Slab.WithProperty("type", "bottom")); } else if (x == 8 && z == 7) { column.SetBlockState(x, 5, z, Slab.WithProperty("type", "top")); } } column.SetSkyLight(x, 0, z, 15); column.SetSkyLight(x, 1, z, 15); column.SetSkyLight(x, 2, z, 15); column.SetSkyLight(x, 3, z, 15); column.SetSkyLight(x, 4, z, 15); } } return(column); }
public void SaveAnvilChunkTest() { int width = 32; int depth = 32; int regionX = 5; int regionZ = 24; AnvilWorldProvider anvil = new AnvilWorldProvider(@"D:\Development\Worlds\KingsLanding\"); anvil.Initialize(); Stopwatch sw = new Stopwatch(); sw.Start(); for (int x = 0; x < 32; x++) { for (int z = 0; z < 32; z++) { int cx = (width*regionX) + x; int cz = (depth*regionZ) + z; ChunkCoordinates coordinates = new ChunkCoordinates(cx, cz); ChunkColumn chunk = anvil.GenerateChunkColumn(coordinates); Assert.NotNull(chunk); } } Console.WriteLine("Read {0} chunks in {1}ms", anvil.NumberOfCachedChunks(), sw.ElapsedMilliseconds); sw.Restart(); anvil.SaveChunks(); Console.WriteLine("Saved {0} chunks in {1}ms", anvil.NumberOfCachedChunks(), sw.ElapsedMilliseconds); for (int x = 0; x < 32; x++) { for (int z = 0; z < 32; z++) { int cx = (width*regionX) + x; int cz = (depth*regionZ) + z; ChunkCoordinates coordinates = new ChunkCoordinates(cx, cz); anvil.GenerateChunkColumn(coordinates); } } }
private void ForcedSendChunksForKnownPosition(PlayerLocation position) { var chunkPosition = new ChunkCoordinates(position); _currentChunkPosition = chunkPosition; foreach (McpeBatch chunk in Level.GenerateChunks(_currentChunkPosition, _chunksUsed)) { SendPackage(chunk, true); } }
public static void SendChunk(ChunkCoordinates position) { ChunkColumn targetchunk = Level[0]._worldProvider.GenerateChunkColumn(position); PcChunkColumn converted = new PcChunkColumn {X = position.X, Z = position.Z}; converted.Pe2Pc(targetchunk); foreach (var player in PcPlayers) { //new BlockChange(player.Wrapper, new MSGBuffer(player.Wrapper)) {BlockID = data.block, MetaData = data.meta, Location = new Vector3(data.x, data.y, data.z)}.Write(); new ChunkData(player.Wrapper) { Chunk = converted, Quee = false}.Write(); } }
public void LoadAnvilChunkLoadTest() { int width = 32; int depth = 32; int cx = (width*4) + 3; int cz = (depth*25) + 0; ChunkCoordinates coordinates = new ChunkCoordinates(cx, cz); int rx = coordinates.X >> 5; int rz = coordinates.Z >> 5; Assert.AreEqual(4, rx); Assert.AreEqual(25, rz); string basePath = @"D:\Downloads\KingsLanding1"; var generator = new FlatlandWorldProvider(); Stopwatch sw = new Stopwatch(); sw.Start(); int iterations = 1024; for (int i = 0; i < iterations; i++) { AnvilWorldProvider.GetChunk(coordinates, basePath, generator, 30); } long ticks = sw.ElapsedTicks; long ms = sw.ElapsedMilliseconds; //Assert.Less(ticks/iterations, 100); Console.WriteLine("Read {0} chunk-columns in {1}ns ({3}ms) at a rate of {2}ns/col", iterations, ticks, ticks / iterations, ms); }
public void LoadFullAnvilRegionLoadTest() { int width = 32; int depth = 32; int regionX = 5; int regionZ = 24; string basePath = @"D:\Downloads\KingsLanding1"; var generator = new FlatlandWorldProvider(); Stopwatch sw = new Stopwatch(); sw.Start(); int noChunksRead = 0; for (int x = 0; x < 32; x++) { for (int z = 0; z < 32; z++) { noChunksRead++; int cx = (width*regionX) + x; int cz = (depth*regionZ) + z; ChunkCoordinates coordinates = new ChunkCoordinates(cx, cz); ChunkColumn chunk = AnvilWorldProvider.GetChunk(coordinates, basePath, generator, 30); Assert.NotNull(chunk); } } Console.WriteLine("Read {0} chunks in {1}ms", noChunksRead, sw.ElapsedMilliseconds); }
public void ChunkLoadTest() { { var chunkPosition = new ChunkCoordinates(0, 0); Dictionary<Tuple<int, int>, double> newOrders = new Dictionary<Tuple<int, int>, double>(); double viewDistance = 250; double radiusSquared = viewDistance/Math.PI; double radius = Math.Ceiling(Math.Sqrt(radiusSquared)); int centerX = chunkPosition.X; int centerZ = chunkPosition.Z; Stopwatch sw = new Stopwatch(); sw.Start(); for (double x = -radius; x <= radius; x++) { for (double z = -radius; z <= radius; z++) { double distance = (x*x) + (z*z); if (distance > radiusSquared) { continue; } int chunkX = (int) (x + centerX); int chunkZ = (int) (z + centerZ); Tuple<int, int> index = new Tuple<int, int>(chunkX, chunkZ); newOrders[index] = distance; } } } { var chunkPosition = new ChunkCoordinates(0, 0); // A = pi r^2 // sqrt(A/pi) = r Dictionary<Tuple<int, int>, double> newOrders = new Dictionary<Tuple<int, int>, double>(); double radius = 9; double radiusSqr = radius*radius; int centerX = chunkPosition.X; int centerZ = chunkPosition.Z; Stopwatch sw = new Stopwatch(); sw.Start(); for (double x = -radius; x <= radius; x++) { for (double z = -radius; z <= radius; z++) { double distanceSqr = (x*x) + (z*z); if (distanceSqr > radiusSqr) continue; int chunkX = (int) (x + centerX); int chunkZ = (int) (z + centerZ); Tuple<int, int> index = new Tuple<int, int>(chunkX, chunkZ); newOrders[index] = distanceSqr; } } } }
public void SaveOneAnvilChunkTest() { int width = 32; int depth = 32; int cx = (width*4) + 3; int cz = (depth*25) + 0; AnvilWorldProvider anvil = new AnvilWorldProvider(@"D:\Development\Worlds\KingsLanding\"); anvil.Initialize(); ChunkCoordinates coordinates = new ChunkCoordinates(cx, cz); ChunkColumn chunk = anvil.GenerateChunkColumn(coordinates); Assert.NotNull(chunk); Stopwatch sw = new Stopwatch(); sw.Start(); anvil.SaveChunks(); Assert.Less(sw.ElapsedMilliseconds, 1); }
/// <summary> /// Sends the chunks for known position. /// </summary> private void SendChunksForKnownPosition() { if (IsBot) return; var chunkPosition = new ChunkCoordinates(KnownPosition); if (IsSpawned && _currentChunkPosition == chunkPosition) return; _currentChunkPosition = chunkPosition; ThreadPool.QueueUserWorkItem(delegate(object state) { int packetCount = 0; if (!IsBot) { while (Rtt < 0) { Thread.Yield(); } } MemoryStream stream = new MemoryStream(); foreach (var chunk in Level.GenerateChunks(_currentChunkPosition, _chunksUsed)) { McpeFullChunkData fullChunkData = McpeFullChunkData.CreateObject(); fullChunkData.chunkX = chunk.x; fullChunkData.chunkZ = chunk.z; fullChunkData.chunkData = chunk.GetBytes(); fullChunkData.chunkDataLength = fullChunkData.chunkData.Length; byte[] bytes = fullChunkData.Encode(); fullChunkData.PutPool(); //if (!IsSpawned) { McpeBatch batch = McpeBatch.CreateObject(); byte[] buffer = CompressBytes(bytes, CompressionLevel.Optimal); batch.payloadSize = buffer.Length; batch.payload = buffer; SendPackage(batch, sendDirect: true); } //else //{ // stream.Write(bytes, 0, bytes.Length); //} // This is to slow down chunk-sending not to overrun old devices. // The timeout should be configurable and enable/disable. //if (Math.Floor(Rtt/10d) > 0) //{ // Thread.Sleep(Math.Min(Math.Max((int) Math.Floor(Rtt/10d), 12) + 10, 40)); //} if (!IsSpawned) { if (packetCount++ == 56) { InitializePlayer(); } } } //if (IsSpawned) //{ // McpeBatch batch = McpeBatch.CreateObject(); // byte[] buffer = CompressBytes(stream.ToArray(), CompressionLevel.Fastest); // batch.payloadSize = buffer.Length; // batch.payload = buffer; // SendPackage(batch, sendDirect: true); //} }); }
public ChunkColumn GenerateChunkColumn(ChunkCoordinates chunkCoordinates) { lock (_chunkCache) { ChunkColumn cachedChunk; if (_chunkCache.TryGetValue(chunkCoordinates, out cachedChunk)) { return cachedChunk; } ChunkColumn chunk = new ChunkColumn(); chunk.x = chunkCoordinates.X; chunk.z = chunkCoordinates.Z; int h = PopulateChunk(chunk); chunk.SetBlock(0, h + 1, 0, 7); chunk.SetBlock(1, h + 1, 0, 41); chunk.SetBlock(2, h + 1, 0, 41); chunk.SetBlock(3, h + 1, 0, 41); chunk.SetBlock(3, h + 1, 0, 41); //chunk.SetBlock(6, h + 1, 6, 57); chunk.SetBlock(6, h, 9, 63); chunk.SetMetadata(6, h, 9, 12); var blockEntity = GetBlockEntity((chunkCoordinates.X*16) + 6, h, (chunkCoordinates.Z*16) + 9); chunk.SetBlockEntity(blockEntity.Coordinates, blockEntity.GetCompound()); if (chunkCoordinates.X == 1 && chunkCoordinates.Z == 1) { for (int x = 0; x < 10; x++) { for (int z = 0; z < 10; z++) { for (int y = h - 2; y < h; y++) { chunk.SetBlock(x, y, z, 8); } } } } if (chunkCoordinates.X == 3 && chunkCoordinates.Z == 1) { for (int x = 0; x < 10; x++) { for (int z = 0; z < 10; z++) { for (int y = h - 1; y < h; y++) { chunk.SetBlock(x, y, z, 10); } } } } for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { for (int y = 127; y != 0; y--) { if (chunk.GetBlock(x, y, z) == 0x00) { chunk.SetSkylight(x, y, z, 0xff); } else { chunk.SetSkylight(x, y, z, 0x00); } } } } _chunkCache[chunkCoordinates] = chunk; return chunk; } }
private void ForcedSendChunks() { if (!Monitor.TryEnter(_sendChunkSync)) return; try { var chunkPosition = new ChunkCoordinates(KnownPosition); _currentChunkPosition = chunkPosition; if (Level == null) return; foreach (McpeBatch chunk in Level.GenerateChunks(_currentChunkPosition, _chunksUsed)) { if (chunk == null) continue; SendPackage(chunk, true); } } finally { Monitor.Exit(_sendChunkSync); } }
private void SendChunksForKnownPosition() { if (!Monitor.TryEnter(_sendChunkSync)) return; try { var chunkPosition = new ChunkCoordinates(KnownPosition); if (IsSpawned && _currentChunkPosition == chunkPosition) return; if (IsSpawned && _currentChunkPosition.DistanceTo(chunkPosition) < 5) { return; } _currentChunkPosition = chunkPosition; int packetCount = 0; if (Level == null) return; foreach (McpeBatch chunk in Level.GenerateChunks(_currentChunkPosition, _chunksUsed)) { if (chunk != null) SendPackage(chunk); if (!IsSpawned) { if (packetCount++ == 56) { InitializePlayer(); } } } } finally { Monitor.Exit(_sendChunkSync); } }
private void ForcedSendChunk(PlayerLocation position) { lock (_sendChunkSync) { var chunkPosition = new ChunkCoordinates(position); McpeBatch chunk = Level.GenerateChunk(chunkPosition); var key = new Tuple<int, int>(chunkPosition.X, chunkPosition.Z); if (!_chunksUsed.ContainsKey(key)) { _chunksUsed.Add(key, chunk); } if (chunk != null) { SendPackage(chunk, true); } } }
public static void SaveChunk(ChunkColumn chunk, string basePath, int yoffset) { var coordinates = new ChunkCoordinates(chunk.x, chunk.z); int width = 32; int depth = 32; int rx = coordinates.X >> 5; int rz = coordinates.Z >> 5; string filePath = Path.Combine(basePath, string.Format(@"region\r.{0}.{1}.mca", rx, rz)); if (!File.Exists(filePath)) { // Make sure directory exist Directory.CreateDirectory(Path.Combine(basePath, "region")); // Create empty region file using (var regionFile = File.Open(filePath, FileMode.CreateNew)) { byte[] buffer = new byte[8192]; regionFile.Write(buffer, 0, buffer.Length); } return; } using (var regionFile = File.Open(filePath, FileMode.Open)) { byte[] buffer = new byte[8192]; regionFile.Read(buffer, 0, buffer.Length); int xi = (coordinates.X%width); if (xi < 0) xi += 32; int zi = (coordinates.Z%depth); if (zi < 0) zi += 32; int tableOffset = (xi + zi*width)*4; regionFile.Seek(tableOffset, SeekOrigin.Begin); byte[] offsetBuffer = new byte[4]; regionFile.Read(offsetBuffer, 0, 3); Array.Reverse(offsetBuffer); int offset = BitConverter.ToInt32(offsetBuffer, 0) << 4; int length = regionFile.ReadByte(); if (offset == 0 || length == 0) { regionFile.Seek(0, SeekOrigin.End); offset = (int) regionFile.Position; regionFile.Seek(tableOffset, SeekOrigin.Begin); byte[] bytes = BitConverter.GetBytes(offset >> 4); Array.Reverse(bytes); regionFile.Write(bytes, 0, 3); regionFile.WriteByte(1); } // Write NBT NbtFile nbt = CreateNbtFromChunkColumn(chunk, yoffset); byte[] nbtBuf = nbt.SaveToBuffer(NbtCompression.ZLib); int lenght = nbtBuf.Length; byte[] lenghtBytes = BitConverter.GetBytes(lenght + 1); Array.Reverse(lenghtBytes); regionFile.Seek(offset, SeekOrigin.Begin); regionFile.Write(lenghtBytes, 0, 4); // Lenght regionFile.WriteByte(0x02); // Compression mode regionFile.Write(nbtBuf, 0, nbtBuf.Length); int reminder; Math.DivRem(lenght + 4, 4096, out reminder); byte[] padding = new byte[4096 - reminder]; if (padding.Length > 0) regionFile.Write(padding, 0, padding.Length); } }
public ChunkColumn GenerateChunkColumn(ChunkCoordinates chunkCoordinates) { lock (_chunkCache) { ChunkColumn cachedChunk; if (_chunkCache.TryGetValue(chunkCoordinates, out cachedChunk)) return cachedChunk; ChunkColumn chunk = GetChunk(chunkCoordinates, _basePath, _flatland, _waterOffsetY); _chunkCache[chunkCoordinates] = chunk; return chunk; } }
public static ChunkColumn GetChunk(ChunkCoordinates coordinates, string basePath, IWorldProvider generator, int yoffset) { int width = 32; int depth = 32; int rx = coordinates.X >> 5; int rz = coordinates.Z >> 5; string filePath = Path.Combine(basePath, string.Format(@"region\r.{0}.{1}.mca", rx, rz)); if (!File.Exists(filePath)) return generator.GenerateChunkColumn(coordinates); using (var regionFile = File.OpenRead(filePath)) { byte[] buffer = new byte[8192]; regionFile.Read(buffer, 0, 8192); int xi = (coordinates.X%width); if (xi < 0) xi += 32; int zi = (coordinates.Z%depth); if (zi < 0) zi += 32; int tableOffset = (xi + zi*width)*4; regionFile.Seek(tableOffset, SeekOrigin.Begin); byte[] offsetBuffer = new byte[4]; regionFile.Read(offsetBuffer, 0, 3); Array.Reverse(offsetBuffer); int offset = BitConverter.ToInt32(offsetBuffer, 0) << 4; int length = regionFile.ReadByte(); if (offset == 0 || length == 0) { return generator.GenerateChunkColumn(coordinates); } regionFile.Seek(offset, SeekOrigin.Begin); byte[] waste = new byte[4]; regionFile.Read(waste, 0, 4); int compressionMode = regionFile.ReadByte(); var nbt = new NbtFile(); nbt.LoadFromStream(regionFile, NbtCompression.ZLib); NbtTag dataTag = nbt.RootTag["Level"]; NbtList sections = dataTag["Sections"] as NbtList; ChunkColumn chunk = new ChunkColumn { x = coordinates.X, z = coordinates.Z, biomeId = dataTag["Biomes"].ByteArrayValue }; for (int i = 0; i < chunk.biomeId.Length; i++) { if (chunk.biomeId[i] > 22) chunk.biomeId[i] = 0; } if (chunk.biomeId.Length > 256) throw new Exception(); // This will turn into a full chunk column foreach (NbtTag sectionTag in sections) { int sy = sectionTag["Y"].ByteValue*16; byte[] blocks = sectionTag["Blocks"].ByteArrayValue; byte[] data = sectionTag["Data"].ByteArrayValue; NbtTag addTag = sectionTag["Add"]; byte[] adddata = new byte[2048]; if (addTag != null) adddata = addTag.ByteArrayValue; byte[] blockLight = sectionTag["BlockLight"].ByteArrayValue; byte[] skyLight = sectionTag["SkyLight"].ByteArrayValue; for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { for (int y = 0; y < 16; y++) { int yi = sy + y - yoffset; if (yi < 0 || yi >= 128) continue; int anvilIndex = y*16*16 + z*16 + x; int blockId = blocks[anvilIndex] + (Nibble4(adddata, anvilIndex) << 8); // Anvil to PE friendly converstion if (blockId == 125) blockId = 5; else if (blockId == 126) blockId = 158; else if (blockId == 75) blockId = 50; else if (blockId == 76) blockId = 50; else if (blockId == 123) blockId = 89; else if (blockId == 124) blockId = 89; else if (blockId == 152) blockId = 73; else if (_ignore.BinarySearch(blockId) >= 0) blockId = 0; else if (_gaps.BinarySearch(blockId) >= 0) { Debug.WriteLine("Missing material: " + blockId); blockId = 133; } if (blockId > 255) blockId = 41; if (yi == 127 && blockId != 0) blockId = 30; if (yi == 0 && (blockId == 8 || blockId == 9 /*|| blockId == 0*/)) blockId = 7; //if (blockId != 0) blockId = 41; chunk.SetBlock(x, yi, z, (byte) blockId); chunk.SetMetadata(x, yi, z, Nibble4(data, anvilIndex)); chunk.SetBlocklight(x, yi, z, Nibble4(blockLight, anvilIndex)); chunk.SetSkylight(x, yi, z, Nibble4(skyLight, anvilIndex)); } } } } NbtList entities = dataTag["Entities"] as NbtList; NbtList blockEntities = dataTag["TileEntities"] as NbtList; if (blockEntities != null) { foreach (var nbtTag in blockEntities) { var blockEntityTag = (NbtCompound) nbtTag; string entityId = blockEntityTag["id"].StringValue; int x = blockEntityTag["x"].IntValue; int y = blockEntityTag["y"].IntValue - yoffset; int z = blockEntityTag["z"].IntValue; blockEntityTag["y"] = new NbtInt("y", y); BlockEntity blockEntity = BlockEntityFactory.GetBlockEntityById(entityId); if (blockEntity != null) { blockEntityTag.Name = string.Empty; chunk.SetBlockEntity(new BlockCoordinates(x, y, z), blockEntityTag); } } } NbtList tileTicks = dataTag["TileTicks"] as NbtList; chunk.isDirty = false; return chunk; } }
private void SendChunksForKnownPosition() { if (!Monitor.TryEnter(_sendChunkSync)) return; try { var chunkPosition = new ChunkCoordinates(KnownPosition); if (IsSpawned && _currentChunkPosition == chunkPosition) return; //if (_currentChunkPosition.DistanceTo(chunkPosition) < 4) //{ // Log.DebugFormat("Denied chunk, too little distance."); // return; //} _currentChunkPosition = chunkPosition; int packetCount = 0; foreach (McpeBatch chunk in Level.GenerateChunks(_currentChunkPosition, _chunksUsed)) { SendPackage(chunk, sendDirect: true); if (!IsSpawned) { if (packetCount++ == 56) { InitializePlayer(); } } } } finally { Monitor.Exit(_sendChunkSync); } }