unsafe void HandleBulkBlockUpdate() { int count = reader.ReadUInt8() + 1; World map = game.World; int mapSize = map.HasBlocks ? map.blocks.Length : 0; int *indices = stackalloc int[bulkCount]; for (int i = 0; i < count; i++) { indices[i] = reader.ReadInt32(); } reader.Skip((bulkCount - count) * sizeof(int)); BlockID *blocks = stackalloc BlockID[bulkCount]; for (int i = 0; i < count; i++) { blocks[i] = reader.buffer[reader.index + i]; } reader.Skip(bulkCount); if (reader.ExtendedBlocks) { for (int i = 0; i < count; i += 4) { byte flags = reader.buffer[reader.index + (i >> 2)]; blocks[i + 0] |= (BlockID)((flags & 0x03) << 8); blocks[i + 1] |= (BlockID)((flags & 0x0C) << 6); blocks[i + 2] |= (BlockID)((flags & 0x30) << 4); blocks[i + 3] |= (BlockID)((flags & 0xC0) << 2); } reader.Skip(bulkCount / 4); } for (int i = 0; i < count; i++) { int index = indices[i]; if (index < 0 || index >= mapSize) { continue; } int x = index % map.Width; int y = index / (map.Width * map.Length); int z = (index / map.Width) % map.Length; if (map.IsValidPos(x, y, z)) { game.UpdateBlock(x, y, z, blocks[i]); } } }
public unsafe override void LightHint(int startX, int startZ, BlockID *mapPtr) { int x1 = Math.Max(startX, 0), x2 = Math.Min(width, startX + 18); int z1 = Math.Max(startZ, 0), z2 = Math.Min(length, startZ + 18); int xCount = x2 - x1, zCount = z2 - z1; int *skip = stackalloc int[xCount * zCount]; int elemsLeft = InitialHeightmapCoverage(x1, z1, xCount, zCount, skip); if (!CalculateHeightmapCoverage(x1, z1, xCount, zCount, elemsLeft, skip, mapPtr)) { FinishHeightmapCoverage(x1, z1, xCount, zCount, skip); } }
bool BuildChunk(int x1, int y1, int z1, ref bool allAir) { light = game.Lighting; PreStretchTiles(x1, y1, z1); BlockID *chunkPtr = stackalloc BlockID[extChunkSize3]; chunk = chunkPtr; byte * countsPtr = stackalloc byte[chunkSize3 * Side.Sides]; counts = countsPtr; int * bitsPtr = stackalloc int[extChunkSize3]; bitFlags = bitsPtr; MemUtils.memset((IntPtr)chunkPtr, 0, 0, extChunkSize3 * sizeof(BlockID)); if (ReadChunkData(x1, y1, z1, ref allAir)) { return(false); } MemUtils.memset((IntPtr)countsPtr, 1, 0, chunkSize3 * Side.Sides); chunkEndX = Math.Min(x1 + chunkSize, width); chunkEndZ = Math.Min(z1 + chunkSize, length); Stretch(x1, y1, z1); PostStretchTiles(x1, y1, z1); int xMax = Math.Min(width, x1 + chunkSize); int yMax = Math.Min(height, y1 + chunkSize); int zMax = Math.Min(length, z1 + chunkSize); for (int y = y1, yy = 0; y < yMax; y++, yy++) { for (int z = z1, zz = 0; z < zMax; z++, zz++) { int chunkIndex = (yy + 1) * extChunkSize2 + (zz + 1) * extChunkSize + (0 + 1); for (int x = x1, xx = 0; x < xMax; x++, xx++) { curBlock = chunk[chunkIndex]; if (info.Draw[curBlock] != DrawType.Gas) { int index = ((yy << 8) | (zz << 4) | xx) * Side.Sides; X = x; Y = y; Z = z; cIndex = chunkIndex; RenderTile(index); } chunkIndex++; } } } return(true); }
unsafe void MapSet(BlockID *ptr, int yStart, int yEnd, BlockID block) { yStart = Math.Max(yStart, 0); yEnd = Math.Max(yEnd, 0); int startIndex = yStart * Length * Width; int endIndex = (yEnd * Length + (Length - 1)) * Width + (Width - 1); int count = (endIndex - startIndex) + 1, offset = 0; while (offset < count) { int bytes = Math.Min(count - offset, Width * Length) * sizeof(BlockID); #if USE16_BIT MemUtils.memset((IntPtr)ptr, (byte)block, startIndex + offset, bytes); #else MemUtils.memset((IntPtr)ptr, block, startIndex + offset, bytes); #endif offset += bytes; CurrentProgress = (float)offset / count; } }
bool BuildChunk(int x1, int y1, int z1, ref bool allAir) { light = game.Lighting; PreStretchTiles(x1, y1, z1); BlockID *chunkPtr = stackalloc BlockID[extChunkSize3]; chunk = chunkPtr; byte * countsPtr = stackalloc byte[chunkSize3 * Side.Sides]; counts = countsPtr; int * bitsPtr = stackalloc int[extChunkSize3]; bitFlags = bitsPtr; MemUtils.memset((IntPtr)chunkPtr, 0, 0, extChunkSize3 * sizeof(BlockID)); bool allSolid = false; fixed(BlockRaw *mapPtr = map.blocks) { #if !ONLY_8BIT if (BlockInfo.MaxUsed >= 256) { ReadChunkData_16Bit(x1, y1, z1, mapPtr, ref allAir, ref allSolid); } else { ReadChunkData_8Bit(x1, y1, z1, mapPtr, ref allAir, ref allSolid); } #else ReadChunkData_8Bit(x1, y1, z1, mapPtr, ref allAir, ref allSolid); #endif if (x1 == 0 || y1 == 0 || z1 == 0 || x1 + chunkSize >= width || y1 + chunkSize >= height || z1 + chunkSize >= length) { allSolid = false; } if (allAir || allSolid) { return(false); } light.LightHint(x1 - 1, z1 - 1, mapPtr); } MemUtils.memset((IntPtr)countsPtr, 1, 0, chunkSize3 * Side.Sides); int xMax = Math.Min(width, x1 + chunkSize); int yMax = Math.Min(height, y1 + chunkSize); int zMax = Math.Min(length, z1 + chunkSize); chunkEndX = xMax; chunkEndZ = zMax; Stretch(x1, y1, z1); PostStretchTiles(x1, y1, z1); for (int y = y1, yy = 0; y < yMax; y++, yy++) { for (int z = z1, zz = 0; z < zMax; z++, zz++) { int chunkIndex = (yy + 1) * extChunkSize2 + (zz + 1) * extChunkSize + (0 + 1); for (int x = x1, xx = 0; x < xMax; x++, xx++) { curBlock = chunk[chunkIndex]; if (BlockInfo.Draw[curBlock] != DrawType.Gas) { int index = ((yy << 8) | (zz << 4) | xx) * Side.Sides; X = x; Y = y; Z = z; cIndex = chunkIndex; RenderTile(index); } chunkIndex++; } } } return(true); }
unsafe bool CalculateHeightmapCoverage(int x1, int z1, int xCount, int zCount, int elemsLeft, int *skip, BlockID *mapPtr) { int prevRunCount = 0; for (int y = height - 1; y >= 0; y--) { if (elemsLeft <= 0) { return(true); } int mapIndex = x1 + width * (z1 + y * length); int heightmapIndex = x1 + z1 * width; for (int z = 0; z < zCount; z++) { int baseIndex = mapIndex; int index = z * xCount; for (int x = 0; x < xCount;) { int curRunCount = skip[index]; x += curRunCount; mapIndex += curRunCount; index += curRunCount; if (x < xCount && info.BlocksLight[mapPtr[mapIndex]]) { int lightOffset = (info.LightOffset[mapPtr[mapIndex]] >> Side.Top) & 1; heightmap[heightmapIndex + x] = (short)(y - lightOffset); elemsLeft--; skip[index] = 0; int offset = prevRunCount + curRunCount; int newRunCount = skip[index - offset] + 1; // consider case 1 0 1 0, where we are at 0 // we need to make this 3 0 0 0 and advance by 1 int oldRunCount = (x - offset + newRunCount) < xCount ? skip[index - offset + newRunCount] : 0; if (oldRunCount != 0) { skip[index - offset + newRunCount] = 0; newRunCount += oldRunCount; } skip[index - offset] = newRunCount; x += oldRunCount; index += oldRunCount; mapIndex += oldRunCount; prevRunCount = newRunCount; } else { prevRunCount = 0; } x++; mapIndex++; index++; } prevRunCount = 0; heightmapIndex += width; mapIndex = baseIndex + width; // advance one Z } } return(false); }
public unsafe override void LightHint(int startX, int startZ, BlockID *mapPtr) { }
// Equivalent to // for x = startX; x < startX + 18; x++ // for z = startZ; z < startZ + 18; z++ // CalcHeightAt(x, maxY, z) if height == short.MaxValue // Except this function is a lot more optimised and minimises cache misses. public unsafe abstract void LightHint(int startX, int startZ, BlockID* mapPtr);