예제 #1
0
        public void UpdateCloudTiles()
        {
            weatherSim.EnsureNoiseCacheIsFresh();
            byte zero = 0;
            int  end  = CloudTileLength - 2;

            // Load density from perlin noise
            for (int dx = 0; dx < CloudTileLength; dx++)
            {
                for (int dz = 0; dz < CloudTileLength; dz++)
                {
                    int x = (tilePosX + dx - CloudTileLength / 2 - tileOffsetX);
                    int z = (tilePosZ + dz - CloudTileLength / 2 - tileOffsetZ);
                    brightnessRand.InitPositionSeed(x, z);
                    double density = weatherSim.GetBlendedCloudDensityAt(dx, dz);

                    CloudTile cloudTile = cloudTiles[dx * CloudTileLength + dz];

                    cloudTile.MaxDensity = (byte)GameMath.Clamp((int)((64 * 255 * density * 3)) / 64, 0, 255);
                    cloudTile.Brightness = (byte)(235 + brightnessRand.NextInt(21));
                    cloudTile.YOffset    = (float)weatherSim.GetBlendedCloudOffsetYAt(dx, dz);
                }
            }


            // Has to be done after all densities have updated
            for (int dx = 0; dx < CloudTileLength; dx++)
            {
                for (int dz = 0; dz < CloudTileLength; dz++)
                {
                    CloudTile cloud = cloudTiles[dx * CloudTileLength + dz];

                    byte northDensity = dz < 1 ? zero : cloudTiles[dx * CloudTileLength + dz - 1].MaxDensity;
                    byte southDensity = dz >= end ? zero : cloudTiles[dx * CloudTileLength + dz + 1].MaxDensity;
                    byte eastDensity  = dx >= end ? zero : cloudTiles[(dx + 1) * CloudTileLength + dz].MaxDensity;
                    byte westDensity  = dx < 1 ? zero : cloudTiles[(dx - 1) * CloudTileLength + dz].MaxDensity;

                    int changeVal = northDensity == 0 || cloud.MaxDensity - northDensity > 5 ? 1 : -1;
                    cloud.NorthFaceDensity = (byte)GameMath.Clamp((cloud.NorthFaceDensity + changeVal), 0, cloud.MaxDensity);

                    changeVal             = eastDensity == 0 || cloud.MaxDensity - eastDensity > 5 ? 1 : -1;
                    cloud.EastFaceDensity = (byte)GameMath.Clamp((cloud.EastFaceDensity + changeVal), 0, cloud.MaxDensity);

                    changeVal = southDensity == 0 || cloud.MaxDensity - southDensity > 5 ? 1 : -1;
                    cloud.SouthFaceDensity = (byte)GameMath.Clamp((cloud.SouthFaceDensity + changeVal), 0, cloud.MaxDensity);

                    changeVal             = westDensity == 0 || cloud.MaxDensity - westDensity > 5 ? 1 : -1;
                    cloud.WestFaceDensity = (byte)GameMath.Clamp((cloud.WestFaceDensity + changeVal), 0, cloud.MaxDensity);

                    cloud.UpDownDensity += (byte)GameMath.Clamp(cloud.MaxDensity - cloud.UpDownDensity, -1, 1);
                }
            }
        }
예제 #2
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);
        }
예제 #3
0
        private void CarveTunnel(IServerChunk[] chunks, int chunkX, int chunkZ, double posX, double posY, double posZ, float horAngle, float vertAngle, float horizontalSize, float verticalSize, int currentIteration, int maxIterations, int branchLevel)
        {
            blockId = airBlockId;

            ushort[] heightmap = chunks[0].MapChunk.WorldGenTerrainHeightMap;


            float horAngleChange       = 0;
            float vertAngleChange      = 0;
            float horRadiusChange      = 0;
            float horRadiusChangeAccum = 0;

            float relPos;

            while (currentIteration++ < maxIterations)
            {
                relPos = (float)currentIteration / maxIterations;

                float horRadius  = 1.5f + GameMath.FastSin(relPos * GameMath.PI) * horizontalSize + horRadiusChangeAccum;
                float vertRadius = (horRadius - horRadiusChangeAccum / 2) * verticalSize;


                float advanceHor = GameMath.FastCos(vertAngle);
                float advanceVer = GameMath.FastSin(vertAngle);



                posX += GameMath.FastCos(horAngle) * advanceHor;
                posY += advanceVer;
                posZ += GameMath.FastSin(horAngle) * advanceHor;

                vertAngle *= 0.8f;

                if (caveRand.NextInt(50) == 0)
                {
                    horRadiusChange = caveRand.NextFloat() * caveRand.NextFloat() * 7;
                }

                horRadiusChangeAccum = Math.Max(0, horRadiusChangeAccum + horRadiusChange * 0.15f);
                horRadiusChange     -= 0.45f;

                horAngle  += 0.1f * horAngleChange;
                vertAngle += 0.1f * vertAngleChange;


                vertAngleChange = 0.9f * vertAngleChange + (caveRand.NextFloat() - caveRand.NextFloat()) * caveRand.NextFloat() * 3;
                horAngleChange  = 0.9f * horAngleChange + (caveRand.NextFloat() - caveRand.NextFloat()) * caveRand.NextFloat() * 1;

                // Horizontal branch
                if (caveRand.NextInt(25 * (branchLevel + 1)) == 0 && branchLevel < 3)
                {
                    CarveTunnel(
                        chunks,
                        chunkX,
                        chunkZ,
                        posX,
                        posY,
                        posZ,
                        horAngle + (caveRand.NextFloat() + caveRand.NextFloat() - 1) + GameMath.PI,
                        vertAngle + (caveRand.NextFloat() - 0.5f) * (caveRand.NextFloat() - 0.5f),
                        horizontalSize,
                        verticalSize,
                        currentIteration,
                        maxIterations - (int)(caveRand.NextFloat() * 0.5 * maxIterations),
                        branchLevel + 1
                        );
                }

                // Vertical branch
                if (horRadius > 3 && posY > 60 && caveRand.NextInt(40) == 0 && branchLevel < 1)
                {
                    CarveShaft(
                        chunks,
                        chunkX,
                        chunkZ,
                        posX,
                        posY,
                        posZ,
                        horAngle + (caveRand.NextFloat() + caveRand.NextFloat() - 1) + GameMath.PI,
                        -GameMath.PI / 2 - 0.1f + 0.2f * caveRand.NextFloat(),
                        Math.Min(3.5f, horRadius - 1),
                        verticalSize,
                        currentIteration,
                        maxIterations - (int)(caveRand.NextFloat() * 0.5 * maxIterations) + (int)((posY / 5) * (0.5f + 0.5f * caveRand.NextFloat())),
                        branchLevel
                        );

                    branchLevel++;
                }


                // Lake

                /* bool end = currentIteration == maxIterations;
                 *
                 * if (end && caveRand.NextInt(4) == 0)
                 * {
                 *   CarveLake(chunks, horRadius, vertRadius, posX, posY, posZ, heightmap, chunkX, chunkZ);
                 *   continue;
                 * }*/

                if (caveRand.NextInt(5) == 0 && horRadius >= 2)
                {
                    continue;
                }

                // Check just to prevent unnecessary calculations
                // As long as we are outside the currently generating chunk, we don't need to generate anything
                if (posX <= -horRadius * 2 || posX >= chunksize + horRadius * 2 || posZ <= -horRadius * 2 || posZ >= chunksize + horRadius * 2)
                {
                    continue;
                }

                SetBlocks(chunks, horRadius, vertRadius, posX, posY, posZ, heightmap, chunkX, chunkZ);
            }
        }