internal bool TryGenerateRuinAtSurface(IBlockAccessor blockAccessor, IWorldAccessor worldForCollectibleResolve, BlockPos pos)
        {
            int num    = rand.NextInt(schematicDatas.Length);
            int orient = rand.NextInt(4);
            BlockSchematicStructure schematic = schematicDatas[num][orient];


            int wdthalf = (int)Math.Ceiling(schematic.SizeX / 2f);
            int lenhalf = (int)Math.Ceiling(schematic.SizeZ / 2f);

            int wdt = schematic.SizeX;
            int len = schematic.SizeZ;


            tmpPos.Set(pos.X + wdthalf, 0, pos.Z + lenhalf);
            int centerY = blockAccessor.GetTerrainMapheightAt(pos);

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

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

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

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

            tmpPos.Set(pos.X + wdt, 0, pos.Z + len);
            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, pos.Y + 1 + OffsetY, pos.Z);
            if (blockAccessor.GetBlock(tmpPos).IsLiquid())
            {
                return(false);
            }

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

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

            tmpPos.Set(pos.X + wdt, pos.Y + 1 + OffsetY, pos.Z + len);
            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);
        }
        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);
        }