Пример #1
0
        private void BlockAccessor_OnStoreHistoryState(HistoryState obj)
        {
            obj.OldStartMarker = prevStartMarker?.Copy();
            obj.OldEndMarker   = prevEndMarker?.Copy();

            obj.NewStartMarker = StartMarker?.Copy();
            obj.NewEndMarker   = EndMarker?.Copy();

            prevStartMarker = StartMarker?.Copy();
            prevEndMarker   = EndMarker?.Copy();
        }
        public EntityBlockFalling(Block block, BlockEntity blockEntity, BlockPos initialPos, AssetLocation fallSound, float impactDamageMul, bool canFallSideways, float dustIntensity)
        {
            this.impactDamageMul = impactDamageMul;
            this.fallSound       = fallSound;
            this.canFallSideways = canFallSideways;
            this.dustIntensity   = dustIntensity;

            WatchedAttributes.SetBool("canFallSideways", canFallSideways);
            WatchedAttributes.SetFloat("dustIntensity", dustIntensity);
            if (fallSound != null)
            {
                WatchedAttributes.SetString("fallSound", fallSound.ToShortString());
            }

            this.Code               = new AssetLocation("blockfalling");
            this.blockCode          = block.Code;
            this.removedBlockentity = blockEntity;
            this.initialPos         = initialPos.Copy(); // Must have a Copy() here!

            ServerPos.SetPos(initialPos);
            ServerPos.X += 0.5;
            ServerPos.Z += 0.5;

            Pos.SetFrom(ServerPos);
        }
        private BlockPos BfsSearchPath(IWorldAccessor world, Queue <BlockPos> uncheckedPositions, BlockPos target, Block ourBlock)
        {
            BlockPos pos, npos = new BlockPos();

            while (uncheckedPositions.Count > 0)
            {
                pos = uncheckedPositions.Dequeue();
                int curDist = pos.ManhattenDistance(target);

                for (int i = 0; i < BlockFacing.HORIZONTALS.Length; i++)
                {
                    BlockFacing facing = BlockFacing.HORIZONTALS[i];
                    npos.Set(pos.X + facing.Normali.X, target.Y, pos.Z + facing.Normali.Z);
                    if (npos.ManhattenDistance(target) > curDist)
                    {
                        continue;
                    }

                    if (npos.Equals(target))
                    {
                        return(pos);
                    }

                    Block block = world.BlockAccessor.GetBlock(npos);
                    if (!block.IsLiquid() && block.Replaceable < ReplacableThreshold)
                    {
                        continue;
                    }

                    uncheckedPositions.Enqueue(npos.Copy());
                }
            }

            return(null);
        }
Пример #4
0
        // http://members.chello.at/~easyfilter/bresenham.html
        public List <BlockPos> PlotLine3d(int x0, int y0, int z0, int x1, int y1, int z1)
        {
            int dx = Math.Abs(x1 - x0), sx = x0 < x1 ? 1 : -1;
            int dy = Math.Abs(y1 - y0), sy = y0 < y1 ? 1 : -1;
            int dz = Math.Abs(z1 - z0), sz = z0 < z1 ? 1 : -1;
            int dm = GameMath.Max(dx, dy, dz), i = dm; /* maximum difference */

            x1 = y1 = z1 = dm / 2;                     /* error offset */

            BlockPos           pos = new BlockPos();
            HashSet <BlockPos> blocks = new HashSet <BlockPos>();

            for (;;)
            {  /* loop */
                pos.Set(x0, y0, z0);
                blocks.Add(pos.Copy());
                if (i-- == 0)
                {
                    break;
                }
                x1 -= dx; if (x1 < 0)
                {
                    x1 += dm; x0 += sx;
                }
                y1 -= dy; if (y1 < 0)
                {
                    y1 += dm; y0 += sy;
                }
                z1 -= dz; if (z1 < 0)
                {
                    z1 += dm; z0 += sz;
                }
            }
            return(blocks.ToList());
        }
Пример #5
0
        private BlockPos getSemiLargeCavePos(IBlockAccessor blockAccessor, BlockPos pos)
        {
            BlockPos outpos = pos.Copy();

            int maxY = pos.Y;
            int minY = pos.Y;

            int minX = pos.X;
            int maxX = pos.X;

            int minZ = pos.Z;
            int maxZ = pos.Z;

            while (pos.Y - minY < 12 && blockAccessor.GetBlockId(pos.X, minY - 1, pos.Z) == 0)
            {
                minY--;
            }
            while (maxY - pos.Y < 12 && blockAccessor.GetBlockId(pos.X, maxY + 1, pos.Z) == 0)
            {
                maxY++;
            }

            outpos.Y = (maxY + minY) / 2;
            if (maxY - minY < 4 || maxY - minY >= 10)
            {
                return(null);
            }

            while (pos.X - minX < 12 && blockAccessor.GetBlockId(minX - 1, pos.Y, pos.Z) == 0)
            {
                minX--;
            }
            while (maxX - pos.X < 12 && blockAccessor.GetBlockId(maxX + 1, pos.Y, pos.Z) == 0)
            {
                maxX++;
            }

            if (maxX - minX < 3)
            {
                return(null);
            }
            outpos.X = (maxX + minX) / 2;

            while (pos.Z - minZ < 12 && blockAccessor.GetBlockId(pos.X, pos.Y, minZ - 1) == 0)
            {
                minZ--;
            }
            while (maxZ - pos.Z < 12 && blockAccessor.GetBlockId(pos.X, pos.Y, maxZ + 1) == 0)
            {
                maxZ++;
            }

            if (maxZ - minZ < 3)
            {
                return(null);
            }
            outpos.Z = (maxZ + minZ) / 2;

            return(outpos);
        }
Пример #6
0
        // Returns the block pos that is adjacent to a hole
        BlockPos FindHoleInPit()
        {
            smokeLocations.Clear();

            HashSet <BlockPos> visitedPositions = new HashSet <BlockPos>();
            Queue <BlockPos>   bfsQueue         = new Queue <BlockPos>();

            bfsQueue.Enqueue(Pos);

            int firewoodBlockId    = Api.World.GetBlock(new AssetLocation("firewoodpile")).BlockId;
            int charcoalPitBlockId = Api.World.GetBlock(new AssetLocation("charcoalpit")).BlockId;

            int maxHalfSize = 6;


            while (bfsQueue.Count > 0)
            {
                BlockPos bpos       = bfsQueue.Dequeue();
                BlockPos bposGround = bpos.Copy();
                bposGround.Y = 0;

                int yMax = 0;
                smokeLocations.TryGetValue(bposGround, out yMax);
                smokeLocations[bposGround] = Math.Max(yMax, bpos.Y);


                foreach (BlockFacing facing in BlockFacing.ALLFACES)
                {
                    BlockPos    npos  = bpos.AddCopy(facing);
                    IWorldChunk chunk = Api.World.BlockAccessor.GetChunkAtBlockPos(npos);
                    if (chunk == null)
                    {
                        continue;                // Maybe at the endge of the loaded chunk
                    }
                    Block nBlock = chunk.GetLocalBlockAtBlockPos(Api.World, npos);

                    if (!nBlock.SideSolid[facing.Opposite.Index] && nBlock.BlockId != firewoodBlockId && nBlock.BlockId != charcoalPitBlockId)
                    {
                        return(bpos);
                    }

                    // Only traverse inside the firewood pile
                    if (nBlock.BlockId != firewoodBlockId)
                    {
                        continue;
                    }

                    // Only traverse within a 12x12x12 block cube
                    bool inCube = Math.Abs(npos.X - Pos.X) <= maxHalfSize && Math.Abs(npos.Y - Pos.Y) <= maxHalfSize && Math.Abs(npos.Z - Pos.Z) <= maxHalfSize;

                    if (inCube && !visitedPositions.Contains(npos))
                    {
                        bfsQueue.Enqueue(npos);
                        visitedPositions.Add(npos);
                    }
                }
            }

            return(null);
        }
Пример #7
0
        public override void OnBuild(WorldEdit worldEdit, int oldBlockId, BlockSelection blockSel, ItemStack withItemStack)
        {
            if (startPos == null)
            {
                return;
            }

            BlockPos destPos = blockSel.Position.AddCopy(blockSel.Face.Opposite);

            Block block = blockAccessRev.GetBlock(blockSel.Position);

            if (PlaceMode)
            {
                block = blockAccessRev.GetBlock(0);
            }
            worldEdit.sapi.World.BlockAccessor.SetBlock(oldBlockId, blockSel.Position);

            if (!worldEdit.MayPlace(block, startPos.ManhattenDistance(destPos)))
            {
                return;
            }

            GameMath.BresenHamPlotLine3d(startPos.X, startPos.Y, startPos.Z, destPos.X, destPos.Y, destPos.Z, (pos) => blockAccessRev.SetBlock(block.BlockId, pos, withItemStack));

            if (LineMode == EnumLineStartPoint.LineStrip)
            {
                startPos = destPos.Copy();
            }

            blockAccessRev.SetHistoryStateBlock(blockSel.Position.X, blockSel.Position.Y, blockSel.Position.Z, oldBlockId, blockAccessRev.GetBlockId(blockSel.Position));
            blockAccessRev.Commit();
        }
        public override void GetBlockInfo(IPlayer forPlayer, StringBuilder dsc)
        {
            if (!FullyRepaired)
            {
                dsc.AppendLine(Lang.Get("Seems to be missing a couple of gears. I think I've seen such gears before."));
                return;
            }
            else
            {
                if (tpLocation == null)
                {
                    string[] lines = new string[] { Lang.Get("Warping spacetime."), Lang.Get("Warping spacetime.."), Lang.Get("Warping spacetime...") };

                    dsc.AppendLine(lines[(int)(Api.World.ElapsedMilliseconds / 1000f) % 3]);
                    return;
                }
            }

            if (forPlayer.WorldData.CurrentGameMode == EnumGameMode.Creative)
            {
                BlockPos pos = Api.World.DefaultSpawnPosition.AsBlockPos;
                dsc.AppendLine(Lang.Get("Teleports to {0}", tpLocation.Copy().Sub(pos.X, 0, pos.Z)));
            }
            else
            {
                dsc.AppendLine(Lang.Get("Spacetime subduction completed."));
            }
        }
Пример #9
0
        private void PlaceMeteorResources(BlockPos bpos, int metalBlockID, int stoneBlockID)
        {
            int placeMeteorBlockRand = explosionRand.Next(0, 101);

            switch (placeMeteorBlockRand < meteorImpactResourceChance)
            {
            case true:
                int metalBlockRand = explosionRand.Next(0, 101);

                switch (metalBlockRand < metalResourceChance)
                {
                case true:
                    blockAccessor.SetBlock(metalBlockID, bpos);
                    break;

                case false:
                    blockAccessor.SetBlock(stoneBlockID, bpos);
                    break;
                }

                positionsChanged.Add(bpos.Copy());
                break;

            case false:
                break;
            }
        }
        public static List <BlockPos> Cuboid(BlockPos start, BlockPos end)
        {
            List <BlockPos> positions = new List <BlockPos>();

            BlockPos startPos = new BlockPos(Math.Min(start.X, end.X), Math.Min(start.Y, end.Y), Math.Min(start.Z, end.Z));
            BlockPos finalPos = new BlockPos(Math.Max(start.X, end.X), Math.Max(start.Y, end.Y), Math.Max(start.Z, end.Z));

            BlockPos curPos = startPos.Copy();

            while (curPos.X < finalPos.X)
            {
                curPos.Y = startPos.Y;

                while (curPos.Y < finalPos.Y)
                {
                    curPos.Z = startPos.Z;
                    while (curPos.Z < finalPos.Z)
                    {
                        positions.Add(curPos.Copy());
                        curPos.Z++;
                    }

                    curPos.Y++;
                }
                curPos.X++;
            }

            return(positions);
        }
Пример #11
0
        public override bool TryPlaceBlockForWorldGen(IBlockAccessor blockAccessor, BlockPos pos, BlockFacing onBlockFace, LCGRandom worldGenRand)
        {
            bool didplace = false;

            if (blockAccessor.GetBlock(pos).Replaceable < 6000)
            {
                return(false);
            }

            BlockPos npos = pos.Copy();

            for (int i = 0; i < 150 + worldGenRand.NextInt(30); i++)
            {
                npos.X = pos.X + worldGenRand.NextInt(11) - 5;
                npos.Y = pos.Y + worldGenRand.NextInt(11) - 5;
                npos.Z = pos.Z + worldGenRand.NextInt(11) - 5;

                if (npos.Y > api.World.SeaLevel - 10 || npos.Y < 25)
                {
                    continue;                                                  // To hot for glowworms
                }
                if (blockAccessor.GetBlock(npos).Replaceable < 6000)
                {
                    continue;
                }

                didplace |= TryGenGlowWorm(blockAccessor, npos, worldGenRand);
            }

            return(didplace);
        }
Пример #12
0
        public void FloodFillAt(WorldEdit worldEdit, Block blockToPlace, ItemStack withItemStack, int posX, int posY, int posZ)
        {
            bfsQueue.Clear();
            fillablePositions.Clear();


            if (posY <= 0 || posY >= mapheight - 1)
            {
                return;
            }

            bfsQueue.Enqueue(new Vec4i(posX, posY, posZ, 0));
            fillablePositions.Add(new BlockPos(posX, posY, posZ));

            float radius = SearchRadius;

            BlockFacing[] faces  = Mode == 2 ? BlockFacing.HORIZONTALS : BlockFacing.ALLFACES;
            BlockPos      curPos = new BlockPos();

            while (bfsQueue.Count > 0)
            {
                Vec4i bpos = bfsQueue.Dequeue();

                foreach (BlockFacing facing in faces)
                {
                    curPos.Set(bpos.X + facing.Normali.X, bpos.Y + facing.Normali.Y, bpos.Z + facing.Normali.Z);

                    Block block    = blockAccessRev.GetBlock(curPos);
                    bool  inBounds = bpos.W < radius;

                    if (inBounds)
                    {
                        if (block.Replaceable >= 6000 && !fillablePositions.Contains(curPos))
                        {
                            bfsQueue.Enqueue(new Vec4i(curPos.X, curPos.Y, curPos.Z, bpos.W + 1));
                            fillablePositions.Add(curPos.Copy());
                        }
                    }
                    else
                    {
                        if (CheckEnclosure)
                        {
                            fillablePositions.Clear();
                            bfsQueue.Clear();
                            worldEdit.Bad("Cannot flood fill here, not enclosed area. Enforce enclosed area or disable enclosure check.");
                            break;
                        }
                    }
                }
            }

            foreach (BlockPos p in fillablePositions)
            {
                blockAccessRev.SetBlock(blockToPlace.BlockId, p, withItemStack);
            }

            worldEdit.Bad(fillablePositions.Count + " blocks placed");
        }
        private int FillArea(ItemStack blockStack, BlockPos start, BlockPos end)
        {
            int updated = 0;

            BlockPos startPos = new BlockPos(Math.Min(start.X, end.X), Math.Min(start.Y, end.Y), Math.Min(start.Z, end.Z));
            BlockPos finalPos = new BlockPos(Math.Max(start.X, end.X), Math.Max(start.Y, end.Y), Math.Max(start.Z, end.Z));
            BlockPos curPos   = startPos.Copy();

            int dx = finalPos.X - startPos.X;
            int dy = finalPos.Y - startPos.Y;
            int dz = finalPos.Z - startPos.Z;

            int   quantityBlocks = dx * dy * dz;
            int   blockId        = 0;
            Block block          = blockStack?.Block;

            if (block != null)
            {
                blockId = block.Id;
            }
            if (block != null && !MayPlace(block, quantityBlocks))
            {
                return(0);
            }

            if (quantityBlocks > 1000)
            {
                Good((block == null ? "Clearing" : "Placing") + " " + (dx * dy * dz) + " blocks...");
            }

            while (curPos.X < finalPos.X)
            {
                curPos.Y = startPos.Y;

                while (curPos.Y < finalPos.Y)
                {
                    curPos.Z = startPos.Z;
                    while (curPos.Z < finalPos.Z)
                    {
                        workspace.revertableBlockAccess.SetLiquidBlock(0, curPos);
                        workspace.revertableBlockAccess.SetBlock(blockId, curPos, blockStack);
                        curPos.Z++;
                        updated++;
                    }

                    curPos.Y++;
                }
                curPos.X++;
            }

            workspace.revertableBlockAccess.Commit();

            return(updated);
        }
Пример #14
0
        private void ImportArea(string filename, BlockPos startPos, EnumOrigin origin)
        {
            string infilepath = Path.Combine(exportFolderPath, filename);

            if (!File.Exists(infilepath) && File.Exists(infilepath + ".json"))
            {
                infilepath += ".json";
            }

            if (!File.Exists(infilepath))
            {
                Bad("Can't import " + filename + ", it does not exist");
                return;
            }

            BlockSchematic blockdata = null;

            try
            {
                using (TextReader textReader = new StreamReader(infilepath))
                {
                    blockdata = JsonConvert.DeserializeObject <BlockSchematic>(textReader.ReadToEnd());
                    textReader.Close();
                }
            }
            catch (IOException e)
            {
                Good("Failed loading " + filename + " : " + e.Message);
                return;
            }

            BlockPos originPos = startPos.Copy();

            if (origin == EnumOrigin.TopCenter)
            {
                originPos.X -= blockdata.SizeX / 2;
                originPos.Y -= blockdata.SizeY;
                originPos.Z -= blockdata.SizeZ / 2;
            }
            if (origin == EnumOrigin.BottomCenter)
            {
                originPos.X -= blockdata.SizeX / 2;
                originPos.Z -= blockdata.SizeZ / 2;
            }


            IBlockAccessor blockAcccessor = api.WorldManager.GetBlockAccessorBulkUpdate(true, true, false);

            blockdata.Place(blockAcccessor, api.World, originPos);

            blockAcccessor.Commit();
        }
        internal TeleporterLocation GetOrCreateLocation(BlockPos pos)
        {
            TeleporterLocation loc = null;

            if (Locations.TryGetValue(pos, out loc))
            {
                return(loc);
            }

            loc = new TeleporterLocation()
            {
                SourceName = "Location-" + (Locations.Count + 1),
                SourcePos  = pos.Copy()
            };

            Locations[loc.SourcePos] = loc;

            return(loc);
        }
Пример #16
0
        internal static void TryCreateData(BlockPos pos, bool available = false)
        {
            if (pos == null)
            {
                throw new ArgumentNullException();
            }
            if (Teleports.ContainsKey(pos))
            {
                return;
            }

            TeleportData data = new TeleportData()
            {
                Available = available,
                Name      = defNames.ElementAt(api.World.Rand.Next(defNames.Count))
            };

            AddTeleport(pos.Copy(), data);
        }
        public void OnFirePlaced(BlockPos firePos, BlockPos fuelPos, string startedByPlayerUid)
        {
            if (IsBurning || !ShouldBurn())
            {
                return;
            }

            this.startedByPlayerUid = startedByPlayerUid;

            FirePos = firePos.Copy();
            FuelPos = fuelPos.Copy();

            if (FuelPos == null || !canBurn(FuelPos))
            {
                foreach (BlockFacing facing in BlockFacing.ALLFACES)
                {
                    BlockPos npos = FirePos.AddCopy(facing);
                    fuelBlock = Api.World.BlockAccessor.GetBlock(npos);
                    if (canBurn(npos))
                    {
                        FuelPos       = npos;
                        startDuration = remainingBurnDuration = fuelBlock.CombustibleProps.BurnDuration;
                        return;
                    }
                }

                startDuration         = 1;
                remainingBurnDuration = 1;
                FuelPos = FirePos.Copy(); // No fuel left
            }
            else
            {
                fuelBlock = Api.World.BlockAccessor.GetBlock(FuelPos);

                if (fuelBlock.CombustibleProps != null)
                {
                    startDuration = remainingBurnDuration = fuelBlock.CombustibleProps.BurnDuration;
                }
            }

            startBurning();
        }
Пример #18
0
        private int FillArea(ushort blockId, BlockPos start, BlockPos end)
        {
            int updated = 0;

            IBlockAccessor blockAcccessor = api.WorldManager.GetBlockAccessorBulkUpdate(true, true);

            BlockPos startPos = new BlockPos(Math.Min(start.X, end.X), Math.Min(start.Y, end.Y), Math.Min(start.Z, end.Z));
            BlockPos finalPos = new BlockPos(Math.Max(start.X, end.X), Math.Max(start.Y, end.Y), Math.Max(start.Z, end.Z));
            BlockPos curPos   = startPos.Copy();

            int dx = finalPos.X - startPos.X;
            int dy = finalPos.Y - startPos.Y;
            int dz = finalPos.Z - startPos.Z;

            if (dx * dy * dz > 1000)
            {
                Good((blockId == 0 ? "Clearing" : "Placing") + " " + (dx * dy * dz) + " blocks...");
            }

            while (curPos.X < finalPos.X)
            {
                curPos.Y = startPos.Y;

                while (curPos.Y < finalPos.Y)
                {
                    curPos.Z = startPos.Z;
                    while (curPos.Z < finalPos.Z)
                    {
                        blockAcccessor.SetBlock(blockId, curPos);
                        curPos.Z++;
                        updated++;
                    }

                    curPos.Y++;
                }
                curPos.X++;
            }

            blockAcccessor.Commit();

            return(updated);
        }
Пример #19
0
        private void GenRareColorPatch(IBlockAccessor blockAccessor, BlockPos pos, Block block, LCGRandom worldGenRand)
        {
            int      cnt   = 2 + worldGenRand.NextInt(6);
            int      tries = 30;
            BlockPos npos  = pos.Copy();

            while (cnt > 0 && tries-- > 0)
            {
                npos.Set(pos).Add(worldGenRand.NextInt(5) - 2, 0, worldGenRand.NextInt(5) - 2);
                npos.Y = blockAccessor.GetTerrainMapheightAt(npos) + 1;

                Block nblock = blockAccessor.GetBlock(npos);

                if ((nblock.IsReplacableBy(block) || nblock is BlockLupine) && CanPlantStay(blockAccessor, npos))
                {
                    blockAccessor.SetBlock(block.BlockId, npos);
                    cnt--;
                }
            }
        }
Пример #20
0
        public void GrowTree(IBlockAccessor blockAccessor, BlockPos pos, bool skipForestFloor, float sizeModifier = 1, float vineGrowthChance = 0, float otherBlockChance = 1, int treesInChunkGenerated = 0)
        {
            float f = otherBlockChance == 0 ? (3 + (float)rand.NextDouble() * 6) : (3 + (float)rand.NextDouble() * 4) * 3 * 3;

            int quantity = GameMath.RoundRandom(rand, f);

            BlockPos npos = pos.Copy();

            sizeModifier = GameMath.Mix(sizeModifier, 1, 0.5f);

            sizeModifier *= 1 + ((float)rand.NextDouble() * 0.5f);

            while (quantity-- > 0)
            {
                float dist = Math.Max(1, pos.DistanceTo(npos) - 2);

                GrowStalk(blockAccessor, npos.UpCopy(), dist, sizeModifier, vineGrowthChance);

                // Potentially grow another one nearby
                npos.Set(pos);
                npos.X += rand.Next(8) - 4;
                npos.Z += rand.Next(8) - 4;

                // Test up to 2 blocks up and down.
                bool foundSuitableBlock = false;
                for (int y = 2; y >= -2; y--)
                {
                    Block block = blockAccessor.GetBlock(npos.X, npos.Y + y, npos.Z);
                    if (block.Fertility > 0)
                    {
                        npos.Y             = npos.Y + y;
                        foundSuitableBlock = true;
                        break;
                    }
                }
                if (!foundSuitableBlock)
                {
                    break;
                }
            }
        }
Пример #21
0
        /// <summary>
        /// Returns true if the given air block position is next to a combustible block, false otherwise. The
        /// block must be combustible and at a burnable temperature
        /// </summary>
        /// <param name="world"></param>
        /// <param name="lavaPos"></param>
        /// <param name="airBlockPos"></param>
        /// <returns></returns>
        private BlockFacing IsNextToCombustibleBlock(IWorldAccessor world, BlockPos lavaPos, BlockPos airBlockPos)
        {
            Block airBlock = world.BlockAccessor.GetBlock(airBlockPos);

            if (airBlock.BlockId == 0)
            {
                foreach (BlockFacing facing in BlockFacing.ALLFACES)
                {
                    if (facing != BlockFacing.DOWN)
                    {
                        BlockPos combustibleBlockPos = airBlockPos.Copy().Add(facing);
                        Block    combustibleBlock    = world.BlockAccessor.GetBlock(combustibleBlockPos);
                        if (combustibleBlock.CombustibleProps != null && combustibleBlock.CombustibleProps.BurnTemperature <= GetTemperatureAtLocation(lavaPos, airBlockPos))
                        {
                            return(facing);
                        }
                    }
                }
            }
            return(null);
        }
Пример #22
0
        public override bool TryPlaceBlockForWorldGen(IBlockAccessor blockAccessor, BlockPos pos, BlockFacing onBlockFace, Random worldGenRand)
        {
            bool didplace = false;

            if (blockAccessor.GetBlock(pos).Replaceable < 6000)
            {
                return(false);
            }

            pos = pos.Copy();
            for (int i = 0; i < 5 + worldGenRand.Next(25); i++)
            {
                if (pos.Y < 15)
                {
                    continue;             // To hot for stalactites
                }
                didplace |= TryGenStalag(blockAccessor, pos, worldGenRand.Next(4), worldGenRand);
                pos.X    += worldGenRand.Next(9) - 4;
                pos.Y    += worldGenRand.Next(3) - 1;
                pos.Z    += worldGenRand.Next(9) - 4;
            }

            return(didplace);
        }
        /// <summary>
        /// For placement of ruins during worldgen, replaces the topsoil with the area specific soil (e.g. sand)
        /// </summary>
        /// <param name="blockAccessor"></param>
        /// <param name="blocks"></param>
        /// <param name="startPos"></param>
        /// <param name="climateUpLeft"></param>
        /// <param name="climateUpRight"></param>
        /// <param name="climateBotLeft"></param>
        /// <param name="climateBotRight"></param>
        /// <param name="replaceblockids"></param>
        /// <returns></returns>
        public int PlaceRespectingBlockLayers(IBlockAccessor blockAccessor, IWorldAccessor worldForCollectibleResolve, BlockPos startPos, int climateUpLeft, int climateUpRight, int climateBotLeft, int climateBotRight, int[] replaceblockids, bool replaceMetaBlocks = true)
        {
            BlockPos curPos    = new BlockPos();
            int      placed    = 0;
            int      chunksize = blockAccessor.ChunkSize;


            for (int x = 0; x < SizeX; x++)
            {
                for (int z = 0; z < SizeZ; z++)
                {
                    curPos.Set(x + startPos.X, startPos.Y, z + startPos.Z);
                    IMapChunk mapchunk    = blockAccessor.GetMapChunkAtBlockPos(curPos);
                    int       rockblockid = mapchunk.TopRockIdMap[(curPos.Z % chunksize) * chunksize + curPos.X % chunksize];
                    int       depth       = 0;

                    int maxY = -1;

                    for (int y = SizeY - 1; y >= 0; y--)
                    {
                        curPos.Set(x + startPos.X, y + startPos.Y, z + startPos.Z);
                        Block newBlock = blocksByPos[x, y, z];
                        if (newBlock == null)
                        {
                            continue;
                        }

                        if (replaceMetaBlocks && newBlock == undergroundBlock)
                        {
                            continue;
                        }


                        if (newBlock.Replaceable < 1000)
                        {
                            if (replaceblockids.Length > depth && newBlock.BlockId == replaceblockids[depth])
                            {
                                int climate = GameMath.BiLerpRgbColor((float)x / chunksize, (float)z / chunksize, climateUpLeft, climateUpRight, climateBotLeft, climateBotRight);

                                newBlock = GetBlockLayerBlock((climate >> 8) & 0xff, (climate >> 16) & 0xff, startPos.Y, rockblockid, depth, newBlock, worldForCollectibleResolve.Blocks);
                            }
                            depth++;
                        }

                        Block oldBlock = blockAccessor.GetBlock(curPos);
                        int   p        = handler(blockAccessor, curPos, oldBlock, newBlock);
                        placed += p;

                        if (p > 0 && !newBlock.RainPermeable)
                        {
                            if (newBlock == fillerBlock || newBlock == pathwayBlock)
                            {
                                int lx = curPos.X % chunksize;
                                int lz = curPos.Z % chunksize;
                                if (mapchunk.RainHeightMap[lz * chunksize + lx] == curPos.Y)
                                {
                                    mapchunk.RainHeightMap[lz * chunksize + lx]--;
                                }
                            }
                            else
                            {
                                maxY = Math.Max(curPos.Y, maxY);
                            }
                        }


                        byte[] lightHsv = newBlock.GetLightHsv(blockAccessor, curPos);

                        if (lightHsv[2] > 0 && blockAccessor is IWorldGenBlockAccessor)
                        {
                            ((IWorldGenBlockAccessor)blockAccessor).ScheduleBlockLightUpdate(curPos.Copy(), oldBlock.BlockId, newBlock.BlockId);
                        }
                    }

                    // In the post pass the rain map does not update, so let's set it ourselves
                    if (maxY >= 0)
                    {
                        int lx = curPos.X % chunksize;
                        int lz = curPos.Z % chunksize;
                        int y  = mapchunk.RainHeightMap[lz * chunksize + lx];
                        mapchunk.RainHeightMap[lz * chunksize + lx] = (ushort)Math.Max(y, maxY);
                    }
                }
            }

            PlaceEntitiesAndBlockEntities(blockAccessor, worldForCollectibleResolve, startPos);

            return(placed);
        }
Пример #24
0
        /// <summary>
        /// Will place all blocks using the supplied replace mode. Note: If you use a revertable or bulk block accessor you will have to call PlaceBlockEntities() after the Commit()
        /// </summary>
        /// <param name="blockAccessor"></param>
        /// <param name="worldForCollectibleResolve"></param>
        /// <param name="startPos"></param>
        /// <param name="mode"></param>
        /// <param name="replaceMetaBlocks"></param>
        /// <returns></returns>
        public virtual int Place(IBlockAccessor blockAccessor, IWorldAccessor worldForCollectibleResolve, BlockPos startPos, EnumReplaceMode mode, bool replaceMetaBlocks = true)
        {
            BlockPos curPos = new BlockPos();
            int      placed = 0;

            PlaceBlockDelegate handler = null;

            switch (ReplaceMode)
            {
            case EnumReplaceMode.ReplaceAll:
                if (replaceMetaBlocks)
                {
                    handler = PlaceReplaceAllReplaceMeta;
                }
                else
                {
                    handler = PlaceReplaceAllKeepMeta;
                }
                break;

            case EnumReplaceMode.Replaceable:
                if (replaceMetaBlocks)
                {
                    handler = PlaceReplaceableReplaceMeta;
                }
                else
                {
                    handler = PlaceReplaceableKeepMeta;
                }
                break;

            case EnumReplaceMode.ReplaceAllNoAir:
                if (replaceMetaBlocks)
                {
                    handler = PlaceReplaceAllNoAirReplaceMeta;
                }
                else
                {
                    handler = PlaceReplaceAllNoAirKeepMeta;
                }
                break;

            case EnumReplaceMode.ReplaceOnlyAir:
                if (replaceMetaBlocks)
                {
                    handler = PlaceReplaceOnlyAirReplaceMeta;
                }
                else
                {
                    handler = PlaceReplaceOnlyAirKeepMeta;
                }
                break;
            }

            for (int i = 0; i < Indices.Count; i++)
            {
                uint index         = Indices[i];
                int  storedBlockid = BlockIds[i];

                int dx = (int)(index & 0x1ff);
                int dy = (int)((index >> 20) & 0x1ff);
                int dz = (int)((index >> 10) & 0x1ff);

                AssetLocation blockCode = BlockCodes[storedBlockid];

                Block newBlock = blockAccessor.GetBlock(blockCode);

                if (newBlock == null || (replaceMetaBlocks && newBlock == undergroundBlock))
                {
                    continue;
                }

                curPos.Set(dx + startPos.X, dy + startPos.Y, dz + startPos.Z);

                Block oldBlock = blockAccessor.GetBlock(curPos);
                placed += handler(blockAccessor, curPos, oldBlock, newBlock);


                if (newBlock.LightHsv[2] > 0 && blockAccessor is IWorldGenBlockAccessor)
                {
                    ((IWorldGenBlockAccessor)blockAccessor).ScheduleBlockLightUpdate(curPos.Copy(), oldBlock.BlockId, newBlock.BlockId);
                }
            }

            if (!(blockAccessor is IBlockAccessorRevertable))
            {
                PlaceEntitiesAndBlockEntities(blockAccessor, worldForCollectibleResolve, startPos);
            }

            return(placed);
        }
        internal bool TryGenerateUnderground(IBlockAccessor blockAccessor, IWorldAccessor worldForCollectibleResolve, BlockPos pos)
        {
            int num = rand.NextInt(schematicDatas.Length);

            BlockSchematicStructure[] schematicStruc = schematicDatas[num];
            BlockPos targetPos = pos.Copy();
            BlockSchematicStructure schematic;


            if (schematicStruc[0].PathwayStarts.Length > 0)
            {
                // 1. Give up if non air block or mapheight is not at least 4 blocks higher
                // 2. Search up to 4 blocks downwards. Give up if no stone is found.
                // 3. Select one pathway randomly
                // 4. For every horizontal orientation
                //    - Get the correctly rotated version for this pathway
                //    - Starting at 2 blocks away, move one block closer each iteration
                //      - Check if
                //        - at every pathway block pos there is stone or air
                //        - at least one pathway block has an air block facing towards center?
                //      - If yes, remove the blocks that are in the way and place schematic

                Block block = blockAccessor.GetBlock(targetPos);
                if (block.Id != 0)
                {
                    return(false);
                }


                // 1./2. Search an underground position that has air and a stone floor below
                bool found = false;
                for (int dy = 0; dy <= 4; dy++)
                {
                    targetPos.Down();
                    block = blockAccessor.GetBlock(targetPos);

                    if (block.BlockMaterial == EnumBlockMaterial.Stone)
                    {
                        targetPos.Up();
                        found = true;
                        break;
                    }
                }

                if (!found)
                {
                    return(false);
                }

                // 3. Random pathway
                found = false;
                int         pathwayNum        = rand.NextInt(schematicStruc[0].PathwayStarts.Length);
                int         targetOrientation = 0;
                int         targetDistance    = -1;
                BlockFacing targetFacing      = null;
                BlockPos[]  pathway           = null;

                // 4. At that position search for a suitable stone wall in any direction
                for (targetOrientation = 0; targetOrientation < 4; targetOrientation++)
                {
                    // Try every rotation
                    pathway = schematicStruc[targetOrientation].PathwayOffsets[pathwayNum];
                    // This is the facing we are currently checking
                    targetFacing = schematicStruc[targetOrientation].PathwaySides[pathwayNum];

                    targetDistance = CanPlacePathwayAt(blockAccessor, pathway, targetFacing, targetPos);
                    if (targetDistance != -1)
                    {
                        break;
                    }
                }

                if (targetDistance == -1)
                {
                    return(false);
                }

                BlockPos pathwayStart = schematicStruc[targetOrientation].PathwayStarts[pathwayNum];

                // Move back the structure so that the door aligns to the cave wall
                targetPos.Add(
                    -pathwayStart.X - targetFacing.Normali.X * targetDistance,
                    -pathwayStart.Y - targetFacing.Normali.Y * targetDistance,
                    -pathwayStart.Z - targetFacing.Normali.Z * targetDistance
                    );

                if (!TestUndergroundCheckPositions(blockAccessor, targetPos, schematicStruc[targetOrientation].UndergroundCheckPositions))
                {
                    return(false);
                }
                if (isStructureAt(targetPos, worldForCollectibleResolve))
                {
                    return(false);
                }

                schematic = schematicStruc[targetOrientation];
                LastPlacedSchematicLocation.Set(targetPos.X, targetPos.Y, targetPos.Z, targetPos.X + schematic.SizeX, targetPos.Y + schematic.SizeY, targetPos.Z + schematic.SizeZ);
                schematic.Place(blockAccessor, worldForCollectibleResolve, targetPos);

                // Free up a layer of blocks in front of the door
                ushort blockId = 0; // blockAccessor.GetBlock(new AssetLocation("creativeblock-37")).BlockId;
                for (int i = 0; i < pathway.Length; i++)
                {
                    for (int d = 0; d <= targetDistance; d++)
                    {
                        tmpPos.Set(
                            targetPos.X + pathwayStart.X + pathway[i].X + (d + 1) * targetFacing.Normali.X,
                            targetPos.Y + pathwayStart.Y + pathway[i].Y + (d + 1) * targetFacing.Normali.Y,
                            targetPos.Z + pathwayStart.Z + pathway[i].Z + (d + 1) * targetFacing.Normali.Z
                            );

                        blockAccessor.SetBlock(blockId, tmpPos);
                    }
                }

                return(true);
            }

            schematic = schematicStruc[rand.NextInt(4)];

            BlockPos placePos = schematic.AdjustStartPos(targetPos.Copy(), Origin);

            LastPlacedSchematicLocation.Set(placePos.X, placePos.Y, placePos.Z, placePos.X + schematic.SizeX, placePos.Y + schematic.SizeY, placePos.Z + schematic.SizeZ);
            LastPlacedSchematic = schematic;

            if (insideblockids.Count > 0 && !insideblockids.Contains(blockAccessor.GetBlock(targetPos).Id))
            {
                return(false);
            }
            if (!TestUndergroundCheckPositions(blockAccessor, placePos, schematic.UndergroundCheckPositions))
            {
                return(false);
            }
            if (!satisfiesMinDistance(pos, worldForCollectibleResolve))
            {
                return(false);
            }
            if (isStructureAt(pos, worldForCollectibleResolve))
            {
                return(false);
            }

            if (resolvedReplaceWithRocktype != null)
            {
                //Console.WriteLine(schematic.FromFileName + " place at " + targetPos +", offseted to " + placePos);

                schematic.PlaceReplacingBlocks(blockAccessor, worldForCollectibleResolve, placePos, schematic.ReplaceMode, resolvedReplaceWithRocktype);
            }
            else
            {
                schematic.Place(blockAccessor, worldForCollectibleResolve, targetPos);
            }



            return(false);
        }
Пример #26
0
        /// <summary>
        /// Places all the entities and blocks in the schematic at the position.
        /// </summary>
        /// <param name="blockAccessor"></param>
        /// <param name="worldForCollectibleResolve"></param>
        /// <param name="startPos"></param>
        public void PlaceEntitiesAndBlockEntities(IBlockAccessor blockAccessor, IWorldAccessor worldForCollectibleResolve, BlockPos startPos)
        {
            BlockPos curPos = new BlockPos();

            int schematicSeed = worldForCollectibleResolve.Rand.Next();

            foreach (var val in BlockEntities)
            {
                uint index = val.Key;
                int  dx    = (int)(index & 0x1ff);
                int  dy    = (int)((index >> 20) & 0x1ff);
                int  dz    = (int)((index >> 10) & 0x1ff);

                curPos.Set(dx + startPos.X, dy + startPos.Y, dz + startPos.Z);

                BlockEntity be = blockAccessor.GetBlockEntity(curPos);


                // Block entities need to be manually initialized for world gen block access
                if (be == null && blockAccessor is IWorldGenBlockAccessor)
                {
                    Block block = blockAccessor.GetBlock(curPos);

                    if (block.EntityClass != null)
                    {
                        blockAccessor.SpawnBlockEntity(block.EntityClass, curPos);
                        be = blockAccessor.GetBlockEntity(curPos);
                    }
                }

                if (be != null)
                {
                    Block block = blockAccessor.GetBlock(curPos);
                    if (block.EntityClass != worldForCollectibleResolve.ClassRegistry.GetBlockEntityClass(be.GetType()))
                    {
                        worldForCollectibleResolve.Logger.Warning("Could not import block entity data for schematic at {0}. There is already {1}, expected {2}. Probably overlapping ruins.", curPos, be.GetType(), block.EntityClass);
                        continue;
                    }

                    ITreeAttribute tree = DecodeBlockEntityData(val.Value);
                    tree.SetInt("posx", curPos.X);
                    tree.SetInt("posy", curPos.Y);
                    tree.SetInt("posz", curPos.Z);

                    be.FromTreeAttributes(tree, worldForCollectibleResolve);
                    be.OnLoadCollectibleMappings(worldForCollectibleResolve, BlockCodes, ItemCodes, schematicSeed);
                    be.Pos = curPos.Copy();
                }
            }

            foreach (string entityData in Entities)
            {
                using (MemoryStream ms = new MemoryStream(Ascii85.Decode(entityData)))
                {
                    BinaryReader reader = new BinaryReader(ms);

                    string className = reader.ReadString();
                    Entity entity    = worldForCollectibleResolve.ClassRegistry.CreateEntity(className);

                    entity.FromBytes(reader, false);
                    entity.DidImportOrExport(startPos);

                    // Not ideal but whatever
                    if (blockAccessor is IWorldGenBlockAccessor)
                    {
                        (blockAccessor as IWorldGenBlockAccessor).AddEntity(entity);
                    }
                    else
                    {
                        worldForCollectibleResolve.SpawnEntity(entity);
                    }
                }
            }
        }
Пример #27
0
 /// <summary>
 /// Gets the starting position of the schematic.
 /// </summary>
 /// <param name="pos"></param>
 /// <param name="origin"></param>
 /// <returns></returns>
 public virtual BlockPos GetStartPos(BlockPos pos, EnumOrigin origin)
 {
     return(AdjustStartPos(pos.Copy(), origin));
 }
Пример #28
0
        public override void GenDeposit(IBlockAccessor blockAccessor, IServerChunk[] chunks, int chunkX, int chunkZ, BlockPos depoCenterPos, ref Dictionary <BlockPos, DepositVariant> subDepositsToPlace)
        {
            int depositGradeIndex = PlaceBlock.MaxGrade == 0 ? 0 : DepositRand.NextInt(PlaceBlock.MaxGrade);

            int radius = Math.Min(64, (int)Radius.nextFloat(1, DepositRand));

            if (radius <= 0)
            {
                return;
            }


            // Let's deform that perfect circle a bit (+/- 25%)
            float deform = GameMath.Clamp(DepositRand.NextFloat() - 0.5f, -0.25f, 0.25f);

            radiusX = radius - (int)(radius * deform);
            radiusZ = radius + (int)(radius * deform);


            int baseX = chunkX * chunksize;
            int baseZ = chunkZ * chunksize;


            // No need to caluclate further if this deposit won't be part of this chunk
            if (depoCenterPos.X + radiusX < baseX - 6 || depoCenterPos.Z + radiusZ < baseZ - 6 || depoCenterPos.X - radiusX >= baseX + chunksize + 6 || depoCenterPos.Z - radiusZ >= baseZ + chunksize + 6)
            {
                return;
            }

            IMapChunk heremapchunk = chunks[0].MapChunk;


            beforeGenDeposit(heremapchunk, depoCenterPos);

            // Ok generate
            float th = Thickness.nextFloat(1, DepositRand);

            depoitThickness = (int)th + (DepositRand.NextFloat() < th - (int)th ? 1 : 0);

            float xRadSqInv = 1f / (radiusX * radiusX);
            float zRadSqInv = 1f / (radiusZ * radiusZ);

            bool parentBlockOk = false;
            ResolvedDepositBlock resolvedPlaceBlock = null;


            bool shouldGenSurfaceDeposit = DepositRand.NextFloat() <= GenSurfaceBlockChance && SurfaceBlock != null;

            int lx = GameMath.Mod(depoCenterPos.X, chunksize);
            int lz = GameMath.Mod(depoCenterPos.Z, chunksize);
            int distx, distz;

            // No need to go search far beyond chunk boundaries
            int minx = baseX - 6;
            int maxx = baseX + chunksize + 6;
            int minz = baseZ - 6;
            int maxz = baseZ + chunksize + 6;

            minx = GameMath.Clamp(depoCenterPos.X - radiusX, minx, maxx);
            maxx = GameMath.Clamp(depoCenterPos.X + radiusX, minx, maxx);
            minz = GameMath.Clamp(depoCenterPos.Z - radiusZ, minz, maxz);
            maxz = GameMath.Clamp(depoCenterPos.Z + radiusZ, minz, maxz);

            //int placed = 0;

            float  invChunkAreaSize = 1f / (chunksize * chunksize);
            double val = 1;

            for (int posx = minx; posx < maxx; posx++)
            {
                targetPos.X = posx;
                lx          = targetPos.X - baseX;
                distx       = posx - depoCenterPos.X;

                float xSq = distx * distx * xRadSqInv;

                for (int posz = minz; posz < maxz; posz++)
                {
                    targetPos.Y = depoCenterPos.Y;
                    targetPos.Z = posz;
                    lz          = targetPos.Z - baseZ;
                    distz       = posz - depoCenterPos.Z;


                    // Kinda weird mathematically speaking, but seems to work as a means to distort the perfect circleness of deposits ¯\_(ツ)_/¯
                    // Also not very efficient to use direct perlin noise in here :/
                    // But after ~10 hours of failing (=weird lines of missing deposit material) with a pre-generated 2d distortion map i give up >.>
                    val = 1 - (radius > 3 ? DistortNoiseGen.Noise(targetPos.X / 3.0, targetPos.Z / 3.0) * 0.2 : 0);
                    double distanceToEdge = val - (xSq + distz * distz * zRadSqInv);

                    if (distanceToEdge < 0 || lx < 0 || lz < 0 || lx >= chunksize || lz >= chunksize)
                    {
                        continue;
                    }


                    loadYPosAndThickness(heremapchunk, lx, lz, targetPos, distanceToEdge);


                    // Some deposits may not appear all over cliffs
                    if (Math.Abs(depoCenterPos.Y - targetPos.Y) > MaxYRoughness)
                    {
                        continue;
                    }


                    for (int y = 0; y < hereThickness; y++)
                    {
                        if (targetPos.Y <= 1 || targetPos.Y >= worldheight)
                        {
                            continue;
                        }

                        int index3d = ((targetPos.Y % chunksize) * chunksize + lz) * chunksize + lx;
                        int blockId = chunks[targetPos.Y / chunksize].Blocks[index3d];


                        if (!IgnoreParentTestPerBlock || !parentBlockOk)
                        {
                            parentBlockOk = placeBlockByInBlockId.TryGetValue(blockId, out resolvedPlaceBlock);
                        }

                        if (parentBlockOk && resolvedPlaceBlock.Blocks.Length > 0)
                        {
                            int gradeIndex = Math.Min(resolvedPlaceBlock.Blocks.Length - 1, depositGradeIndex);

                            Block placeblock = resolvedPlaceBlock.Blocks[gradeIndex];

                            if (variant.WithBlockCallback || (WithLastLayerBlockCallback && y == hereThickness - 1))
                            {
                                placeblock.TryPlaceBlockForWorldGen(blockAccessor, targetPos.Copy(), BlockFacing.UP, rand);
                            }
                            else
                            {
                                chunks[targetPos.Y / chunksize].Blocks[index3d] = placeblock.BlockId;
                                //placed++;
                            }

                            if (variant.ChildDeposits != null)
                            {
                                for (int i = 0; i < variant.ChildDeposits.Length; i++)
                                {
                                    float rndVal   = DepositRand.NextFloat();
                                    float quantity = variant.ChildDeposits[i].TriesPerChunk * invChunkAreaSize;

                                    if (quantity > rndVal)
                                    {
                                        if (ShouldPlaceAdjustedForOreMap(variant.ChildDeposits[i], targetPos.X, targetPos.Z, quantity, rndVal))
                                        {
                                            subDepositsToPlace[targetPos.Copy()] = variant.ChildDeposits[i];
                                        }
                                    }
                                }
                            }

                            if (shouldGenSurfaceDeposit)
                            {
                                int   surfaceY = heremapchunk.RainHeightMap[lz * chunksize + lx];
                                int   depth    = surfaceY - targetPos.Y;
                                float chance   = SurfaceBlockChance * Math.Max(0, 1.11f - depth / 9f);
                                if (surfaceY < worldheight && DepositRand.NextFloat() < chance)
                                {
                                    Block belowBlock = Api.World.Blocks[chunks[surfaceY / chunksize].Blocks[((surfaceY % chunksize) * chunksize + lz) * chunksize + lx]];

                                    index3d = (((surfaceY + 1) % chunksize) * chunksize + lz) * chunksize + lx;
                                    if (belowBlock.SideSolid[BlockFacing.UP.Index] && chunks[(surfaceY + 1) / chunksize].Blocks[index3d] == 0)
                                    {
                                        chunks[(surfaceY + 1) / chunksize].Blocks[index3d] = surfaceBlockByInBlockId[blockId].Blocks[0].BlockId;
                                    }
                                }
                            }
                        }

                        targetPos.Y--;
                    }
                }
            }

            //Console.WriteLine("placed {0} blocks", placed);
        }
Пример #29
0
        private void onCmdAStar(IServerPlayer player, int groupId, CmdArgs args)
        {
            string subcmd = args.PopWord();

            BlockPos       plrPos = player.Entity.ServerPos.XYZ.AsBlockPos;
            PathfindSystem pfs    = sapi.ModLoader.GetModSystem <PathfindSystem>();

            Cuboidf narrow   = new Cuboidf(-0.4f, 0, -0.4f, 0.4f, 1.5f, 0.4f);
            Cuboidf narrower = new Cuboidf(-0.2f, 0, -0.2f, 0.2f, 1.5f, 0.2f);
            Cuboidf wide     = new Cuboidf(-0.6f, 0, -0.6f, 0.6f, 1.5f, 0.6f);

            Cuboidf collbox       = narrow;
            int     maxFallHeight = 3;
            float   stepHeight    = 1.01f;


            switch (subcmd)
            {
            case "start":
                start = plrPos.Copy();
                sapi.World.HighlightBlocks(player, 26, new List <BlockPos>()
                {
                    start
                }, new List <int>()
                {
                    ColorUtil.ColorFromRgba(255, 255, 0, 128)
                }, EnumHighlightBlocksMode.Absolute, EnumHighlightShape.Arbitrary);
                break;

            case "end":
                end = plrPos.Copy();
                sapi.World.HighlightBlocks(player, 27, new List <BlockPos>()
                {
                    end
                }, new List <int>()
                {
                    ColorUtil.ColorFromRgba(255, 0, 255, 128)
                }, EnumHighlightBlocksMode.Absolute, EnumHighlightShape.Arbitrary);
                break;

            case "bench":
                if (start == null || end == null)
                {
                    return;
                }

                Stopwatch sw = new Stopwatch();
                sw.Start();

                for (int i = 0; i < 15; i++)
                {
                    List <PathNode> nodes = pfs.FindPath(start, end, maxFallHeight, stepHeight, collbox);
                }

                sw.Stop();
                float timeMs = (float)sw.ElapsedMilliseconds / 15f;

                player.SendMessage(groupId, string.Format("15 searches average: {0} ms", (int)timeMs), EnumChatType.Notification);
                return;

            case "clear":
                start = null;
                end   = null;

                sapi.World.HighlightBlocks(player, 2, new List <BlockPos>(), EnumHighlightBlocksMode.Absolute, EnumHighlightShape.Arbitrary);
                sapi.World.HighlightBlocks(player, 26, new List <BlockPos>(), EnumHighlightBlocksMode.Absolute, EnumHighlightShape.Arbitrary);
                sapi.World.HighlightBlocks(player, 27, new List <BlockPos>(), EnumHighlightBlocksMode.Absolute, EnumHighlightShape.Arbitrary);
                break;
            }

            if (start == null || end == null)
            {
                sapi.World.HighlightBlocks(player, 2, new List <BlockPos>(), EnumHighlightBlocksMode.Absolute, EnumHighlightShape.Arbitrary);
            }
            if (start != null && end != null)
            {
                Stopwatch sw = new Stopwatch();
                sw.Start();

                List <PathNode> nodes = pfs.FindPath(start, end, maxFallHeight, stepHeight, collbox);
                sw.Stop();
                int timeMs = (int)sw.ElapsedMilliseconds;

                player.SendMessage(groupId, string.Format("Search took {0} ms, {1} nodes checked", timeMs, pfs.astar.NodesChecked), EnumChatType.Notification);

                if (nodes == null)
                {
                    player.SendMessage(groupId, "No path found", EnumChatType.CommandError);

                    sapi.World.HighlightBlocks(player, 2, new List <BlockPos>(), EnumHighlightBlocksMode.Absolute, EnumHighlightShape.Arbitrary);
                    sapi.World.HighlightBlocks(player, 3, new List <BlockPos>(), EnumHighlightBlocksMode.Absolute, EnumHighlightShape.Arbitrary);
                    return;
                }

                List <BlockPos> poses = new List <BlockPos>();
                foreach (var node in nodes)
                {
                    poses.Add(node);
                }

                sapi.World.HighlightBlocks(player, 2, poses, new List <int>()
                {
                    ColorUtil.ColorFromRgba(128, 128, 128, 30)
                }, EnumHighlightBlocksMode.Absolute, EnumHighlightShape.Arbitrary);


                List <Vec3d> wps = pfs.ToWaypoints(nodes);
                poses = new List <BlockPos>();
                foreach (var node in wps)
                {
                    poses.Add(node.AsBlockPos);
                }

                sapi.World.HighlightBlocks(player, 3, poses, new List <int>()
                {
                    ColorUtil.ColorFromRgba(128, 0, 0, 100)
                }, EnumHighlightBlocksMode.Absolute, EnumHighlightShape.Arbitrary);
            }
        }
Пример #30
0
        public Stack <BlockPos> FindTree(IWorldAccessor world, BlockPos startPos, out string treeType)
        {
            Queue <Vec4i>      queue            = new Queue <Vec4i>();
            HashSet <BlockPos> checkedPositions = new HashSet <BlockPos>();
            Stack <BlockPos>   foundPositions   = new Stack <BlockPos>();

            treeType = "";


            Block block = world.BlockAccessor.GetBlock(startPos);

            if (block.Code == null)
            {
                return(foundPositions);
            }

            if (block.Code.Path.StartsWith("log-grown") || block.Code.Path.StartsWith("beehive-inlog-") || block.Code.Path.StartsWith("log-resin") || block.Code.Path.StartsWith("bamboo-grown-"))
            {
                treeType = block.FirstCodePart(2);

                queue.Enqueue(new Vec4i(startPos.X, startPos.Y, startPos.Z, 2));
                foundPositions.Push(startPos);
                checkedPositions.Add(startPos);
            }

            string logcode = block.Code.Path.StartsWith("bamboo") ? "bamboo-grown-" + treeType : "log-grown-" + treeType;

            if (block is BlockFernTree)
            {
                treeType = "fern";
                logcode  = "ferntree-normal";
                queue.Enqueue(new Vec4i(startPos.X, startPos.Y, startPos.Z, 2));
                foundPositions.Push(startPos);
                checkedPositions.Add(startPos);
            }

            string logcode2          = "log-resin-" + treeType;
            string logcode3          = "log-resinharvested-" + treeType;
            string leavescode        = block.Code.Path.StartsWith("bamboo") ? "bambooleaves-" + treeType + "-grown"  : "leaves-grown-" + treeType;
            string leavesbranchycode = "leavesbranchy-grown-" + treeType;



            while (queue.Count > 0)
            {
                if (foundPositions.Count > 2000)
                {
                    break;
                }

                Vec4i pos = queue.Dequeue();

                for (int i = 0; i < Vec3i.DirectAndIndirectNeighbours.Length; i++)
                {
                    Vec3i    facing  = Vec3i.DirectAndIndirectNeighbours[i];
                    BlockPos neibPos = new BlockPos(pos.X + facing.X, pos.Y + facing.Y, pos.Z + facing.Z);

                    float hordist  = GameMath.Sqrt(neibPos.HorDistanceSqTo(startPos.X, startPos.Z));
                    float vertdist = (neibPos.Y - startPos.Y);

                    // "only breaks blocks inside an upside down square base pyramid"
                    if (hordist - 1 >= 2 * vertdist)
                    {
                        continue;
                    }
                    if (checkedPositions.Contains(neibPos))
                    {
                        continue;
                    }

                    block = world.BlockAccessor.GetBlock(neibPos);
                    if (block.Code == null)
                    {
                        continue;
                    }

                    if (block.Code.Path.StartsWith(logcode) || block.Code.Path.StartsWith(logcode2) || block.Code.Path.StartsWith(logcode3))
                    {
                        if (pos.W < 2)
                        {
                            continue;
                        }

                        foundPositions.Push(neibPos.Copy());
                        queue.Enqueue(new Vec4i(neibPos.X, neibPos.Y, neibPos.Z, 2));
                    }
                    else if (block.Code.Path.StartsWith(leavesbranchycode))
                    {
                        if (pos.W < 1)
                        {
                            continue;
                        }

                        foundPositions.Push(neibPos.Copy());
                        queue.Enqueue(new Vec4i(neibPos.X, neibPos.Y, neibPos.Z, 1));
                    }
                    else if (block.Code.Path.StartsWith(leavescode))
                    {
                        foundPositions.Push(neibPos.Copy());
                        queue.Enqueue(new Vec4i(neibPos.X, neibPos.Y, neibPos.Z, 0));
                    }

                    checkedPositions.Add(neibPos);
                }
            }

            return(foundPositions);
        }