public ChunkLightUpdate(Chunk chunk, int x, int y, int z) { _X = x; _Y = y; _Z = z; _Chunk = chunk; }
public ChunkLightUpdate(Chunk chunk) { _X = -1; _Y = -1; _Z = -1; _Chunk = chunk; }
public Chunk ProvideChunk(int x, int z, WorldManager world) { Chunk chunk = new Chunk(world, UniversalCoords.FromChunk(x, z)); InitGen(); byte[] data = new byte[32768]; #if PROFILE Stopwatch watch = new Stopwatch(); watch.Start(); #endif GenerateTerrain(chunk, data, x, z); GenerateFlora(chunk, data, x, z); chunk.SetAllBlocks(data); chunk.RecalculateHeight(); chunk.LightToRecalculate = true; #if PROFILE watch.Stop(); _World.Logger.Log(Logger.LogLevel.Info, "Chunk {0} {1}, {2}", false, x, z, watch.ElapsedMilliseconds); #endif _World.AddChunk(chunk); chunk.MarkToSave(); return chunk; }
internal void SendChunk(Chunk chunk) { MapChunkPacket packet = new MapChunkPacket { Chunk = chunk }; PacketHandler.SendPacket(packet); }
public static MapChunkData GetMapChunkData(Chunk chunk, bool firstInit) { MapChunkData chunkData = new MapChunkData(); ushort mask = 1; Queue<Section> sectionsToBeSent = new Queue<Section>(); for (int i = 0; i < 16; ++i) { Section currentSection = chunk.Sections[i]; if (currentSection != null && (firstInit || (chunk.SectionsToBeUpdated & 1) << i != 0)) { sectionsToBeSent.Enqueue(currentSection); } } int dataDim = sectionsToBeSent.Count * (Section.BYTESIZE + Section.SIZE); if (firstInit) dataDim += 256; chunkData.Data = new byte[dataDim]; int halfSize = sectionsToBeSent.Count * Section.HALFSIZE; int offsetData = sectionsToBeSent.Count * Section.SIZE; int offsetLight = offsetData + halfSize; int offsetSkyLight = offsetLight + halfSize; int sectionIndex = 0; while(sectionsToBeSent.Count > 0) { Section section = sectionsToBeSent.Dequeue(); Buffer.BlockCopy(section.Types, 0, chunkData.Data, sectionIndex * Section.SIZE, Section.SIZE); Buffer.BlockCopy(section.Data.Data, 0, chunkData.Data, offsetData + (sectionIndex * Section.HALFSIZE), Section.HALFSIZE); Buffer.BlockCopy(chunk.Light.Data, section.SectionId * Section.HALFSIZE, chunkData.Data, offsetLight + (sectionIndex * Section.HALFSIZE), Section.HALFSIZE); Buffer.BlockCopy(chunk.SkyLight.Data, section.SectionId * Section.HALFSIZE, chunkData.Data, offsetSkyLight + (sectionIndex * Section.HALFSIZE), Section.HALFSIZE); chunkData.PrimaryBitMask |= mask << section.SectionId; ++sectionIndex; // TODO: we leave add array and biome array to 0 (ocean), we need to change the chunk generator accordingly } return chunkData; }
public static void LoadContainersFromDisk(Chunk chunk) { string containerPath = Path.Combine(chunk.World.Folder, ChraftConfig.ContainersFolder, "x" + chunk.Coords.ChunkX + "z" + chunk.Coords.ChunkZ); if (!Directory.Exists(containerPath)) return; string[] files = Directory.GetFiles(containerPath); PersistentContainer container; UniversalCoords containerCoords; BlockData.Blocks containerType; string id; int x, y, z, startPos, endPos; string coordStr; foreach (var file in files) { coordStr = file.Substring(file.LastIndexOf(Path.DirectorySeparatorChar) + 1); startPos = coordStr.IndexOf("x") + 1; endPos = coordStr.IndexOf("y"); if (!Int32.TryParse(coordStr.Substring(startPos, endPos - startPos), out x)) continue; startPos = endPos + 1; endPos = coordStr.IndexOf("z"); if (!Int32.TryParse(coordStr.Substring(startPos, endPos - startPos), out y)) continue; startPos = endPos + 1; endPos = coordStr.IndexOf("."); if (!Int32.TryParse(coordStr.Substring(startPos, endPos - startPos), out z)) continue; containerCoords = UniversalCoords.FromWorld(x, y, z); containerType = chunk.GetType(containerCoords); switch (containerType) { case BlockData.Blocks.Dispenser: container = new DispenserContainer(); container.Initialize(chunk.World, containerCoords); break; case BlockData.Blocks.Furnace: case BlockData.Blocks.Burning_Furnace: container = new FurnaceContainer(); container.Initialize(chunk.World, containerCoords); (container as FurnaceContainer).StartBurning(); break; default: continue; } chunk.Containers.TryAdd(containerCoords.BlockPackedCoords, container); } }
public override void Read(PacketReader stream) { int posX = stream.ReadInt(); short posY = stream.ReadShort(); int posZ = stream.ReadInt(); byte sizeX = (byte)(stream.ReadByte() + 1); byte sizeY = (byte)(stream.ReadByte() + 1); byte sizeZ = (byte)(stream.ReadByte() + 1); int o = sizeX * sizeY * sizeZ; Chunk = new Chunk(null, UniversalCoords.FromWorld(posX, posY, posZ)); int len = stream.ReadInt(); stream.ReadBytes(len); }
public override void Read(PacketReader stream) { int posX = stream.ReadInt(); short posY = stream.ReadShort(); int posZ = stream.ReadInt(); byte sizeX = (byte)(stream.ReadByte() + 1); byte sizeY = (byte)(stream.ReadByte() + 1); byte sizeZ = (byte)(stream.ReadByte() + 1); int o = sizeX * sizeY * sizeZ; Chunk = new Chunk(null, posX << 4, posZ << 4); int len = stream.ReadInt(); byte[] data = new byte[o * 5 / 2]; byte[] comp = stream.ReadBytes(len); }
public override void Read(BigEndianStream stream) { int posX = stream.ReadInt(); short posY = stream.ReadShort(); int posZ = stream.ReadInt(); byte sizeX = (byte)(stream.ReadByte() + 1); byte sizeY = (byte)(stream.ReadByte() + 1); byte sizeZ = (byte)(stream.ReadByte() + 1); int o = sizeX * sizeY * sizeZ; Chunk = new Chunk(null, posX, posZ); int len = stream.ReadInt(); byte[] comp = new byte[len]; byte[] data = new byte[o * 5 / 2]; len = stream.Read(comp, 0, len); }
public void ProvideChunk(int x, int z, Chunk chunk, bool recalculate) { InitGen(); byte[] data = new byte[32768]; Stopwatch watch = new Stopwatch(); watch.Start(); GenerateTerrain(chunk, data, x, z); GenerateFlora(chunk, data, x, z); chunk.SetAllBlocks(data); watch.Stop(); if(recalculate) chunk.Recalculate(); Console.WriteLine("Chunk {0} {1}, {2}", x, z, watch.ElapsedMilliseconds); //chunk.Save(); _World.AddChunk(chunk); chunk.MarkToSave(); }
public Chunk ProvideChunk(int x, int z, Chunk chunk, bool recalculate) { InitGen(); byte[] data = new byte[32768]; Stopwatch watch = new Stopwatch(); watch.Start(); GenerateTerrain(chunk, data, x, z); GenerateFlora(chunk, data, x, z); chunk.SetAllBlocks(data); if(recalculate) chunk.Recalculate(); watch.Stop(); Console.WriteLine("Chunk {0} {1}", x, z); //chunk.Save(); _World.AddChunk(chunk); return chunk; }
private void GenerateOuterLayer(int x, int y, int z, int firstBlockHeight, BIOME_TYPE type, Chunk c, byte[] data) { double heightPercentage = (firstBlockHeight - y) / 128.0; short currentIndex = (short)(x << 11 | z << 7 | y); switch (type) { case BIOME_TYPE.PLAINS: case BIOME_TYPE.MOUNTAINS: // Beach if (y >= 60 && y <= 66) { data[currentIndex] = (byte)BlockData.Blocks.Sand; break; } if (heightPercentage == 0.0 && y > 66) { // Grass on top data[currentIndex] = (byte)BlockData.Blocks.Grass; } else if (heightPercentage > 0.2) { // Stone data[currentIndex] = (byte)BlockData.Blocks.Stone; } else { // Dirt data[currentIndex] = (byte)BlockData.Blocks.Dirt; } GenerateRiver(c, x, y, z, heightPercentage, type, data); break; case BIOME_TYPE.SNOW: if (heightPercentage == 0.0 && y > 65) { // Snow on top data[currentIndex] = (byte)BlockData.Blocks.Snow; // Grass under the snow data[x << 11 | z << 7 | y - 1] = (byte)BlockData.Blocks.Grass; } else if (heightPercentage > 0.2) { // Stone data[currentIndex] = (byte)BlockData.Blocks.Stone; } else if (data[x << 11 | z << 7 | (y + 1)] == (byte)BlockData.Blocks.Air) { // Grass under the snow data[currentIndex] = (byte)BlockData.Blocks.Grass; data[x << 11 | z << 7 | (y + 1)] = (byte)BlockData.Blocks.Snow; } else { // Dirt data[currentIndex] = (byte)BlockData.Blocks.Dirt; } GenerateRiver(c, x, y, z, heightPercentage, type, data); break; case BIOME_TYPE.DESERT: /*if (heightPercentage > 0.6 && y < 75) { // Stone data[x << 11 | z << 7 | y] = (byte)BlockData.Blocks.Stone; } else*/ if (y < 80) { data[currentIndex] = (byte)BlockData.Blocks.Sand; } break; } }
private void GenerateTerrain(Chunk c, byte[] data, int x, int z) { double[, ,] density = new double[17, 129, 17]; // Build the density map with lower resolution, 4*4*16 instead of 16*16*128 for (int bx = 0; bx <= 16; bx += 4) { int worldX = bx + (x * 16); for (int bz = 0; bz <= 16; bz += 4) { BIOME_TYPE type = CalcBiomeType(x, z); int worldZ = bz + (z * 16); for (int by = 0; by <= 128; by += 8) { density[bx, by, bz] = CalcDensity(worldX, by, worldZ, type); } } } triLerpDensityMap(density); for (int bx = 0; bx < 16; bx++) { int worldX = bx + (x * 16); for (int bz = 0; bz < 16; bz++) { int worldZ = bz + (z * 16); int firstBlockHeight = -1; BIOME_TYPE type = CalcBiomeType(worldX, worldZ); for (int by = 127; by >= 0; --by) { int index = bx << 11 | bz << 7 | by; if (by == 0) // First bedrock Layer { data[index] = (byte)BlockData.Blocks.Bedrock; continue; } else if (by > 0 && by < 5 && _FastRandom.randomDouble() > 0.3) // Randomly put blocks of the remaining 4 layers of bedrock { data[index] = (byte)BlockData.Blocks.Bedrock; continue; } else if (by <= 55) data[index] = (byte)BlockData.Blocks.Stone; else { if (by > 55 && by < 64) { data[index] = (byte)BlockData.Blocks.Still_Water; if (by == 63 && type == BIOME_TYPE.SNOW) { data[index] = (byte)BlockData.Blocks.Ice; } } double dens = density[bx, by, bz]; if (dens >= 0.009 && dens <= 0.02) { // Some block was set... if (firstBlockHeight == -1) firstBlockHeight = by; GenerateOuterLayer(bx, by, bz, firstBlockHeight, type, c, data); } else if (dens > 0.02) { // Some block was set... if (firstBlockHeight == -1) firstBlockHeight = by; if (CalcCaveDensity(worldX, by, worldZ) > -0.6) GenerateInnerLayer(bx, by, bz, type, data); } else firstBlockHeight = -1; } if (data[index] == (byte)BlockData.Blocks.Stone) GenerateResource(bx, by, bz, data); } } } }
protected void GenerateRiver(Chunk c, int x, int y, int z, double heightPercentage, BIOME_TYPE type, byte[] data) { // Rivers under water? Nope. if (y <= 63) return; double lakeIntens = CalcLakeIntensity(x + c.Coords.ChunkX * 16, z + c.Coords.ChunkZ * 16); short currentIndex = (short)(x << 11 | z << 7 | y); if (lakeIntens < 0.2 ) { if (heightPercentage < 0.001) data[currentIndex] = (byte)BlockData.Blocks.Air; else if (heightPercentage < 0.02) { if (type == BIOME_TYPE.SNOW) { // To be sure that there's no snow above us data[x << 11 | z << 7 | y + 1] = (byte)BlockData.Blocks.Air; data[currentIndex] = (byte)BlockData.Blocks.Ice; } else { data[currentIndex] = (byte)BlockData.Blocks.Still_Water; } } } }
private void GenerateFlora(Chunk c, byte[] data, int x, int z) { BIOME_TYPE biome = CalcBiomeType(x, z); for (int bx = 0; bx < 16; ++bx) { int worldX = bx + x * 16; for (int bz = 0; bz < 16; ++bz) { int worldZ = bz + z * 16; for (int by = 64; by < 128; ++by) { int worldY = by; int index = bx << 11 | bz << 7 | by + 1; if (data[bx << 11 | bz << 7 | by] == (byte)BlockData.Blocks.Grass && data[index] == (byte)BlockData.Blocks.Air) { double grassDens = CalcGrassDensity(worldX, worldZ); if (grassDens > 0.0) { // Generate high grass. double rand = _FastRandom.standNormalDistrDouble(); if (rand > -0.2 && rand < 0.2) { data[index] = (byte)BlockData.Blocks.TallGrass; c.Data.setNibble(bx, by + 1, bz, 1); } //Generate flowers. if (_FastRandom.standNormalDistrDouble() < -2) { if (_FastRandom.randomBoolean()) data[index] = (byte)BlockData.Blocks.Rose; else data[index] = (byte)BlockData.Blocks.Yellow_Flower; } } if (by < 110 && bx % 4 == 0 && bz % 4 == 0) { double forestDens = CalcForestDensity(worldX, worldZ); if (forestDens > 0.005) { int randX = bx + _FastRandom.randomInt() % 12 + 4; int randZ = bz + _FastRandom.randomInt() % 12 + 4; if (randX < 3) randX = 3; else if (randX > 12) randX = 12; if (randZ < 3) randZ = 3; else if (randZ > 15) randZ = 12; if (data[randX << 11 | randZ << 7 | by] == (byte)BlockData.Blocks.Grass) { GenerateTree(c, randX, by, randZ, data); } else if (biome == BIOME_TYPE.DESERT && data[randX << 11 | randZ << 7 | by] == (byte)BlockData.Blocks.Sand) { GenerateCactus(randX, by, randZ, data); } } } } } } } }
public Section(Chunk parent) { _Parent = parent; _NonAirBlocks = 0; }
internal void SendSignTexts(Chunk chunk) { foreach (var signKVP in chunk.SignsText) { int blockX = signKVP.Key >> 11; int blockY = (signKVP.Key & 0xFF) % 128; int blockZ = (signKVP.Key >> 7) & 0xF; UniversalCoords coords = UniversalCoords.FromBlock(chunk.Coords.ChunkX, chunk.Coords.ChunkZ, blockX, blockY, blockZ); string[] lines = new string[4]; int length = signKVP.Value.Length; for (int i = 0; i < 4; ++i, length -= 15) { int currentLength = length; if (currentLength > 15) currentLength = 15; if (length > 0) lines[i] = signKVP.Value.Substring(i * 15, currentLength); else lines[i] = ""; } SendPacket(new UpdateSignPacket { X = coords.WorldX, Y = coords.WorldY, Z = coords.WorldZ, Lines = lines }); } }
public static bool IsDoubleChest(Chunk chunk, UniversalCoords coords) { if (chunk == null) return false; return chunk.IsNSEWTo(coords,(byte) BlockData.Blocks.Chest); }
public Section(Chunk parent, int sectionId) { _Parent = parent; _NonAirBlocks = 0; SectionId = sectionId; }
public static MapChunkData GetMapChunkData(Chunk chunk) { MapChunkData chunkData = new MapChunkData(); ushort mask = 1; int sectionIndex = 0; int sectionsSent = 0; for (int i = 0; i < 16; ++i ) { Section currentSection = chunk.Sections[i]; if (currentSection != null) ++sectionsSent; } int dataDim = (sectionsSent * Section.BYTESIZE) + 256; // (Number of sections * (Section dimension + Add array) + Biome array chunkData.Data = new byte[dataDim]; int halfSize = sectionsSent * Section.HALFSIZE; int offsetData = sectionsSent * Section.SIZE; int offsetLight = offsetData + halfSize; int offsetSkyLight = offsetLight + halfSize; for (int i = 0; i < 16; ++i) { Section currentSection = chunk.Sections[i]; if (currentSection != null) { Buffer.BlockCopy(currentSection.Types, 0, chunkData.Data, sectionIndex * Section.SIZE, Section.SIZE); Buffer.BlockCopy(currentSection.Data.Data, 0, chunkData.Data, offsetData + (sectionIndex * Section.HALFSIZE), Section.HALFSIZE); Buffer.BlockCopy(chunk.Light.Data, i * Section.HALFSIZE, chunkData.Data, offsetLight + (sectionIndex * Section.HALFSIZE), Section.HALFSIZE); Buffer.BlockCopy(chunk.SkyLight.Data, i * Section.HALFSIZE, chunkData.Data, offsetSkyLight + (sectionIndex * Section.HALFSIZE), Section.HALFSIZE); chunkData.PrimaryBitMask |= mask << i; ++sectionIndex; } // TODO: we leave add array and biome array to 0 (ocean), we need to change the chunk generator accordingly } return chunkData; }
public static void UnloadContainers(Chunk chunk) { foreach (var container in chunk.Containers) { container.Value.Save(); if (container.Value is FurnaceContainer) (container.Value as FurnaceContainer).Unload(); } chunk.Containers.Clear(); }
internal bool Remove(Chunk chunk) { chunk.Deleted = true; return Remove(chunk.Coords); }
private Chunk LoadChunk(int x, int z) { lock (ChunkGenLock) { Chunk chunk = new Chunk(this, x << 4, z << 4); if (chunk.Load()) Chunks.Add(chunk); else chunk = Generator.ProvideChunk(x, z); return chunk; } }
private Chunk LoadChunk(UniversalCoords coords, bool create, bool recalculate) { lock (ChunkGenLock) { // We should check again since two threads can enter here, one after the other, with the same chunk to load Chunk chunk; if ((chunk = Chunks[coords]) != null) return chunk; chunk = new Chunk(this, coords); if (chunk.Load()) AddChunk(chunk); else if (create) _generator.ProvideChunk(coords.ChunkX, coords.ChunkZ, chunk, recalculate); else chunk = null; if(chunk != null) chunk.InitGrowableCache(); return chunk; } }
private void GenerateTree(Chunk c, int x, int y, int z, byte[] data) { // Trees should only be placed in direct sunlight if (!CanSeeTheSky(x, y + 1, z, data)) return; double r2 = _FastRandom.standNormalDistrDouble(); /*if (r2 > -2 && r2 < -1) {*/ // Standard tree for (int by = y + 4; by < y + 6; by++) for (int bx = x - 2; bx <= x + 2; bx++) for (int bz = z - 2; bz <= z + 2; bz++) { data[bx << 11 | bz << 7 | by] = (byte)BlockData.Blocks.Leaves; c.Data.setNibble(bx, by, bz, 0); } for (int bx = x - 1; bx <= x + 1; bx++) for (int bz = z - 1; bz <= z + 1; bz++) { data[bx << 11 | bz << 7 | y + 6] = (byte)BlockData.Blocks.Leaves; c.Data.setNibble(bx, y + 6, bz, 0); } for (int by = y + 1; by < y + 6; by++) { data[x << 11 | z << 7 | by] = (byte)BlockData.Blocks.Log; c.Data.setNibble(x, by, z, 0); } //} // TODO: other tree types /*else if (r2 > 1 && r2 < 2) { c.setBlock(x, y + 1, z, (byte)0x0); c.getParent().getObjectGenerator("firTree").generate(c.getBlockWorldPosX(x), y + 1, c.getBlockWorldPosZ(z), false); } else { c.setBlock(x, y + 1, z, (byte)0x0); c.getParent().getObjectGenerator("tree").generate(c.getBlockWorldPosX(x), y + 1, c.getBlockWorldPosZ(z), false); }*/ }
public void Add(Chunk chunk) { this[chunk.Coords] = chunk; Interlocked.Increment(ref Changes); }
public void AddChunk(Chunk c) { c.CreationDate = DateTime.Now; Chunks.Add(c); }
internal void SendChunk(Chunk chunk, bool sync) { MapChunkPacket packet = new MapChunkPacket { Chunk = chunk, Async = !sync }; SendPacket(packet); }
public static Chunk Load(UniversalCoords coords, WorldManager world) { string path = world.Folder + "/x" + coords.ChunkX + "_z" + coords.ChunkZ + ".gz"; if (!CanLoad(path)) return null; Stream zip = null; Chunk chunk = new Chunk(world, coords); try { zip = new DeflateStream(File.Open(path, FileMode.Open), CompressionMode.Decompress); int version = zip.ReadByte(); switch(version) { /* When there's a new mod you do: case 1: { * dosomething * goto case 0; }*/ case 0: { chunk.LightToRecalculate = Convert.ToBoolean(zip.ReadByte()); chunk.HeightMap = new byte[16,16]; int height; chunk.MaxHeight = 0; for (int x = 0; x < 16; ++x) { for (int z = 0; z < 16; ++z) { height = chunk.HeightMap[x, z] = (byte) zip.ReadByte(); if (chunk.MaxHeight < height) chunk.MaxHeight = height; } } chunk.LoadAllBlocks(zip); break; } } } catch (Exception ex) { world.Logger.Log(ex); return null; } if (zip != null) zip.Dispose(); (BlockHelper.Instance((byte) BlockData.Blocks.Sign_Post) as BlockSignBase).LoadSignsFromDisk(chunk, world.SignsFolder); return chunk; }
public void RemoveChunk(Chunk c) { Chunks.Remove(c); }