Beispiel #1
0
        public void Generate(IBlockAccessor blockAccessor, LCGRandom rnd, int posX, int posY, int posZ, int firstBlockId)
        {
            float quantity  = Quantity.nextFloat() + 1;
            int   chunkSize = blockAccessor.ChunkSize;

            Block[] blocks = getBlocks(firstBlockId);
            if (blocks.Length == 0)
            {
                return;
            }

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

                pos.X = posX + (int)OffsetX.nextFloat();
                pos.Z = posZ + (int)OffsetZ.nextFloat();

                int index = GameMath.Mod((int)BlockCodeIndex.nextFloat(), blocks.Length);

                IServerChunk chunk = (IServerChunk)blockAccessor.GetChunk(pos.X / chunkSize, 0, pos.Z / chunkSize);
                if (chunk == null)
                {
                    break;
                }

                int lx = GameMath.Mod(pos.X, chunkSize);
                int lz = GameMath.Mod(pos.Z, chunkSize);

                if (Placement == EnumBlockPatchPlacement.Underground)
                {
                    pos.Y = rnd.NextInt(Math.Max(1, chunk.MapChunk.WorldGenTerrainHeightMap[lz * blockAccessor.ChunkSize + lx] - 1));
                }
                else
                {
                    pos.Y = chunk.MapChunk.RainHeightMap[lz * blockAccessor.ChunkSize + lx] + 1;

                    if (Math.Abs(pos.Y - posY) > 8 || pos.Y >= blockAccessor.MapSizeY - 1)
                    {
                        continue;
                    }

                    if (Placement == EnumBlockPatchPlacement.UnderWater)
                    {
                        tempPos.Set(pos.X, pos.Y - GameMath.Max(1, MinWaterDepth), pos.Z);
                        Block downBlock = blockAccessor.GetBlock(tempPos);
                        if (downBlock == null || downBlock.LiquidCode != "water")
                        {
                            continue;
                        }
                    }
                }

                blocks[index].TryPlaceBlockForWorldGen(blockAccessor, pos, BlockFacing.UP, rnd);
            }
        }
Beispiel #2
0
        private bool isChunkAreaLoaded(IBlockAccessor blockAccessor, int growRange)
        {
            int chunksize = blockAccessor.ChunkSize;
            int mincx     = (Pos.X - growRange) / chunksize;
            int maxcx     = (Pos.X + growRange) / chunksize;

            int mincz = (Pos.Z - growRange) / chunksize;
            int maxcz = (Pos.Z + growRange) / chunksize;

            for (int cx = mincx; cx <= maxcx; cx++)
            {
                for (int cz = mincz; cz <= maxcz; cz++)
                {
                    if (blockAccessor.GetChunk(cx, Pos.Y / chunksize, cz) == null)
                    {
                        return(false);
                    }
                }
            }

            return(true);
        }
Beispiel #3
0
        public void TryPlacePondAt(int dx, int pondYPos, int dz, int chunkX, int chunkZ, int depth = 0)
        {
            searchPositionsDeltas.Clear();
            pondPositions.Clear();

            // Clear Array
            for (int i = 0; i < didCheckPosition.Length; i++)
            {
                didCheckPosition[i] = false;
            }


            int   basePosX = chunkX * chunksize;
            int   basePosZ = chunkZ * chunksize;
            Vec2i tmp      = new Vec2i();


            searchPositionsDeltas.Enqueue(new Vec2i(dx, dz));
            pondPositions.Enqueue(new Vec2i(basePosX + dx, basePosZ + dz));
            didCheckPosition[(dz + mapOffset) * searchSize + dx + mapOffset] = true;


            while (searchPositionsDeltas.Count > 0)
            {
                Vec2i p = searchPositionsDeltas.Dequeue();

                foreach (BlockFacing facing in BlockFacing.HORIZONTALS)
                {
                    ndx = p.X + facing.Normali.X;
                    ndz = p.Y + facing.Normali.Z;

                    tmp.Set(chunkX * chunksize + ndx, chunkZ * chunksize + ndz);

                    Block belowBlock = blockAccessor.GetBlock(tmp.X, pondYPos - 1, tmp.Y);

                    bool inBoundary = ndx > minBoundary && ndz > minBoundary && ndx < maxBoundary && ndz < maxBoundary;

                    // Only continue when within our 3x3 chunk search area and having a more or less solid block below (or water)
                    if (inBoundary && (belowBlock.Replaceable < 6000 || belowBlock.BlockId == GlobalConfig.waterBlockId))
                    {
                        int arrayIndex = (ndz + mapOffset) * searchSize + ndx + mapOffset;

                        // Already checked or did we reach a pond border?
                        if (!didCheckPosition[arrayIndex] && blockAccessor.GetBlock(tmp.X, pondYPos, tmp.Y).Replaceable >= 6000)
                        {
                            searchPositionsDeltas.Enqueue(new Vec2i(ndx, ndz));
                            pondPositions.Enqueue(tmp.Copy());

                            didCheckPosition[arrayIndex] = true;
                        }
                    }
                    else
                    {
                        pondPositions.Clear();
                        searchPositionsDeltas.Clear();
                        return;
                    }
                }
            }

            if (pondPositions.Count == 0)
            {
                return;
            }


            int          curChunkX, curChunkZ;
            int          prevChunkX = -1, prevChunkZ = -1;
            int          regionChunkSize    = api.WorldManager.RegionSize / chunksize;
            IMapChunk    mapchunk           = null;
            IServerChunk chunk              = null;
            IServerChunk chunkOneBlockBelow = null;

            int ly = GameMath.Mod(pondYPos, chunksize);

            bool extraPondDepth = rand.NextDouble() > 0.5;
            bool withSeabed     = extraPondDepth || pondPositions.Count > 16;

            foreach (Vec2i p in pondPositions)
            {
                curChunkX = p.X / chunksize;
                curChunkZ = p.Y / chunksize;

                int lx = GameMath.Mod(p.X, chunksize);
                int lz = GameMath.Mod(p.Y, chunksize);

                // Get correct chunk and correct climate data if we don't have it already
                if (curChunkX != prevChunkX || curChunkZ != prevChunkZ)
                {
                    chunk = (IServerChunk)blockAccessor.GetChunk(curChunkX, pondYPos / chunksize, curChunkZ);
                    if (chunk == null)
                    {
                        chunk = api.WorldManager.GetChunk(curChunkX, pondYPos / chunksize, curChunkZ);
                    }
                    chunk.Unpack();

                    if (ly == 0)
                    {
                        chunkOneBlockBelow = ((IServerChunk)blockAccessor.GetChunk(curChunkX, (pondYPos - 1) / chunksize, curChunkZ));
                        if (chunkOneBlockBelow == null)
                        {
                            return;
                        }
                        chunkOneBlockBelow.Unpack();
                    }
                    else
                    {
                        chunkOneBlockBelow = chunk;
                    }

                    mapchunk = chunk.MapChunk;
                    IntDataMap2D climateMap = mapchunk.MapRegion.ClimateMap;

                    float fac = (float)climateMap.InnerSize / regionChunkSize;
                    int   rlX = curChunkX % regionChunkSize;
                    int   rlZ = curChunkZ % regionChunkSize;

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

                    prevChunkX = curChunkX;
                    prevChunkZ = curChunkZ;

                    chunkOneBlockBelow.MarkModified();
                    chunk.MarkModified();
                }


                // Raise heightmap by 1
                mapchunk.RainHeightMap[lz * chunksize + lx] = Math.Max(mapchunk.RainHeightMap[lz * chunksize + lx], (ushort)pondYPos);

                // Identify correct climate at this position
                int   climate = GameMath.BiLerpRgbColor((float)lx / chunksize, (float)lz / chunksize, climateUpLeft, climateUpRight, climateBotLeft, climateBotRight);
                float temp    = TerraGenConfig.GetScaledAdjustedTemperatureFloat((climate >> 16) & 0xff, pondYPos - TerraGenConfig.seaLevel);


                // 1. Place water or ice block
                chunk.Blocks[(ly * chunksize + lz) * chunksize + lx] = temp < -5 ? GlobalConfig.lakeIceBlockId : GlobalConfig.waterBlockId;


                // 2. Let's make a nice muddy gravely sea bed
                if (!withSeabed)
                {
                    continue;
                }

                // Need to check the block below first
                int index = ly == 0 ?
                            ((31 * chunksize + lz) * chunksize + lx) :
                            (((ly - 1) * chunksize + lz) * chunksize + lx)
                ;

                Block belowBlock = api.World.Blocks[chunkOneBlockBelow.Blocks[index]];

                // Water below? Seabed already placed
                if (belowBlock.IsLiquid())
                {
                    continue;
                }

                float rainRel     = TerraGenConfig.GetRainFall((climate >> 8) & 0xff, pondYPos) / 255f;
                int   rockBlockId = mapchunk.TopRockIdMap[lz * chunksize + lx];
                if (rockBlockId == 0)
                {
                    continue;
                }

                for (int i = 0; i < lakebedLayerConfig.BlockCodeByMin.Length; i++)
                {
                    if (lakebedLayerConfig.BlockCodeByMin[i].Suitable(temp, rainRel, (float)pondYPos / mapheight, rand))
                    {
                        chunkOneBlockBelow.Blocks[index] = lakebedLayerConfig.BlockCodeByMin[i].GetBlockForMotherRock(rockBlockId);
                        break;
                    }
                }
            }


            if (pondPositions.Count > 0 && extraPondDepth)
            {
                TryPlacePondAt(dx, pondYPos + 1, dz, chunkX, chunkZ, depth + 1);
            }
        }