Exemplo n.º 1
0
        protected BlockSchematicStructure GetGeneratableStructure(VillageSchematic schem, IBlockAccessor blockAccessor, IWorldAccessor worldForCollectibleResolve, BlockPos pos)
        {
            int chunksize = blockAccessor.ChunkSize;
            int climate   = GameMath.BiLerpRgbColor((float)(pos.X % chunksize) / chunksize, (float)(pos.Z % chunksize) / chunksize, climateUpLeft, climateUpRight, climateBotLeft, climateBotRight);


            int num = rand.NextInt(schem.Structures.Length);
            BlockSchematicStructure schematic = schem.Structures[num];

            int widthHalf  = (int)Math.Ceiling(schematic.SizeX / 2f);
            int lengthHalf = (int)Math.Ceiling(schematic.SizeZ / 2f);

            pos.Y += schem.OffsetY;

            // Probe all 4 corners + center if they are on the same height

            int centerY = blockAccessor.GetTerrainMapheightAt(pos);

            tmpPos.Set(pos.X - widthHalf, 0, pos.Z - lengthHalf);
            int topLeftY = blockAccessor.GetTerrainMapheightAt(tmpPos);

            tmpPos.Set(pos.X + widthHalf, 0, pos.Z - lengthHalf);
            int topRightY = blockAccessor.GetTerrainMapheightAt(tmpPos);

            tmpPos.Set(pos.X - widthHalf, 0, pos.Z + lengthHalf);
            int botLeftY = blockAccessor.GetTerrainMapheightAt(tmpPos);

            tmpPos.Set(pos.X + widthHalf, 0, pos.Z + lengthHalf);
            int botRightY = blockAccessor.GetTerrainMapheightAt(tmpPos);


            int diff = GameMath.Max(centerY, topLeftY, topRightY, botLeftY, botRightY) - GameMath.Min(centerY, topLeftY, topRightY, botLeftY, botRightY);

            if (diff > 2)
            {
                return(null);
            }

            pos.Y += centerY - pos.Y + 1 + schem.OffsetY;
            if (pos.Y <= 0)
            {
                return(null);
            }

            // Ensure not floating on water
            tmpPos.Set(pos.X - widthHalf, pos.Y - 1, pos.Z - lengthHalf);
            if (blockAccessor.GetBlock(tmpPos).IsLiquid())
            {
                return(null);
            }

            tmpPos.Set(pos.X + widthHalf, pos.Y - 1, pos.Z - lengthHalf);
            if (blockAccessor.GetBlock(tmpPos).IsLiquid())
            {
                return(null);
            }

            tmpPos.Set(pos.X - widthHalf, pos.Y - 1, pos.Z + lengthHalf);
            if (blockAccessor.GetBlock(tmpPos).IsLiquid())
            {
                return(null);
            }

            tmpPos.Set(pos.X + widthHalf, pos.Y - 1, pos.Z + lengthHalf);
            if (blockAccessor.GetBlock(tmpPos).IsLiquid())
            {
                return(null);
            }

            // Ensure not submerged in water
            tmpPos.Set(pos.X - widthHalf, pos.Y, pos.Z - lengthHalf);
            if (blockAccessor.GetBlock(tmpPos).IsLiquid())
            {
                return(null);
            }

            tmpPos.Set(pos.X + widthHalf, pos.Y, pos.Z - lengthHalf);
            if (blockAccessor.GetBlock(tmpPos).IsLiquid())
            {
                return(null);
            }

            tmpPos.Set(pos.X - widthHalf, pos.Y, pos.Z + lengthHalf);
            if (blockAccessor.GetBlock(tmpPos).IsLiquid())
            {
                return(null);
            }

            tmpPos.Set(pos.X + widthHalf, pos.Y, pos.Z + lengthHalf);
            if (blockAccessor.GetBlock(tmpPos).IsLiquid())
            {
                return(null);
            }



            tmpPos.Set(pos.X - widthHalf, pos.Y + 1, pos.Z - lengthHalf);
            if (blockAccessor.GetBlock(tmpPos).IsLiquid())
            {
                return(null);
            }

            tmpPos.Set(pos.X + widthHalf, pos.Y + 1, pos.Z - lengthHalf);
            if (blockAccessor.GetBlock(tmpPos).IsLiquid())
            {
                return(null);
            }

            tmpPos.Set(pos.X - widthHalf, pos.Y + 1, pos.Z + lengthHalf);
            if (blockAccessor.GetBlock(tmpPos).IsLiquid())
            {
                return(null);
            }

            tmpPos.Set(pos.X + widthHalf, pos.Y + 1, pos.Z + lengthHalf);
            if (blockAccessor.GetBlock(tmpPos).IsLiquid())
            {
                return(null);
            }

            if (!TestUndergroundCheckPositions(blockAccessor, pos, schematic.UndergroundCheckPositions))
            {
                return(null);
            }

            if (isStructureAt(pos, worldForCollectibleResolve))
            {
                return(null);
            }

            return(schematic);
        }
Exemplo n.º 2
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;
                    }
                }
            }
        }
Exemplo n.º 3
0
        private bool asyncParticleSpawn(float dt, IAsyncParticleManager manager)
        {
            WeatherDataSnapshot weatherData = ws.BlendedWeatherData;

            ClimateCondition conds = ws.clientClimateCond;

            if (conds == null || !ws.playerChunkLoaded)
            {
                return(true);
            }

            EntityPos plrPos        = capi.World.Player.Entity.Pos;
            float     precIntensity = conds.Rainfall;

            float plevel = precIntensity * capi.Settings.Int["particleLevel"] / 100f;

            float dryness = GameMath.Clamp(1 - precIntensity, 0, 1);

            tmpPos.Set((int)plrPos.X, (int)plrPos.Y, (int)plrPos.Z);

            precIntensity = Math.Max(0, precIntensity - (float)Math.Max(0, (plrPos.Y - capi.World.SeaLevel - 5000) / 10000f));


            EnumPrecipitationType precType = weatherData.BlendedPrecType;

            if (precType == EnumPrecipitationType.Auto)
            {
                precType = conds.Temperature < weatherData.snowThresholdTemp ? EnumPrecipitationType.Snow : EnumPrecipitationType.Rain;
            }

            int rainYPos = capi.World.BlockAccessor.GetRainMapHeightAt((int)particlePos.X, (int)particlePos.Z);

            particlePos.Set(capi.World.Player.Entity.Pos.X, rainYPos, capi.World.Player.Entity.Pos.Z);


            int onwaterSplashParticleColor = capi.World.ApplyColorMapOnRgba(lblock.ClimateColorMapResolved, lblock.SeasonColorMapResolved, ColorUtil.WhiteArgb, (int)particlePos.X, (int)particlePos.Y, (int)particlePos.Z, false);

            byte[] col = ColorUtil.ToBGRABytes(onwaterSplashParticleColor);
            onwaterSplashParticleColor = ColorUtil.ToRgba(94, col[0], col[1], col[2]);

            centerPos.Set((int)particlePos.X, 0, (int)particlePos.Z);
            for (int lx = 0; lx < 16; lx++)
            {
                int dx = (lx - 8) * 4;
                for (int lz = 0; lz < 16; lz++)
                {
                    int dz = (lz - 8) * 4;

                    lowResRainHeightMap[lx, lz] = capi.World.BlockAccessor.GetRainMapHeightAt(centerPos.X + dx, centerPos.Z + dz);
                }
            }



            parentVeloSnow.X = -Math.Max(0, weatherData.curWindSpeed.X / 2 - 0.15f);
            parentVeloSnow.Y = 0;

            parentVeloSnow.Z = 0;

            // Don't spawn if wind speed below 50% or if the player is 10 blocks above ground
            if (weatherData.curWindSpeed.X > 0.5f) // && particlePos.Y - rainYPos < 10
            {
                SpawnDustParticles(manager, weatherData, plrPos, dryness, onwaterSplashParticleColor);
            }

            particlePos.Y = capi.World.Player.Entity.Pos.Y;

            if (precIntensity <= 0.02)
            {
                return(true);
            }

            if (precType == EnumPrecipitationType.Hail)
            {
                SpawnHailParticles(manager, weatherData, conds, plrPos, plevel);
                return(true);
            }


            if (precType == EnumPrecipitationType.Rain)
            {
                SpawnRainParticles(manager, weatherData, conds, plrPos, plevel, onwaterSplashParticleColor);
            }


            if (precType == EnumPrecipitationType.Snow)
            {
                SpawnSnowParticles(manager, weatherData, conds, plrPos, plevel);
            }

            return(true);
        }
Exemplo n.º 4
0
        private void GrowStalk(IBlockAccessor blockAccessor, BlockPos upos, float sizeModifier, float vineGrowthChance)
        {
            Block block  = this;
            int   height = 7 + rand.Next(4);
            int   nextSegmentAtHeight = height / 3;

            BlockPos npos = upos.Copy();

            for (int i = 0; i < height; i++)
            {
                if (!blockAccessor.GetBlock(upos).IsReplacableBy(block))
                {
                    break;
                }

                blockAccessor.SetBlock(block.BlockId, upos);

                if (nextSegmentAtHeight <= i)
                {
                    block = ((BlockBamboo)block).NextSegment(blockAccessor);
                    nextSegmentAtHeight += height / 3;
                }

                if (block == null)
                {
                    break;
                }

                if (block == greenSeg3 || block == brownSeg3)
                {
                    foreach (BlockFacing facing in BlockFacing.ALLFACES)
                    {
                        float chanceFac = facing == BlockFacing.UP ? 0 : 0.25f;

                        if (rand.NextDouble() > chanceFac)
                        {
                            npos.Set(upos.X + facing.Normali.X, upos.Y + facing.Normali.Y, upos.Z + facing.Normali.Z);

                            if (blockAccessor.GetBlock(npos).Replaceable >= leaves.Replaceable)
                            {
                                blockAccessor.SetBlock(leaves.BlockId, npos);
                            }
                            else
                            {
                                continue;
                            }

                            foreach (BlockFacing facing2 in BlockFacing.ALLFACES)
                            {
                                if (rand.NextDouble() > 0.5)
                                {
                                    npos.Set(upos.X + facing.Normali.X + facing2.Normali.X, upos.Y + facing.Normali.Y + facing2.Normali.Y, upos.Z + facing.Normali.Z + facing2.Normali.Z);

                                    if (blockAccessor.GetBlock(npos).Replaceable >= leaves.Replaceable)
                                    {
                                        blockAccessor.SetBlock(leaves.BlockId, npos);
                                    }

                                    break;
                                }
                            }
                        }
                    }
                }

                upos.Up();
            }
        }
Exemplo n.º 5
0
        void ConvertPit()
        {
            Dictionary <BlockPos, Vec2i> quantityPerColumn = new Dictionary <BlockPos, Vec2i>();

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

            bfsQueue.Enqueue(pos);

            int maxHalfSize     = 6;
            int firewoodBlockId = api.World.GetBlock(new AssetLocation("firewoodpile")).BlockId;

            Vec2i curQuantityAndYPos = new Vec2i();

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

                BlockPos bposGround = bpos.Copy();
                bposGround.Y = 0;

                if (quantityPerColumn.TryGetValue(bposGround, out curQuantityAndYPos))
                {
                    curQuantityAndYPos.Y = Math.Min(curQuantityAndYPos.Y, bpos.Y);
                }
                else
                {
                    curQuantityAndYPos = quantityPerColumn[bposGround] = new Vec2i(0, bpos.Y);
                }

                BlockEntityFirewoodPile be = api.World.BlockAccessor.GetBlockEntity(bpos) as BlockEntityFirewoodPile;
                if (be != null)
                {
                    curQuantityAndYPos.X += be.OwnStackSize;
                }
                api.World.BlockAccessor.SetBlock(0, bpos);

                foreach (BlockFacing facing in BlockFacing.ALLFACES)
                {
                    BlockPos npos   = bpos.AddCopy(facing);
                    Block    nBlock = api.World.BlockAccessor.GetBlock(npos);

                    // 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);
                    }
                }
            }


            BlockPos lpos = new BlockPos();

            foreach (var val in quantityPerColumn)
            {
                lpos.Set(val.Key.X, val.Value.Y, val.Key.Z);
                int logQuantity      = val.Value.X;
                int charCoalQuantity = (int)(logQuantity * (0.125f + (float)api.World.Rand.NextDouble() / 8));

                while (charCoalQuantity > 0)
                {
                    Block charcoalBlock = api.World.GetBlock(new AssetLocation("charcoalpile-" + GameMath.Clamp(charCoalQuantity, 1, 8)));
                    api.World.BlockAccessor.SetBlock(charcoalBlock.BlockId, lpos);
                    charCoalQuantity -= 8;
                    lpos.Up();
                }
            }

            api.World.BlockAccessor.SetBlock(0, pos);
        }
Exemplo n.º 6
0
        private void updateSounds(float dt)
        {
            float targetRainVolumeLeafy    = 0;
            float targetRainVolumeLeafless = 0;
            float targetHailVolume         = 0;
            float targetTrembleVolume      = 0;

            float targetRainPitch = 1;
            float targetHailPitch = 1;

            WeatherDataSnapshot weatherData = weatherSys.BlendedWeatherData;

            if (searchComplete)
            {
                EntityPlayer eplr = capi.World.Player.Entity;
                plrPos.Set((int)eplr.Pos.X, (int)eplr.Pos.Y, (int)eplr.Pos.Z);
                searchComplete = false;

                TyronThreadPool.QueueTask(() =>
                {
                    float val           = (float)Math.Pow(Math.Max(0, (capi.World.BlockAccessor.GetDistanceToRainFall(plrPos, 12, 4) - 2) / 10f), 2);
                    roomVolumePitchLoss = GameMath.Clamp(val, 0, 1);
                    searchComplete      = true;
                });
            }

            EnumPrecipitationType precType = weatherData.BlendedPrecType;

            if (precType == EnumPrecipitationType.Auto)
            {
                precType = weatherSys.clientClimateCond?.Temperature < weatherData.snowThresholdTemp ? EnumPrecipitationType.Snow : EnumPrecipitationType.Rain;
            }

            float nearbyLeaviness = GameMath.Clamp(GlobalConstants.CurrentNearbyRelLeavesCountClient * 60, 0, 1);

            ClimateCondition conds = weatherSys.clientClimateCond;

            if (conds.Rainfall > 0)
            {
                if (precType == EnumPrecipitationType.Rain || weatherSys.clientClimateCond.Temperature < weatherData.snowThresholdTemp)
                {
                    targetRainVolumeLeafy = nearbyLeaviness * GameMath.Clamp(conds.Rainfall * 2f - Math.Max(0, 2f * (weatherData.snowThresholdTemp - weatherSys.clientClimateCond.Temperature)), 0, 1);
                    targetRainVolumeLeafy = GameMath.Max(0, targetRainVolumeLeafy - roomVolumePitchLoss);

                    targetRainVolumeLeafless = Math.Max(0.3f, 1 - nearbyLeaviness) * GameMath.Clamp(conds.Rainfall * 2f - Math.Max(0, 2f * (weatherData.snowThresholdTemp - weatherSys.clientClimateCond.Temperature)), 0, 1);
                    targetRainVolumeLeafless = GameMath.Max(0, targetRainVolumeLeafless - roomVolumePitchLoss);

                    targetRainPitch = Math.Max(0.7f, 1.25f - conds.Rainfall * 0.7f);
                    targetRainPitch = Math.Max(0, targetRainPitch - roomVolumePitchLoss / 4f);

                    targetTrembleVolume = GameMath.Clamp(conds.Rainfall * 1.6f - 0.8f - roomVolumePitchLoss * 0.25f, 0, 1);

                    if (!rainSoundsOn && (targetRainVolumeLeafy > 0.01 || targetRainVolumeLeafless > 0.01))
                    {
                        for (int i = 0; i < rainSoundsLeafless.Length; i++)
                        {
                            rainSoundsLeafless[i]?.Start();
                        }
                        for (int i = 0; i < rainSoundsLeafy.Length; i++)
                        {
                            rainSoundsLeafy[i]?.Start();
                        }

                        lowTrembleSound?.Start();
                        rainSoundsOn = true;

                        curRainPitch = targetRainPitch;
                    }

                    if (capi.World.Player.Entity.IsEyesSubmerged())
                    {
                        curRainPitch              = targetRainPitch / 2;
                        targetRainVolumeLeafy    *= 0.75f;
                        targetRainVolumeLeafless *= 0.75f;
                    }
                }

                if (precType == EnumPrecipitationType.Hail)
                {
                    targetHailVolume = GameMath.Clamp(conds.Rainfall * 2f - roomVolumePitchLoss, 0, 1);
                    targetHailVolume = GameMath.Max(0, targetHailVolume - roomVolumePitchLoss);

                    targetHailPitch = Math.Max(0.7f, 1.25f - conds.Rainfall * 0.7f);
                    targetHailPitch = Math.Max(0, targetHailPitch - roomVolumePitchLoss / 4f);

                    if (!hailSoundsOn && targetHailVolume > 0.01)
                    {
                        hailSound?.Start();
                        hailSoundsOn = true;
                        curHailPitch = targetHailPitch;
                    }
                }
            }


            curRainVolumeLeafy    += (targetRainVolumeLeafy - curRainVolumeLeafy) * dt / 2;
            curRainVolumeLeafless += (targetRainVolumeLeafless - curRainVolumeLeafless) * dt / 2;

            curTrembleVolume += (targetTrembleVolume - curTrembleVolume) * dt;
            curHailVolume    += (targetHailVolume - curHailVolume) * dt;

            curHailPitch += (targetHailPitch - curHailPitch) * dt;
            curRainPitch += (targetRainPitch - curRainPitch) * dt;



            if (rainSoundsOn)
            {
                for (int i = 0; i < rainSoundsLeafless.Length; i++)
                {
                    rainSoundsLeafless[i]?.SetVolume(curRainVolumeLeafless);
                    rainSoundsLeafless[i]?.SetPitch(curRainPitch);
                }
                for (int i = 0; i < rainSoundsLeafy.Length; i++)
                {
                    rainSoundsLeafy[i]?.SetVolume(curRainVolumeLeafy);
                    rainSoundsLeafy[i]?.SetPitch(curRainPitch);
                }

                lowTrembleSound?.SetVolume(curTrembleVolume);
            }
            if (hailSoundsOn)
            {
                hailSound?.SetVolume(curHailVolume);
                hailSound?.SetPitch(curHailPitch);
            }


            if (curRainVolumeLeafless < 0.01 && curRainVolumeLeafy < 0.01)
            {
                for (int i = 0; i < rainSoundsLeafless.Length; i++)
                {
                    rainSoundsLeafless[i]?.Stop();
                }
                for (int i = 0; i < rainSoundsLeafy.Length; i++)
                {
                    rainSoundsLeafy[i]?.Stop();
                }
                rainSoundsOn = false;
            }

            if (curHailVolume < 0.01)
            {
                hailSound?.Stop();
                hailSoundsOn = false;
            }



            float wstr = (1 - roomVolumePitchLoss) * weatherData.curWindSpeed.X - 0.3f;

            if (wstr > 0.03f || curWindVolumeLeafy > 0.01f || curWindVolumeLeafless > 0.01f)
            {
                if (!windSoundsOn)
                {
                    windSoundLeafy?.Start();
                    windSoundLeafless?.Start();
                    windSoundsOn = true;
                }

                float targetVolumeLeafy    = nearbyLeaviness * 1.2f * wstr;
                float targetVolumeLeafless = (1 - nearbyLeaviness) * 1.2f * wstr;

                curWindVolumeLeafy    += (targetVolumeLeafy - curWindVolumeLeafy) * dt;
                curWindVolumeLeafless += (targetVolumeLeafless - curWindVolumeLeafless) * dt;

                windSoundLeafy?.SetVolume(curWindVolumeLeafy);
                windSoundLeafless?.SetVolume(curWindVolumeLeafless);
            }
            else
            {
                if (windSoundsOn)
                {
                    windSoundLeafy?.Stop();
                    windSoundLeafless?.Stop();
                    windSoundsOn = false;
                }
            }
        }
Exemplo n.º 7
0
        public override void OnGameTick(float deltaTime)
        {
            accum         += deltaTime;
            slowaccum     += deltaTime;
            veryslowaccum += deltaTime;

            plrpos.Set((int)entity.Pos.X, (int)entity.Pos.Y, (int)entity.Pos.Z);

            if (veryslowaccum > 10 && damagingFreezeHours > 3)
            {
                if (api.World.Config.GetString("harshWinters").ToBool(true))
                {
                    entity.ReceiveDamage(new DamageSource()
                    {
                        DamageTier = 0, Source = EnumDamageSource.Weather, Type = EnumDamageType.Frost
                    }, 0.2f);
                }

                veryslowaccum = 0;

                if (eagent.Controls.Sprint)
                {
                    sprinterCounter = GameMath.Clamp(sprinterCounter + 1, 0, 10);
                }
                else
                {
                    sprinterCounter = GameMath.Clamp(sprinterCounter - 1, 0, 10);
                }
            }

            if (slowaccum > 3)
            {
                Room room = api.ModLoader.GetModSystem <RoomRegistry>().GetRoomForPosition(plrpos);
                inEnclosedRoom         = room.ExitCount == 0 || room.SkylightCount < room.NonSkylightCount;
                nearHeatSourceStrength = 0;

                api.World.BlockAccessor.WalkBlocks(plrpos.AddCopy(-3, -3, -3), plrpos.AddCopy(3, 3, 3), (block, pos) =>
                {
                    BlockBehavior src;
                    if ((src = block.GetBehavior(typeof(IHeatSource), true)) != null)
                    {
                        nearHeatSourceStrength += (src as IHeatSource).GetHeatStrength(api.World, pos, plrpos);
                    }
                });

                slowaccum = 0;

                updateWearableConditions();

                entity.WatchedAttributes.MarkPathDirty("bodyTemp");
            }

            if (accum > 1)
            {
                IPlayer plr = (entity as EntityPlayer)?.Player;
                if (plr?.WorldData.CurrentGameMode == EnumGameMode.Creative || plr?.WorldData.CurrentGameMode == EnumGameMode.Spectator)
                {
                    CurBodyTemperature = NormalBodyTemperature;
                    entity.WatchedAttributes.SetFloat("freezingEffectStrength", 0);
                    return;
                }

                if (plr.Entity.Controls.TriesToMove || plr.Entity.Controls.Jump || plr.Entity.Controls.LeftMouseDown || plr.Entity.Controls.RightMouseDown)
                {
                    lastMoveMs = entity.World.ElapsedMilliseconds;
                }

                ClimateCondition conds = api.World.BlockAccessor.GetClimateAt(plrpos, EnumGetClimateMode.NowValues);
                if (conds == null)
                {
                    return;
                }
                Vec3d windspeed = api.World.BlockAccessor.GetWindSpeedAt(plrpos);

                bool rainExposed = api.World.BlockAccessor.GetRainMapHeightAt(plrpos) <= plrpos.Y;

                Wetness = GameMath.Clamp(
                    Wetness
                    + conds.Rainfall * (rainExposed ? 0.06f : 0) * (conds.Temperature < -1 ? 0.2f : 1) /* Get wet 5 times slower with snow */
                    + (entity.Swimming ? 1 : 0)
                    - (float)Math.Max(0, (api.World.Calendar.TotalHours - LastWetnessUpdateTotalHours) * GameMath.Clamp(nearHeatSourceStrength, 1, 2))
                    , 0, 1);

                LastWetnessUpdateTotalHours = api.World.Calendar.TotalHours;
                accum = 0;

                float sprintBonus   = sprinterCounter / 2f;
                float wetnessDebuff = (float)Math.Max(0, Wetness - 0.1) * 10f;

                // Can bear anything above 10 degrees without clothing, while standing still
                float hereTemperature = conds.Temperature + clothingBonus + sprintBonus - wetnessDebuff;

                float tempDiff = hereTemperature - GameMath.Clamp(hereTemperature, bodyTemperatureResistance, 30);
                // Above 10 degrees, slowly warms up
                if (tempDiff == 0)
                {
                    tempDiff = Math.Max((hereTemperature - bodyTemperatureResistance), 0);
                }

                float ambientTempChange = GameMath.Clamp(tempDiff / 6f, -6, 6);

                tempChange = nearHeatSourceStrength + (inEnclosedRoom ? 1 : -(float)Math.Max((windspeed.Length() - 0.15) * 2, 0) + ambientTempChange);

                bool sleeping = entity.GetBehavior <EntityBehaviorTiredness>()?.IsSleeping == true;
                if (sleeping)
                {
                    if (inEnclosedRoom)
                    {
                        tempChange = GameMath.Clamp(NormalBodyTemperature - CurBodyTemperature, -0.15f, 0.15f);
                    }
                    else if (!rainExposed)
                    {
                        tempChange += GameMath.Clamp(NormalBodyTemperature - CurBodyTemperature, 1f, 1f);
                    }
                }

                float tempUpdateHoursPassed = (float)(api.World.Calendar.TotalHours - BodyTempUpdateTotalHours);
                if (tempUpdateHoursPassed > 0.01)
                {
                    if (tempChange < -0.5 || tempChange > 0)
                    {
                        if (tempChange > 0.5)
                        {
                            tempChange *= 2;                   // Warming up with a firepit is twice as fast, because nobody wants to wait forever
                        }
                        CurBodyTemperature = GameMath.Clamp(CurBodyTemperature + tempChange * tempUpdateHoursPassed, 31, 45);
                    }

                    BodyTempUpdateTotalHours = api.World.Calendar.TotalHours;

                    entity.WatchedAttributes.SetFloat("freezingEffectStrength", GameMath.Clamp((NormalBodyTemperature - CurBodyTemperature) / 4f - 0.5f, 0, 1));

                    if (NormalBodyTemperature - CurBodyTemperature > 4)
                    {
                        damagingFreezeHours += tempUpdateHoursPassed;
                    }
                    else
                    {
                        damagingFreezeHours = 0;
                    }
                }
            }
        }
        private bool asyncParticleSpawn(float dt, IAsyncParticleManager manager)
        {
            WeatherDataSnapshot weatherData = ws.BlendedWeatherData;

            ClimateCondition conds = ws.clientClimateCond;

            if (conds == null || !ws.playerChunkLoaded)
            {
                return(true);
            }

            EntityPos plrPos        = capi.World.Player.Entity.Pos;
            float     precIntensity = conds.Rainfall;

            float plevel = precIntensity * capi.Settings.Int["particleLevel"] / 100f;

            tmpPos.Set((int)plrPos.X, (int)plrPos.Y, (int)plrPos.Z);


            //float plevel = weatherData.PrecIntensity * capi.Settings.Int["particleLevel"] / 100f;

            EnumPrecipitationType precType = weatherData.BlendedPrecType;

            if (precType == EnumPrecipitationType.Auto)
            {
                precType = conds.Temperature < weatherData.snowThresholdTemp ? EnumPrecipitationType.Snow : EnumPrecipitationType.Rain;
            }


            particlePos.Set(capi.World.Player.Entity.Pos.X, capi.World.Player.Entity.Pos.Y, capi.World.Player.Entity.Pos.Z);


            int onwaterSplashParticleColor = capi.World.ApplyColorMapOnRgba(lblock.ClimateColorMapForMap, lblock.SeasonColorMapForMap, ColorUtil.WhiteArgb, (int)particlePos.X, (int)particlePos.Y, (int)particlePos.Z, false);

            byte[] col = ColorUtil.ToBGRABytes(onwaterSplashParticleColor);
            onwaterSplashParticleColor = ColorUtil.ToRgba(94, col[0], col[1], col[2]);

            centerPos.Set((int)particlePos.X, 0, (int)particlePos.Z);
            for (int lx = 0; lx < 16; lx++)
            {
                int dx = (lx - 8) * 4;
                for (int lz = 0; lz < 16; lz++)
                {
                    int dz = (lz - 8) * 4;

                    lowResRainHeightMap[lx, lz] = capi.World.BlockAccessor.GetRainMapHeightAt(centerPos.X + dx, centerPos.Z + dz);
                }
            }


            int rainYPos = capi.World.BlockAccessor.GetRainMapHeightAt((int)particlePos.X, (int)particlePos.Z);


            parentVeloSnow.X = -Math.Max(0, weatherData.curWindSpeed.X / 2 - 0.15f);
            parentVeloSnow.Y = 0;
            parentVeloSnow.Z = 0;

            // Don't spawn if wind speed below 70% or if the player is 10 blocks above ground
            if (weatherData.curWindSpeed.X > 0.7f && particlePos.Y - rainYPos < 10)
            {
                float dx = (float)(plrPos.Motion.X * 40) - 50 * weatherData.curWindSpeed.X;
                float dy = (float)(plrPos.Motion.Y * 40);
                float dz = (float)(plrPos.Motion.Z * 40);

                dustParticles.MinPos.Set(particlePos.X - 40 + dx, particlePos.Y + 15 + dy, particlePos.Z - 40 + dz);
                dustParticles.AddPos.Set(80, -20, 80);
                dustParticles.GravityEffect      = -0.1f - (float)rand.NextDouble() * 0.1f;
                dustParticles.ParticleModel      = EnumParticleModel.Quad;
                dustParticles.LifeLength         = 1f;
                dustParticles.DieOnRainHeightmap = true;
                dustParticles.WindAffectednes    = 8f;
                dustParticles.MinQuantity        = 0;
                dustParticles.AddQuantity        = 6 * (weatherData.curWindSpeed.X - 0.7f);

                dustParticles.MinSize = 0.1f;
                dustParticles.MaxSize = 0.4f;

                dustParticles.MinVelocity.Set(-0.025f + 8 * weatherData.curWindSpeed.X, -0.2f, -0.025f);
                dustParticles.AddVelocity.Set(0.05f + 4 * weatherData.curWindSpeed.X, 0.05f, 0.05f);


                for (int i = 0; i < 6; i++)
                {
                    double px = particlePos.X + dx + (rand.NextDouble() * rand.NextDouble()) * 60 * (1 - 2 * rand.Next(2));
                    double pz = particlePos.Z + dz + (rand.NextDouble() * rand.NextDouble()) * 60 * (1 - 2 * rand.Next(2));

                    int   py    = capi.World.BlockAccessor.GetRainMapHeightAt((int)px, (int)pz);
                    Block block = capi.World.BlockAccessor.GetBlock((int)px, py, (int)pz);
                    if (block.IsLiquid())
                    {
                        continue;
                    }

                    tmpPos.Set((int)px, py, (int)pz);
                    dustParticles.Color  = ColorUtil.ReverseColorBytes(block.GetColor(capi, tmpPos));
                    dustParticles.Color |= 255 << 24;

                    manager.Spawn(dustParticles);
                }
            }


            if (precIntensity <= 0.02)
            {
                return(true);
            }

            if (precType == EnumPrecipitationType.Hail)
            {
                float dx = (float)(plrPos.Motion.X * 40) - 4 * weatherData.curWindSpeed.X;
                float dy = (float)(plrPos.Motion.Y * 40);
                float dz = (float)(plrPos.Motion.Z * 40);

                hailParticle.MinPos.Set(particlePos.X + dx, particlePos.Y + 15 + dy, particlePos.Z + dz);

                hailParticle.MinSize = 0.3f * (0.5f + conds.Rainfall); // * weatherData.PrecParticleSize;
                hailParticle.MaxSize = 1f * (0.5f + conds.Rainfall);   // * weatherData.PrecParticleSize;
                //hailParticle.AddPos.Set(80, 5, 80);

                hailParticle.Color = ColorUtil.ToRgba(220, 210, 230, 255);

                hailParticle.MinQuantity = 100 * plevel;
                hailParticle.AddQuantity = 25 * plevel;
                hailParticle.MinVelocity.Set(-0.025f + 7.5f * weatherData.curWindSpeed.X, -5f, -0.025f);
                hailParticle.AddVelocity.Set(0.05f + 7.5f * weatherData.curWindSpeed.X, 0.05f, 0.05f);

                manager.Spawn(hailParticle);
                return(true);
            }


            if (precType == EnumPrecipitationType.Rain)
            {
                float dx = (float)(plrPos.Motion.X * 80);
                float dy = (float)(plrPos.Motion.Y * 80);
                float dz = (float)(plrPos.Motion.Z * 80);

                rainParticle.MinPos.Set(particlePos.X - 30 + dx, particlePos.Y + 15 + dy, particlePos.Z - 30 + dz);
                rainParticle.WithTerrainCollision = false;
                rainParticle.MinQuantity          = 1000 * plevel;
                rainParticle.LifeLength           = 1f;
                rainParticle.AddQuantity          = 25 * plevel;
                rainParticle.MinSize = 0.15f * (0.5f + conds.Rainfall); // * weatherData.PrecParticleSize;
                rainParticle.MaxSize = 0.22f * (0.5f + conds.Rainfall); // weatherData.PrecParticleSize;
                rainParticle.Color   = rainParticleColor;

                rainParticle.MinVelocity.Set(-0.025f + 8 * weatherData.curWindSpeed.X, -10f, -0.025f);
                rainParticle.AddVelocity.Set(0.05f + 8 * weatherData.curWindSpeed.X, 0.05f, 0.05f);

                manager.Spawn(rainParticle);


                splashParticles.MinVelocity        = new Vec3f(-1f, 3, -1f);
                splashParticles.AddVelocity        = new Vec3f(2, 0, 2);
                splashParticles.LifeLength         = 0.1f;
                splashParticles.MinSize            = 0.07f * (0.5f + 0.65f * conds.Rainfall); // weatherData.PrecParticleSize;
                splashParticles.MaxSize            = 0.2f * (0.5f + 0.65f * conds.Rainfall);  // weatherData.PrecParticleSize;
                splashParticles.ShouldSwimOnLiquid = true;
                splashParticles.Color = rainParticleColor;

                float cnt = 100 * plevel;

                for (int i = 0; i < cnt; i++)
                {
                    double px = particlePos.X + (rand.NextDouble() * rand.NextDouble()) * 60 * (1 - 2 * rand.Next(2));
                    double pz = particlePos.Z + (rand.NextDouble() * rand.NextDouble()) * 60 * (1 - 2 * rand.Next(2));

                    int py = capi.World.BlockAccessor.GetRainMapHeightAt((int)px, (int)pz);

                    Block block = capi.World.BlockAccessor.GetBlock((int)px, py, (int)pz);

                    if (block.IsLiquid())
                    {
                        splashParticles.MinPos.Set(px, py + block.TopMiddlePos.Y - 1 / 8f, pz);
                        splashParticles.AddVelocity.Y = 1.5f;
                        splashParticles.LifeLength    = 0.17f;
                        splashParticles.Color         = onwaterSplashParticleColor;
                    }
                    else
                    {
                        double b  = 0.75 + 0.25 * rand.NextDouble();
                        int    ca = 230 - rand.Next(100);
                        int    cr = (int)(((rainParticleColor >> 16) & 0xff) * b);
                        int    cg = (int)(((rainParticleColor >> 8) & 0xff) * b);
                        int    cb = (int)(((rainParticleColor >> 0) & 0xff) * b);

                        splashParticles.Color         = (ca << 24) | (cr << 16) | (cg << 8) | cb;
                        splashParticles.AddVelocity.Y = 0f;
                        splashParticles.LifeLength    = 0.1f;
                        splashParticles.MinPos.Set(px, py + block.TopMiddlePos.Y + 0.05, pz);
                    }

                    manager.Spawn(splashParticles);
                }
            }

            if (precType == EnumPrecipitationType.Snow)
            {
                float wetness = 2.5f * GameMath.Clamp(ws.clientClimateCond.Temperature + 1, 0, 4) / 4f;

                float dx = (float)(plrPos.Motion.X * 40) - (30 - 9 * wetness) * weatherData.curWindSpeed.X;
                float dy = (float)(plrPos.Motion.Y * 40);
                float dz = (float)(plrPos.Motion.Z * 40);

                snowParticle.MinVelocity.Set(-0.5f + 5 * weatherData.curWindSpeed.X, -1f, -0.5f);
                snowParticle.AddVelocity.Set(1f + 5 * weatherData.curWindSpeed.X, 0.05f, 1f);
                snowParticle.Color = ColorUtil.ToRgba(255, 255, 255, 255);

                snowParticle.MinQuantity       = 90 * plevel * (1 + wetness / 3);
                snowParticle.AddQuantity       = 15 * plevel * (1 + wetness / 3);
                snowParticle.ParentVelocity    = parentVeloSnow;
                snowParticle.ShouldDieInLiquid = true;

                snowParticle.LifeLength    = Math.Max(1f, 4f - wetness);
                snowParticle.Color         = ColorUtil.ColorOverlay(ColorUtil.ToRgba(255, 255, 255, 255), rainParticle.Color, wetness / 4f);
                snowParticle.GravityEffect = 0.005f * (1 + 20 * wetness);
                snowParticle.MinSize       = 0.1f * conds.Rainfall;                 // weatherData.PrecParticleSize;
                snowParticle.MaxSize       = 0.3f * conds.Rainfall / (1 + wetness); // weatherData.PrecParticleSize / (1 + wetness);

                float hrange = 40;
                float vrange = 20;
                snowParticle.MinPos.Set(particlePos.X - hrange + dx, particlePos.Y + vrange + dy, particlePos.Z - hrange + dz);
                snowParticle.AddPos.Set(2 * hrange + dx, -0.66f * vrange + dy, 2 * hrange + dz);

                manager.Spawn(snowParticle);
            }

            return(true);
        }
Exemplo n.º 9
0
        public override bool TryPlaceBlockForWorldGen(IBlockAccessor blAcc, BlockPos pos, BlockFacing onBlockFace, LCGRandom worldgenRand)
        {
            int   cnt          = 2 + worldgenRand.NextInt(25);
            float depth        = GameMath.Sqrt(GameMath.Sqrt(cnt));
            float craterRadius = GameMath.Sqrt(cnt) * 1.25f;

            // Look for even or downwards curved ground
            if (pos.Y > 250 ||
                !IsSolid(blAcc, pos.X, pos.Y - 3, pos.Z) ||
                !IsSolid(blAcc, pos.X, pos.Y - (int)depth, pos.Z) ||
                !IsSolid(blAcc, pos.X + (int)craterRadius, pos.Y - 1, pos.Z) ||
                !IsSolid(blAcc, pos.X - (int)craterRadius, pos.Y - 1, pos.Z) ||
                !IsSolid(blAcc, pos.X, pos.Y - 1, pos.Z - (int)craterRadius) ||
                !IsSolid(blAcc, pos.X, pos.Y - 1, pos.Z + (int)craterRadius)
                )
            {
                return(false);
            }

            int y1 = blAcc.GetTerrainMapheightAt(tmpPos.Set(pos.X - 5, pos.Y, pos.Z));
            int y2 = blAcc.GetTerrainMapheightAt(tmpPos.Set(pos.X + 5, pos.Y, pos.Z));
            int y3 = blAcc.GetTerrainMapheightAt(tmpPos.Set(pos.X - 0, pos.Y, pos.Z + 5));
            int y4 = blAcc.GetTerrainMapheightAt(tmpPos.Set(pos.X - 0, pos.Y, pos.Z - 5));

            if ((GameMath.Max(y1, y2, y3, y4) - GameMath.Min(y1, y2, y3, y4)) > 4)
            {
                return(false);
            }



            tmpPos = tmpPos.Set(pos.X, pos.Y - (int)depth - 2, pos.Z);
            while (cnt-- > 0)
            {
                tmpPos.X += worldgenRand.NextInt(3) == 0 ? (worldgenRand.NextInt(3) - 1) : 0;
                tmpPos.Y += worldgenRand.NextInt(8) == 0 ? (worldgenRand.NextInt(3) - 1) : 0;
                tmpPos.Z += worldgenRand.NextInt(3) == 0 ? (worldgenRand.NextInt(3) - 1) : 0;

                blAcc.SetBlock(this.BlockId, tmpPos);
            }



            int sueviteBlockId      = api.World.GetBlock(new AssetLocation("rock-suevite")).BlockId;
            int fragmentBlockId     = api.World.GetBlock(new AssetLocation("loosestones-meteorite-iron-free")).BlockId;
            int looseSueviteBlockId = api.World.GetBlock(new AssetLocation("loosestones-suevite-free")).BlockId;

            float impactRockRadius = craterRadius * 1.2f;
            int   range            = (int)Math.Ceiling(impactRockRadius);
            int   chunksize        = api.World.BlockAccessor.ChunkSize;
            Vec2i vecTmp           = new Vec2i();

            // 1. Generate a basin of suevite and lower terrain
            for (int dx = -range; dx <= range; dx++)
            {
                for (int dz = -range; dz <= range; dz++)
                {
                    float distImpactRockEdge = (dx * dx + dz * dz) / (impactRockRadius * impactRockRadius);
                    if (distImpactRockEdge > 1)
                    {
                        continue;
                    }

                    tmpPos.X = pos.X + dx;
                    tmpPos.Z = pos.Z + dz;
                    int surfaceY = blAcc.GetTerrainMapheightAt(tmpPos);
                    tmpPos.Y = surfaceY - (int)depth;

                    vecTmp.X = tmpPos.X / chunksize;
                    vecTmp.Y = tmpPos.Z / chunksize;
                    IMapChunk mapchunk = blAcc.GetMapChunk(vecTmp);


                    float q = 3 * Math.Max(0, 2 * (1 - distImpactRockEdge) - 0.2f);
                    tmpPos.Y -= (int)q + 1;


                    while (q > 0)
                    {
                        if (q < 1 && worldgenRand.NextDouble() > q)
                        {
                            break;
                        }

                        Block block = blAcc.GetBlock(tmpPos);

                        if (block != this && block.BlockMaterial == EnumBlockMaterial.Stone)
                        {
                            blAcc.SetBlock(sueviteBlockId, tmpPos);
                        }
                        q--;
                        tmpPos.Y++;
                    }

                    float distToCraterEdge = (dx * dx + dz * dz) / (craterRadius * craterRadius) + (float)worldgenRand.NextDouble() * 0.1f;
                    if (distToCraterEdge > 1)
                    {
                        continue;
                    }

                    q = depth * (1 - distToCraterEdge);

                    tmpPos.Y = surfaceY;
                    Block surfaceblock      = blAcc.GetBlock(tmpPos);
                    Block abovesurfaceblock = blAcc.GetBlock(tmpPos.X, tmpPos.Y + 1, tmpPos.Z);

                    for (int i = -1; i <= (int)q; i++)
                    {
                        tmpPos.Y = surfaceY - i;
                        int id = i == (int)q ? surfaceblock.BlockId : 0;

                        Block bblock = blAcc.GetBlock(tmpPos);
                        if (!bblock.IsLiquid())
                        {
                            blAcc.SetBlock(id, tmpPos);
                        }
                    }

                    mapchunk.WorldGenTerrainHeightMap[(tmpPos.Z % chunksize) * chunksize + (tmpPos.X % chunksize)] -= (ushort)q;

                    tmpPos.Y = blAcc.GetTerrainMapheightAt(tmpPos) + 1;

                    blAcc.SetBlock(abovesurfaceblock.BlockId, tmpPos);
                }
            }

            int quantityFragments = 0;

            if (worldgenRand.NextInt(10) == 0)
            {
                quantityFragments = worldgenRand.NextInt(10);
            }
            else if (worldgenRand.NextInt(5) == 0)
            {
                quantityFragments = worldgenRand.NextInt(5);
            }

            while (quantityFragments-- > 0)
            {
                tmpPos.Set(
                    pos.X + (worldgenRand.NextInt(11) + worldgenRand.NextInt(11)) / 2 - 5,
                    0,
                    pos.Z + (worldgenRand.NextInt(11) + worldgenRand.NextInt(11)) / 2 - 5
                    );
                tmpPos.Y = blAcc.GetTerrainMapheightAt(tmpPos) + 1;

                if (!blAcc.GetBlock(tmpPos.X, tmpPos.Y - 1, tmpPos.Z).SideSolid[BlockFacing.UP.Index])
                {
                    continue;
                }

                if (worldgenRand.NextDouble() < 0.3)
                {
                    blAcc.SetBlock(fragmentBlockId, tmpPos);
                }
                else
                {
                    blAcc.SetBlock(looseSueviteBlockId, tmpPos);
                }
            }

            //blAcc.SetBlock(61, pos.AddCopy(0, 20, 0));


            return(true);
        }
Exemplo n.º 10
0
        private void OnChunkColumnGen(IServerChunk[] chunks, int chunkX, int chunkZ)
        {
            if (!TerraGenConfig.GenerateStructures)
            {
                return;
            }

            IMapRegion region = chunks[0].MapChunk.MapRegion;

            IntMap forestMap  = region.ForestMap;
            IntMap climateMap = region.ClimateMap;
            int    rlX        = chunkX % regionChunkSize;
            int    rlZ        = chunkZ % regionChunkSize;


            // A region has 16 chunks
            // Size of the forest map is RegionSize / TerraGenConfig.forestMapScale  => 32*16 / 32  = 16 pixel
            // rlX, rlZ goes from 0..16 pixel
            // facF = 16/16 = 1
            // Get 4 pixels for chunkx, chunkz, chunkx+1 and chunkz+1 inside the map
            float facF = (float)forestMap.InnerSize / regionChunkSize;

            forestUpLeft   = forestMap.GetUnpaddedInt((int)(rlX * facF), (int)(rlZ * facF));
            forestUpRight  = forestMap.GetUnpaddedInt((int)(rlX * facF + facF), (int)(rlZ * facF));
            forestBotLeft  = forestMap.GetUnpaddedInt((int)(rlX * facF), (int)(rlZ * facF + facF));
            forestBotRight = forestMap.GetUnpaddedInt((int)(rlX * facF + facF), (int)(rlZ * facF + facF));

            float facC = (float)climateMap.InnerSize / regionChunkSize;

            climateUpLeft   = climateMap.GetUnpaddedInt((int)(rlX * facC), (int)(rlZ * facC));
            climateUpRight  = climateMap.GetUnpaddedInt((int)(rlX * facC + facC), (int)(rlZ * facC));
            climateBotLeft  = climateMap.GetUnpaddedInt((int)(rlX * facC), (int)(rlZ * facC + facC));
            climateBotRight = climateMap.GetUnpaddedInt((int)(rlX * facC + facC), (int)(rlZ * facC + facC));

            heightmap = chunks[0].MapChunk.WorldGenTerrainHeightMap;

            BlockPos pos = new BlockPos();

            for (int i = 0; i < scfg.Structures.Length; i++)
            {
                WorldGenStructure struc  = scfg.Structures[i];
                float             chance = struc.Chance * scfg.ChanceMultiplier;

                while (chance-- > rnd.NextDouble())
                {
                    int dx       = rnd.Next(chunksize);
                    int dz       = rnd.Next(chunksize);
                    int ySurface = heightmap[dz * chunksize + dx];
                    if (ySurface <= 0 || ySurface >= worldheight - 15)
                    {
                        continue;
                    }


                    if (struc.Placement == EnumStructurePlacement.Underground)
                    {
                        if (struc.Depth != null)
                        {
                            pos.Set(chunkX * chunksize + dx, ySurface - (int)struc.Depth.nextFloat(), chunkZ * chunksize + dz);
                        }
                        else
                        {
                            pos.Set(chunkX * chunksize + dx, 8 + rnd.Next(ySurface - 8 - 5), chunkZ * chunksize + dz);
                        }
                    }
                    else
                    {
                        pos.Set(chunkX * chunksize + dx, ySurface, chunkZ * chunksize + dz);
                    }

                    struc.TryGenerate(worldgenBlockAccessor, api.World, pos, climateUpLeft, climateUpRight, climateBotLeft, climateBotRight);
                }
            }
        }
Exemplo n.º 11
0
        protected bool traversable(PathNode node, float stepHeight, int maxFallHeight, Cuboidf entityCollBox, bool isDiagonal, ref float extraCost)
        {
            tmpVec.Set(node.X + centerOffsetX, node.Y, node.Z + centerOffsetZ);

            if (!api.World.CollisionTester.IsColliding(blockAccess, entityCollBox, tmpVec, false))
            {
                // Down ok?
                while (true)
                {
                    tmpPos.Set(node.X, node.Y - 1, node.Z);

                    Block block = blockAccess.GetBlock(tmpPos);
                    if (block.LiquidCode == "lava")
                    {
                        return(false);                            // TODO: Turn into an entityAvoid boolean
                    }
                    if (block.LiquidCode == "water")
                    {
                        extraCost = 5;
                        //node.Y--; - we swim on top
                        break;
                    }

                    tmpVec.Y--;

                    // Do we collide if we go one block down?
                    // Our hitbox size might be >1 and we might collide with a wall only
                    // so also test if there is actually any collision box right below us.

                    // If collision but no collision box below: Can't really wall-walk, so fail
                    // If no collision but hitbox below: I guess we can step on it to continue from here?
                    // If no collision and no hitbox below: Free fall, lets keep searching downwards

                    Cuboidf[] collboxes           = block.GetCollisionBoxes(blockAccess, tmpPos);
                    bool      collidingBlockBelow = collboxes != null && collboxes.Length > 0;

                    if (api.World.CollisionTester.IsColliding(blockAccess, entityCollBox, tmpVec, false))
                    {
                        if (!collidingBlockBelow)
                        {
                            return(false);
                        }

                        extraCost -= (block.WalkSpeedMultiplier - 1) * 8;
                        break;
                    }
                    else
                    {
                        if (collidingBlockBelow)
                        {
                            extraCost -= (block.WalkSpeedMultiplier - 1) * 8;
                            break;
                        }
                    }


                    node.Y--;
                    maxFallHeight--;

                    if (maxFallHeight < 0)
                    {
                        return(false);
                    }
                }

                // Up ok?
                float height = entityCollBox.Height;
                while (height-- > 0)
                {
                    tmpVec.Y++;
                    if (api.World.CollisionTester.IsColliding(blockAccess, entityCollBox, tmpVec, false))
                    {
                        return(false);
                    }
                }

                return(true);
            }
            else
            {
                tmpVec.Set(node.X + centerOffsetX, node.Y + stepHeight, node.Z + centerOffsetZ);
                bool collideAbove = api.World.CollisionTester.GetCollidingCollisionBox(blockAccess, entityCollBox, tmpVec, ref tmpCub, false);

                if (!collideAbove)
                {
                    if (isDiagonal)
                    {
                        tmpPos.Set(node.X, node.Y, node.Z);
                        Block     block     = blockAccess.GetBlock(tmpPos);
                        Cuboidf[] collboxes = block.GetCollisionBoxes(blockAccess, tmpPos);

                        if (collboxes != null && collboxes.Length > 0)
                        {
                            // Ok, can step on this block
                            node.Y++;
                            return(true);
                        }
                    }
                    else
                    {
                        node.Y++;
                        return(true);
                    }
                }
            }


            return(false);
        }
Exemplo n.º 12
0
        public Vec3d loadNextWanderTarget()
        {
            int      tries      = 9;
            Vec4d    bestTarget = null;
            Vec4d    curTarget  = new Vec4d();
            BlockPos tmpPos     = new BlockPos();

            if (FailedConsecutivePathfinds > 10)
            {
                WanderRangeMul = Math.Max(0.1f, WanderRangeMul * 0.9f);
            }
            else
            {
                WanderRangeMul = Math.Min(1, WanderRangeMul * 1.1f);
                if (rand.NextDouble() < 0.05)
                {
                    WanderRangeMul = Math.Min(1, WanderRangeMul * 1.5f);
                }
            }

            float  wRangeMul = WanderRangeMul;
            double dx, dy, dz;

            if (rand.NextDouble() < 0.05)
            {
                wRangeMul *= 3;
            }

            while (tries-- > 0)
            {
                dx = wanderRangeHorizontal.nextFloat() * (rand.Next(2) * 2 - 1) * wRangeMul;
                dy = wanderRangeVertical.nextFloat() * (rand.Next(2) * 2 - 1) * wRangeMul;
                dz = wanderRangeHorizontal.nextFloat() * (rand.Next(2) * 2 - 1) * wRangeMul;

                curTarget.X = entity.ServerPos.X + dx;
                curTarget.Y = entity.ServerPos.Y + dy;
                curTarget.Z = entity.ServerPos.Z + dz;
                curTarget.W = 1;

                Block block;

                block = entity.World.BlockAccessor.GetBlock((int)curTarget.X, (int)curTarget.Y, (int)curTarget.Z);
                if (!block.IsLiquid())
                {
                    curTarget.W = 0;
                }
                else
                {
                    curTarget.W = 1 / (Math.Abs(dy) + 1);   //prefer not too much vertical change when underwater
                }
                //TODO: reject (or de-weight) targets not in direct line of sight (avoiding terrain)


                if (preferredLightLevel != null && curTarget.W != 0)
                {
                    tmpPos.Set((int)curTarget.X, (int)curTarget.Y, (int)curTarget.Z);
                    int lightdiff = Math.Abs((int)preferredLightLevel - entity.World.BlockAccessor.GetLightLevel(tmpPos, EnumLightLevelType.MaxLight));

                    curTarget.W /= Math.Max(1, lightdiff);
                }

                if (bestTarget == null || curTarget.W > bestTarget.W)
                {
                    bestTarget = new Vec4d(curTarget.X, curTarget.Y, curTarget.Z, curTarget.W);
                    if (curTarget.W >= 1.0)
                    {
                        break;                      //have a good enough target, no need for further tries
                    }
                }
            }


            if (bestTarget.W > 0)
            {
                FailedConsecutivePathfinds = Math.Max(FailedConsecutivePathfinds - 3, 0);
                return(bestTarget.XYZ);
            }

            FailedConsecutivePathfinds++;
            return(null);
        }
        public UpdateSnowLayerChunk UpdateSnowLayer(SnowAccumSnapshot sumsnapshot, bool ignoreOldAccum, IServerMapChunk mc, Vec2i chunkPos, IWorldChunk[] chunksCol)
        {
            UpdateSnowLayerChunk updateChunk = new UpdateSnowLayerChunk();
            var layers = ws.GeneralConfig.SnowLayerBlocks;

            int chunkX = chunkPos.X;
            int chunkZ = chunkPos.Y;

            int regionX = (chunkX * chunksize) / regionsize;
            int regionZ = (chunkZ * chunksize) / regionsize;

            int regionBasePosX = regionX * regionsize;
            int regionBasePosZ = regionZ * regionsize;

            BlockPos pos                 = new BlockPos();
            BlockPos placePos            = new BlockPos();
            float    aboveSeaLevelHeight = sapi.World.BlockAccessor.MapSizeY - sapi.World.SeaLevel;

            int[] posIndices = randomShuffles[sapi.World.Rand.Next(randomShuffles.Length)];

            int         prevChunkY = -99999;
            IWorldChunk chunk      = null;

            int maxY = sapi.World.BlockAccessor.MapSizeY - 1;

            for (int i = 0; i < posIndices.Length; i++)
            {
                int posIndex = posIndices[i];
                int posY     = GameMath.Clamp(mc.RainHeightMap[posIndex], 0, maxY);
                int chunkY   = posY / chunksize;

                pos.Set(
                    chunkX * chunksize + posIndex % chunksize,
                    posY,
                    chunkZ * chunksize + posIndex / chunksize
                    );

                if (prevChunkY != chunkY)
                {
                    chunk      = chunksCol?[chunkY] ?? sapi.WorldManager.GetChunk(chunkX, chunkY, chunkZ);
                    prevChunkY = chunkY;
                }
                if (chunk == null)
                {
                    return(null);
                }

                float relx = (pos.X - regionBasePosX) / (float)regionsize;
                float rely = GameMath.Clamp((pos.Y - sapi.World.SeaLevel) / aboveSeaLevelHeight, 0, 1);
                float relz = (pos.Z - regionBasePosZ) / (float)regionsize;


                // What needs to be done here?
                // 1. Get desired snow cover level

                // 2. Get current snow cover level
                //    - Get topmmost block. Is it snow?
                //      - Yes. Use it as reference pos and stuff
                //      - No. Must have no snow, increment pos.Y by 1

                // 3. Compare and place block accordingly
                // Idea: New method Block.UpdateSnowLayer() returns a new block instance if a block change is needed


                // What needs to be done here, take 2
                // We have 3 possible cases per-block
                // 1: We find upside solid block. That means it has no snow on top
                // 2: We find snow. That means below is a solid block.
                // 3: We find some other block: That means we should try to find its snow-covered variant

                // We have the following input data
                // 1. Snow accumulation changes since the last update (usually an in-game hour or 2)
                // 2. A precise snow level value from the position (if not set, load from snowlayer block type) (set to zero if the snowlayer is removed)
                // 3. The current block at position, which is either
                //    - A snow layer: Override with internal level + accum changes
                //    - A solid block: Plase snow on top based on internal level + accum changes
                //    - A snow variantable block: Call the method with the new level


                Block block = chunk.GetLocalLiquidOrBlockAtBlockPos(sapi.World, pos);

                float hereAccum = 0;

                Vec2i vec = new Vec2i(pos.X, pos.Z);
                if (!ignoreOldAccum && !mc.SnowAccum.TryGetValue(vec, out hereAccum))
                {
                    hereAccum = block.GetSnowLevel(pos);
                }

                float nowAccum = hereAccum + sumsnapshot.GetAvgSnowAccumByRegionCorner(relx, rely, relz);

                mc.SnowAccum[vec] = GameMath.Clamp(nowAccum, -1, ws.GeneralConfig.SnowLayerBlocks.Count + 0.6f);

                float hereShouldLevel = nowAccum - GameMath.MurmurHash3Mod(pos.X, 0, pos.Z, 150) / 300f;

                float shouldIndexf = GameMath.Clamp(hereShouldLevel - 1.1f, -1, ws.GeneralConfig.SnowLayerBlocks.Count - 1);
                int   shouldIndex  = shouldIndexf < 0 ? -1 : (int)shouldIndexf;

                placePos.Set(pos.X, Math.Min(pos.Y + 1, sapi.World.BlockAccessor.MapSizeY - 1), pos.Z);
                chunkY = placePos.Y / chunksize;

                if (prevChunkY != chunkY)
                {
                    chunk      = chunksCol?[chunkY] ?? sapi.WorldManager.GetChunk(chunkX, chunkY, chunkZ);
                    prevChunkY = chunkY;
                }
                if (chunk == null)
                {
                    return(null);
                }

                Block upBlock = chunk.GetLocalLiquidOrBlockAtBlockPos(sapi.World, placePos);


                // Case 1: We have a block that can become snow covered (or more snow covered)
                placePos.Set(pos);
                Block newblock = block.GetSnowCoveredVariant(placePos, hereShouldLevel);
                if (newblock != null)
                {
                    if (block.Id != newblock.Id && upBlock.Replaceable > 6000)
                    {
                        updateChunk.SetBlocks[placePos.Copy()] = new BlockIdAndSnowLevel(newblock, hereShouldLevel);
                    }
                }
                // Case 2: We have a solid block that can have snow on top
                else if (block.AllowSnowCoverage(sapi.World, placePos))
                {
                    placePos.Set(pos.X, pos.Y + 1, pos.Z);

                    if (upBlock.Id != 0)
                    {
                        newblock = upBlock.GetSnowCoveredVariant(placePos, hereShouldLevel);
                        if (newblock != null && upBlock.Id != newblock.Id)
                        {
                            updateChunk.SetBlocks[placePos.Copy()] = new BlockIdAndSnowLevel(newblock, hereShouldLevel);
                        }

                        continue;
                    }

                    if (shouldIndex >= 0)
                    {
                        Block toPlaceBlock = layers.GetKeyAtIndex(shouldIndex);
                        updateChunk.SetBlocks[placePos.Copy()] = new BlockIdAndSnowLevel(toPlaceBlock, hereShouldLevel);
                    }
                }
            }


            return(updateChunk);
        }
Exemplo n.º 14
0
        public int[] GenerateChunkImage(Vec2i chunkPos, IMapChunk mc, bool withSnow = true)
        {
            ICoreClientAPI capi = api as ICoreClientAPI;

            //capi.Logger.Notification("GenImg @{0}/{1}", chunkPos.X, chunkPos.Y);

            BlockPos tmpPos   = new BlockPos();
            Vec2i    localpos = new Vec2i();

            // Prefetch chunks
            for (int cy = 0; cy < chunksTmp.Length; cy++)
            {
                chunksTmp[cy] = capi.World.BlockAccessor.GetChunk(chunkPos.X, cy, chunkPos.Y);
                if (chunksTmp[cy] == null)
                {
                    return(null);
                }
            }

            // Prefetch map chunks
            IMapChunk[] mapChunks = new IMapChunk[]
            {
                capi.World.BlockAccessor.GetMapChunk(chunkPos.X - 1, chunkPos.Y - 1),
                capi.World.BlockAccessor.GetMapChunk(chunkPos.X - 1, chunkPos.Y),
                capi.World.BlockAccessor.GetMapChunk(chunkPos.X, chunkPos.Y - 1)
            };

            int[] texDataTmp = new int[chunksize * chunksize];
            for (int i = 0; i < texDataTmp.Length; i++)
            {
                int y  = mc.RainHeightMap[i];
                int cy = y / chunksize;
                if (cy >= chunksTmp.Length)
                {
                    continue;
                }

                MapUtil.PosInt2d(i, chunksize, localpos);
                int lx = localpos.X;
                int lz = localpos.Y;

                float b = 1;
                int   leftTop, rightTop, leftBot;

                IMapChunk leftTopMapChunk = mc;
                IMapChunk rightTopMapChunk = mc;
                IMapChunk leftBotMapChunk = mc;

                int topX   = lx - 1;
                int botX   = lx;
                int leftZ  = lz - 1;
                int rightZ = lz;

                if (topX < 0 && leftZ < 0)
                {
                    leftTopMapChunk  = mapChunks[0];
                    rightTopMapChunk = mapChunks[1];
                    leftBotMapChunk  = mapChunks[2];
                }
                else
                {
                    if (topX < 0)
                    {
                        leftTopMapChunk  = mapChunks[1];
                        rightTopMapChunk = mapChunks[1];
                    }
                    if (leftZ < 0)
                    {
                        leftTopMapChunk = mapChunks[2];
                        leftBotMapChunk = mapChunks[2];
                    }
                }

                topX  = GameMath.Mod(topX, chunksize);
                leftZ = GameMath.Mod(leftZ, chunksize);

                leftTop  = leftTopMapChunk == null ? 0 : Math.Sign(y - leftTopMapChunk.RainHeightMap[leftZ * chunksize + topX]);
                rightTop = rightTopMapChunk == null ? 0 : Math.Sign(y - rightTopMapChunk.RainHeightMap[rightZ * chunksize + topX]);
                leftBot  = leftBotMapChunk == null ? 0 : Math.Sign(y - leftBotMapChunk.RainHeightMap[leftZ * chunksize + botX]);

                float slopeness = (leftTop + rightTop + leftBot);

                if (slopeness > 0)
                {
                    b = 1.18f;
                }
                if (slopeness < 0)
                {
                    b = 0.82f;
                }

                chunksTmp[cy].Unpack();
                int   blockId = chunksTmp[cy].Blocks[MapUtil.Index3d(localpos.X, y % chunksize, localpos.Y, chunksize, chunksize)];
                Block block   = api.World.Blocks[blockId];

                /*if (i == 0)
                 * {
                 *  capi.Logger.Notification("GenImg @{0}/{1}, first block is {2}", chunkPos.X, chunkPos.Y, block.Code);
                 * }*/

                if (!withSnow && block.BlockMaterial == EnumBlockMaterial.Snow)
                {
                    y--;
                    cy = y / chunksize;
                    chunksTmp[cy].Unpack();
                    blockId = chunksTmp[cy].Blocks[MapUtil.Index3d(localpos.X, y % chunksize, localpos.Y, chunksize, chunksize)];
                    block   = api.World.Blocks[blockId];
                }

                tmpPos.Set(chunksize * chunkPos.X + localpos.X, y, chunksize * chunkPos.Y + localpos.Y);

                int avgCol = block.GetColor(capi, tmpPos);
                int rndCol = block.GetRandomColor(capi, tmpPos, BlockFacing.UP);

                // Add a bit of randomness to each pixel
                int col = ColorUtil.ColorOverlay(avgCol, rndCol, 0.2f);

                texDataTmp[i] = ColorUtil.ColorMultiply3Clamped(col, b) | 255 << 24;
            }

            for (int cy = 0; cy < chunksTmp.Length; cy++)
            {
                chunksTmp[cy] = null;
            }

            return(texDataTmp);
        }
Exemplo n.º 15
0
        /// <summary>
        /// Attempts to transform each block as they are placed in directions different from the schematic.
        /// </summary>
        /// <param name="worldForResolve"></param>
        /// <param name="aroundOrigin"></param>
        /// <param name="angle"></param>
        /// <param name="flipAxis"></param>
        public virtual void TransformWhilePacked(IWorldAccessor worldForResolve, EnumOrigin aroundOrigin, int angle, EnumAxis?flipAxis = null)
        {
            BlockPos curPos   = new BlockPos();
            BlockPos startPos = new BlockPos(1024, 1024, 1024);

            BlocksUnpacked.Clear();
            BlockEntitiesUnpacked.Clear();
            DecorsUnpacked.Clear();
            EntitiesUnpacked.Clear();

            angle = GameMath.Mod(angle, 360);

            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 = worldForResolve.GetBlock(blockCode);
                if (newBlock == null)
                {
                    BlockEntities.Remove(index);
                    continue;
                }

                if (flipAxis != null)
                {
                    if (flipAxis == EnumAxis.Y)
                    {
                        dy = SizeY - dy;

                        AssetLocation newCode = newBlock.GetVerticallyFlippedBlockCode();
                        newBlock = worldForResolve.GetBlock(newCode);
                    }

                    if (flipAxis == EnumAxis.X)
                    {
                        dx = SizeX - dx;

                        AssetLocation newCode = newBlock.GetHorizontallyFlippedBlockCode((EnumAxis)flipAxis);
                        newBlock = worldForResolve.GetBlock(newCode);
                    }

                    if (flipAxis == EnumAxis.Z)
                    {
                        dz = SizeZ - dz;

                        AssetLocation newCode = newBlock.GetHorizontallyFlippedBlockCode((EnumAxis)flipAxis);
                        newBlock = worldForResolve.GetBlock(newCode);
                    }
                }

                if (angle != 0)
                {
                    AssetLocation newCode = newBlock.GetRotatedBlockCode(angle);
                    newBlock = worldForResolve.GetBlock(newCode);
                }

                if (aroundOrigin != EnumOrigin.StartPos)
                {
                    dx -= SizeX / 2;
                    dz -= SizeZ / 2;
                }

                BlockPos pos = new BlockPos(dx, dy, dz);

                // 90 deg:
                // xNew = -yOld
                // yNew = xOld

                // 180 deg:
                // xNew = -xOld
                // yNew = -yOld

                // 270 deg:
                // xNew = yOld
                // yNew = -xOld

                switch (angle)
                {
                case 90:
                    pos.Set(-dz, dy, dx);
                    break;

                case 180:
                    pos.Set(-dx, dy, -dz);
                    break;

                case 270:
                    pos.Set(dz, dy, -dx);
                    break;
                }

                if (aroundOrigin != EnumOrigin.StartPos)
                {
                    pos.X += SizeX / 2;
                    pos.Z += SizeZ / 2;
                }

                BlocksUnpacked[pos] = newBlock.BlockId;
            }


            for (int i = 0; i < DecorIndices.Count; i++)
            {
                uint index         = DecorIndices[i];
                int  storedBlockid = DecorIds[i];
                byte faceIndex     = (byte)(storedBlockid >> 24);
                if (faceIndex > 5)
                {
                    continue;
                }
                BlockFacing face = BlockFacing.ALLFACES[faceIndex];

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

                AssetLocation blockCode = BlockCodes[storedBlockid & 0xFFFFFF];

                Block newBlock = worldForResolve.GetBlock(blockCode);
                if (newBlock == null)
                {
                    continue;
                }

                if (flipAxis != null)
                {
                    if (flipAxis == EnumAxis.Y)
                    {
                        dy = SizeY - dy;

                        AssetLocation newCode = newBlock.GetVerticallyFlippedBlockCode();
                        newBlock = worldForResolve.GetBlock(newCode);
                        if (face.IsVertical)
                        {
                            face = face.Opposite;
                        }
                    }

                    if (flipAxis == EnumAxis.X)
                    {
                        dx = SizeX - dx;

                        AssetLocation newCode = newBlock.GetHorizontallyFlippedBlockCode((EnumAxis)flipAxis);
                        newBlock = worldForResolve.GetBlock(newCode);
                        if (face.Axis == EnumAxis.X)
                        {
                            face = face.Opposite;
                        }
                    }

                    if (flipAxis == EnumAxis.Z)
                    {
                        dz = SizeZ - dz;

                        AssetLocation newCode = newBlock.GetHorizontallyFlippedBlockCode((EnumAxis)flipAxis);
                        newBlock = worldForResolve.GetBlock(newCode);
                        if (face.Axis == EnumAxis.Z)
                        {
                            face = face.Opposite;
                        }
                    }
                }

                if (angle != 0)
                {
                    AssetLocation newCode = newBlock.GetRotatedBlockCode(angle);
                    newBlock = worldForResolve.GetBlock(newCode);
                }

                if (aroundOrigin != EnumOrigin.StartPos)
                {
                    dx -= SizeX / 2;
                    dz -= SizeZ / 2;
                }

                BlockPos pos = new BlockPos(dx, dy, dz);

                // 90 deg:
                // xNew = -yOld
                // yNew = xOld

                // 180 deg:
                // xNew = -xOld
                // yNew = -yOld

                // 270 deg:
                // xNew = yOld
                // yNew = -xOld

                switch (angle)
                {
                case 90:
                    pos.Set(-dz, dy, dx);
                    if (face.IsHorizontal)
                    {
                        face = face.GetCW();
                    }
                    break;

                case 180:
                    pos.Set(-dx, dy, -dz);
                    if (face.IsHorizontal)
                    {
                        face = face.Opposite;
                    }
                    break;

                case 270:
                    pos.Set(dz, dy, -dx);
                    if (face.IsHorizontal)
                    {
                        face = face.GetCCW();
                    }
                    break;
                }

                if (aroundOrigin != EnumOrigin.StartPos)
                {
                    pos.X += SizeX / 2;
                    pos.Z += SizeZ / 2;
                }

                DecorsUnpacked.TryGetValue(pos, out Block[] decorsTmp);
                if (decorsTmp == null)
                {
                    decorsTmp           = new Block[6];
                    DecorsUnpacked[pos] = decorsTmp;
                }
                decorsTmp[face.Index] = newBlock;
            }


            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);

                dx -= SizeX / 2;
                dz -= SizeZ / 2;

                BlockPos pos = new BlockPos(dx, dy, dz);

                // 90 deg:
                // xNew = -yOld
                // yNew = xOld

                // 180 deg:
                // xNew = -xOld
                // yNew = -yOld

                // 270 deg:
                // xNew = yOld
                // yNew = -xOld

                switch (angle)
                {
                case 90:
                    pos.Set(-dz, dy, dx);
                    break;

                case 180:
                    pos.Set(-dx, dy, -dz);
                    break;

                case 270:
                    pos.Set(dz, dy, -dx);
                    break;
                }

                pos.X += SizeX / 2;
                pos.Z += SizeZ / 2;

                curPos.Set(pos.X + startPos.X, pos.Y + startPos.Y, pos.Z + startPos.Z);

                string beData = val.Value;


                string entityclass = worldForResolve.GetBlock(BlocksUnpacked[pos]).EntityClass;

                if (entityclass != null)
                {
                    BlockEntity be = worldForResolve.ClassRegistry.CreateBlockEntity(entityclass);
                    if (be is IBlockEntityRotatable)
                    {
                        ITreeAttribute tree = DecodeBlockEntityData(beData);
                        (be as IBlockEntityRotatable).OnTransformed(tree, angle, flipAxis);
                        beData = StringEncodeTreeAttribute(tree);
                    }

                    BlockEntitiesUnpacked[pos] = beData;
                }
            }


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

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

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

                    double dx = entity.ServerPos.X - startPos.X;
                    double dy = entity.ServerPos.Y - startPos.Y;
                    double dz = entity.ServerPos.Z - startPos.Z;

                    dx -= SizeX / 2;
                    dz -= SizeZ / 2;

                    Vec3d pos = new Vec3d();

                    // 90 deg:
                    // xNew = -yOld
                    // yNew = xOld

                    // 180 deg:
                    // xNew = -xOld
                    // yNew = -yOld

                    // 270 deg:
                    // xNew = yOld
                    // yNew = -xOld

                    switch (angle)
                    {
                    case 90:
                        pos.Set(-dz, dy, dx);
                        break;

                    case 180:
                        pos.Set(-dx, dy, -dz);
                        break;

                    case 270:
                        pos.Set(dz, dy, -dx);
                        break;
                    }

                    pos.X += SizeX / 2;
                    pos.Z += SizeZ / 2;

                    entity.ServerPos.SetPos(startPos.X + pos.X, entity.ServerPos.Y, startPos.Z + pos.Z);
                    entity.Pos.SetPos(startPos.X + pos.X, entity.Pos.Y, startPos.Z + pos.Z);
                    entity.PositionBeforeFalling.Set(startPos.X + pos.X, entity.PositionBeforeFalling.Y, startPos.Z + pos.Z);

                    EntitiesUnpacked.Add(entity);
                }
            }


            Pack(worldForResolve, startPos);
        }
Exemplo n.º 16
0
        public override void OnGameTick(float dt)
        {
            base.OnGameTick(dt);

            if (Itemstack != null)
            {
                if (!Collided && !Swimming && World.Side == EnumAppSide.Server)
                {
                    getWindSpeedAccum += dt;
                    if (getWindSpeedAccum > 0.25)
                    {
                        getWindSpeedAccum = 0;
                        tmpPos.Set(Pos.XInt, Pos.YInt, Pos.ZInt);
                        windSpeed = World.BlockAccessor.GetWindSpeedAt(tmpPos);

                        windSpeed.X = Math.Max(0, Math.Abs(windSpeed.X) - windLoss) * Math.Sign(windSpeed.X);
                        windSpeed.Y = Math.Max(0, Math.Abs(windSpeed.Y) - windLoss) * Math.Sign(windSpeed.Y);
                        windSpeed.Z = Math.Max(0, Math.Abs(windSpeed.Z) - windLoss) * Math.Sign(windSpeed.Z);
                    }

                    float fac = GameMath.Clamp(1000f / Itemstack.Collectible.MaterialDensity, 1f, 10);

                    SidedPos.Motion.X += windSpeed.X / 1000.0 * fac * GameMath.Clamp(1f / (1 + Math.Abs(SidedPos.Motion.X)), 0, 1);
                    SidedPos.Motion.Y += windSpeed.Y / 1000.0 * fac * GameMath.Clamp(1f / (1 + Math.Abs(SidedPos.Motion.Y)), 0, 1);
                    SidedPos.Motion.Z += windSpeed.Z / 1000.0 * fac * GameMath.Clamp(1f / (1 + Math.Abs(SidedPos.Motion.Z)), 0, 1);
                }

                Itemstack.Collectible.OnGroundIdle(this);

                if (FeetInLiquid && !InLava)
                {
                    float temp = Itemstack.Collectible.GetTemperature(World, Itemstack);

                    if (temp > 20)
                    {
                        Itemstack.Collectible.SetTemperature(World, Itemstack, Math.Max(20, temp - 5));

                        if (temp > 90)
                        {
                            SplashParticleProps.BasePos.Set(Pos.X, Pos.Y, Pos.Z);
                            SplashParticleProps.AddVelocity.Set(0, 0, 0);
                            SplashParticleProps.QuantityMul = 0.1f;
                            World.SpawnParticles(SplashParticleProps);
                        }

                        if (temp > 200 && World.Side == EnumAppSide.Client && World.ElapsedMilliseconds - lastPlayedSizzlesTotalMs > 10000)
                        {
                            World.PlaySoundAt(new AssetLocation("sounds/sizzle"), this, null);
                            lastPlayedSizzlesTotalMs = World.ElapsedMilliseconds;
                        }
                    }
                }

                /*if (!FeetInLiquid && !InLava && Api.World.Rand.NextDouble() < 0.1f && Api.World.Side == EnumAppSide.Server)
                 * {
                 *  // Die on rainfall
                 *  WeatherSystemBase wsys;
                 *  wsys = api.ModLoader.GetModSystem<WeatherSystemBase>();
                 *  BlockPos tmpPos = new BlockPos(Pos.X + 0.5, Pos.Y + 0.5, Pos.Z + 0.5);
                 *  double rainLevel = wsys.GetRainFall(tmpPos);
                 *  if (rainLevel > 0.04 && Api.World.Rand.NextDouble() < rainLevel * 5)
                 *  {
                 *      if (Api.World.BlockAccessor.GetRainMapHeightAt(Pos.X, Pos.Z) > Pos.Y) return;
                 *
                 *      Api.World.PlaySoundAt(new AssetLocation("sounds/effect/extinguish"), Pos.X + 0.5, Pos.Y, Pos.Z + 0.5, null, false, 16);
                 *
                 *      fuelBurnTime -= (float)rainLevel / 10f;
                 *
                 *      if (Api.World.Rand.NextDouble() < rainLevel / 5f || fuelBurnTime <= 0)
                 *      {
                 *          setBlockState("cold");
                 *          extinguishedTotalHours = -99;
                 *          canIgniteFuel = false;
                 *          fuelBurnTime = 0;
                 *          maxFuelBurnTime = 0;
                 *      }
                 *
                 *      MarkDirty(true);
                 *  }
                 * }*/
            }
            else
            {
                Die();
            }
        }
Exemplo n.º 17
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);
                    }
                }
            }
        }
Exemplo n.º 18
0
        /// <summary>
        /// Updates the velocity vector according to the amount of passed time, gravity and terrain collision.
        /// </summary>
        /// <param name="pos"></param>
        /// <param name="motion"></param>
        /// <param name="size"></param>
        /// <returns></returns>
        public EnumCollideFlags UpdateMotion(Vec3d pos, Vec3f motion, float size)
        {
            particleCollBox.Set(
                pos.X - size / 2, pos.Y - 0 / 2, pos.Z - size / 2,
                pos.X + size / 2, pos.Y + size / 2, pos.Z + size / 2
                );

            motion.X = GameMath.Clamp(motion.X, -MotionCap, MotionCap);
            motion.Y = GameMath.Clamp(motion.Y, -MotionCap, MotionCap);
            motion.Z = GameMath.Clamp(motion.Z, -MotionCap, MotionCap);

            EnumCollideFlags flags = 0;

            minPos.Set(
                (int)(particleCollBox.X1 + Math.Min(0, motion.X)),
                (int)(particleCollBox.Y1 + Math.Min(0, motion.Y) - 1), // -1 for the extra high collision box of fences
                (int)(particleCollBox.Z1 + Math.Min(0, motion.Z))
                );

            maxPos.Set(
                (int)(particleCollBox.X2 + Math.Max(0, motion.X)),
                (int)(particleCollBox.Y2 + Math.Max(0, motion.Y)),
                (int)(particleCollBox.Z2 + Math.Max(0, motion.Z))
                );

            CollisionBoxList.Clear();
            BlockAccess.WalkBlocks(minPos, maxPos, (cblock, bpos) => {
                Cuboidf[] collisionBoxes = cblock.GetParticleCollisionBoxes(BlockAccess, bpos);

                for (int i = 0; collisionBoxes != null && i < collisionBoxes.Length; i++)
                {
                    CollisionBoxList.Add(collisionBoxes[i], bpos, cblock);
                }
            }, false);


            //  Y - Collision (Vertical)
            EnumPushDirection pushDirection = EnumPushDirection.None;

            for (int i = 0; i < CollisionBoxList.Count; i++)
            {
                blockCollBox = CollisionBoxList.cuboids[i];

                motion.Y = (float)blockCollBox.pushOutY(particleCollBox, motion.Y, ref pushDirection);

                if (pushDirection != EnumPushDirection.None)
                {
                    flags |= EnumCollideFlags.CollideY;
                }
            }


            particleCollBox.Translate(0, motion.Y, 0);


            // X - Collision (Horizontal)
            for (int i = 0; i < CollisionBoxList.Count; i++)
            {
                blockCollBox = CollisionBoxList.cuboids[i];

                motion.X = (float)blockCollBox.pushOutX(particleCollBox, motion.X, ref pushDirection);

                if (pushDirection != EnumPushDirection.None)
                {
                    flags |= EnumCollideFlags.CollideX;
                }
            }

            particleCollBox.Translate(motion.X, 0, 0);


            // Z - Collision (Horizontal)
            for (int i = 0; i < CollisionBoxList.Count; i++)
            {
                blockCollBox = CollisionBoxList.cuboids[i];

                motion.Z = (float)blockCollBox.pushOutZ(particleCollBox, motion.Z, ref pushDirection);

                if (pushDirection != EnumPushDirection.None)
                {
                    flags |= EnumCollideFlags.CollideZ;
                }
            }


            return(flags);
        }
Exemplo n.º 19
0
        public void DisplaceWithBlockCollision(EntityPos pos, EntityControls controls, float dt)
        {
            IBlockAccessor blockAccess = entity.World.BlockAccessor;

            nextPosition.Set(pos.X + pos.Motion.X, pos.Y + pos.Motion.Y, pos.Z + pos.Motion.Z);
            bool falling            = pos.Motion.Y < 0;
            bool feetInLiquidBefore = entity.FeetInLiquid;
            bool onGroundBefore     = entity.OnGround;
            bool swimmingBefore     = entity.Swimming;

            double prevYMotion = pos.Motion.Y;

            controls.IsClimbing = false;

            if (!onGroundBefore && entity.Properties.CanClimb == true)
            {
                int height = (int)Math.Ceiling(entity.CollisionBox.Y2);

                entityBox.Set(entity.CollisionBox).Translate(pos.X, pos.Y, pos.Z);

                for (int dy = 0; dy < height; dy++)
                {
                    tmpPos.Set((int)pos.X, (int)pos.Y + dy, (int)pos.Z);
                    Block nblock = blockAccess.GetBlock(tmpPos);
                    if (!nblock.Climbable && !entity.Properties.CanClimbAnywhere)
                    {
                        continue;
                    }

                    Cuboidf[] collBoxes = nblock.GetCollisionBoxes(blockAccess, tmpPos);
                    if (collBoxes == null)
                    {
                        continue;
                    }

                    for (int i = 0; i < collBoxes.Length; i++)
                    {
                        double dist = entityBox.ShortestDistanceFrom(collBoxes[i], tmpPos);
                        controls.IsClimbing |= dist < entity.Properties.ClimbTouchDistance;

                        if (controls.IsClimbing)
                        {
                            entity.ClimbingOnFace = null;
                            break;
                        }
                    }
                }

                for (int i = 0; !controls.IsClimbing && i < BlockFacing.HORIZONTALS.Length; i++)
                {
                    BlockFacing facing = BlockFacing.HORIZONTALS[i];
                    for (int dy = 0; dy < height; dy++)
                    {
                        tmpPos.Set((int)pos.X + facing.Normali.X, (int)pos.Y + dy, (int)pos.Z + facing.Normali.Z);
                        Block nblock = blockAccess.GetBlock(tmpPos);
                        if (!nblock.Climbable && !entity.Properties.CanClimbAnywhere)
                        {
                            continue;
                        }

                        Cuboidf[] collBoxes = nblock.GetCollisionBoxes(blockAccess, tmpPos);
                        if (collBoxes == null)
                        {
                            continue;
                        }

                        for (int j = 0; j < collBoxes.Length; j++)
                        {
                            double dist = entityBox.ShortestDistanceFrom(collBoxes[j], tmpPos);
                            controls.IsClimbing |= dist < entity.Properties.ClimbTouchDistance;

                            if (controls.IsClimbing)
                            {
                                entity.ClimbingOnFace = facing;
                                break;
                            }
                        }
                    }
                }
            }


            if (controls.IsClimbing)
            {
                if (controls.WalkVector.Y == 0)
                {
                    pos.Motion.Y = controls.Sneak ? Math.Max(-0.07, pos.Motion.Y - 0.07) : pos.Motion.Y;
                    if (controls.Jump)
                    {
                        pos.Motion.Y = 0.04;
                    }
                }

                nextPosition.Set(pos.X + pos.Motion.X, pos.Y + pos.Motion.Y, pos.Z + pos.Motion.Z);
            }

            collisionTester.ApplyTerrainCollision(entity, pos, ref outposition, !(entity is EntityPlayer));

            bool isStepping = HandleSteppingOnBlocks(pos, controls);

            HandleSneaking(pos, controls, dt);



            if (blockAccess.IsNotTraversable((int)(pos.X + pos.Motion.X), (int)pos.Y, (int)pos.Z))
            {
                outposition.X = pos.X;
            }
            if (blockAccess.IsNotTraversable((int)pos.X, (int)(pos.Y + pos.Motion.Y), (int)pos.Z))
            {
                outposition.Y = pos.Y;
            }
            if (blockAccess.IsNotTraversable((int)pos.X, (int)pos.Y, (int)(pos.Z + pos.Motion.Z)))
            {
                outposition.Z = pos.Z;
            }

            pos.SetPos(outposition);


            // Set the players motion to zero if he collided.

            if ((nextPosition.X < outposition.X && pos.Motion.X < 0) || (nextPosition.X > outposition.X && pos.Motion.X > 0))
            {
                pos.Motion.X = 0;
            }

            if ((nextPosition.Y < outposition.Y && pos.Motion.Y < 0) || (nextPosition.Y > outposition.Y && pos.Motion.Y > 0))
            {
                pos.Motion.Y = 0;
            }

            if ((nextPosition.Z < outposition.Z && pos.Motion.Z < 0) || (nextPosition.Z > outposition.Z && pos.Motion.Z > 0))
            {
                pos.Motion.Z = 0;
            }



            Block block       = blockAccess.GetBlock((int)pos.X, (int)(pos.Y), (int)pos.Z);
            Block aboveblock  = blockAccess.GetBlock((int)pos.X, (int)(pos.Y + 1), (int)pos.Z);
            Block middleBlock = blockAccess.GetBlock((int)pos.X, (int)(pos.Y + entity.CollisionBox.Y1 + entity.CollisionBox.Y2 * 0.66f), (int)pos.Z);


            entity.OnGround     = (entity.CollidedVertically && falling && !controls.IsClimbing) || isStepping;
            entity.FeetInLiquid = block.IsLiquid() && ((block.LiquidLevel + (aboveblock.LiquidLevel > 0 ? 1 : 0)) / 8f >= pos.Y - (int)pos.Y);
            entity.Swimming     = middleBlock.IsLiquid();
            //    Console.WriteLine(entity.World.Side + ": "+ entity.OnGround + " / " + pos.Y);

            if (!onGroundBefore && entity.OnGround)
            {
                entity.OnFallToGround(prevYMotion);
            }

            if ((!entity.Swimming && !feetInLiquidBefore && entity.FeetInLiquid) || (!entity.FeetInLiquid && !swimmingBefore && entity.Swimming))
            {
                entity.OnCollideWithLiquid();
            }

            if ((swimmingBefore && !entity.Swimming && !entity.FeetInLiquid) || (feetInLiquidBefore && !entity.FeetInLiquid && !entity.Swimming))
            {
                entity.OnExitedLiquid();
            }

            if (!falling || entity.OnGround || controls.IsClimbing)
            {
                entity.PositionBeforeFalling.Set(outposition);
            }

            Cuboidd testedEntityBox = collisionTester.entityBox;

            for (int y = (int)testedEntityBox.Y1; y <= (int)testedEntityBox.Y2; y++)
            {
                for (int x = (int)testedEntityBox.X1; x <= (int)testedEntityBox.X2; x++)
                {
                    for (int z = (int)testedEntityBox.Z1; z <= (int)testedEntityBox.Z2; z++)
                    {
                        collisionTester.tmpPos.Set(x, y, z);
                        collisionTester.tempCuboid.Set(x, y, z, x + 1, y + 1, z + 1);

                        if (collisionTester.tempCuboid.IntersectsOrTouches(testedEntityBox))
                        {
                            // Saves us a few cpu cycles
                            if (x == (int)pos.X && y == (int)pos.Y && z == (int)pos.Z)
                            {
                                block.OnEntityInside(entity.World, entity, collisionTester.tmpPos);
                                continue;
                            }

                            blockAccess.GetBlock(x, y, z).OnEntityInside(entity.World, entity, collisionTester.tmpPos);
                        }
                    }
                }
            }
        }
Exemplo n.º 20
0
        public void HandleBoyancy(Vec3d pos, Vec3f velocity, bool boyant, float gravityStrength, float deltatime, float height)
        {
            int xPrev = (int)pos.X;
            int yPrev = (int)pos.Y;
            int zPrev = (int)pos.Z;

            tmpPos.Set(xPrev, yPrev, zPrev);
            Block block     = BlockAccess.GetBlock(tmpPos);
            Block prevBlock = block;

            if (block == null)
            {
                return;
            }

            if (boyant)
            {
                if (block.IsLiquid())
                {
                    tmpPos.Set(xPrev, (int)(pos.Y + 1), zPrev);
                    block = BlockAccess.GetBlock(tmpPos);
                    if (block == null)
                    {
                        return;
                    }

                    float waterY = (int)pos.Y + prevBlock.LiquidLevel / 8f + (block.IsLiquid() ? 9 / 8f : 0);
                    float bottomSubmergedness = waterY - (float)pos.Y;

                    float swimlineSubmergedness = GameMath.Clamp(bottomSubmergedness + height, 0, 1);

                    float boyancyStrength = GameMath.Clamp(9 * swimlineSubmergedness, -1.25f, 1.25f); // was 3* before. Dunno why it has to be 9* now

                    velocity.Y += gravityStrength * deltatime * boyancyStrength;

                    float waterDrag = (float)GameMath.Clamp(30 * Math.Abs(velocity.Y) - 0.02f, 1, 1.25f);

                    velocity.Y /= waterDrag;
                    velocity.X *= 0.99f;
                    velocity.Z *= 0.99f;

                    if (prevBlock.PushVector != null && swimlineSubmergedness >= 0)
                    {
                        float factor = deltatime / (33f / 1000f);
                        velocity.Add(
                            (float)prevBlock.PushVector.X * 15 * factor,
                            (float)prevBlock.PushVector.Y * 15 * factor,
                            (float)prevBlock.PushVector.Z * 15 * factor
                            );
                    }
                }
            }
            else
            {
                if (block.PushVector != null)
                {
                    velocity.Add(
                        (float)block.PushVector.X * 30 * deltatime,
                        (float)block.PushVector.Y * 30 * deltatime,
                        (float)block.PushVector.Z * 30 * deltatime
                        );
                }
            }
        }
Exemplo n.º 21
0
        // Requirements:
        // - ✔ Try to not move a lot vertically
        // - ✔ If territorial: Stay close to the spawn point
        // - ✔ If air habitat: Don't go above maxHeight blocks above surface
        // - ✔ If land habitat: Don't walk into water, prefer surface
        // - ~~If cave habitat: Prefer caves~~
        // - ✔ If water habitat: Don't walk onto land
        // - ✔ Try not to fall from very large heights. Try not to fall from any large heights if entity has FallDamage
        // - ✔ Prefer preferredLightLevel
        // - ✔ If land habitat: Must be above a block the entity can stand on
        // - ✔ if failed searches is high, reduce wander range
        public Vec3d loadNextWanderTarget()
        {
            EnumHabitat habitat       = entity.Properties.Habitat;
            bool        canFallDamage = entity.Properties.FallDamage;
            bool        territorial   = StayCloseToSpawn;
            int         tries         = 9;
            Vec4d       bestTarget    = null;
            Vec4d       curTarget     = new Vec4d();
            BlockPos    tmpPos        = new BlockPos();

            if (FailedConsecutivePathfinds > 10)
            {
                WanderRangeMul = Math.Max(0.1f, WanderRangeMul * 0.9f);
            }
            else
            {
                WanderRangeMul = Math.Min(1, WanderRangeMul * 1.1f);
                if (rand.NextDouble() < 0.05)
                {
                    WanderRangeMul = Math.Min(1, WanderRangeMul * 1.5f);
                }
            }

            float  wRangeMul = WanderRangeMul;
            double dx, dy, dz;

            if (rand.NextDouble() < 0.05)
            {
                wRangeMul *= 3;
            }

            while (tries-- > 0)
            {
                dx = wanderRangeHorizontal.nextFloat() * (rand.Next(2) * 2 - 1) * wRangeMul;
                dy = wanderRangeVertical.nextFloat() * (rand.Next(2) * 2 - 1) * wRangeMul;
                dz = wanderRangeHorizontal.nextFloat() * (rand.Next(2) * 2 - 1) * wRangeMul;

                curTarget.X = entity.ServerPos.X + dx;
                curTarget.Y = entity.ServerPos.Y + dy;
                curTarget.Z = entity.ServerPos.Z + dz;
                curTarget.W = 1;

                if (StayCloseToSpawn)
                {
                    double distToEdge = curTarget.SquareDistanceTo(SpawnPosition) / (MaxDistanceToSpawn * MaxDistanceToSpawn);
                    // Prefer staying close to spawn
                    curTarget.W = 1 - distToEdge;
                }

                Block block;


                switch (habitat)
                {
                case EnumHabitat.Air:
                    int rainMapY = world.BlockAccessor.GetRainMapHeightAt((int)curTarget.X, (int)curTarget.Z);
                    // Don't fly above max height
                    curTarget.Y = Math.Min(curTarget.Y, rainMapY + maxHeight);

                    // Cannot be in water
                    block = entity.World.BlockAccessor.GetBlock((int)curTarget.X, (int)curTarget.Y, (int)curTarget.Z);
                    if (block.IsLiquid())
                    {
                        curTarget.W = 0;
                    }
                    break;

                case EnumHabitat.Land:
                    curTarget.Y = moveDownToFloor((int)curTarget.X, curTarget.Y, (int)curTarget.Z);
                    // No floor found
                    if (curTarget.Y < 0)
                    {
                        curTarget.W = 0;
                    }
                    else
                    {
                        // Does not like water
                        block = entity.World.BlockAccessor.GetBlock((int)curTarget.X, (int)curTarget.Y, (int)curTarget.Z);
                        if (block.IsLiquid())
                        {
                            curTarget.W /= 2;
                        }

                        // Lets make a straight line plot to see if we would fall off a cliff
                        bool stop     = false;
                        bool willFall = false;

                        float angleHor          = (float)Math.Atan2(dx, dz) + GameMath.PIHALF;
                        Vec3d target1BlockAhead = curTarget.XYZ.Ahead(1, 0, angleHor);
                        Vec3d startAhead        = entity.ServerPos.XYZ.Ahead(1, 0, angleHor); // Otherwise they are forever stuck if they stand over the edge

                        int prevY = (int)startAhead.Y;

                        GameMath.BresenHamPlotLine2d((int)startAhead.X, (int)startAhead.Z, (int)target1BlockAhead.X, (int)target1BlockAhead.Z, (x, z) =>
                        {
                            if (stop)
                            {
                                return;
                            }

                            double nowY = moveDownToFloor(x, prevY, z);

                            // Not more than 4 blocks down
                            if (nowY < 0 || prevY - nowY > 4)
                            {
                                willFall = true;
                                stop     = true;
                            }

                            // Not more than 2 blocks up
                            if (nowY - prevY > 2)
                            {
                                stop = true;
                            }

                            prevY = (int)nowY;
                        });

                        if (willFall)
                        {
                            curTarget.W = 0;
                        }
                    }
                    break;

                case EnumHabitat.Sea:
                    block = entity.World.BlockAccessor.GetBlock((int)curTarget.X, (int)curTarget.Y, (int)curTarget.Z);
                    if (!block.IsLiquid())
                    {
                        curTarget.W = 0;
                    }
                    break;
                }

                if (curTarget.W > 0)
                {
                    // Try to not hug the wall so much
                    for (int i = 0; i < BlockFacing.HORIZONTALS.Length; i++)
                    {
                        BlockFacing face = BlockFacing.HORIZONTALS[i];
                        block = entity.World.BlockAccessor.GetBlock((int)curTarget.X + face.Normali.X, (int)curTarget.Y, (int)curTarget.Z + face.Normali.Z);
                        if (block.SideSolid[face.Opposite.Index])
                        {
                            curTarget.W *= 0.5;
                        }
                    }
                }


                if (preferredLightLevel != null)
                {
                    tmpPos.Set((int)curTarget.X, (int)curTarget.Y, (int)curTarget.Z);
                    int lightdiff = Math.Abs((int)preferredLightLevel - entity.World.BlockAccessor.GetLightLevel(tmpPos, EnumLightLevelType.MaxLight));

                    curTarget.W /= Math.Max(1, lightdiff);
                }

                if (bestTarget == null || curTarget.W > bestTarget.W)
                {
                    bestTarget = new Vec4d(curTarget.X, curTarget.Y, curTarget.Z, curTarget.W);
                }
            }


            if (bestTarget.W > 0)
            {
                //double bla = bestTarget.Y;
                //bestTarget.Y += 1;
                //dx = bestTarget.X - entity.ServerPos.X;
                //dz = bestTarget.Z - entity.ServerPos.Z;
                //Vec3d sadf = bestTarget.XYZ.Ahead(1, 0, (float)Math.Atan2(dx, dz) + GameMath.PIHALF);

                /*(entity.Api as ICoreServerAPI).World.HighlightBlocks(world.AllOnlinePlayers[0], 10, new List<BlockPos>() {
                 * new BlockPos((int)bestTarget.X, (int)bestTarget.Y, (int)bestTarget.Z) }, new List<int>() { ColorUtil.ColorFromRgba(0, 255, 0, 80) }, EnumHighlightBlocksMode.Absolute, EnumHighlightShape.Arbitrary);
                 * (entity.Api as ICoreServerAPI).World.HighlightBlocks(world.AllOnlinePlayers[0], 11, new List<BlockPos>() {
                 * new BlockPos((int)sadf.X, (int)sadf.Y, (int)sadf.Z) }, new List<int>() { ColorUtil.ColorFromRgba(0, 255, 255, 180) }, EnumHighlightBlocksMode.Absolute, EnumHighlightShape.Arbitrary);*/

                //bestTarget.Y = bla;


                FailedConsecutivePathfinds = Math.Max(FailedConsecutivePathfinds - 3, 0);
                return(bestTarget.XYZ);
            }

            FailedConsecutivePathfinds++;
            return(null);
        }
Exemplo n.º 22
0
        /// <summary>
        /// forceInitialPosY is for subdeposits
        /// </summary>
        /// <param name="chunks"></param>
        /// <param name="chunkX"></param>
        /// <param name="chunkZ"></param>
        /// <param name="offsetX"></param>
        /// <param name="offsetZ"></param>
        /// <param name="variant"></param>
        /// <param name="forceInitialPosY"></param>
        /// <returns></returns>
        Dictionary <Vec3i, DepositVariant> GenDeposit(IServerChunk[] chunks, int chunkX, int chunkZ, int offsetX, int offsetZ, DepositVariant variant, int?forceInitialPosY = null)
        {
            Dictionary <Vec3i, DepositVariant> SubDepositsToPlace = new Dictionary <Vec3i, DepositVariant>();

            IMapChunk mapchunk = chunks[0].MapChunk;

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

            if (radius <= 0)
            {
                return(SubDepositsToPlace);
            }

            // Let's deform that perfect circle a bit (+/- 25%)
            float deform  = GameMath.Clamp(depositRand.NextFloat() - 0.5f, -0.25f, 0.25f);
            int   radiusX = radius - (int)(radius * deform);
            int   radiusZ = radius + (int)(radius * deform);
            int   posY;

            // No need to caluclate further if this deposit won't be part of this chunk
            if (radiusX + offsetX < 0 || radiusZ + offsetZ < 0 || offsetX - radiusX >= chunksize || offsetZ - radiusZ >= chunksize)
            {
                return(SubDepositsToPlace);
            }


            IMapChunk originMapchunk = null;
            int       origPosY       = 0;

            int lx = GameMath.Mod(offsetX, chunksize);
            int lz = GameMath.Mod(offsetZ, chunksize);

            if (variant.MaxY < 1 || variant.CheckClimate)
            {
                originMapchunk = api.WorldManager.GetMapChunk((chunkX * chunksize + offsetX) / chunksize, (chunkZ * chunksize + offsetZ) / chunksize);
                if (originMapchunk == null)
                {
                    return(SubDepositsToPlace);                        // argh >.<
                }
                origPosY = originMapchunk.RainHeightMap[lz * chunksize + lx];
                if ((float)origPosY / api.World.BlockAccessor.MapSizeY > variant.MaxY)
                {
                    return(SubDepositsToPlace);
                }
            }



            // Check if suited for this area, climate wise
            if (variant.CheckClimate)
            {
                IntMap climateMap = api.World.BlockAccessor.GetMapRegion((chunkX * chunksize + offsetX) / regionSize, (chunkZ * chunksize + offsetZ) / regionSize).ClimateMap;

                float posXInRegionClimate = ((float)lx / regionSize - lx / regionSize) * noiseSizeClimate;
                float posZInRegionClimate = ((float)lz / regionSize - lz / regionSize) * noiseSizeClimate;

                int   climate = climateMap.GetUnpaddedColorLerped(posXInRegionClimate, posZInRegionClimate);
                float temp    = TerraGenConfig.GetScaledAdjustedTemperatureFloat((climate >> 16) & 0xff, origPosY - TerraGenConfig.seaLevel);
                float rainRel = TerraGenConfig.GetRainFall((climate >> 8) & 0xff, origPosY) / 255f;

                if (rainRel < variant.MinRain || rainRel > variant.MaxRain || temp < variant.MinTemp || temp > variant.MaxTemp)
                {
                    return(SubDepositsToPlace);
                }
            }


            // Ok generate
            float th        = variant.Thickness.nextFloat(1, depositRand);
            int   thickness = (int)th + (depositRand.NextFloat() < th - (int)th ? 1 : 0);

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

            int  blockIndex    = 0;
            bool parentBlockOk = false;

            float depthf;

            bool shouldGenSurfaceDeposit = depositRand.NextFloat() > 0.35f && variant.SurfaceBlockCode != null;

            if (forceInitialPosY != null)
            {
                depthf = (float)forceInitialPosY / mapchunk.WorldGenTerrainHeightMap[offsetX * chunksize + offsetZ];
            }
            else
            {
                depthf = variant.Depth.nextFloat(1, depositRand);
            }

            int depthi = (int)depthf;

            int topLeft  = 2 * depositRand.NextInt(radiusX + 1) - radiusX;
            int topRight = 2 * depositRand.NextInt(radiusZ + 1) - radiusZ;
            int botLeft  = 2 * depositRand.NextInt(radiusX + 1) - radiusX;
            int botRight = 2 * depositRand.NextInt(radiusZ + 1) - radiusZ;
            int yOff     = 0;

            // Only generate inside this current chunk column
            int minx = GameMath.Clamp(offsetX - radiusX, 0, chunksize);
            int maxx = GameMath.Clamp(offsetX + radiusX, 0, chunksize);
            int minz = GameMath.Clamp(offsetZ - radiusZ, 0, chunksize);
            int maxz = GameMath.Clamp(offsetZ + radiusZ, 0, chunksize);

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

            for (int x = minx; x < maxx; x++)
            {
                float xSq = (x - offsetX) * (x - offsetX) * xRadSqInv;
                for (int z = minz; z < maxz; z++)
                {
                    if (xSq + (z - offsetZ) * (z - offsetZ) * zRadSqInv > 1)
                    {
                        continue;
                    }

                    if (variant.Placement == EnumDepositPlacement.FollowSurfaceBelow)
                    {
                        posY = mapchunk.WorldGenTerrainHeightMap[z * chunksize + x] - depthi;
                    }
                    else if (variant.Placement == EnumDepositPlacement.FollowSurface)
                    {
                        yOff = (int)GameMath.BiLerp(topLeft, topRight, botLeft, botRight, (x - offsetX + radiusX) / (2f * radiusX), (z - offsetZ + radiusZ) / (2f * radiusZ));

                        posY = (int)(depthf * mapchunk.WorldGenTerrainHeightMap[z * chunksize + x]) + yOff / 2;
                    }
                    else if (variant.Placement == EnumDepositPlacement.Straight)
                    {
                        posY = (int)(depthf * mapchunk.WorldGenTerrainHeightMap[z * chunksize + x]);
                    }
                    else
                    {
                        yOff = (int)GameMath.BiLerp(topLeft, topRight, botLeft, botRight, (x - offsetX + radiusX) / (2f * radiusX), (z - offsetZ + radiusZ) / (2f * radiusZ));

                        posY = depthi + yOff;
                    }

                    // Some deposits may not appear all over cliffs
                    if (variant.CheckClimate && Math.Abs(origPosY - posY) > variant.MaxYRoughness)
                    {
                        continue;
                    }

                    for (int y = 0; y < thickness; y++)
                    {
                        if (posY <= 1 || posY >= worldheight)
                        {
                            continue;
                        }

                        long   index3d = ((posY % chunksize) * chunksize + z) * chunksize + x;
                        ushort blockId = chunks[posY / chunksize].Blocks[index3d];

                        // Check if we are in mother material, but only if it has changed since last iteration (should reduce amount of these checks by 50-100%)
                        parentBlockOk = false;
                        for (int i = 0; i < variant.ParentBlockIds.Length; i++)
                        {
                            if (variant.ParentBlockIds[i] == blockId)
                            {
                                parentBlockOk = true;
                                blockIndex    = i;
                                break;
                            }
                        }

                        if (parentBlockOk)
                        {
                            if (variant.WithBlockCallback)
                            {
                                tmpPos.Set(chunkX * chunksize + x, posY, chunkZ * chunksize + z);
                                blockTypes[variant.BlockIds[blockIndex]].TryPlaceBlockForWorldGen(blockAccessor, tmpPos, BlockFacing.UP);
                            }
                            else
                            {
                                chunks[posY / chunksize].Blocks[index3d] = variant.BlockIds[blockIndex];
                            }


                            for (int i = 0; i < variant.ChildDeposits.Length; i++)
                            {
                                float rndVal   = depositRand.NextFloat();
                                float quantity = variant.ChildDeposits[i].Quantity * invChunkAreaSize;

                                if (quantity > rndVal)
                                {
                                    Vec3i pos = new Vec3i(x, posY, z);

                                    if (ShouldPlaceAdjustedForOreMap(variant.ChildDeposits[i], chunkX * chunksize + x, chunkZ * chunksize + z, quantity, rndVal))
                                    {
                                        SubDepositsToPlace[pos] = variant.ChildDeposits[i];
                                    }
                                }
                            }

                            if (shouldGenSurfaceDeposit)
                            {
                                int   surfaceY = mapchunk.RainHeightMap[z * chunksize + x];
                                int   depth    = surfaceY - posY;
                                float chance   = variant.SurfaceBlockChance * Math.Max(0, 1 - depth / 8f);
                                if (depositRand.NextFloat() < chance)
                                {
                                    index3d = (((surfaceY + 1) % chunksize) * chunksize + z) * chunksize + x;

                                    Block belowBlock = api.World.Blocks[chunks[surfaceY / chunksize].Blocks[((surfaceY % chunksize) * chunksize + z) * chunksize + x]];

                                    if (belowBlock.SideSolid[BlockFacing.UP.Index] && chunks[(surfaceY + 1) / chunksize].Blocks[index3d] == 0)
                                    {
                                        chunks[(surfaceY + 1) / chunksize].Blocks[index3d] = variant.SurfaceBlockIds[blockIndex];
                                    }
                                }
                            }
                        }

                        posY--;
                    }
                }
            }

            return(SubDepositsToPlace);
        }
Exemplo n.º 23
0
        public override bool ShouldExecute()
        {
            if (rand.NextDouble() > searchFrequency)
            {
                return(false);
            }

            reason = EnumRestReason.NoReason;

            float dayLightStrength = entity.World.Calendar.GetDayLightStrength(entity.Pos.X, entity.Pos.Z);

            if (cooldownUntilTotalHours < entity.World.Calendar.TotalHours)
            {
                reason = EnumRestReason.TakingABreak;
            }
            else if (dayLightStrength < 0.6)
            {
                // Hardcoded: Rest at night
                reason = EnumRestReason.Night;
            }
            else if (wsys?.WeatherDataSlowAccess.GetWindSpeed(entity.ServerPos.XYZ) > 0.75 || wsys?.GetPrecipitation(entity.ServerPos.XYZ) > 0.1)
            {
                // Hardcoded: Rest during heavy winds or during rain
                reason = EnumRestReason.Wind;
            }

            if (reason == EnumRestReason.NoReason)
            {
                return(false);
            }


            double dx = rand.NextDouble() * 4 - 2;
            double dz = rand.NextDouble() * 4 - 2;

            for (int i = 1; i >= 0; i--)
            {
                tmpPos.Set((int)(entity.ServerPos.X + dx), 0, (int)(entity.ServerPos.Z + dz));
                tmpPos.Y = entity.World.BlockAccessor.GetTerrainMapheightAt(tmpPos) + i;

                Block block = entity.World.BlockAccessor.GetBlock(tmpPos);
                if (block.IsLiquid())
                {
                    return(false);
                }

                bool weak = block.VertexFlags?.WindMode == EnumWindBitMode.WeakWind || block.VertexFlags?.WindMode == EnumWindBitMode.TallBend;

                if (block.Attributes?.IsTrue("butterflyFeed") == true)
                {
                    double topPos = block.Attributes["sitHeight"].AsDouble(block.TopMiddlePos.Y);

                    entity.WatchedAttributes.SetDouble("windWaveIntensity", block.VertexFlags.WindMode != EnumWindBitMode.NoWind ? (weak ? topPos / 2 : topPos) : 0);

                    MainTarget = tmpPos.ToVec3d().Add(block.TopMiddlePos.X, topPos, block.TopMiddlePos.Z);
                    return(true);
                }

                if (block.SideSolid[BlockFacing.UP.Index])
                {
                    double topPos = block.TopMiddlePos.Y;
                    entity.WatchedAttributes.SetDouble("windWaveIntensity", block.VertexFlags?.WindMode != EnumWindBitMode.NoWind ? (weak ? topPos / 2 : topPos) : 0);
                    MainTarget = tmpPos.ToVec3d().Add(block.TopMiddlePos.X, topPos - 1, block.TopMiddlePos.Z);
                    return(true);
                }
            }

            return(false);
        }
        private void OnChunkColumnGen(IServerChunk[] chunks, int chunkX, int chunkZ, ITreeAttribute chunkGenParams = null)
        {
            IMapChunk mapChunk = chunks[0].MapChunk;

            IntMap forestMap  = mapChunk.MapRegion.ForestMap;
            IntMap shrubMap   = mapChunk.MapRegion.ShrubMap;
            IntMap climateMap = mapChunk.MapRegion.ClimateMap;
            int    rlX        = chunkX % regionChunkSize;
            int    rlZ        = chunkZ % regionChunkSize;

            float facS = (float)shrubMap.InnerSize / regionChunkSize;

            shrubUpLeft   = shrubMap.GetUnpaddedInt((int)(rlX * facS), (int)(rlZ * facS));
            shrubUpRight  = shrubMap.GetUnpaddedInt((int)(rlX * facS + facS), (int)(rlZ * facS));
            shrubBotLeft  = shrubMap.GetUnpaddedInt((int)(rlX * facS), (int)(rlZ * facS + facS));
            shrubBotRight = shrubMap.GetUnpaddedInt((int)(rlX * facS + facS), (int)(rlZ * facS + facS));

            // A region has 16 chunks
            // Size of the forest map is RegionSize / TerraGenConfig.forestMapScale  => 32*16 / 32  = 16 pixel
            // rlX, rlZ goes from 0..16 pixel
            // facF = 16/16 = 1
            // Get 4 pixels for chunkx, chunkz, chunkx+1 and chunkz+1 inside the map
            float facF = (float)forestMap.InnerSize / regionChunkSize;

            forestUpLeft   = forestMap.GetUnpaddedInt((int)(rlX * facF), (int)(rlZ * facF));
            forestUpRight  = forestMap.GetUnpaddedInt((int)(rlX * facF + facF), (int)(rlZ * facF));
            forestBotLeft  = forestMap.GetUnpaddedInt((int)(rlX * facF), (int)(rlZ * facF + facF));
            forestBotRight = forestMap.GetUnpaddedInt((int)(rlX * facF + facF), (int)(rlZ * facF + facF));

            float facC = (float)climateMap.InnerSize / regionChunkSize;

            climateUpLeft   = climateMap.GetUnpaddedInt((int)(rlX * facC), (int)(rlZ * facC));
            climateUpRight  = climateMap.GetUnpaddedInt((int)(rlX * facC + facC), (int)(rlZ * facC));
            climateBotLeft  = climateMap.GetUnpaddedInt((int)(rlX * facC), (int)(rlZ * facC + facC));
            climateBotRight = climateMap.GetUnpaddedInt((int)(rlX * facC + facC), (int)(rlZ * facC + facC));

            heightmap = chunks[0].MapChunk.RainHeightMap;


            structuresIntersectingChunk.Clear();
            api.World.BlockAccessor.WalkStructures(chunkBase.Set(chunkX * chunksize, 0, chunkZ * chunksize), chunkend.Set(chunkX * chunksize + chunksize, chunkMapSizeY * chunksize, chunkZ * chunksize + chunksize), (struc) =>
            {
                if (struc.Code.StartsWith("trader"))
                {
                    structuresIntersectingChunk.Add(struc);
                }
            });

            if (TerraGenConfig.GenerateVegetation)
            {
                genPatches(chunkX, chunkZ, false);
                genShrubs(chunkX, chunkZ);
                genTrees(chunkX, chunkZ);
                genPatches(chunkX, chunkZ, true);
            }
        }
Exemplo n.º 25
0
        internal bool TryGenerateRuinAtSurface(IBlockAccessor blockAccessor, IWorldAccessor worldForCollectibleResolve, BlockPos pos)
        {
            int chunksize = blockAccessor.ChunkSize;
            int climate   = GameMath.BiLerpRgbColor((float)(pos.X % chunksize) / chunksize, (float)(pos.Z % chunksize) / chunksize, climateUpLeft, climateUpRight, climateBotLeft, climateBotRight);

            int num    = rand.NextInt(schematicDatas.Length);
            int orient = rand.NextInt(4);
            BlockSchematicStructure schematic = schematicDatas[num][orient];


            int widthHalf  = (int)Math.Ceiling(schematic.SizeX / 2f);
            int lengthHalf = (int)Math.Ceiling(schematic.SizeZ / 2f);



            // Probe all 4 corners + center if they either touch the surface or are sightly below ground

            int centerY = blockAccessor.GetTerrainMapheightAt(pos);


            tmpPos.Set(pos.X - widthHalf, 0, pos.Z - lengthHalf);
            int topLeftY = blockAccessor.GetTerrainMapheightAt(tmpPos);

            tmpPos.Set(pos.X + widthHalf, 0, pos.Z - lengthHalf);
            int topRightY = blockAccessor.GetTerrainMapheightAt(tmpPos);

            tmpPos.Set(pos.X - widthHalf, 0, pos.Z + lengthHalf);
            int botLeftY = blockAccessor.GetTerrainMapheightAt(tmpPos);

            tmpPos.Set(pos.X + widthHalf, 0, pos.Z + lengthHalf);
            int botRightY = blockAccessor.GetTerrainMapheightAt(tmpPos);


            int maxY = GameMath.Max(centerY, topLeftY, topRightY, botLeftY, botRightY);
            int minY = GameMath.Min(centerY, topLeftY, topRightY, botLeftY, botRightY);
            int diff = Math.Abs(maxY - minY);

            if (diff > 3)
            {
                return(false);
            }

            pos.Y = minY;


            // Ensure not deeply submerged in water

            tmpPos.Set(pos.X - widthHalf, pos.Y + 1 + OffsetY, pos.Z - lengthHalf);
            if (blockAccessor.GetBlock(tmpPos).IsLiquid())
            {
                return(false);
            }

            tmpPos.Set(pos.X + widthHalf, pos.Y + 1 + OffsetY, pos.Z - lengthHalf);
            if (blockAccessor.GetBlock(tmpPos).IsLiquid())
            {
                return(false);
            }

            tmpPos.Set(pos.X - widthHalf, pos.Y + 1 + OffsetY, pos.Z + lengthHalf);
            if (blockAccessor.GetBlock(tmpPos).IsLiquid())
            {
                return(false);
            }

            tmpPos.Set(pos.X + widthHalf, pos.Y + 1 + OffsetY, pos.Z + lengthHalf);
            if (blockAccessor.GetBlock(tmpPos).IsLiquid())
            {
                return(false);
            }


            pos.Y--;

            if (!satisfiesMinDistance(pos, worldForCollectibleResolve))
            {
                return(false);
            }
            if (isStructureAt(pos, worldForCollectibleResolve))
            {
                return(false);
            }

            LastPlacedSchematicLocation.Set(pos.X, pos.Y, pos.Z, pos.X + schematic.SizeX, pos.Y + schematic.SizeY, pos.Z + schematic.SizeZ);
            LastPlacedSchematic = schematic;
            schematic.PlaceRespectingBlockLayers(blockAccessor, worldForCollectibleResolve, pos, climateUpLeft, climateUpRight, climateBotLeft, climateBotRight, replaceblockids);

            return(true);
        }
        void genPatches(int chunkX, int chunkZ, bool postPass)
        {
            int   dx, dz, x, z;
            Block block;

            for (int i = 0; i < bpc.Patches.Length; i++)
            {
                BlockPatch blockPatch = bpc.Patches[i];
                if (blockPatch.PostPass != postPass)
                {
                    continue;
                }

                float chance = blockPatch.Chance * bpc.ChanceMultiplier.nextFloat();

                while (chance-- > rnd.NextDouble())
                {
                    dx = rnd.Next(chunksize);
                    dz = rnd.Next(chunksize);
                    x  = dx + chunkX * chunksize;
                    z  = dz + chunkZ * chunksize;

                    int y = heightmap[dz * chunksize + dx];
                    if (y <= 0 || y >= worldheight - 15)
                    {
                        continue;
                    }

                    tmpPos.Set(x, y, z);
                    block = blockAccessor.GetBlock(tmpPos);

                    // Place according to forest value
                    float forestRel = GameMath.BiLerp(forestUpLeft, forestUpRight, forestBotLeft, forestBotRight, (float)dx / chunksize, (float)dz / chunksize) / 255f;
                    int   climate   = GameMath.BiLerpRgbColor((float)dx / chunksize, (float)dz / chunksize, climateUpLeft, climateUpRight, climateBotLeft, climateBotRight);
                    //float shrubChance = GameMath.BiLerp(shrubUpLeft, shrubUpRight, shrubBotLeft, shrubBotRight, (float)dx / chunksize, (float)dz / chunksize);

                    if (bpc.IsPatchSuitableAt(blockPatch, block, api.WorldManager, climate, y, forestRel))
                    {
                        int  firstBlockId = 0;
                        bool found        = true;

                        if (blockPatch.BlocksByRockType != null)
                        {
                            found = false;
                            int dy = 1;
                            while (dy < 5 && y - dy > 0)
                            {
                                string lastCodePart = blockAccessor.GetBlock(x, y - dy, z).LastCodePart();
                                if (RockBlockIdsByType.TryGetValue(lastCodePart, out firstBlockId))
                                {
                                    found = true; break;
                                }
                                dy++;
                            }
                        }

                        if (found)
                        {
                            blockPatch.Generate(blockAccessor, rnd, x, y, z, firstBlockId);
                        }
                    }
                }
            }
        }
Exemplo n.º 27
0
        private Room FindRoomForPosition(BlockPos pos, ChunkRooms otherRooms)
        {
            QueueOfInt bfsQueue = new QueueOfInt();

            int halfSize = (ARRAYSIZE - 1) / 2;
            int maxSize  = halfSize + halfSize;

            bfsQueue.Enqueue(halfSize << 10 | halfSize << 5 | halfSize);

            int visitedIndex = (halfSize * ARRAYSIZE + halfSize) * ARRAYSIZE + halfSize; // Center node
            int iteration    = ++this.iteration;

            currentVisited[visitedIndex] = iteration;

            int coolingWallCount    = 0;
            int nonCoolingWallCount = 0;

            int skyLightCount    = 0;
            int nonSkyLightCount = 0;
            int exitCount        = 0;

            blockAccess.Begin();

            bool allChunksLoaded = true;

            int      minx = halfSize, miny = halfSize, minz = halfSize, maxx = halfSize, maxy = halfSize, maxz = halfSize;
            int      posX = pos.X - halfSize;
            int      posY = pos.Y - halfSize;
            int      posZ = pos.Z - halfSize;
            BlockPos npos = new BlockPos();
            BlockPos bpos = new BlockPos();
            int      dx, dy, dz;

            while (bfsQueue.Count > 0)
            {
                int compressedPos = bfsQueue.Dequeue();
                dx = compressedPos >> 10;
                dy = (compressedPos >> 5) & 0x1f;
                dz = compressedPos & 0x1f;
                npos.Set(posX + dx, posY + dy, posZ + dz);
                bpos.Set(npos);

                if (dx < minx)
                {
                    minx = dx;
                }
                else if (dx > maxx)
                {
                    maxx = dx;
                }

                if (dy < miny)
                {
                    miny = dy;
                }
                else if (dy > maxy)
                {
                    maxy = dy;
                }

                if (dz < minz)
                {
                    minz = dz;
                }
                else if (dz > maxz)
                {
                    maxz = dz;
                }

                Block bBlock = blockAccess.GetBlock(bpos);

                foreach (BlockFacing facing in BlockFacing.ALLFACES)
                {
                    facing.IterateThruFacingOffsets(npos);  // This must be the first command in the loop, to ensure all facings will be properly looped through regardless of any 'continue;' statements

                    // We cannot exit current block, if the facing is heat retaining (e.g. chiselled block with solid side)
                    if (bBlock.Id != 0 && bBlock.GetHeatRetention(bpos, facing) != 0)
                    {
                        continue;
                    }

                    if (!blockAccess.IsValidPos(npos))
                    {
                        nonCoolingWallCount++;
                        continue;
                    }

                    Block nBlock = blockAccess.GetBlock(npos);
                    allChunksLoaded &= blockAccess.LastChunkLoaded;
                    int heatRetention = nBlock.GetHeatRetention(npos, facing.Opposite);

                    // We hit a wall, no need to scan further
                    if (heatRetention != 0)
                    {
                        if (heatRetention < 0)
                        {
                            coolingWallCount -= heatRetention;
                        }
                        else
                        {
                            nonCoolingWallCount += heatRetention;
                        }

                        continue;
                    }

                    // Compute the new dx, dy, dz offsets for npos
                    dx = npos.X - posX;
                    dy = npos.Y - posY;
                    dz = npos.Z - posZ;

                    // Only traverse within maxSize range, and overall room size must not exceed MAXROOMSIZE
                    //   If outside that, count as an exit and don't continue searching in this direction
                    //   Note: for performance, this switch statement ensures only one conditional check in each case on the dimension which has actually changed, instead of 6 conditionals or more
                    bool outsideCube = false;
                    switch (facing.Index)
                    {
                    case 0:     // North
                        if (dz < minz)
                        {
                            outsideCube = dz < 0 || maxz - minz >= MAXROOMSIZE;
                        }
                        break;

                    case 1:     // East
                        if (dx > maxx)
                        {
                            outsideCube = dx > maxSize || maxx - minx >= MAXROOMSIZE;
                        }
                        break;

                    case 2:     // South
                        if (dz > maxz)
                        {
                            outsideCube = dz > maxSize || maxz - minz >= MAXROOMSIZE;
                        }
                        break;

                    case 3:     // West
                        if (dx < minx)
                        {
                            outsideCube = dx < 0 || maxx - minx >= MAXROOMSIZE;
                        }
                        break;

                    case 4:     // Up
                        if (dy > maxy)
                        {
                            outsideCube = dy > maxSize || maxy - miny >= MAXROOMSIZE;
                        }
                        break;

                    case 5:     // Down
                        if (dy < miny)
                        {
                            outsideCube = dy < 0 || maxy - miny >= MAXROOMSIZE;
                        }
                        break;
                    }
                    if (outsideCube)
                    {
                        exitCount++;
                        continue;
                    }


                    visitedIndex = (dx * ARRAYSIZE + dy) * ARRAYSIZE + dz;
                    if (currentVisited[visitedIndex] == iteration)
                    {
                        continue;                                              // continue if block position was already visited
                    }
                    currentVisited[visitedIndex] = iteration;

                    // We only need to check the skylight if it's a block position not already visited ...
                    int skyLightIndex = dx * ARRAYSIZE + dz;
                    if (skyLightXZChecked[skyLightIndex] < iteration)
                    {
                        skyLightXZChecked[skyLightIndex] = iteration;
                        int light = blockAccess.GetLightLevel(npos, EnumLightLevelType.OnlySunLight);

                        if (light >= api.World.SunBrightness - 1)
                        {
                            skyLightCount++;
                        }
                        else
                        {
                            nonSkyLightCount++;
                        }
                    }

                    bfsQueue.Enqueue(dx << 10 | dy << 5 | dz);
                }
            }



            int sizex = maxx - minx + 1;
            int sizey = maxy - miny + 1;
            int sizez = maxz - minz + 1;

            byte[] posInRoom = new byte[(sizex * sizey * sizez + 7) / 8];

            int volumeCount = 0;

            for (dx = 0; dx < sizex; dx++)
            {
                for (dy = 0; dy < sizey; dy++)
                {
                    visitedIndex = ((dx + minx) * ARRAYSIZE + (dy + miny)) * ARRAYSIZE + minz;
                    for (dz = 0; dz < sizez; dz++)
                    {
                        if (currentVisited[visitedIndex + dz] == iteration)
                        {
                            int index = (dy * sizez + dz) * sizex + dx;

                            posInRoom[index / 8] = (byte)(posInRoom[index / 8] | (1 << (index % 8)));
                            volumeCount++;
                        }
                    }
                }
            }

            bool isCellar = sizex <= MAXCELLARSIZE && sizey <= MAXCELLARSIZE && sizez <= MAXCELLARSIZE;

            if (!isCellar && volumeCount <= ALTMAXCELLARVOLUME)
            {
                isCellar = sizex <= ALTMAXCELLARSIZE && sizey <= MAXCELLARSIZE && sizez <= MAXCELLARSIZE ||
                           sizex <= MAXCELLARSIZE && sizey <= ALTMAXCELLARSIZE && sizez <= MAXCELLARSIZE ||
                           sizex <= MAXCELLARSIZE && sizey <= MAXCELLARSIZE && sizez <= ALTMAXCELLARSIZE;
            }


            return(new Room()
            {
                CoolingWallCount = coolingWallCount,
                NonCoolingWallCount = nonCoolingWallCount,
                SkylightCount = skyLightCount,
                NonSkylightCount = nonSkyLightCount,
                ExitCount = exitCount,
                AnyChunkUnloaded = allChunksLoaded ? 0 : 1,
                Location = new Cuboidi(posX + minx, posY + miny, posZ + minz, posX + maxx, posY + maxy, posZ + maxz),
                PosInRoom = posInRoom,
                IsSmallRoom = isCellar && exitCount == 0
            });
        }
Exemplo n.º 28
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 (mode)
            {
            case EnumReplaceMode.ReplaceAll:
                if (replaceMetaBlocks)
                {
                    handler = PlaceReplaceAllReplaceMeta;
                }
                else
                {
                    handler = PlaceReplaceAllKeepMeta;
                }

                for (int dx = 0; dx < SizeX; dx++)
                {
                    for (int dy = 0; dy < SizeY; dy++)
                    {
                        for (int dz = 0; dz < SizeZ; dz++)
                        {
                            curPos.Set(dx + startPos.X, dy + startPos.Y, dz + startPos.Z);
                            blockAccessor.SetBlock(0, curPos);
                        }
                    }
                }
                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);
        }
Exemplo n.º 29
0
        public void EnsureMapFullyLoaded()
        {
            int chunksize = api.World.BlockAccessor.ChunkSize;

            nowVisible.Clear();
            nowHidden.Clear();

            Cuboidi worldBounds = CurrentViewBounds.ToCuboidi();

            worldBounds.Div(chunksize);
            //worldBounds.GrowBy(1);

            BlockPos cur = new BlockPos().Set(worldBounds.X1, 0, worldBounds.Z1);

            //     StringBuilder debug = new StringBuilder();

            while (cur.X <= worldBounds.X2)
            {
                cur.Z = worldBounds.Z1;

                while (cur.Z <= worldBounds.Z2)
                {
                    if (!worldBoundsBefore.ContainsOrTouches(cur))
                    {
                        nowVisible.Add(new Vec2i(cur.X, cur.Z));
                        //       debug.Append(string.Format("{0}/{1}, ", cur.X, cur.Z));
                    }

                    cur.Z++;
                }

                cur.X++;
            }

            //        if (nowVisible.Count > 0) Console.WriteLine("{0} chunks now visible: {1}", nowVisible.Count, debug.ToString());


            cur.Set(worldBoundsBefore.X1, 0, worldBoundsBefore.Z1);

            while (cur.X <= worldBoundsBefore.X2)
            {
                cur.Z = worldBoundsBefore.Z1;

                while (cur.Z <= worldBoundsBefore.Z2)
                {
                    if (!worldBounds.ContainsOrTouches(cur))
                    {
                        nowHidden.Add(new Vec2i(cur.X, cur.Z));
                    }

                    cur.Z++;
                }

                cur.X++;
            }


            worldBoundsBefore = worldBounds.Clone();

            viewChanged(nowVisible, nowHidden);
        }
Exemplo n.º 30
0
        public bool TryGenerate(IBlockAccessor blockAccessor, IWorldAccessor worldForCollectibleResolve, BlockPos pos, int climateUpLeft, int climateUpRight, int climateBotLeft, int climateBotRight, DidGenerate didGenerateStructure)
        {
            this.climateUpLeft   = climateUpLeft;
            this.climateUpRight  = climateUpRight;
            this.climateBotLeft  = climateBotLeft;
            this.climateBotRight = climateBotRight;

            float    cnt         = QuantityStructures.nextFloat();
            int      minQuantity = (int)cnt;
            BlockPos schemPos    = pos.Copy();
            Cuboidi  location    = new Cuboidi();

            rand.InitPositionSeed(pos.X, pos.Z);

            List <GeneratableStructure> generatables = new List <GeneratableStructure>();

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

                int tries = 30;
                while (tries-- > 0)
                {
                    schemPos.Set(pos);
                    schemPos.Add(rand.NextInt(50) - 25, 0, rand.NextInt(50) - 25);
                    schemPos.Y = blockAccessor.GetTerrainMapheightAt(schemPos);

                    double           rndVal = rand.NextDouble() * totalWeight;
                    int              i      = 0;
                    VillageSchematic schem  = null;
                    while (rndVal > 0)
                    {
                        schem   = Schematics[i++];
                        rndVal -= schem.Weight;
                    }
                    BlockSchematicStructure struc = GetGeneratableStructure(schem, blockAccessor, worldForCollectibleResolve, schemPos);

                    if (struc != null)
                    {
                        location.Set(schemPos.X, schemPos.Y, schemPos.Z, schemPos.X + struc.SizeX, schemPos.Y + struc.SizeY, schemPos.Z + struc.SizeZ);
                        bool intersect = false;
                        for (int k = 0; k < generatables.Count; k++)
                        {
                            if (location.IntersectsOrTouches(generatables[k].location))
                            {
                                intersect = true;
                                break;
                            }
                        }

                        if (!intersect)
                        {
                            generatables.Add(new GeneratableStructure()
                            {
                                struc = struc, pos = schemPos.Copy(), location = location.Clone()
                            });
                        }
                        break;
                    }
                }
            }

            if (generatables.Count >= minQuantity)
            {
                foreach (var val in generatables)
                {
                    val.struc.PlaceRespectingBlockLayers(blockAccessor, worldForCollectibleResolve, val.pos, climateUpLeft, climateUpRight, climateBotLeft, climateBotRight, replaceblockids);
                    didGenerateStructure(val.location, val.struc);
                }
            }

            return(true);
        }