Skip to content

Structure search error #9

@ghost

Description

  • There is a 1 in 10 chance that you will be misjudged when using this code to find an end city:
   private static List<BlockPos> locateStructure(Seed seed, Feature feature, EndCityMode endCityMode, BlockPos center, int radius, int maxResults) {
        Dimension dimension = getDimension(feature);
        MCVersion mcVersion = seed.version;
        Structure<?, ?> structure = getStructure(feature, mcVersion);
        if (structure == null) return null;
        BiomeSource biomeSource = BiomeSource.of(dimension, mcVersion, seed.seed);
        if (!structure.isValidDimension(biomeSource.getDimension()))
            return null;
        List<BPos> structurePos = locateStructures(structure, new BPos(center.getX(), center.getY(), center.getZ()), endCityMode, radius, maxResults, new ChunkRand(), biomeSource, TerrainGenerator.of(biomeSource));

        return toBlockPosList(structurePos);
    }

private static List<BPos> locateStructures(Structure<?, ?> structure, BPos center, EndCityMode endCityMode, int radius, int maxResults, ChunkRand chunkRand, BiomeSource source, TerrainGenerator terrainGenerator) {
        List<BPos> result = new ArrayList<>();
        if (structure instanceof EndCity endCity) {
            SpiralIterator<CPos> spiralIterator = new SpiralIterator<>(new CPos(center.getX() >> 4, center.getZ() >> 4), new CPos(radius, radius), (x, y, z) -> new CPos(x, z));

            StreamSupport.stream(spiralIterator.spliterator(), false)
                    .filter(cPos -> {
                        com.seedfinding.mcfeature.Feature.Data<?> data = endCity.at(cPos.getX(), cPos.getZ());
                        EndCityGenerator endCityGenerator = new EndCityGenerator(source.getVersion());
                        return data.testStart(source.getWorldSeed(), chunkRand)
                                && data.testBiome(source)
                                && data.testGenerate(terrainGenerator)
                                && switch (endCityMode) {
                            case OnlyHasShip -> endCityGenerator.generate(terrainGenerator, cPos) && endCityGenerator.hasShip();
                            case OnlyNotShip -> endCityGenerator.generate(terrainGenerator, cPos) && !endCityGenerator.hasShip();
                            case Both -> endCityGenerator.generate(terrainGenerator, cPos);
                        };
                    })
                    .limit(maxResults)
                    .forEach(cPos -> result.add(cPos.toBlockPos().add(9, 0, 9)));
        } else if (structure instanceof RegionStructure<?, ?> regionStructure) {
            int chunkInRegion = regionStructure.getSpacing();
            int regionSize = chunkInRegion * 16;

            final int border = 30_000_000;
            SpiralIterator<RPos> spiralIterator = new SpiralIterator<>(center.toRegionPos(regionSize), new BPos(-border, 0, -border).toRegionPos(regionSize), new BPos(border, 0, border).toRegionPos(regionSize), 1, (x, y, z) -> new RPos(x, z, regionSize));


            StreamSupport.stream(spiralIterator.spliterator(), false)
                    .map(rPos -> regionStructure.getInRegion(source.getWorldSeed(), rPos.getX(), rPos.getZ(), chunkRand))
                    .filter(Objects::nonNull)
                    .filter(cPos -> (regionStructure.canSpawn(cPos, source)) && (terrainGenerator == null || regionStructure.canGenerate(cPos, terrainGenerator)))
                    .limit(maxResults)
                    .forEach(cPos -> result.add(cPos.toBlockPos().add(9, 0, 9)));
        } else {
            if (structure instanceof Stronghold strongholdStructure) {
                CPos currentChunkPos = center.toChunkPos();
                int squaredDistance = Integer.MAX_VALUE;


                for (CPos stronghold : strongholdStructure.getAllStarts(source, chunkRand)) {
                    if (result.size() >= maxResults) {
                        break;
                    }
                    int newSquaredDistance = (currentChunkPos.getX() - stronghold.getX()) * (currentChunkPos.getX() - stronghold.getX()) + (currentChunkPos.getZ() - stronghold.getZ()) * (currentChunkPos.getZ() - stronghold.getZ());
                    if (newSquaredDistance < squaredDistance) {
                        squaredDistance = newSquaredDistance;
                        result.clear();
                        result.add(stronghold.toBlockPos().add(9, 0, 9));
                    }
                }
            } else if (structure instanceof Mineshaft mineshaft) {
                SpiralIterator<CPos> spiralIterator = new SpiralIterator<>(new CPos(center.getX() >> 4, center.getZ() >> 4), new CPos(radius, radius), (x, y, z) -> new CPos(x, z));

                StreamSupport.stream(spiralIterator.spliterator(), false)
                        .filter(cPos -> {
                            com.seedfinding.mcfeature.Feature.Data<Mineshaft> data = mineshaft.at(cPos.getX(), cPos.getZ());
                            return data.testStart(source.getWorldSeed(), chunkRand) && data.testBiome(source) && data.testGenerate(terrainGenerator);
                        })
                        .limit(maxResults)
                        .forEach(cPos -> result.add(cPos.toBlockPos().add(9, 0, 9)));
            }
        }

        return result;
    }


    private static Dimension getDimension(Feature feature) {
        return switch (feature) {
            case buried_treasure -> Dimension.OVERWORLD;
            case mansion -> Dimension.OVERWORLD;
            case stronghold -> Dimension.OVERWORLD;
            case nether_fortress -> Dimension.NETHER;
            case ocean_monument -> Dimension.OVERWORLD;
            case bastion_remnant -> Dimension.NETHER;
            case slime_chunk -> Dimension.OVERWORLD;
            case village -> Dimension.OVERWORLD;
            case mineshaft -> Dimension.OVERWORLD;
            case end_city -> Dimension.END;
            case desert_pyramid -> Dimension.OVERWORLD;
            default -> Dimension.OVERWORLD;
        };
    }

    private static boolean checkIfInDimension(Dimension dimension) {
        return switch (dimension) {
            case OVERWORLD -> (PlayerUtils.getDimension() == meteordevelopment.meteorclient.utils.world.Dimension.Overworld);
            case NETHER -> (PlayerUtils.getDimension() == meteordevelopment.meteorclient.utils.world.Dimension.Nether);
            case END -> (PlayerUtils.getDimension() == meteordevelopment.meteorclient.utils.world.Dimension.End);
        };
    }

    private static Structure<?, ?> getStructure(Feature feature, MCVersion version) {
        return switch (feature) {
            case buried_treasure -> new BuriedTreasure(version);
            case mansion -> new Mansion(version);
            case stronghold -> new Stronghold(version);
            case nether_fortress -> new Fortress(version);
            case ocean_monument -> new Monument(version);
            case bastion_remnant -> new BastionRemnant(version);
            case end_city -> new EndCity(version);
            case village -> new Village(version);
            case mineshaft -> new Mineshaft(version);
            case desert_pyramid -> new DesertPyramid(version);
            default -> null;
        };
    }
    
    private static List<BlockPos> toBlockPosList(List<BPos> posList) {
        List<BlockPos> blockPosList = new ArrayList<>();
        for (BPos pos : posList) {
            blockPosList.add(new BlockPos(pos.getX(), pos.getY(), pos.getZ()));
        }
        return blockPosList;
    }

Seed: -3396536410594980164, Location: -3428 60-13070.

Judging from the seedMap, the location below 1.18.2 will refresh the end city, but above 1.18.2 is useless, I also tried to change the MCVersion of BiomeSource, but the result remains the same, so I suspect that it is an API problem.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions