public bool CheckChest() { if (workChest == null) { return(false); } blockCheck.Begin(); Block check = blockCheck.GetBlock(workChest); if (!blockCheck.LastChunkLoaded) { return(false); } if (entity.World.BlockAccessor.GetBlockEntity(workChest) is BlockEntityGenericTypedContainer) { return(true); } RemoveChest(); return(false); }
protected bool traversable(PathNode node, float stepHeight, int maxFallHeight, Cuboidf entityCollBox, bool isDiagonal, ref float extraCost) { tmpVec.Set(node.X + centerOffsetX, node.Y, node.Z + centerOffsetZ); if (!api.World.CollisionTester.IsColliding(blockAccess, entityCollBox, tmpVec, false)) { // Down ok? while (true) { tmpPos.Set(node.X, node.Y - 1, node.Z); Block block = blockAccess.GetBlock(tmpPos); if (block.LiquidCode == "lava") { return(false); // TODO: Turn into an entityAvoid boolean } if (block.LiquidCode == "water") { extraCost = 5; //node.Y--; - we swim on top break; } tmpVec.Y--; // Do we collide if we go one block down? // Our hitbox size might be >1 and we might collide with a wall only // so also test if there is actually any collision box right below us. // If collision but no collision box below: Can't really wall-walk, so fail // If no collision but hitbox below: I guess we can step on it to continue from here? // If no collision and no hitbox below: Free fall, lets keep searching downwards Cuboidf[] collboxes = block.GetCollisionBoxes(blockAccess, tmpPos); bool collidingBlockBelow = collboxes != null && collboxes.Length > 0; if (api.World.CollisionTester.IsColliding(blockAccess, entityCollBox, tmpVec, false)) { if (!collidingBlockBelow) { return(false); } extraCost -= (block.WalkSpeedMultiplier - 1) * 8; break; } else { if (collidingBlockBelow) { extraCost -= (block.WalkSpeedMultiplier - 1) * 8; break; } } node.Y--; maxFallHeight--; if (maxFallHeight < 0) { return(false); } } // Up ok? float height = entityCollBox.Height; while (height-- > 0) { tmpVec.Y++; if (api.World.CollisionTester.IsColliding(blockAccess, entityCollBox, tmpVec, false)) { return(false); } } return(true); } else { tmpVec.Set(node.X + centerOffsetX, node.Y + stepHeight, node.Z + centerOffsetZ); bool collideAbove = api.World.CollisionTester.GetCollidingCollisionBox(blockAccess, entityCollBox, tmpVec, ref tmpCub, false); if (!collideAbove) { if (isDiagonal) { tmpPos.Set(node.X, node.Y, node.Z); Block block = blockAccess.GetBlock(tmpPos); Cuboidf[] collboxes = block.GetCollisionBoxes(blockAccess, tmpPos); if (collboxes != null && collboxes.Length > 0) { // Ok, can step on this block node.Y++; return(true); } } else { node.Y++; return(true); } } } return(false); }
private Room FindRoomForPosition(BlockPos pos, ChunkRooms otherRooms) { QueueOfInt bfsQueue = new QueueOfInt(); int halfSize = (ARRAYSIZE - 1) / 2; int maxSize = halfSize + halfSize; bfsQueue.Enqueue(halfSize << 10 | halfSize << 5 | halfSize); int visitedIndex = (halfSize * ARRAYSIZE + halfSize) * ARRAYSIZE + halfSize; // Center node int iteration = ++this.iteration; currentVisited[visitedIndex] = iteration; int coolingWallCount = 0; int nonCoolingWallCount = 0; int skyLightCount = 0; int nonSkyLightCount = 0; int exitCount = 0; blockAccess.Begin(); bool allChunksLoaded = true; int minx = halfSize, miny = halfSize, minz = halfSize, maxx = halfSize, maxy = halfSize, maxz = halfSize; int posX = pos.X - halfSize; int posY = pos.Y - halfSize; int posZ = pos.Z - halfSize; BlockPos npos = new BlockPos(); BlockPos bpos = new BlockPos(); int dx, dy, dz; while (bfsQueue.Count > 0) { int compressedPos = bfsQueue.Dequeue(); dx = compressedPos >> 10; dy = (compressedPos >> 5) & 0x1f; dz = compressedPos & 0x1f; npos.Set(posX + dx, posY + dy, posZ + dz); bpos.Set(npos); if (dx < minx) { minx = dx; } else if (dx > maxx) { maxx = dx; } if (dy < miny) { miny = dy; } else if (dy > maxy) { maxy = dy; } if (dz < minz) { minz = dz; } else if (dz > maxz) { maxz = dz; } Block bBlock = blockAccess.GetBlock(bpos); foreach (BlockFacing facing in BlockFacing.ALLFACES) { facing.IterateThruFacingOffsets(npos); // This must be the first command in the loop, to ensure all facings will be properly looped through regardless of any 'continue;' statements // We cannot exit current block, if the facing is heat retaining (e.g. chiselled block with solid side) if (bBlock.Id != 0 && bBlock.GetHeatRetention(bpos, facing) != 0) { continue; } if (!blockAccess.IsValidPos(npos)) { nonCoolingWallCount++; continue; } Block nBlock = blockAccess.GetBlock(npos); allChunksLoaded &= blockAccess.LastChunkLoaded; int heatRetention = nBlock.GetHeatRetention(npos, facing.Opposite); // We hit a wall, no need to scan further if (heatRetention != 0) { if (heatRetention < 0) { coolingWallCount -= heatRetention; } else { nonCoolingWallCount += heatRetention; } continue; } // Compute the new dx, dy, dz offsets for npos dx = npos.X - posX; dy = npos.Y - posY; dz = npos.Z - posZ; // Only traverse within maxSize range, and overall room size must not exceed MAXROOMSIZE // If outside that, count as an exit and don't continue searching in this direction // Note: for performance, this switch statement ensures only one conditional check in each case on the dimension which has actually changed, instead of 6 conditionals or more bool outsideCube = false; switch (facing.Index) { case 0: // North if (dz < minz) { outsideCube = dz < 0 || maxz - minz >= MAXROOMSIZE; } break; case 1: // East if (dx > maxx) { outsideCube = dx > maxSize || maxx - minx >= MAXROOMSIZE; } break; case 2: // South if (dz > maxz) { outsideCube = dz > maxSize || maxz - minz >= MAXROOMSIZE; } break; case 3: // West if (dx < minx) { outsideCube = dx < 0 || maxx - minx >= MAXROOMSIZE; } break; case 4: // Up if (dy > maxy) { outsideCube = dy > maxSize || maxy - miny >= MAXROOMSIZE; } break; case 5: // Down if (dy < miny) { outsideCube = dy < 0 || maxy - miny >= MAXROOMSIZE; } break; } if (outsideCube) { exitCount++; continue; } visitedIndex = (dx * ARRAYSIZE + dy) * ARRAYSIZE + dz; if (currentVisited[visitedIndex] == iteration) { continue; // continue if block position was already visited } currentVisited[visitedIndex] = iteration; // We only need to check the skylight if it's a block position not already visited ... int skyLightIndex = dx * ARRAYSIZE + dz; if (skyLightXZChecked[skyLightIndex] < iteration) { skyLightXZChecked[skyLightIndex] = iteration; int light = blockAccess.GetLightLevel(npos, EnumLightLevelType.OnlySunLight); if (light >= api.World.SunBrightness - 1) { skyLightCount++; } else { nonSkyLightCount++; } } bfsQueue.Enqueue(dx << 10 | dy << 5 | dz); } } int sizex = maxx - minx + 1; int sizey = maxy - miny + 1; int sizez = maxz - minz + 1; byte[] posInRoom = new byte[(sizex * sizey * sizez + 7) / 8]; int volumeCount = 0; for (dx = 0; dx < sizex; dx++) { for (dy = 0; dy < sizey; dy++) { visitedIndex = ((dx + minx) * ARRAYSIZE + (dy + miny)) * ARRAYSIZE + minz; for (dz = 0; dz < sizez; dz++) { if (currentVisited[visitedIndex + dz] == iteration) { int index = (dy * sizez + dz) * sizex + dx; posInRoom[index / 8] = (byte)(posInRoom[index / 8] | (1 << (index % 8))); volumeCount++; } } } } bool isCellar = sizex <= MAXCELLARSIZE && sizey <= MAXCELLARSIZE && sizez <= MAXCELLARSIZE; if (!isCellar && volumeCount <= ALTMAXCELLARVOLUME) { isCellar = sizex <= ALTMAXCELLARSIZE && sizey <= MAXCELLARSIZE && sizez <= MAXCELLARSIZE || sizex <= MAXCELLARSIZE && sizey <= ALTMAXCELLARSIZE && sizez <= MAXCELLARSIZE || sizex <= MAXCELLARSIZE && sizey <= MAXCELLARSIZE && sizez <= ALTMAXCELLARSIZE; } return(new Room() { CoolingWallCount = coolingWallCount, NonCoolingWallCount = nonCoolingWallCount, SkylightCount = skyLightCount, NonSkylightCount = nonSkyLightCount, ExitCount = exitCount, AnyChunkUnloaded = allChunksLoaded ? 0 : 1, Location = new Cuboidi(posX + minx, posY + miny, posZ + minz, posX + maxx, posY + maxy, posZ + maxz), PosInRoom = posInRoom, IsSmallRoom = isCellar && exitCount == 0 }); }
private Room FindRoomForPosition(BlockPos pos, ChunkRooms otherRooms, HashSet <BlockPos> visitedPositions) { Queue <BlockPos> bfsQueue = new Queue <BlockPos>(); bfsQueue.Enqueue(pos); visitedPositions.Add(pos); int maxHalfSize = 7; int coolingWallCount = 0; int nonCoolingWallCount = 0; int skyLightCount = 0; int nonSkyLightCount = 0; int exitCount = 0; blockAccess.Begin(); HashSet <Vec2i> skyLightXZChecked = new HashSet <Vec2i>(); bool allChunksLoaded = true; int minx = pos.X, miny = pos.Y, minz = pos.Z, maxx = pos.X + 1, maxy = pos.Y + 1, maxz = pos.Z + 1; while (bfsQueue.Count > 0) { BlockPos bpos = bfsQueue.Dequeue(); foreach (BlockFacing facing in BlockFacing.ALLFACES) { BlockPos npos = bpos.AddCopy(facing); if (!api.World.BlockAccessor.IsValidPos(npos)) { nonCoolingWallCount++; continue; } Block nBlock = blockAccess.GetBlock(npos); allChunksLoaded &= blockAccess.LastChunkLoaded; int heatRetention = nBlock.GetHeatRetention(npos, facing); // We hit a wall, no need to scan further if (heatRetention != 0) { if (heatRetention < 0) { coolingWallCount -= heatRetention; } else { nonCoolingWallCount += heatRetention; } continue; } // Only traverse within maxHalfSize range bool inCube = Math.Abs(npos.X - pos.X) <= maxHalfSize && Math.Abs(npos.Y - pos.Y) <= maxHalfSize && Math.Abs(npos.Z - pos.Z) <= maxHalfSize; // Outside maxHalfSize range. Count as exit and don't continue searching in this direction if (!inCube) { exitCount++; continue; } minx = Math.Min(minx, bpos.X); miny = Math.Min(miny, bpos.Y); minz = Math.Min(minz, bpos.Z); maxx = Math.Max(maxx, bpos.X); maxy = Math.Max(maxy, bpos.Y); maxz = Math.Max(maxz, bpos.Z); Vec2i vec = new Vec2i(npos.X, npos.Z); if (!skyLightXZChecked.Contains(vec)) { skyLightXZChecked.Add(vec); int light = api.World.BlockAccessor.GetLightLevel(npos, EnumLightLevelType.OnlySunLight); if (light >= api.World.SunBrightness - 1) { skyLightCount++; } else { nonSkyLightCount++; } } if (!visitedPositions.Contains(npos)) { bfsQueue.Enqueue(npos); visitedPositions.Add(npos); } } } // Find all rooms inside this boundary // Lame but what can we do salasinji /*BlockPos cpos = new BlockPos(); * for (int x = minx; x < maxx; x++) * { * for (int y = miny; y < maxy; y++) * { * for (int z = minz; z < maxz; z++) * { * cpos.Set(x, y, z); * if (visitedPositions.Contains(cpos)) continue; * * Block cBlock = api.World.BlockAccessor.GetBlock(cpos); * if (cBlock.Replaceable > 6000) * { * bool contains = false; * for (int i = 0; !contains && i < otherRooms.Rooms.Count; i++) * { * Room exroom = otherRooms.Rooms[i]; * contains = exroom.Location.Contains(pos); * } * * if (!contains) * { * Room room = FindRoomForPosition(cpos, otherRooms, visitedPositions); * otherRooms.AddRoom(room); * } * } * } * } * }*/ return(new Room() { CoolingWallCount = coolingWallCount, NonCoolingWallCount = nonCoolingWallCount, SkylightCount = skyLightCount, NonSkylightCount = nonSkyLightCount, ExitCount = exitCount, AnyChunkUnloaded = !allChunksLoaded, Location = new Cuboidi(minx, miny, minz, maxx, maxy, maxz) }); }