예제 #1
0
        private void GenHere(IBlockAccessor blockAccessor, BlockPos pos, LCGRandom worldGenRand)
        {
            int rnd = worldGenRand.NextInt(bases.Length);

            Block placeblock = api.World.GetBlock(CodeWithVariant("type", bases[rnd]));

            blockAccessor.SetBlock(placeblock.Id, pos);

            if (segments[rnd] != null)
            {
                placeblock = api.World.GetBlock(CodeWithVariant("type", segments[rnd]));

                int len = worldGenRand.NextInt(3);
                while (len-- > 0)
                {
                    pos.Down();
                    if (blockAccessor.GetBlock(pos).Replaceable > 6000)
                    {
                        blockAccessor.SetBlock(placeblock.Id, pos);
                    }
                }

                pos.Down();
                placeblock = api.World.GetBlock(CodeWithVariant("type", ends[rnd]));
                if (blockAccessor.GetBlock(pos).Replaceable > 6000)
                {
                    blockAccessor.SetBlock(placeblock.Id, pos);
                }
            }
        }
예제 #2
0
        public override bool TryPlaceBlockForWorldGen(IBlockAccessor blockAccessor, BlockPos pos, BlockFacing onBlockFace, LCGRandom worldGenRand)
        {
            Block block = blockAccessor.GetBlock(pos);


            if (block.IsReplacableBy(this) && block.SideSolid[BlockFacing.UP.Index])
            {
                blockAccessor.SetBlock(rndGearBlock().BlockId, pos);
                return(true);
            }

            pos   = pos.DownCopy();
            block = blockAccessor.GetBlock(pos);

            if (block.IsReplacableBy(this) && block.SideSolid[BlockFacing.UP.Index])
            {
                blockAccessor.SetBlock(rndGearBlock().BlockId, pos);
                return(true);
            }

            pos.Down();
            block = blockAccessor.GetBlock(pos);

            if (block.IsReplacableBy(this) && block.SideSolid[BlockFacing.UP.Index])
            {
                blockAccessor.SetBlock(rndGearBlock().BlockId, pos);
                return(true);
            }

            return(false);
        }
예제 #3
0
 private void Erode(float quantity, BlockPos dpos)
 {
     while (quantity-- >= 1)
     {
         //if (quantity < 1 && rand.NextDouble() > quantity) break;
         blockAccessRev.SetBlock(0, dpos);
         dpos.Down();
     }
 }
예제 #4
0
        protected bool TryStackDown(IPlayer byPlayer, IWorldAccessor world, BlockPos pos, BlockFacing face, ItemStack itemstack)
        {
            Block  ladderBlock = world.BlockAccessor.GetBlock(pos);
            string ladderType  = ladderBlock.GetBehavior <BlockBehaviorLadder>()?.LadderType;

            if (ladderType != LadderType)
            {
                return(false);
            }

            BlockPos belowPos   = pos.DownCopy();
            Block    belowBlock = null;

            while (belowPos.Y > 0)
            {
                belowBlock = world.BlockAccessor.GetBlock(belowPos);
                if (belowBlock.FirstCodePart() != ownFirstCodePart)
                {
                    break;
                }

                belowPos.Down();
            }

            string useless = "";

            if (belowBlock == null || belowBlock.FirstCodePart() == ownFirstCodePart)
            {
                return(false);
            }
            if (!belowBlock.IsReplacableBy(block))
            {
                return(false);
            }
            if (!ladderBlock.CanPlaceBlock(world, byPlayer, new BlockSelection()
            {
                Position = belowPos, Face = face
            }, ref useless))
            {
                return(false);
            }

            ladderBlock.DoPlaceBlock(world, byPlayer, new BlockSelection()
            {
                Position = belowPos, Face = face
            }, itemstack);

            BlockPos neibPos = new BlockPos();

            foreach (BlockFacing facing in BlockFacing.ALLFACES)
            {
                neibPos.Set(belowPos).Offset(facing);
                world.BlockAccessor.GetBlock(neibPos).OnNeighbourBlockChange(world, neibPos, belowPos);
            }

            return(true);
        }
예제 #5
0
        protected bool TryCollectLowest(IPlayer byPlayer, IWorldAccessor world, BlockPos pos)
        {
            Block ladderBlock = world.BlockAccessor.GetBlock(pos);

            if (ladderBlock.FirstCodePart() != ownFirstCodePart)
            {
                return(false);
            }

            BlockPos belowPos = pos.DownCopy();
            Block    belowBlock;

            while (belowPos.Y > 0)
            {
                belowBlock = world.BlockAccessor.GetBlock(belowPos);
                if (belowBlock.FirstCodePart() != ownFirstCodePart)
                {
                    break;
                }

                belowPos.Down();
            }

            belowPos.Up();
            Block collectBlock = world.BlockAccessor.GetBlock(belowPos);

            var bh = collectBlock.GetBehavior <BlockBehaviorLadder>();

            if (bh == null || !bh.isFlexible)
            {
                return(false);
            }

            if (!world.Claims.TryAccess(byPlayer, belowPos, EnumBlockAccessFlags.BuildOrBreak))
            {
                return(false);
            }

            ItemStack[] stacks = collectBlock.GetDrops(world, pos, byPlayer);

            world.BlockAccessor.SetBlock(0, belowPos);
            world.PlaySoundAt(collectBlock.Sounds.Break, pos.X + 0.5, pos.Y + 0.5, pos.Z + 0.5, byPlayer);

            if (stacks.Length > 0)
            {
                if (!byPlayer.InventoryManager.TryGiveItemstack(stacks[0], true))
                {
                    world.SpawnItemEntity(stacks[0], byPlayer.Entity.Pos.XYZ);
                }
            }


            return(true);
        }
예제 #6
0
        private bool TryStackDown(IPlayer byPlayer, IWorldAccessor world, BlockPos pos, BlockFacing face, ItemStack itemstack)
        {
            Block ladderBlock = world.BlockAccessor.GetBlock(pos);

            if (ladderBlock.FirstCodePart() != ownFirstCodePart)
            {
                return(false);
            }

            BlockPos belowPos   = pos.DownCopy();
            Block    belowBlock = null;

            while (belowPos.Y > 0)
            {
                belowBlock = world.BlockAccessor.GetBlock(belowPos);
                if (belowBlock.FirstCodePart() != ownFirstCodePart)
                {
                    break;
                }

                belowPos.Down();
            }

            string useless = "";

            if (belowBlock == null || belowBlock.FirstCodePart() == ownFirstCodePart)
            {
                return(false);
            }
            if (!belowBlock.IsReplacableBy(block))
            {
                return(false);
            }
            if (!ladderBlock.CanPlaceBlock(world, byPlayer, new BlockSelection()
            {
                Position = belowPos, Face = face
            }, ref useless))
            {
                return(false);
            }

            ladderBlock.DoPlaceBlock(world, byPlayer, new BlockSelection()
            {
                Position = belowPos, Face = face
            }, itemstack);
            return(true);
        }
예제 #7
0
        private string GetBlocksAround(BlockLogSection[] around, IBlockAccessor blockAccessor, BlockPos pos)
        {
            string[] any      = new string[3];
            int[]    anyCount = new int[3];
            if (blockAccessor.GetBlock(pos.North()) is BlockLogSection n)
            {
                around[0] = n;
                UpdateAny(n.LastCodePart(), any, anyCount);
            }
            if (blockAccessor.GetBlock(pos.South().East()) is BlockLogSection e)
            {
                around[1] = e;
                UpdateAny(e.LastCodePart(), any, anyCount);
            }
            if (blockAccessor.GetBlock(pos.South().West()) is BlockLogSection s)
            {
                around[2] = s;
                UpdateAny(s.LastCodePart(), any, anyCount);
            }
            if (blockAccessor.GetBlock(pos.North().West()) is BlockLogSection w)
            {
                around[3] = w;
                UpdateAny(w.LastCodePart(), any, anyCount);
            }
            if (blockAccessor.GetBlock(pos.East().Up()) is BlockLogSection u)
            {
                around[4] = u;
                UpdateAny(u.LastCodePart(), any, anyCount);
            }
            if (blockAccessor.GetBlock(pos.Down().Down()) is BlockLogSection d)
            {
                around[5] = d;
                UpdateAny(d.LastCodePart(), any, anyCount);
            }

            if (anyCount[1] > anyCount[0])
            {
                any[0]      = any[1];
                anyCount[0] = anyCount[1];
            }
            return((anyCount[2] > anyCount[0]) ? any[2] : any[0]);
        }
예제 #8
0
        public override bool TryPlaceBlockForWorldGen(IBlockAccessor blockAccessor, BlockPos pos, BlockFacing onBlockFace, LCGRandom worldGenRand)
        {
            BlockPos rootPos = onBlockFace.IsHorizontal ? pos.AddCopy(onBlockFace) : pos.AddCopy(onBlockFace.Opposite);

            var block = blockAccessor.GetBlock(rootPos);

            if (!block.HasBehavior <BehaviorMyceliumHost>())
            {
                rootPos.Down();
                block = blockAccessor.GetBlock(rootPos);
                if (!block.HasBehavior <BehaviorMyceliumHost>())
                {
                    return(false);
                }
            }

            blockAccessor.SpawnBlockEntity("Mycelium", rootPos);
            (blockAccessor.GetBlockEntity(rootPos) as BlockEntityMycelium).OnGenerated(blockAccessor, worldGenRand, this);
            return(true);
        }
예제 #9
0
        public static BlockPos GetRecommendedPos(this BlockSelection sel, ICoreAPI api, Block block)
        {
            BlockPos adjPos = sel.Position.Copy();

            if (!api.World.BlockAccessor.GetBlock(adjPos).IsReplacableBy(block))
            {
                switch (sel.Face.Code)
                {
                case "up":
                    adjPos.Up();
                    break;

                case "down":
                    adjPos.Down();
                    break;

                case "north":
                    adjPos.West();
                    break;

                case "south":
                    adjPos.East();
                    break;

                case "east":
                    adjPos.North();
                    break;

                case "west":
                    adjPos.South();
                    break;

                default:
                    break;
                }
            }
            return(adjPos);
        }
예제 #10
0
        public override bool TryPlaceBlockForWorldGen(IBlockAccessor blockAccessor, BlockPos pos, BlockFacing onBlockFace, LCGRandom worldGenRand)
        {
            BlockPos belowPos = pos.DownCopy();

            Block block = blockAccessor.GetBlock(belowPos);

            if (block.LiquidCode != "water")
            {
                return(false);
            }

            int depth = 1;

            while (depth < 10)
            {
                belowPos.Down();
                block = blockAccessor.GetBlock(belowPos);

                if (block.Fertility > 0)
                {
                    belowPos.Up();
                    PlaceSeaweed(blockAccessor, belowPos, depth);
                    return(true);
                }
                else
                {
                    if (!block.IsLiquid())
                    {
                        return(false);
                    }
                }

                depth++;
            }

            return(false);
        }
예제 #11
0
        void TestTree(IServerPlayer player, CmdArgs arguments)
        {
            if (arguments.Length < 2)
            {
                player.SendMessage(groupId, "/wgen tree {treeWorldPropertyCode} [0.1 - 3] [aheadoffset]", EnumChatType.CommandError);
                return;
            }

            float size        = 1f;
            int   aheadoffset = 0;

            if (arguments.Length > 2)
            {
                float.TryParse(arguments[2], out size);
            }

            if (arguments.Length > 3)
            {
                int.TryParse(arguments[3], out aheadoffset);
            }

            BlockPos pos = player.Entity.Pos.HorizontalAheadCopy(aheadoffset).AsBlockPos;

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

            while (blockAccessor.GetBlockId(pos) == 0 && pos.Y > 1)
            {
                pos.Down();
            }

            treeGenerators.ReloadTreeGenerators();
            treeGenerators.RunGenerator(new AssetLocation(arguments[1]), blockAccessor, pos, size);

            blockAccessor.Commit();

            player.SendMessage(groupId, arguments[1] + " size " + size + " generated.", EnumChatType.CommandError);
        }
        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);
        }
예제 #13
0
        private void growBranch(Random rand, int depth, BlockPos pos, float dx, float dy, float dz, float angleVerStart, float angleHorStart, float curWidth, float dieAt, float trunkWidthLoss, bool wideTrunk)
        {
            if (depth > 30)
            {
                Console.WriteLine("TreeGen.growBranch() aborted, too many branches!"); return;
            }

            TreeGenBranch branch = branchesByDepth[Math.Min(depth, branchesByDepth.Count - 1)];

            short[] outline = forestFloor.GetOutline();

            float widthloss                  = depth == 0 ? trunkWidthLoss : branch.WidthLoss(rand);
            float widthlossCurve             = branch.widthlossCurve;
            float branchspacing              = branch.branchSpacing.nextFloat(1, rand);
            float branchstart                = branch.branchStart.nextFloat(1, rand);
            float branchQuantityStart        = branch.branchQuantity.nextFloat(1, rand);
            float branchWidthMulitplierStart = branch.branchWidthMultiplier.nextFloat(1, rand);

            float reldistance, lastreldistance = 0;
            float totaldistance = curWidth / widthloss;

            int   iteration             = 0;
            float sequencesPerIteration = 1f / (curWidth / widthloss);


            float ddrag, angleVer, angleHor;

            // we want to place around the trunk/branch => offset the coordinates when growing stuff from the base
            float trunkOffsetX, trunkOffsetZ;

            BlockPos currentPos = new BlockPos();

            float branchQuantity, branchWidth;
            float sinAngleVer, cosAnglerHor, sinAngleHor;

            float currentSequence;

            LCGRandom lcgrand = lcgrandTL.Value;

            while (curWidth > 0 && iteration++ < 5000)
            {
                curWidth -= widthloss;
                if (widthlossCurve + curWidth / 20 < 1f)
                {
                    widthloss *= (widthlossCurve + curWidth / 20);
                }

                currentSequence = sequencesPerIteration * (iteration - 1);

                if (curWidth < dieAt)
                {
                    break;
                }

                angleVer = branch.angleVertEvolve.nextFloat(angleVerStart, currentSequence);
                angleHor = branch.angleHoriEvolve.nextFloat(angleHorStart, currentSequence);

                sinAngleVer  = GameMath.FastSin(angleVer);
                cosAnglerHor = GameMath.FastCos(angleHor);
                sinAngleHor  = GameMath.FastSin(angleHor);

                trunkOffsetX = Math.Max(-0.5f, Math.Min(0.5f, 0.7f * sinAngleVer * cosAnglerHor));
                trunkOffsetZ = Math.Max(-0.5f, Math.Min(0.5f, 0.7f * sinAngleVer * sinAngleHor));

                ddrag = branch.gravityDrag * (float)Math.Sqrt(dx * dx + dz * dz);

                dx += sinAngleVer * cosAnglerHor / Math.Max(1, Math.Abs(ddrag));
                dy += Math.Min(1, Math.Max(-1, GameMath.FastCos(angleVer) - ddrag));
                dz += sinAngleVer * sinAngleHor / Math.Max(1, Math.Abs(ddrag));

                int blockId = branch.getBlockId(curWidth, config.treeBlocks, this);
                if (blockId == 0)
                {
                    return;
                }

                currentPos.Set(pos.X + dx, pos.Y + dy, pos.Z + dz);

                PlaceResumeState state = getPlaceResumeState(currentPos, blockId, wideTrunk);

                if (state == PlaceResumeState.CanPlace)
                {
                    api.SetBlock(blockId, currentPos);

                    // Update the canopy outline of the tree for this block position
                    int idz = (int)(dz + 16);
                    int idx = (int)(dx + 16);
                    if (idz > 1 && idz < 31 && idx > 1 && idx < 31)
                    {
                        int canopyIndex = idz * 33 + idx;
                        outline[canopyIndex - 68]++;
                        outline[canopyIndex - 67]++;  //bias canopy shading towards the North (- z direction) for sun effects
                        outline[canopyIndex - 66]++;
                        outline[canopyIndex - 65]++;
                        outline[canopyIndex - 64]++;
                        outline[canopyIndex - 35]++;
                        outline[canopyIndex - 34] += 2;
                        outline[canopyIndex - 33] += 2;
                        outline[canopyIndex - 32] += 2;
                        outline[canopyIndex - 31]++;
                        outline[canopyIndex - 2]++;
                        outline[canopyIndex - 1] += 2;
                        outline[canopyIndex + 0] += 3;
                        outline[canopyIndex + 1] += 2;
                        outline[canopyIndex + 2]++;
                        outline[canopyIndex + 33]++;
                    }

                    if (vineGrowthChance > 0 && rand.NextDouble() < vineGrowthChance && config.treeBlocks.vinesBlock != null)
                    {
                        BlockFacing facing = BlockFacing.HORIZONTALS[rand.Next(4)];

                        BlockPos vinePos = currentPos.AddCopy(facing);
                        float    cnt     = 1 + rand.Next(11) * (vineGrowthChance + 0.2f);

                        while (api.GetBlockId(vinePos) == 0 && cnt-- > 0)
                        {
                            Block block = config.treeBlocks.vinesBlock;

                            if (cnt <= 0 && config.treeBlocks.vinesEndBlock != null)
                            {
                                block = config.treeBlocks.vinesEndBlock;
                            }

                            block.TryPlaceBlockForWorldGen(api, vinePos, facing, lcgrand);
                            vinePos.Down();
                        }
                    }
                }
                else
                {
                    if (state == PlaceResumeState.Stop)
                    {
                        return;
                    }
                }

                reldistance = (float)Math.Sqrt(dx * dx + dy * dy + dz * dz) / totaldistance;


                if (reldistance < branchstart)
                {
                    continue;
                }

                if (reldistance > lastreldistance + branchspacing * (1f - reldistance))
                {
                    branchspacing   = branch.branchSpacing.nextFloat(1, rand);
                    lastreldistance = reldistance;

                    if (branch.branchQuantityEvolve != null)
                    {
                        branchQuantity = branch.branchQuantityEvolve.nextFloat(branchQuantityStart, currentSequence);
                    }
                    else
                    {
                        branchQuantity = branch.branchQuantity.nextFloat(1, rand);
                    }

                    float prevHorAngle = 0f;
                    float horAngle;
                    float minHorangleDist = Math.Min(GameMath.PI / 5, branch.branchHorizontalAngle.var / 5);


                    bool first = true;

                    while (branchQuantity-- > 0)
                    {
                        if (branchQuantity < 1 && rand.NextDouble() < branchQuantity)
                        {
                            break;
                        }

                        curWidth *= branch.branchWidthLossMul;

                        horAngle = angleHor + branch.branchHorizontalAngle.nextFloat(1, rand);

                        int tries = 10;
                        while (!first && Math.Abs(horAngle - prevHorAngle) < minHorangleDist && tries-- > 0)
                        {
                            float newAngle = angleHor + branch.branchHorizontalAngle.nextFloat(1, rand);
                            if (Math.Abs(horAngle - prevHorAngle) < Math.Abs(newAngle - prevHorAngle))
                            {
                                horAngle = newAngle;
                            }
                        }

                        if (branch.branchWidthMultiplierEvolve != null)
                        {
                            branchWidth = curWidth * branch.branchWidthMultiplierEvolve.nextFloat(branchWidthMulitplierStart, currentSequence);
                        }
                        else
                        {
                            branchWidth = branch.branchWidthMultiplier.nextFloat(curWidth, rand);
                        }

                        growBranch(
                            rand,
                            depth + 1,
                            pos, dx + trunkOffsetX, dy, dz + trunkOffsetZ,
                            branch.branchVerticalAngle.nextFloat(1, rand),
                            horAngle,
                            branchWidth,
                            Math.Max(0, branch.dieAt.nextFloat(1, rand)),
                            trunkWidthLoss, false
                            );

                        first        = false;
                        prevHorAngle = angleHor + horAngle;
                    }
                }
            }
        }
예제 #14
0
        void OnUse(WorldEdit worldEdit, BlockPos pos, int oldBlockId, int sign, ItemStack withItemStack)
        {
            if (Radius <= 0)
            {
                return;
            }

            int   radInt = (int)Math.Ceiling(Radius);
            float radSq  = Radius * Radius;

            Block block = blockAccessRev.GetBlock(pos);

            if (sign > 0)
            {
                worldEdit.sapi.World.BlockAccessor.SetBlock(oldBlockId, pos);
            }

            float maxhgt            = Depth;
            EnumHeightToolMode dist = Mode;

            int quantityBlocks = (int)(GameMath.PI * radSq) * (int)maxhgt;

            if (!worldEdit.MayPlace(block, quantityBlocks))
            {
                return;
            }

            for (int dx = -radInt; dx <= radInt; dx++)
            {
                for (int dz = -radInt; dz <= radInt; dz++)
                {
                    float distanceSq = dx * dx + dz * dz;
                    if (distanceSq > radSq)
                    {
                        continue;
                    }

                    BlockPos dpos = pos.AddCopy(dx, 0, dz);

                    float height = sign * maxhgt;
                    switch (dist)
                    {
                    case EnumHeightToolMode.Pyramid:
                        height *= 1 - distanceSq / radSq;
                        break;

                    case EnumHeightToolMode.Gaussian:
                        float sigmaSq = 0.1f;
                        float sigma   = GameMath.Sqrt(sigmaSq);
                        float a       = 1f / (sigma * GameMath.Sqrt(GameMath.TWOPI));
                        float x       = distanceSq / radSq;

                        double gaussValue = a * Math.Exp(-(x * x) / (2 * sigmaSq));

                        height *= (float)gaussValue;
                        break;

                    case EnumHeightToolMode.Perlin:

                        height *= (float)noiseGen.Noise(dpos.X, dpos.Y, dpos.Z);

                        break;
                    }

                    while (dpos.Y > 0 && blockAccessRev.GetBlock(dpos).Replaceable >= 6000)
                    {
                        dpos.Down();
                    }


                    if (height < 0)
                    {
                        Erode(-height, dpos);
                    }
                    else
                    {
                        dpos.Up();
                        Grow(worldEdit.sapi.World, height, dpos, block, BlockFacing.UP, withItemStack);
                    }
                }
            }

            blockAccessRev.SetHistoryStateBlock(pos.X, pos.Y, pos.Z, oldBlockId, blockAccessRev.GetBlockId(pos));
            blockAccessRev.Commit();
        }
예제 #15
0
        private void growBranch(int depth, BlockPos pos, float dx, float dy, float dz, float angleVerStart, float angleHorStart, float curWidth, float dieAt)
        {
            if (depth > 30)
            {
                Console.WriteLine("TreeGen.growBranch() aborted, too many branches!"); return;
            }

            TreeGenBranch branch = branchesByDepth[Math.Min(depth, branchesByDepth.Count - 1)];


            float branchspacing              = branch.branchSpacing.nextFloat();
            float branchstart                = branch.branchStart.nextFloat();
            float branchQuantityStart        = branch.branchQuantity.nextFloat();
            float branchWidthMulitplierStart = branch.branchWidthMultiplier.nextFloat();

            float reldistance = 0, lastreldistance = 0;
            float totaldistance = curWidth / branch.widthloss;

            int   iteration             = 0;
            float sequencesPerIteration = 1f / (curWidth / branch.widthloss);


            float ddrag = 0, angleVer = 0, angleHor = 0;

            // we want to place around the trunk/branch => offset the coordinates when growing stuff from the base
            float trunkOffsetX = 0, trunkOffsetZ = 0, trunkOffsetY = 0;

            BlockPos currentPos;

            float branchQuantity, branchWidth;
            float sinAngleVer, cosAnglerHor, sinAngleHor;

            float currentSequence;

            while (curWidth > 0 && iteration++ < 5000)
            {
                curWidth -= branch.widthloss;

                currentSequence = sequencesPerIteration * (iteration - 1);

                if (curWidth < dieAt)
                {
                    break;
                }

                angleVer = branch.angleVertEvolve.nextFloat(angleVerStart, currentSequence);
                angleHor = branch.angleHoriEvolve.nextFloat(angleHorStart, currentSequence);

                sinAngleVer  = GameMath.FastSin(angleVer);
                cosAnglerHor = GameMath.FastCos(angleHor);
                sinAngleHor  = GameMath.FastSin(angleHor);

                trunkOffsetX = Math.Max(-0.5f, Math.Min(0.5f, 0.7f * sinAngleVer * cosAnglerHor));
                trunkOffsetY = Math.Max(-0.5f, Math.Min(0.5f, 0.7f * cosAnglerHor)) + 0.5f;
                trunkOffsetZ = Math.Max(-0.5f, Math.Min(0.5f, 0.7f * sinAngleVer * sinAngleHor));

                ddrag = branch.gravityDrag * GameMath.FastSqrt(dx * dx + dz * dz);

                dx += sinAngleVer * cosAnglerHor / Math.Max(1, Math.Abs(ddrag));
                dy += Math.Min(1, Math.Max(-1, GameMath.FastCos(angleVer) - ddrag));
                dz += sinAngleVer * sinAngleHor / Math.Max(1, Math.Abs(ddrag));

                ushort blockId = getBlockId(curWidth);
                if (blockId == 0)
                {
                    return;
                }

                currentPos = pos.AddCopy(dx, dy, dz);

                if (canPlace(currentPos, blockId))
                {
                    api.SetBlock(blockId, currentPos);

                    if (vineGrowthChance > 0 && rand.NextDouble() < vineGrowthChance && config.treeBlocks.vinesBlock != null)
                    {
                        BlockFacing facing = BlockFacing.HORIZONTALS[rand.Next(4)];

                        BlockPos vinePos = currentPos.AddCopy(facing);
                        float    cnt     = 1 + rand.Next(11) * (vineGrowthChance + 0.2f);

                        while (api.GetBlockId(vinePos) == 0 && cnt-- > 0)
                        {
                            Block block = config.treeBlocks.vinesBlock;

                            if (cnt <= 0 && config.treeBlocks.vinesEndBlock != null)
                            {
                                block = config.treeBlocks.vinesEndBlock;
                            }

                            block.TryPlaceBlockForWorldGen(api, vinePos, facing);
                            vinePos.Down();
                        }
                    }
                }

                reldistance = GameMath.FastSqrt(dx * dx + dy * dy + dz * dz) / totaldistance;


                if (reldistance < branchstart)
                {
                    continue;
                }

                if (reldistance > lastreldistance + branchspacing * (1f - reldistance))
                {
                    branchspacing   = branch.branchSpacing.nextFloat();
                    lastreldistance = reldistance;

                    if (branch.branchQuantityEvolve != null)
                    {
                        branchQuantity = branch.branchQuantityEvolve.nextFloat(branchQuantityStart, currentSequence);
                    }
                    else
                    {
                        branchQuantity = branch.branchQuantity.nextFloat();
                    }

                    float prevHorAngle = 0f;
                    float horAngle;
                    float minHorangleDist = Math.Min(GameMath.PI / 10, branch.branchHorizontalAngle.var / 5);


                    bool first = true;

                    while (branchQuantity-- > 0)
                    {
                        if (branchQuantity < 1 && rand.NextDouble() < branchQuantity)
                        {
                            break;
                        }

                        curWidth *= branch.branchWidthLossMul;

                        horAngle = branch.branchHorizontalAngle.nextFloat();

                        int tries = 5;
                        while (!first && Math.Abs(horAngle - prevHorAngle) < minHorangleDist && tries-- > 0)
                        {
                            horAngle = branch.branchHorizontalAngle.nextFloat();
                        }

                        if (branch.branchWidthMultiplierEvolve != null)
                        {
                            branchWidth = curWidth * branch.branchWidthMultiplierEvolve.nextFloat(branchWidthMulitplierStart, currentSequence);
                        }
                        else
                        {
                            branchWidth = branch.branchWidthMultiplier.nextFloat(curWidth);
                        }

                        growBranch(
                            depth + 1,
                            pos, dx + trunkOffsetX, dy, dz + trunkOffsetZ,
                            branch.branchVerticalAngle.nextFloat(),
                            angleHor + branch.branchHorizontalAngle.nextFloat(),
                            branchWidth,
                            Math.Max(0, branch.dieAt.nextFloat())
                            );

                        first        = false;
                        prevHorAngle = horAngle;
                    }
                }
            }
        }