From 5642d373e9964ed573d80fac29fe330ff0bba41e Mon Sep 17 00:00:00 2001 From: Frederik van der Els Date: Fri, 25 Apr 2025 14:58:18 +0200 Subject: [PATCH 01/15] (Re!)add the sm:highlight command --- .gitignore | 1 + .gitmodules | 1 + includes.txt | 83 ++++++++++ src/main/c | 2 +- .../java/dev/xpple/seedmapper/SeedMapper.java | 5 + .../seedmapper/command/CommandExceptions.java | 1 + .../command/arguments/BlockArgument.java | 84 +++++++++++ .../command/commands/ClearCommand.java | 21 +++ .../command/commands/HighlightCommand.java | 142 ++++++++++++++++++ .../xpple/seedmapper/feature/OreTypes.java | 56 +++++++ .../xpple/seedmapper/render/NoDepthLayer.java | 25 +++ .../assets/seedmapper/lang/en_us.json | 7 +- 12 files changed, 426 insertions(+), 2 deletions(-) create mode 100644 src/main/java/dev/xpple/seedmapper/command/arguments/BlockArgument.java create mode 100644 src/main/java/dev/xpple/seedmapper/command/commands/ClearCommand.java create mode 100644 src/main/java/dev/xpple/seedmapper/command/commands/HighlightCommand.java create mode 100644 src/main/java/dev/xpple/seedmapper/feature/OreTypes.java create mode 100644 src/main/java/dev/xpple/seedmapper/render/NoDepthLayer.java diff --git a/.gitignore b/.gitignore index 91ba3933..788e4c22 100644 --- a/.gitignore +++ b/.gitignore @@ -31,6 +31,7 @@ bin/ # fabric run/ +logs/ # github diff --git a/.gitmodules b/.gitmodules index f8d0f6fc..e7a3f3d6 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,7 @@ [submodule "src/main/c"] path = src/main/c url = https://github.com/xpple/cubiomes + branch = ore-generation [submodule "jextract"] path = jextract url = https://github.com/xpple/jextract diff --git a/includes.txt b/includes.txt index f7daef62..c3ee104a 100644 --- a/includes.txt +++ b/includes.txt @@ -270,11 +270,16 @@ --include-function isShallowOcean --include-function isSnowy +--include-constant ANCIENT_DEBRIS +--include-constant ANDESITE --include-constant Ancient_City +--include-constant AndesiteOre +--include-constant BASALT --include-constant BASE_FLOOR --include-constant BASE_ROOF --include-constant BF_APPROX --include-constant BF_FORCED_OCEAN +--include-constant BLACKSTONE --include-constant BRIDGE_CORRIDOR_ENTRANCE --include-constant BRIDGE_CROSSING --include-constant BRIDGE_END @@ -287,7 +292,13 @@ --include-constant BRIDGE_STRAIGHT --include-constant Bastion --include-constant Blacksmith +--include-constant BlackstoneOre +--include-constant BuriedDiamondOre +--include-constant BuriedLapisOre --include-constant Butcher +--include-constant CLAY +--include-constant COAL_ORE +--include-constant COPPER_ORE --include-constant CORRIDOR_CROSSING --include-constant CORRIDOR_NETHER_WART --include-constant CORRIDOR_STAIRS @@ -296,13 +307,27 @@ --include-constant CORRIDOR_TURN_RIGHT --include-constant CORRIDOR_T_CROSSING --include-constant Church +--include-constant ClayOre +--include-constant CoalOre +--include-constant CopperOre +--include-constant DEEPSLATE +--include-constant DIAMOND_ORE +--include-constant DIORITE +--include-constant DIRT +--include-constant DeepslateOre --include-constant Desert_Pyramid --include-constant Desert_Well +--include-constant DiamondOre +--include-constant DioriteOre +--include-constant DirtOre +--include-constant EMERALD_ORE --include-constant END_CITY_PIECES_MAX --include-constant END_SHIP +--include-constant EmeraldOre --include-constant End_City --include-constant End_Gateway --include-constant End_Island +--include-constant ExtraGoldOre --include-constant FAT_TOWER_BASE --include-constant FAT_TOWER_MIDDLE --include-constant FAT_TOWER_TOP @@ -313,27 +338,63 @@ --include-constant FarmSmall --include-constant Feature --include-constant Fortress +--include-constant GOLD_ORE +--include-constant GRANITE +--include-constant GRAVEL --include-constant Geode +--include-constant GoldOre +--include-constant GraniteOre +--include-constant GravelOre --include-constant HOUSE_NUM --include-constant HouseLarge --include-constant HouseSmall +--include-constant IRON_ORE --include-constant Igloo +--include-constant IronOre --include-constant Jungle_Pyramid --include-constant Jungle_Temple +--include-constant LAPIS_ORE +--include-constant LapisOre +--include-constant LargeCopperOre +--include-constant LargeDebrisOre +--include-constant LargeDiamondOre --include-constant Library +--include-constant LowerAndesiteOre +--include-constant LowerCoalOre +--include-constant LowerDioriteOre +--include-constant LowerGoldOre +--include-constant LowerGraniteOre +--include-constant LowerRedstoneOre +--include-constant MAGMA_BLOCK --include-constant MASK48 +--include-constant MagmaOre --include-constant Mansion +--include-constant MediumDiamondOre +--include-constant MiddleIronOre --include-constant Mineshaft --include-constant Monument +--include-constant NETHERRACK +--include-constant NETHER_GOLD_ORE +--include-constant NETHER_QUARTZ_ORE +--include-constant NetherGoldOre +--include-constant NetherGravelOre --include-constant Ocean_Ruin --include-constant Outpost --include-constant PIECE_COUNT +--include-constant QuartzOre +--include-constant REDSTONE_ORE +--include-constant RedstoneOre --include-constant Ruined_Portal --include-constant Ruined_Portal_N --include-constant SECOND_FLOOR_1 --include-constant SECOND_FLOOR_2 --include-constant SECOND_ROOF +--include-constant SOUL_SAND +--include-constant STONE --include-constant Shipwreck +--include-constant SmallDebrisOre +--include-constant SmallIronOre +--include-constant SoulSandOre --include-constant Swamp_Hut --include-constant THIRD_FLOOR_1 --include-constant THIRD_FLOOR_2 @@ -342,19 +403,34 @@ --include-constant TOWER_FLOOR --include-constant TOWER_PIECE --include-constant TOWER_TOP +--include-constant TUFF --include-constant Trail_Ruins --include-constant Treasure --include-constant Trial_Chambers +--include-constant TuffOre +--include-constant UpperAndesiteOre +--include-constant UpperCoalOre +--include-constant UpperDioriteOre +--include-constant UpperGraniteOre +--include-constant UpperIronOre --include-constant Village --include-constant WoodHut +--include-function appendPos3List --include-function canBiomeGenerate --include-function checkForBiomes --include-function checkForBiomesAtLayer --include-function checkForTemps +--include-function createPos3List --include-function estimateSpawn +--include-function freePos3List --include-function genPotential +--include-function generateBaseOrePosition +--include-function generateOrePositions +--include-function generateOres +--include-function generateVeinPart --include-function getAvailableBiomes --include-function getBiomeCenters +--include-function getBiomeForOreGen --include-function getBiomeParaExtremes --include-function getBiomeParaLimits --include-function getEndCityPieces @@ -366,6 +442,8 @@ --include-function getLinkedGatewayChunk --include-function getLinkedGatewayPos --include-function getMineshafts +--include-function getOreConfig +--include-function getOreYPos --include-function getParaDescent --include-function getParaRange --include-function getPossibleBiomesForLimits @@ -377,6 +455,7 @@ --include-function isEndChunkEmpty --include-function isViableEndCityTerrain --include-function isViableFeatureBiome +--include-function isViableOreBiome --include-function isViableStructurePos --include-function isViableStructureTerrain --include-function locateBiome @@ -386,9 +465,11 @@ --include-function setupBiomeFilter --include-struct BiomeFilter --include-struct EndIsland +--include-struct OreConfig --include-struct Piece --include-struct Pos --include-struct Pos3 +--include-struct Pos3List --include-struct StrongholdIter --include-struct StructureConfig --include-struct StructureVariant @@ -581,10 +662,12 @@ --include-typedef u32 --include-typedef u64 --include-typedef u8 +--include-struct RandomSource --include-struct Xoroshiro --include-function biome2str --include-function biomesToImage +--include-function free_ptr --include-function initBiomeColors --include-function initBiomeTypeColors --include-function loadSavedSeeds diff --git a/src/main/c b/src/main/c index 2e6c2643..9acedf46 160000 --- a/src/main/c +++ b/src/main/c @@ -1 +1 @@ -Subproject commit 2e6c26438b253531c31b79df7b52be239d9e1ebe +Subproject commit 9acedf46e545187e05c8c16ae4abb84d892f20b0 diff --git a/src/main/java/dev/xpple/seedmapper/SeedMapper.java b/src/main/java/dev/xpple/seedmapper/SeedMapper.java index b250772e..b548c21d 100644 --- a/src/main/java/dev/xpple/seedmapper/SeedMapper.java +++ b/src/main/java/dev/xpple/seedmapper/SeedMapper.java @@ -4,6 +4,8 @@ import dev.xpple.betterconfig.api.ModConfigBuilder; import dev.xpple.seedmapper.command.arguments.SeedResolutionArgument; import dev.xpple.seedmapper.command.commands.CheckSeedCommand; +import dev.xpple.seedmapper.command.commands.ClearCommand; +import dev.xpple.seedmapper.command.commands.HighlightCommand; import dev.xpple.seedmapper.command.commands.LocateCommand; import dev.xpple.seedmapper.command.commands.SourceCommand; import dev.xpple.seedmapper.config.Configs; @@ -49,11 +51,14 @@ public void onInitializeClient() { SeedDatabaseHelper.fetchSeeds(); ClientCommandRegistrationCallback.EVENT.register(SeedMapper::registerCommands); + HighlightCommand.registerEvents(); } private static void registerCommands(CommandDispatcher dispatcher, CommandBuildContext context) { LocateCommand.register(dispatcher); SourceCommand.register(dispatcher); CheckSeedCommand.register(dispatcher); + HighlightCommand.register(dispatcher); + ClearCommand.register(dispatcher); } } diff --git a/src/main/java/dev/xpple/seedmapper/command/CommandExceptions.java b/src/main/java/dev/xpple/seedmapper/command/CommandExceptions.java index 7e714fb0..8df0600b 100644 --- a/src/main/java/dev/xpple/seedmapper/command/CommandExceptions.java +++ b/src/main/java/dev/xpple/seedmapper/command/CommandExceptions.java @@ -18,6 +18,7 @@ private CommandExceptions() { public static final DynamicCommandExceptionType UNKNOWN_STRUCTURE_PIECE_EXCEPTION = new DynamicCommandExceptionType(arg -> Component.translatable("commands.exceptions.unknownStructurePiece", arg)); public static final DynamicCommandExceptionType UNKNOWN_VARIANT_KEY_EXCEPTION = new DynamicCommandExceptionType(arg -> Component.translatable("commands.exceptions.unknownVariantKey", arg)); public static final DynamicCommandExceptionType UNKNOWN_VARIANT_VALUE_EXCEPTION = new DynamicCommandExceptionType(arg -> Component.translatable("commands.exceptions.unknownVariantValue", arg)); + public static final DynamicCommandExceptionType UNKNOWN_BLOCK_EXCEPTION = new DynamicCommandExceptionType(arg -> Component.translatable("commands.exceptions.unknownOre", arg)); public static final SimpleCommandExceptionType NO_SEED_AVAILABLE_EXCEPTION = new SimpleCommandExceptionType(Component.translatable("commands.exceptions.noSeedAvailable")); public static final DynamicCommandExceptionType NO_BIOME_FOUND_EXCEPTION = new DynamicCommandExceptionType(arg -> Component.translatable("commands.exceptions.noBiomeFound", arg)); public static final DynamicCommandExceptionType NO_STRUCTURE_FOUND_EXCEPTION = new DynamicCommandExceptionType(arg -> Component.translatable("commands.exceptions.noStructureFound", arg)); diff --git a/src/main/java/dev/xpple/seedmapper/command/arguments/BlockArgument.java b/src/main/java/dev/xpple/seedmapper/command/arguments/BlockArgument.java new file mode 100644 index 00000000..c36b8780 --- /dev/null +++ b/src/main/java/dev/xpple/seedmapper/command/arguments/BlockArgument.java @@ -0,0 +1,84 @@ +package dev.xpple.seedmapper.command.arguments; + +import com.github.cubiomes.Cubiomes; +import com.google.common.collect.ImmutableMap; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import com.mojang.datafixers.util.Pair; +import dev.xpple.seedmapper.command.CommandExceptions; +import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; +import net.minecraft.commands.SharedSuggestionProvider; +import net.minecraft.world.level.block.Blocks; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Map; +import java.util.concurrent.CompletableFuture; + +public class BlockArgument implements ArgumentType> { + + private static final Collection EXAMPLES = Arrays.asList("diamond_ore", "gold_ore", "quartz_ore"); + + public static final Map> BLOCKS = ImmutableMap.>builder() + .put("ancient_debris", Pair.of(Cubiomes.ANCIENT_DEBRIS(), Blocks.ANCIENT_DEBRIS.defaultMapColor().col)) + .put("andesite", Pair.of(Cubiomes.ANDESITE(), Blocks.ANDESITE.defaultMapColor().col)) + .put("basalt", Pair.of(Cubiomes.BASALT(), Blocks.BASALT.defaultMapColor().col)) + .put("blackstone", Pair.of(Cubiomes.BLACKSTONE(), Blocks.BLACKSTONE.defaultMapColor().col)) + .put("clay", Pair.of(Cubiomes.CLAY(), Blocks.CLAY.defaultMapColor().col)) + .put("coal_ore", Pair.of(Cubiomes.COAL_ORE(), Blocks.COAL_ORE.defaultMapColor().col)) + .put("copper_ore", Pair.of(Cubiomes.COPPER_ORE(), Blocks.COPPER_ORE.defaultMapColor().col)) + .put("deepslate", Pair.of(Cubiomes.DEEPSLATE(), Blocks.DEEPSLATE.defaultMapColor().col)) + .put("diamond_ore", Pair.of(Cubiomes.DIAMOND_ORE(), Blocks.DIAMOND_ORE.defaultMapColor().col)) + .put("diorite", Pair.of(Cubiomes.DIORITE(), Blocks.DIORITE.defaultMapColor().col)) + .put("dirt", Pair.of(Cubiomes.DIRT(), Blocks.DIRT.defaultMapColor().col)) + .put("emerald_ore", Pair.of(Cubiomes.EMERALD_ORE(), Blocks.EMERALD_ORE.defaultMapColor().col)) + .put("gold_ore", Pair.of(Cubiomes.GOLD_ORE(), Blocks.GOLD_ORE.defaultMapColor().col)) + .put("granite", Pair.of(Cubiomes.GRANITE(), Blocks.GRANITE.defaultMapColor().col)) + .put("gravel", Pair.of(Cubiomes.GRAVEL(), Blocks.GRAVEL.defaultMapColor().col)) + .put("iron_ore", Pair.of(Cubiomes.IRON_ORE(), Blocks.IRON_ORE.defaultMapColor().col)) + .put("lapis_ore", Pair.of(Cubiomes.LAPIS_ORE(), Blocks.LAPIS_ORE.defaultMapColor().col)) + .put("magma_block", Pair.of(Cubiomes.MAGMA_BLOCK(), Blocks.MAGMA_BLOCK.defaultMapColor().col)) + .put("netherrack", Pair.of(Cubiomes.NETHERRACK(), Blocks.NETHERRACK.defaultMapColor().col)) + .put("nether_gold_ore", Pair.of(Cubiomes.NETHER_GOLD_ORE(), Blocks.NETHER_GOLD_ORE.defaultMapColor().col)) + .put("nether_quartz_ore", Pair.of(Cubiomes.NETHER_QUARTZ_ORE(), Blocks.NETHER_QUARTZ_ORE.defaultMapColor().col)) + .put("redstone_ore", Pair.of(Cubiomes.REDSTONE_ORE(), Blocks.REDSTONE_ORE.defaultMapColor().col)) + .put("soul_sand", Pair.of(Cubiomes.SOUL_SAND(), Blocks.SOUL_SAND.defaultMapColor().col)) + .put("stone", Pair.of(Cubiomes.STONE(), Blocks.STONE.defaultMapColor().col)) + .put("tuff", Pair.of(Cubiomes.TUFF(), Blocks.TUFF.defaultMapColor().col)) + .build(); + + public static BlockArgument block() { + return new BlockArgument(); + } + + @SuppressWarnings("unchecked") + public static Pair getBlock(CommandContext context, String name) { + return (Pair) context.getArgument(name, Pair.class); + } + + @Override + public Pair parse(StringReader reader) throws CommandSyntaxException { + int cursor = reader.getCursor(); + String blockString = reader.readUnquotedString(); + Pair blockPair = BLOCKS.get(blockString); + if (blockPair == null) { + reader.setCursor(cursor); + throw CommandExceptions.UNKNOWN_BLOCK_EXCEPTION.create(blockString); + } + return blockPair; + } + + @Override + public CompletableFuture listSuggestions(CommandContext context, SuggestionsBuilder builder) { + return SharedSuggestionProvider.suggest(BLOCKS.keySet(), builder); + } + + @Override + public Collection getExamples() { + return EXAMPLES; + } +} diff --git a/src/main/java/dev/xpple/seedmapper/command/commands/ClearCommand.java b/src/main/java/dev/xpple/seedmapper/command/commands/ClearCommand.java new file mode 100644 index 00000000..7859c6e5 --- /dev/null +++ b/src/main/java/dev/xpple/seedmapper/command/commands/ClearCommand.java @@ -0,0 +1,21 @@ +package dev.xpple.seedmapper.command.commands; + +import com.mojang.brigadier.CommandDispatcher; +import dev.xpple.seedmapper.command.CustomClientCommandSource; +import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; +import net.minecraft.network.chat.Component; + +import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.*; + +public class ClearCommand { + public static void register(CommandDispatcher dispatcher) { + dispatcher.register(literal("sm:clear") + .executes(ctx -> clear(CustomClientCommandSource.of(ctx.getSource())))); + } + + private static int clear(CustomClientCommandSource source) { + int count = HighlightCommand.clearRenders(); + source.sendFeedback(Component.translatable("command.clear.success", count)); + return count; + } +} diff --git a/src/main/java/dev/xpple/seedmapper/command/commands/HighlightCommand.java b/src/main/java/dev/xpple/seedmapper/command/commands/HighlightCommand.java new file mode 100644 index 00000000..8eebfa64 --- /dev/null +++ b/src/main/java/dev/xpple/seedmapper/command/commands/HighlightCommand.java @@ -0,0 +1,142 @@ +package dev.xpple.seedmapper.command.commands; + +import com.github.cubiomes.Cubiomes; +import com.github.cubiomes.Generator; +import com.github.cubiomes.OreConfig; +import com.github.cubiomes.Pos3; +import com.github.cubiomes.Pos3List; +import com.github.cubiomes.SurfaceNoise; +import com.google.common.cache.CacheBuilder; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.datafixers.util.Pair; +import dev.xpple.seedmapper.command.CustomClientCommandSource; +import dev.xpple.seedmapper.feature.OreTypes; +import dev.xpple.seedmapper.render.NoDepthLayer; +import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; +import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; +import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents; +import net.minecraft.client.renderer.ShapeRenderer; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; +import net.minecraft.util.ARGB; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.phys.AABB; + +import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment; +import java.time.Duration; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import static dev.xpple.seedmapper.command.arguments.BlockArgument.*; +import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.*; + +public class HighlightCommand { + + private static final Set> blockRenders = Collections.newSetFromMap(CacheBuilder.newBuilder().expireAfterWrite(Duration.ofMinutes(5))., Boolean>build().asMap()); + + public static void register(CommandDispatcher dispatcher) { + dispatcher.register(literal("sm:highlight") + .then(literal("block") + .then(argument("block", block()) + .executes(ctx -> highlightBlock(CustomClientCommandSource.of(ctx.getSource()), getBlock(ctx, "block")))))); + } + + private static int highlightBlock(CustomClientCommandSource source, Pair blockPair) throws CommandSyntaxException { + int version = source.getVersion(); + int dimension = source.getDimension(); + long seed = source.getSeed().getSecond(); + try (Arena arena = Arena.ofConfined()) { + MemorySegment generator = Generator.allocate(arena); + Cubiomes.setupGenerator(generator, version, 0); + Cubiomes.applySeed(generator, dimension, seed); + MemorySegment surfaceNoise = SurfaceNoise.allocate(arena); + Cubiomes.initSurfaceNoise(surfaceNoise, dimension, seed); + + ChunkPos chunk = new ChunkPos(BlockPos.containing(source.getPosition())); + int biome = Cubiomes.getBiomeForOreGen(generator, chunk.x, chunk.z); + + // TODO: multiple chunks + Map generatedOres = new HashMap<>(); + OreTypes.ORE_TYPES.stream() + .mapMulti((oreType, consumer) -> { + MemorySegment oreConfig = OreConfig.allocate(arena); + if (Cubiomes.getOreConfig(oreType, version, biome, oreConfig) != 0) { + consumer.accept(oreConfig); + } + }) + .filter(oreConfig -> Cubiomes.isViableOreBiome(version, OreConfig.oreType(oreConfig), biome) != 0) + .sorted(Comparator.comparingInt(OreConfig::index)) + .forEachOrdered(oreConfig -> { + int oreBlock = OreConfig.oreBlock(oreConfig); + int numReplaceBlocks = OreConfig.numReplaceBlocks(oreConfig); + MemorySegment replaceBlocks = OreConfig.replaceBlocks(oreConfig); + MemorySegment pos3List = Cubiomes.generateOres(arena, generator, surfaceNoise, oreConfig, chunk.x, chunk.z); + int size = Pos3List.size(pos3List); + MemorySegment pos3s = Pos3List.pos3s(pos3List); + for (int i = 0; i < size; i++) { + MemorySegment pos3 = Pos3.asSlice(pos3s, i); + BlockPos pos = new BlockPos(Pos3.x(pos3), Pos3.y(pos3), Pos3.z(pos3)); + Integer previouslyGeneratedOre = generatedOres.get(pos); + if (previouslyGeneratedOre != null) { + boolean contains = false; + for (int j = 0; j < numReplaceBlocks; j++) { + int replaceBlock = replaceBlocks.getAtIndex(Cubiomes.C_INT, j); + if (replaceBlock == previouslyGeneratedOre) { + contains = true; + break; + } + } + if (!contains) { + continue; + } + } + generatedOres.put(pos, oreBlock); + } + Cubiomes.freePos3List(pos3List); + }); + int[] count = {0}; + int block = blockPair.getFirst(); + int colour = blockPair.getSecond(); + generatedOres.forEach((pos, oreBlock) -> { + if (oreBlock == block) { + blockRenders.add(Pair.of(new AABB(pos), colour)); + count[0]++; + } + }); + + source.sendFeedback(Component.translatable("command.highlight.success", count[0])); + return count[0]; + } + } + + public static void registerEvents() { + WorldRenderEvents.AFTER_ENTITIES.register(HighlightCommand::renderOres); + } + + private static void renderOres(WorldRenderContext context) { + blockRenders.forEach(boxColourPair -> { + AABB box = boxColourPair.getFirst(); + AABB relativeBox = box.move(context.camera().getPosition().scale(-1)); + PoseStack stack = context.matrixStack(); + stack.pushPose(); + int colour = boxColourPair.getSecond(); + float red = ARGB.redFloat(colour); + float green = ARGB.greenFloat(colour); + float blue = ARGB.blueFloat(colour); + ShapeRenderer.renderLineBox(stack, context.consumers().getBuffer(NoDepthLayer.LINES_NO_DEPTH_LAYER), relativeBox, red, green, blue, 1); + stack.popPose(); + }); + } + + public static int clearRenders() { + int size = blockRenders.size(); + blockRenders.clear(); + return size; + } +} diff --git a/src/main/java/dev/xpple/seedmapper/feature/OreTypes.java b/src/main/java/dev/xpple/seedmapper/feature/OreTypes.java new file mode 100644 index 00000000..99a5ed34 --- /dev/null +++ b/src/main/java/dev/xpple/seedmapper/feature/OreTypes.java @@ -0,0 +1,56 @@ +package dev.xpple.seedmapper.feature; + +import com.github.cubiomes.Cubiomes; +import com.google.common.collect.ImmutableSet; + +import java.util.Set; + +public final class OreTypes { + private OreTypes() { + } + + public static final Set ORE_TYPES = ImmutableSet.builder() + .add(Cubiomes.AndesiteOre()) + .add(Cubiomes.BlackstoneOre()) + .add(Cubiomes.BuriedDiamondOre()) + .add(Cubiomes.BuriedLapisOre()) + .add(Cubiomes.ClayOre()) + .add(Cubiomes.CoalOre()) + .add(Cubiomes.CopperOre()) + .add(Cubiomes.DeepslateOre()) + .add(Cubiomes.DiamondOre()) + .add(Cubiomes.DioriteOre()) + .add(Cubiomes.DirtOre()) + .add(Cubiomes.EmeraldOre()) + .add(Cubiomes.ExtraGoldOre()) + .add(Cubiomes.GoldOre()) + .add(Cubiomes.GraniteOre()) + .add(Cubiomes.GravelOre()) + .add(Cubiomes.IronOre()) + .add(Cubiomes.LapisOre()) + .add(Cubiomes.LargeCopperOre()) + .add(Cubiomes.LargeDebrisOre()) + .add(Cubiomes.LargeDiamondOre()) + .add(Cubiomes.LowerAndesiteOre()) + .add(Cubiomes.LowerCoalOre()) + .add(Cubiomes.LowerDioriteOre()) + .add(Cubiomes.LowerGoldOre()) + .add(Cubiomes.LowerGraniteOre()) + .add(Cubiomes.LowerRedstoneOre()) + .add(Cubiomes.MagmaOre()) + .add(Cubiomes.MiddleIronOre()) + .add(Cubiomes.NetherGoldOre()) + .add(Cubiomes.NetherGravelOre()) + .add(Cubiomes.QuartzOre()) + .add(Cubiomes.RedstoneOre()) + .add(Cubiomes.SmallDebrisOre()) + .add(Cubiomes.SmallIronOre()) + .add(Cubiomes.SoulSandOre()) + .add(Cubiomes.TuffOre()) + .add(Cubiomes.UpperAndesiteOre()) + .add(Cubiomes.UpperCoalOre()) + .add(Cubiomes.UpperDioriteOre()) + .add(Cubiomes.UpperGraniteOre()) + .add(Cubiomes.UpperIronOre()) + .build(); +} diff --git a/src/main/java/dev/xpple/seedmapper/render/NoDepthLayer.java b/src/main/java/dev/xpple/seedmapper/render/NoDepthLayer.java new file mode 100644 index 00000000..0a28618e --- /dev/null +++ b/src/main/java/dev/xpple/seedmapper/render/NoDepthLayer.java @@ -0,0 +1,25 @@ +package dev.xpple.seedmapper.render; + +import com.mojang.blaze3d.pipeline.RenderPipeline; +import com.mojang.blaze3d.platform.DepthTestFunction; +import net.minecraft.client.renderer.RenderPipelines; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.resources.ResourceLocation; + +import java.util.OptionalDouble; + +public final class NoDepthLayer { + private NoDepthLayer() { + } + + private static final RenderPipeline LINES_NO_DEPTH_PIPELINE = RenderPipelines.register( + RenderPipeline.builder(RenderPipelines.LINES_SNIPPET) + .withLocation(ResourceLocation.fromNamespaceAndPath("seedmapper", "pipeline/lines_no_depth")) + .withDepthTestFunction(DepthTestFunction.NO_DEPTH_TEST) + .build() + ); + public static final RenderType LINES_NO_DEPTH_LAYER = RenderType.create("seedmapper_no_depth", 3 * 512, LINES_NO_DEPTH_PIPELINE, RenderType.CompositeState.builder() + .setLayeringState(RenderType.VIEW_OFFSET_Z_LAYERING) + .setLineState(new RenderType.LineStateShard(OptionalDouble.of(2))) + .createCompositeState(false)); +} diff --git a/src/main/resources/assets/seedmapper/lang/en_us.json b/src/main/resources/assets/seedmapper/lang/en_us.json index 8db8505d..2cecb2f0 100644 --- a/src/main/resources/assets/seedmapper/lang/en_us.json +++ b/src/main/resources/assets/seedmapper/lang/en_us.json @@ -13,6 +13,7 @@ "commands.exceptions.unknownVariantKey": "Unknown structure variant key \"%s\".", "commands.exceptions.unknownVariantValue": "Unknown structure variant value \"%s\".", "commands.exceptions.noStructureFound": "Couldn't locate structure within %s blocks.", + "commands.exceptions.unknownOre": "Unknown block \"%s\".", "commands.exceptions.incompatibleParameters": "Incompatible parameters.", "commands.exceptions.unknownResolutionMethod": "Unknowing resolution method \"%s\".", @@ -56,5 +57,9 @@ "command.locate.feature.slimeChunk.foundAt": "Slime chunk found at %s (chunk %s).", "command.locate.feature.slimeChunk.copy": "Click to copy coordinates of this slime chunk", "command.locate.feature.slimeChunk.copyChunk": "Click to copy chunk coordinates of this slime chunk", - "command.locate.spawn.success": "Spawn point estimated to be at %s." + "command.locate.spawn.success": "Spawn point estimated to be at %s.", + + "command.highlight.success": "Highlighted %s ores.", + + "command.clear.success": "Cleared %s renders." } From f8d76b7e181b3d23a27f3174ecc7f1ac8036e46a Mon Sep 17 00:00:00 2001 From: Frederik van der Els Date: Mon, 28 Apr 2025 19:23:26 +0200 Subject: [PATCH 02/15] Add missing ore type --- src/main/java/dev/xpple/seedmapper/feature/OreTypes.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/dev/xpple/seedmapper/feature/OreTypes.java b/src/main/java/dev/xpple/seedmapper/feature/OreTypes.java index 99a5ed34..2c5f051e 100644 --- a/src/main/java/dev/xpple/seedmapper/feature/OreTypes.java +++ b/src/main/java/dev/xpple/seedmapper/feature/OreTypes.java @@ -38,6 +38,7 @@ private OreTypes() { .add(Cubiomes.LowerGraniteOre()) .add(Cubiomes.LowerRedstoneOre()) .add(Cubiomes.MagmaOre()) + .add(Cubiomes.MediumDiamondOre()) .add(Cubiomes.MiddleIronOre()) .add(Cubiomes.NetherGoldOre()) .add(Cubiomes.NetherGravelOre()) From 8eb2efc624a6b156879d915ff84c738aabbbd9cb Mon Sep 17 00:00:00 2001 From: Frederik van der Els Date: Tue, 29 Apr 2025 21:29:48 +0200 Subject: [PATCH 03/15] Improve rendering --- includes.txt | 1 - src/main/c | 2 +- .../java/dev/xpple/seedmapper/SeedMapper.java | 3 +- .../command/arguments/BlockArgument.java | 54 +++++------ .../command/commands/ClearCommand.java | 3 +- .../command/commands/HighlightCommand.java | 41 +-------- .../dev/xpple/seedmapper/render/Line.java | 18 ++++ .../seedmapper/render/RenderManager.java | 91 +++++++++++++++++++ 8 files changed, 143 insertions(+), 70 deletions(-) create mode 100644 src/main/java/dev/xpple/seedmapper/render/Line.java create mode 100644 src/main/java/dev/xpple/seedmapper/render/RenderManager.java diff --git a/includes.txt b/includes.txt index c3ee104a..878bbb37 100644 --- a/includes.txt +++ b/includes.txt @@ -667,7 +667,6 @@ --include-function biome2str --include-function biomesToImage ---include-function free_ptr --include-function initBiomeColors --include-function initBiomeTypeColors --include-function loadSavedSeeds diff --git a/src/main/c b/src/main/c index 9acedf46..94d90932 160000 --- a/src/main/c +++ b/src/main/c @@ -1 +1 @@ -Subproject commit 9acedf46e545187e05c8c16ae4abb84d892f20b0 +Subproject commit 94d9093220b4379bc96099e092ebec787088139f diff --git a/src/main/java/dev/xpple/seedmapper/SeedMapper.java b/src/main/java/dev/xpple/seedmapper/SeedMapper.java index b548c21d..0f60859b 100644 --- a/src/main/java/dev/xpple/seedmapper/SeedMapper.java +++ b/src/main/java/dev/xpple/seedmapper/SeedMapper.java @@ -10,6 +10,7 @@ import dev.xpple.seedmapper.command.commands.SourceCommand; import dev.xpple.seedmapper.config.Configs; import dev.xpple.seedmapper.config.SeedResolutionAdapter; +import dev.xpple.seedmapper.render.RenderManager; import dev.xpple.seedmapper.util.SeedDatabaseHelper; import net.fabricmc.api.ClientModInitializer; import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; @@ -51,7 +52,7 @@ public void onInitializeClient() { SeedDatabaseHelper.fetchSeeds(); ClientCommandRegistrationCallback.EVENT.register(SeedMapper::registerCommands); - HighlightCommand.registerEvents(); + RenderManager.registerEvents(); } private static void registerCommands(CommandDispatcher dispatcher, CommandBuildContext context) { diff --git a/src/main/java/dev/xpple/seedmapper/command/arguments/BlockArgument.java b/src/main/java/dev/xpple/seedmapper/command/arguments/BlockArgument.java index c36b8780..d651609f 100644 --- a/src/main/java/dev/xpple/seedmapper/command/arguments/BlockArgument.java +++ b/src/main/java/dev/xpple/seedmapper/command/arguments/BlockArgument.java @@ -12,7 +12,7 @@ import dev.xpple.seedmapper.command.CommandExceptions; import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; import net.minecraft.commands.SharedSuggestionProvider; -import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.material.MapColor; import java.util.Arrays; import java.util.Collection; @@ -21,34 +21,34 @@ public class BlockArgument implements ArgumentType> { - private static final Collection EXAMPLES = Arrays.asList("diamond_ore", "gold_ore", "quartz_ore"); + private static final Collection EXAMPLES = Arrays.asList("diamond_ore", "gold_ore", "nether_quartz_ore"); public static final Map> BLOCKS = ImmutableMap.>builder() - .put("ancient_debris", Pair.of(Cubiomes.ANCIENT_DEBRIS(), Blocks.ANCIENT_DEBRIS.defaultMapColor().col)) - .put("andesite", Pair.of(Cubiomes.ANDESITE(), Blocks.ANDESITE.defaultMapColor().col)) - .put("basalt", Pair.of(Cubiomes.BASALT(), Blocks.BASALT.defaultMapColor().col)) - .put("blackstone", Pair.of(Cubiomes.BLACKSTONE(), Blocks.BLACKSTONE.defaultMapColor().col)) - .put("clay", Pair.of(Cubiomes.CLAY(), Blocks.CLAY.defaultMapColor().col)) - .put("coal_ore", Pair.of(Cubiomes.COAL_ORE(), Blocks.COAL_ORE.defaultMapColor().col)) - .put("copper_ore", Pair.of(Cubiomes.COPPER_ORE(), Blocks.COPPER_ORE.defaultMapColor().col)) - .put("deepslate", Pair.of(Cubiomes.DEEPSLATE(), Blocks.DEEPSLATE.defaultMapColor().col)) - .put("diamond_ore", Pair.of(Cubiomes.DIAMOND_ORE(), Blocks.DIAMOND_ORE.defaultMapColor().col)) - .put("diorite", Pair.of(Cubiomes.DIORITE(), Blocks.DIORITE.defaultMapColor().col)) - .put("dirt", Pair.of(Cubiomes.DIRT(), Blocks.DIRT.defaultMapColor().col)) - .put("emerald_ore", Pair.of(Cubiomes.EMERALD_ORE(), Blocks.EMERALD_ORE.defaultMapColor().col)) - .put("gold_ore", Pair.of(Cubiomes.GOLD_ORE(), Blocks.GOLD_ORE.defaultMapColor().col)) - .put("granite", Pair.of(Cubiomes.GRANITE(), Blocks.GRANITE.defaultMapColor().col)) - .put("gravel", Pair.of(Cubiomes.GRAVEL(), Blocks.GRAVEL.defaultMapColor().col)) - .put("iron_ore", Pair.of(Cubiomes.IRON_ORE(), Blocks.IRON_ORE.defaultMapColor().col)) - .put("lapis_ore", Pair.of(Cubiomes.LAPIS_ORE(), Blocks.LAPIS_ORE.defaultMapColor().col)) - .put("magma_block", Pair.of(Cubiomes.MAGMA_BLOCK(), Blocks.MAGMA_BLOCK.defaultMapColor().col)) - .put("netherrack", Pair.of(Cubiomes.NETHERRACK(), Blocks.NETHERRACK.defaultMapColor().col)) - .put("nether_gold_ore", Pair.of(Cubiomes.NETHER_GOLD_ORE(), Blocks.NETHER_GOLD_ORE.defaultMapColor().col)) - .put("nether_quartz_ore", Pair.of(Cubiomes.NETHER_QUARTZ_ORE(), Blocks.NETHER_QUARTZ_ORE.defaultMapColor().col)) - .put("redstone_ore", Pair.of(Cubiomes.REDSTONE_ORE(), Blocks.REDSTONE_ORE.defaultMapColor().col)) - .put("soul_sand", Pair.of(Cubiomes.SOUL_SAND(), Blocks.SOUL_SAND.defaultMapColor().col)) - .put("stone", Pair.of(Cubiomes.STONE(), Blocks.STONE.defaultMapColor().col)) - .put("tuff", Pair.of(Cubiomes.TUFF(), Blocks.TUFF.defaultMapColor().col)) + .put("ancient_debris", Pair.of(Cubiomes.ANCIENT_DEBRIS(), MapColor.TERRACOTTA_BROWN.col)) + .put("andesite", Pair.of(Cubiomes.ANDESITE(), MapColor.STONE.col)) + .put("basalt", Pair.of(Cubiomes.BASALT(), MapColor.COLOR_BLACK.col)) + .put("blackstone", Pair.of(Cubiomes.BLACKSTONE(), MapColor.COLOR_BLACK.col)) + .put("clay", Pair.of(Cubiomes.CLAY(), MapColor.CLAY.col)) + .put("coal_ore", Pair.of(Cubiomes.COAL_ORE(), MapColor.COLOR_BLACK.col)) + .put("copper_ore", Pair.of(Cubiomes.COPPER_ORE(), MapColor.COLOR_ORANGE.col)) + .put("deepslate", Pair.of(Cubiomes.DEEPSLATE(), MapColor.DEEPSLATE.col)) + .put("diamond_ore", Pair.of(Cubiomes.DIAMOND_ORE(), MapColor.DIAMOND.col)) + .put("diorite", Pair.of(Cubiomes.DIORITE(), MapColor.QUARTZ.col)) + .put("dirt", Pair.of(Cubiomes.DIRT(), MapColor.DIRT.col)) + .put("emerald_ore", Pair.of(Cubiomes.EMERALD_ORE(), MapColor.EMERALD.col)) + .put("gold_ore", Pair.of(Cubiomes.GOLD_ORE(), MapColor.GOLD.col)) + .put("granite", Pair.of(Cubiomes.GRANITE(), MapColor.DIRT.col)) + .put("gravel", Pair.of(Cubiomes.GRAVEL(), MapColor.STONE.col)) + .put("iron_ore", Pair.of(Cubiomes.IRON_ORE(), MapColor.RAW_IRON.col)) + .put("lapis_ore", Pair.of(Cubiomes.LAPIS_ORE(), MapColor.LAPIS.col)) + .put("magma_block", Pair.of(Cubiomes.MAGMA_BLOCK(), MapColor.NETHER.col)) + .put("netherrack", Pair.of(Cubiomes.NETHERRACK(), MapColor.NETHER.col)) + .put("nether_gold_ore", Pair.of(Cubiomes.NETHER_GOLD_ORE(), MapColor.GOLD.col)) + .put("nether_quartz_ore", Pair.of(Cubiomes.NETHER_QUARTZ_ORE(), MapColor.QUARTZ.col)) + .put("redstone_ore", Pair.of(Cubiomes.REDSTONE_ORE(), MapColor.FIRE.col)) + .put("soul_sand", Pair.of(Cubiomes.SOUL_SAND(), MapColor.COLOR_BROWN.col)) + .put("stone", Pair.of(Cubiomes.STONE(), MapColor.STONE.col)) + .put("tuff", Pair.of(Cubiomes.TUFF(), MapColor.COLOR_GRAY.col)) .build(); public static BlockArgument block() { diff --git a/src/main/java/dev/xpple/seedmapper/command/commands/ClearCommand.java b/src/main/java/dev/xpple/seedmapper/command/commands/ClearCommand.java index 7859c6e5..78e07302 100644 --- a/src/main/java/dev/xpple/seedmapper/command/commands/ClearCommand.java +++ b/src/main/java/dev/xpple/seedmapper/command/commands/ClearCommand.java @@ -2,6 +2,7 @@ import com.mojang.brigadier.CommandDispatcher; import dev.xpple.seedmapper.command.CustomClientCommandSource; +import dev.xpple.seedmapper.render.RenderManager; import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; import net.minecraft.network.chat.Component; @@ -14,7 +15,7 @@ public static void register(CommandDispatcher dispatc } private static int clear(CustomClientCommandSource source) { - int count = HighlightCommand.clearRenders(); + int count = RenderManager.clear(); source.sendFeedback(Component.translatable("command.clear.success", count)); return count; } diff --git a/src/main/java/dev/xpple/seedmapper/command/commands/HighlightCommand.java b/src/main/java/dev/xpple/seedmapper/command/commands/HighlightCommand.java index 8eebfa64..673a980b 100644 --- a/src/main/java/dev/xpple/seedmapper/command/commands/HighlightCommand.java +++ b/src/main/java/dev/xpple/seedmapper/command/commands/HighlightCommand.java @@ -6,40 +6,28 @@ import com.github.cubiomes.Pos3; import com.github.cubiomes.Pos3List; import com.github.cubiomes.SurfaceNoise; -import com.google.common.cache.CacheBuilder; -import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.datafixers.util.Pair; import dev.xpple.seedmapper.command.CustomClientCommandSource; import dev.xpple.seedmapper.feature.OreTypes; -import dev.xpple.seedmapper.render.NoDepthLayer; +import dev.xpple.seedmapper.render.RenderManager; import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; -import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; -import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents; -import net.minecraft.client.renderer.ShapeRenderer; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; -import net.minecraft.util.ARGB; import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.phys.AABB; import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; -import java.time.Duration; -import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.Map; -import java.util.Set; import static dev.xpple.seedmapper.command.arguments.BlockArgument.*; import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.*; public class HighlightCommand { - private static final Set> blockRenders = Collections.newSetFromMap(CacheBuilder.newBuilder().expireAfterWrite(Duration.ofMinutes(5))., Boolean>build().asMap()); - public static void register(CommandDispatcher dispatcher) { dispatcher.register(literal("sm:highlight") .then(literal("block") @@ -105,7 +93,7 @@ private static int highlightBlock(CustomClientCommandSource source, Pair { if (oreBlock == block) { - blockRenders.add(Pair.of(new AABB(pos), colour)); + RenderManager.drawBox(pos, colour); count[0]++; } }); @@ -114,29 +102,4 @@ private static int highlightBlock(CustomClientCommandSource source, Pair { - AABB box = boxColourPair.getFirst(); - AABB relativeBox = box.move(context.camera().getPosition().scale(-1)); - PoseStack stack = context.matrixStack(); - stack.pushPose(); - int colour = boxColourPair.getSecond(); - float red = ARGB.redFloat(colour); - float green = ARGB.greenFloat(colour); - float blue = ARGB.blueFloat(colour); - ShapeRenderer.renderLineBox(stack, context.consumers().getBuffer(NoDepthLayer.LINES_NO_DEPTH_LAYER), relativeBox, red, green, blue, 1); - stack.popPose(); - }); - } - - public static int clearRenders() { - int size = blockRenders.size(); - blockRenders.clear(); - return size; - } } diff --git a/src/main/java/dev/xpple/seedmapper/render/Line.java b/src/main/java/dev/xpple/seedmapper/render/Line.java new file mode 100644 index 00000000..be6aa6ba --- /dev/null +++ b/src/main/java/dev/xpple/seedmapper/render/Line.java @@ -0,0 +1,18 @@ +package dev.xpple.seedmapper.render; + +import net.minecraft.world.phys.Vec3; + +public record Line(Vec3 start, Vec3 end, int colour) { + public Line { + // ensure consistent ordering, the ordering itself doesn't matter + if (start.hashCode() > end.hashCode()) { + Vec3 temp = start; + start = end; + end = temp; + } + } + + public Line offset(Vec3 offset) { + return new Line(this.start.add(offset), this.end.add(offset), this.colour); + } +} diff --git a/src/main/java/dev/xpple/seedmapper/render/RenderManager.java b/src/main/java/dev/xpple/seedmapper/render/RenderManager.java new file mode 100644 index 00000000..5af351b5 --- /dev/null +++ b/src/main/java/dev/xpple/seedmapper/render/RenderManager.java @@ -0,0 +1,91 @@ +package dev.xpple.seedmapper.render; + +import com.google.common.cache.CacheBuilder; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; +import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents; +import net.minecraft.core.BlockPos; +import net.minecraft.util.ARGB; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; + +import java.time.Duration; +import java.util.Collections; +import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; + +public final class RenderManager { + + private RenderManager() { + } + + private static final Set lines = Collections.newSetFromMap(CacheBuilder.newBuilder().expireAfterWrite(Duration.ofMinutes(5)).build().asMap());; + private static final AtomicInteger boxCount = new AtomicInteger(0); + + public static void drawBox(BlockPos pos, int colour) { + drawBox(new AABB(pos), colour); + } + + public static void drawBox(AABB box, int colour) { + boxCount.getAndIncrement(); + Vec3 minPosition = box.getMinPosition(); + Vec3 size = box.getMaxPosition().subtract(box.getMinPosition()); + + addLine(new Line(minPosition, minPosition.add(size.x(), 0, 0), colour)); + addLine(new Line(minPosition, minPosition.add(0, size.y(), 0), colour)); + addLine(new Line(minPosition, minPosition.add(0, 0, size.z()), colour)); + addLine(new Line(minPosition.add(size.x(), 0, size.z()), minPosition.add(size.x(), 0, 0), colour)); + addLine(new Line(minPosition.add(size.x(), 0, size.z()), minPosition.add(size.x(), size.y(), size.z()), colour)); + addLine(new Line(minPosition.add(size.x(), 0, size.z()), minPosition.add(0, 0, size.z()), colour)); + addLine(new Line(minPosition.add(size.x(), size.y(), 0), minPosition.add(size.x(), 0, 0), colour)); + addLine(new Line(minPosition.add(size.x(), size.y(), 0), minPosition.add(0, size.y(), 0), colour)); + addLine(new Line(minPosition.add(size.x(), size.y(), 0), minPosition.add(size.x(), size.y(), size.z()), colour)); + addLine(new Line(minPosition.add(0, size.y(), size.z()), minPosition.add(0, 0, size.z()), colour)); + addLine(new Line(minPosition.add(0, size.y(), size.z()), minPosition.add(0, size.y(), 0), colour)); + addLine(new Line(minPosition.add(0, size.y(), size.z()), minPosition.add(size.x(), size.y(), size.z()), colour)); + } + + public static int clear() { + int size = boxCount.getAndSet(0); + lines.clear(); + return size; + } + + private static void addLine(Line line) { + if (!lines.add(line)) { + lines.remove(line); + } + } + + public static void registerEvents() { + WorldRenderEvents.AFTER_ENTITIES.register(RenderManager::renderLines); + } + + private static void renderLines(WorldRenderContext context) { + lines.forEach(line -> { + Line relativeLine = line.offset(context.camera().getPosition().scale(-1)); + Vec3 start = relativeLine.start(); + Vec3 end = relativeLine.end(); + Vec3 normal = end.subtract(start).normalize(); + int colour = line.colour(); + float red = ARGB.redFloat(colour); + float green = ARGB.greenFloat(colour); + float blue = ARGB.blueFloat(colour); + + PoseStack stack = context.matrixStack(); + stack.pushPose(); + PoseStack.Pose pose = stack.last(); + VertexConsumer buffer = context.consumers().getBuffer(NoDepthLayer.LINES_NO_DEPTH_LAYER); + buffer + .addVertex(pose, (float) start.x, (float) start.y, (float) start.z) + .setColor(red, green, blue, 1.0F) + .setNormal(pose, (float) normal.x, (float) normal.y, (float) normal.z); + buffer + .addVertex(pose, (float) end.x, (float) end.y, (float) end.z) + .setColor(red, green, blue, 1.0F) + .setNormal(pose, (float) normal.x, (float) normal.y, (float) normal.z); + stack.popPose(); + }); + } +} From 19e071e019af6c69cce4fda935b39f9d83b3b94e Mon Sep 17 00:00:00 2001 From: Frederik van der Els Date: Tue, 29 Apr 2025 21:30:36 +0200 Subject: [PATCH 04/15] Update README --- README.md | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 6d4a80cf..27e4e449 100644 --- a/README.md +++ b/README.md @@ -25,22 +25,27 @@ If you run into issues, contact your launcher's support. Before using any of these commands, make sure the seed has been configured using `/cconfig seedmapper Seed set `. ### Biome locating -Usage: `/sm:locate biome ` +Usage: `/sm:locate biome `. Locates a given biome closest to the player. All biomes in all dimensions are supported. ### Structure locating -Usage: `/sm:locate feature structure []{}` +Usage: `/sm:locate feature structure []{}`. Locates a given structure closest to the player. All structures in all dimensions are supported. However, due to limitations in the underlying library, some structures (in particular desert pyramids, jungle temples and woodland mansions) may result in occasional false positives. For more advanced querying you can also use piece and variant data to further restrict the search. For example, the following command will search for end cities with ships: `/sm:locate feature structure end_city[end_ship]`. +### Ore highlighting +Usage: `/sm:highlight block `. + +Highlights the specified block in the world. All versions from 1.13 onwards are supported. Due to high dependence on the [`OCEAN_FLOOR_WG`](https://minecraft.wiki/w/Heightmap#OCEAN_FLOOR_WG) heightmap, coal, copper and emerald ore locations may be off. + ### Slime chunk locating -Usage: `/sm:locate feature slimechunk` +Usage: `/sm:locate feature slimechunk`. Locates a slime chunk closest to the player. This will always be accurate. ### Source mutation -Usage: `/sm:source (run)|(as )|(positioned )|(rotated )|(in )|(versioned )|(seeded )` +Usage: `/sm:source (run)|(as )|(positioned )|(rotated )|(in )|(versioned )|(seeded )`. Executes a given command from a modified source. For example, modifying the source's position will execute the command as if you were in that position. This command is really powerful, use it! From 3bb249bbe60b7d05b9d74d7e5c1c8abd682000b5 Mon Sep 17 00:00:00 2001 From: Frederik van der Els Date: Wed, 30 Apr 2025 13:12:50 +0200 Subject: [PATCH 05/15] Update cubiomes --- includes.txt | 4 +++- src/main/c | 2 +- src/main/java/dev/xpple/seedmapper/feature/OreTypes.java | 4 +++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/includes.txt b/includes.txt index 878bbb37..7981b413 100644 --- a/includes.txt +++ b/includes.txt @@ -315,6 +315,8 @@ --include-constant DIORITE --include-constant DIRT --include-constant DeepslateOre +--include-constant DeltasGoldOre +--include-constant DeltasQuartzOre --include-constant Desert_Pyramid --include-constant Desert_Well --include-constant DiamondOre @@ -378,10 +380,10 @@ --include-constant NETHER_QUARTZ_ORE --include-constant NetherGoldOre --include-constant NetherGravelOre +--include-constant NetherQuartzOre --include-constant Ocean_Ruin --include-constant Outpost --include-constant PIECE_COUNT ---include-constant QuartzOre --include-constant REDSTONE_ORE --include-constant RedstoneOre --include-constant Ruined_Portal diff --git a/src/main/c b/src/main/c index 94d90932..e7ecf854 160000 --- a/src/main/c +++ b/src/main/c @@ -1 +1 @@ -Subproject commit 94d9093220b4379bc96099e092ebec787088139f +Subproject commit e7ecf8547ea5d57311630dde581097ff3073e2a4 diff --git a/src/main/java/dev/xpple/seedmapper/feature/OreTypes.java b/src/main/java/dev/xpple/seedmapper/feature/OreTypes.java index 2c5f051e..22905194 100644 --- a/src/main/java/dev/xpple/seedmapper/feature/OreTypes.java +++ b/src/main/java/dev/xpple/seedmapper/feature/OreTypes.java @@ -18,6 +18,8 @@ private OreTypes() { .add(Cubiomes.CoalOre()) .add(Cubiomes.CopperOre()) .add(Cubiomes.DeepslateOre()) + .add(Cubiomes.DeltasGoldOre()) + .add(Cubiomes.DeltasQuartzOre()) .add(Cubiomes.DiamondOre()) .add(Cubiomes.DioriteOre()) .add(Cubiomes.DirtOre()) @@ -42,7 +44,7 @@ private OreTypes() { .add(Cubiomes.MiddleIronOre()) .add(Cubiomes.NetherGoldOre()) .add(Cubiomes.NetherGravelOre()) - .add(Cubiomes.QuartzOre()) + .add(Cubiomes.NetherQuartzOre()) .add(Cubiomes.RedstoneOre()) .add(Cubiomes.SmallDebrisOre()) .add(Cubiomes.SmallIronOre()) From ef4012ca9f7fd55b091e679863f6fc5e54a7e152 Mon Sep 17 00:00:00 2001 From: Frederik van der Els Date: Thu, 1 May 2025 00:57:57 +0200 Subject: [PATCH 06/15] Add chunk range argument --- src/main/c | 2 +- .../command/commands/HighlightCommand.java | 89 +++++++++++-------- 2 files changed, 51 insertions(+), 40 deletions(-) diff --git a/src/main/c b/src/main/c index e7ecf854..d2d88a10 160000 --- a/src/main/c +++ b/src/main/c @@ -1 +1 @@ -Subproject commit e7ecf8547ea5d57311630dde581097ff3073e2a4 +Subproject commit d2d88a10291f4c430f1f2f57bc6889f384237a16 diff --git a/src/main/java/dev/xpple/seedmapper/command/commands/HighlightCommand.java b/src/main/java/dev/xpple/seedmapper/command/commands/HighlightCommand.java index 673a980b..574d0bca 100644 --- a/src/main/java/dev/xpple/seedmapper/command/commands/HighlightCommand.java +++ b/src/main/java/dev/xpple/seedmapper/command/commands/HighlightCommand.java @@ -12,6 +12,7 @@ import dev.xpple.seedmapper.command.CustomClientCommandSource; import dev.xpple.seedmapper.feature.OreTypes; import dev.xpple.seedmapper.render.RenderManager; +import dev.xpple.seedmapper.util.SpiralLoop; import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; @@ -23,6 +24,7 @@ import java.util.HashMap; import java.util.Map; +import static com.mojang.brigadier.arguments.IntegerArgumentType.*; import static dev.xpple.seedmapper.command.arguments.BlockArgument.*; import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.*; @@ -32,10 +34,16 @@ public static void register(CommandDispatcher dispatc dispatcher.register(literal("sm:highlight") .then(literal("block") .then(argument("block", block()) - .executes(ctx -> highlightBlock(CustomClientCommandSource.of(ctx.getSource()), getBlock(ctx, "block")))))); + .executes(ctx -> highlightBlock(CustomClientCommandSource.of(ctx.getSource()), getBlock(ctx, "block"))) + .then(argument("chunks", integer(0)) + .executes(ctx -> highlightBlock(CustomClientCommandSource.of(ctx.getSource()), getBlock(ctx, "block"), getInteger(ctx, "chunks"))))))); } private static int highlightBlock(CustomClientCommandSource source, Pair blockPair) throws CommandSyntaxException { + return highlightBlock(source, blockPair, 0); + } + + private static int highlightBlock(CustomClientCommandSource source, Pair blockPair, int chunkRange) throws CommandSyntaxException { int version = source.getVersion(); int dimension = source.getDimension(); long seed = source.getSeed().getSecond(); @@ -46,48 +54,51 @@ private static int highlightBlock(CustomClientCommandSource source, Pair generatedOres = new HashMap<>(); - OreTypes.ORE_TYPES.stream() - .mapMulti((oreType, consumer) -> { - MemorySegment oreConfig = OreConfig.allocate(arena); - if (Cubiomes.getOreConfig(oreType, version, biome, oreConfig) != 0) { - consumer.accept(oreConfig); - } - }) - .filter(oreConfig -> Cubiomes.isViableOreBiome(version, OreConfig.oreType(oreConfig), biome) != 0) - .sorted(Comparator.comparingInt(OreConfig::index)) - .forEachOrdered(oreConfig -> { - int oreBlock = OreConfig.oreBlock(oreConfig); - int numReplaceBlocks = OreConfig.numReplaceBlocks(oreConfig); - MemorySegment replaceBlocks = OreConfig.replaceBlocks(oreConfig); - MemorySegment pos3List = Cubiomes.generateOres(arena, generator, surfaceNoise, oreConfig, chunk.x, chunk.z); - int size = Pos3List.size(pos3List); - MemorySegment pos3s = Pos3List.pos3s(pos3List); - for (int i = 0; i < size; i++) { - MemorySegment pos3 = Pos3.asSlice(pos3s, i); - BlockPos pos = new BlockPos(Pos3.x(pos3), Pos3.y(pos3), Pos3.z(pos3)); - Integer previouslyGeneratedOre = generatedOres.get(pos); - if (previouslyGeneratedOre != null) { - boolean contains = false; - for (int j = 0; j < numReplaceBlocks; j++) { - int replaceBlock = replaceBlocks.getAtIndex(Cubiomes.C_INT, j); - if (replaceBlock == previouslyGeneratedOre) { - contains = true; - break; + + SpiralLoop.spiral(center.x, center.z, chunkRange, (chunkX, chunkZ) -> { + // TODO: check biome at multiple altitudes (technically should check 3x3 square of chunks) + int biome = Cubiomes.getBiomeForOreGen(generator, chunkX, chunkZ); + OreTypes.ORE_TYPES.stream() + .filter(oreType -> Cubiomes.isViableOreBiome(version, oreType, biome) != 0) + .mapMulti((oreType, consumer) -> { + MemorySegment oreConfig = OreConfig.allocate(arena); + if (Cubiomes.getOreConfig(oreType, version, biome, oreConfig) != 0) { + consumer.accept(oreConfig); + } + }) + .sorted(Comparator.comparingInt(OreConfig::index)) + .forEachOrdered(oreConfig -> { + int oreBlock = OreConfig.oreBlock(oreConfig); + int numReplaceBlocks = OreConfig.numReplaceBlocks(oreConfig); + MemorySegment replaceBlocks = OreConfig.replaceBlocks(oreConfig); + MemorySegment pos3List = Cubiomes.generateOres(arena, generator, surfaceNoise, oreConfig, chunkX, chunkZ); + int size = Pos3List.size(pos3List); + MemorySegment pos3s = Pos3List.pos3s(pos3List); + for (int i = 0; i < size; i++) { + MemorySegment pos3 = Pos3.asSlice(pos3s, i); + BlockPos pos = new BlockPos(Pos3.x(pos3), Pos3.y(pos3), Pos3.z(pos3)); + Integer previouslyGeneratedOre = generatedOres.get(pos); + if (previouslyGeneratedOre != null) { + boolean contains = false; + for (int j = 0; j < numReplaceBlocks; j++) { + int replaceBlock = replaceBlocks.getAtIndex(Cubiomes.C_INT, j); + if (replaceBlock == previouslyGeneratedOre) { + contains = true; + break; + } + } + if (!contains) { + continue; } } - if (!contains) { - continue; - } + generatedOres.put(pos, oreBlock); } - generatedOres.put(pos, oreBlock); - } - Cubiomes.freePos3List(pos3List); - }); + Cubiomes.freePos3List(pos3List); + }); + return false; + }); int[] count = {0}; int block = blockPair.getFirst(); int colour = blockPair.getSecond(); From 471527324cf37c0ae1e4228439e13b3cdc7bc784 Mon Sep 17 00:00:00 2001 From: Frederik van der Els Date: Thu, 1 May 2025 19:01:41 +0200 Subject: [PATCH 07/15] Render ores per batch --- .gitmodules | 1 - includes.txt | 1 + src/main/c | 2 +- .../command/commands/ClearCommand.java | 7 +-- .../command/commands/HighlightCommand.java | 17 +++---- .../seedmapper/render/RenderManager.java | 50 +++++++++---------- .../assets/seedmapper/lang/en_us.json | 2 +- 7 files changed, 38 insertions(+), 42 deletions(-) diff --git a/.gitmodules b/.gitmodules index e7a3f3d6..f8d0f6fc 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,7 +1,6 @@ [submodule "src/main/c"] path = src/main/c url = https://github.com/xpple/cubiomes - branch = ore-generation [submodule "jextract"] path = jextract url = https://github.com/xpple/jextract diff --git a/includes.txt b/includes.txt index 7981b413..d4a1cf9d 100644 --- a/includes.txt +++ b/includes.txt @@ -673,6 +673,7 @@ --include-function initBiomeTypeColors --include-function loadSavedSeeds --include-function mc2str +--include-function ore2str --include-function parseBiomeColors --include-function savePPM --include-function str2mc diff --git a/src/main/c b/src/main/c index d2d88a10..88a0d609 160000 --- a/src/main/c +++ b/src/main/c @@ -1 +1 @@ -Subproject commit d2d88a10291f4c430f1f2f57bc6889f384237a16 +Subproject commit 88a0d609f554be539ff2dd7a6b62a2fffd3958e0 diff --git a/src/main/java/dev/xpple/seedmapper/command/commands/ClearCommand.java b/src/main/java/dev/xpple/seedmapper/command/commands/ClearCommand.java index 78e07302..8338bd13 100644 --- a/src/main/java/dev/xpple/seedmapper/command/commands/ClearCommand.java +++ b/src/main/java/dev/xpple/seedmapper/command/commands/ClearCommand.java @@ -1,5 +1,6 @@ package dev.xpple.seedmapper.command.commands; +import com.mojang.brigadier.Command; import com.mojang.brigadier.CommandDispatcher; import dev.xpple.seedmapper.command.CustomClientCommandSource; import dev.xpple.seedmapper.render.RenderManager; @@ -15,8 +16,8 @@ public static void register(CommandDispatcher dispatc } private static int clear(CustomClientCommandSource source) { - int count = RenderManager.clear(); - source.sendFeedback(Component.translatable("command.clear.success", count)); - return count; + RenderManager.clear(); + source.sendFeedback(Component.translatable("command.clear.success")); + return Command.SINGLE_SUCCESS; } } diff --git a/src/main/java/dev/xpple/seedmapper/command/commands/HighlightCommand.java b/src/main/java/dev/xpple/seedmapper/command/commands/HighlightCommand.java index 574d0bca..dbcbf8e5 100644 --- a/src/main/java/dev/xpple/seedmapper/command/commands/HighlightCommand.java +++ b/src/main/java/dev/xpple/seedmapper/command/commands/HighlightCommand.java @@ -22,6 +22,7 @@ import java.lang.foreign.MemorySegment; import java.util.Comparator; import java.util.HashMap; +import java.util.List; import java.util.Map; import static com.mojang.brigadier.arguments.IntegerArgumentType.*; @@ -99,18 +100,16 @@ private static int highlightBlock(CustomClientCommandSource source, Pair { - if (oreBlock == block) { - RenderManager.drawBox(pos, colour); - count[0]++; - } - }); + List blockOres = generatedOres.entrySet().stream() + .filter(entry -> entry.getValue() == block) + .map(Map.Entry::getKey) + .toList(); + RenderManager.drawBoxes(blockOres, colour); - source.sendFeedback(Component.translatable("command.highlight.success", count[0])); - return count[0]; + source.sendFeedback(Component.translatable("command.highlight.success", blockOres.size())); + return blockOres.size(); } } } diff --git a/src/main/java/dev/xpple/seedmapper/render/RenderManager.java b/src/main/java/dev/xpple/seedmapper/render/RenderManager.java index 5af351b5..509defb8 100644 --- a/src/main/java/dev/xpple/seedmapper/render/RenderManager.java +++ b/src/main/java/dev/xpple/seedmapper/render/RenderManager.java @@ -7,13 +7,13 @@ import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents; import net.minecraft.core.BlockPos; import net.minecraft.util.ARGB; -import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec3; import java.time.Duration; import java.util.Collections; +import java.util.HashSet; +import java.util.List; import java.util.Set; -import java.util.concurrent.atomic.AtomicInteger; public final class RenderManager { @@ -21,38 +21,34 @@ private RenderManager() { } private static final Set lines = Collections.newSetFromMap(CacheBuilder.newBuilder().expireAfterWrite(Duration.ofMinutes(5)).build().asMap());; - private static final AtomicInteger boxCount = new AtomicInteger(0); - public static void drawBox(BlockPos pos, int colour) { - drawBox(new AABB(pos), colour); - } - - public static void drawBox(AABB box, int colour) { - boxCount.getAndIncrement(); - Vec3 minPosition = box.getMinPosition(); - Vec3 size = box.getMaxPosition().subtract(box.getMinPosition()); + public static void drawBoxes(List posBatch, int colour) { + Set lines = new HashSet<>(); - addLine(new Line(minPosition, minPosition.add(size.x(), 0, 0), colour)); - addLine(new Line(minPosition, minPosition.add(0, size.y(), 0), colour)); - addLine(new Line(minPosition, minPosition.add(0, 0, size.z()), colour)); - addLine(new Line(minPosition.add(size.x(), 0, size.z()), minPosition.add(size.x(), 0, 0), colour)); - addLine(new Line(minPosition.add(size.x(), 0, size.z()), minPosition.add(size.x(), size.y(), size.z()), colour)); - addLine(new Line(minPosition.add(size.x(), 0, size.z()), minPosition.add(0, 0, size.z()), colour)); - addLine(new Line(minPosition.add(size.x(), size.y(), 0), minPosition.add(size.x(), 0, 0), colour)); - addLine(new Line(minPosition.add(size.x(), size.y(), 0), minPosition.add(0, size.y(), 0), colour)); - addLine(new Line(minPosition.add(size.x(), size.y(), 0), minPosition.add(size.x(), size.y(), size.z()), colour)); - addLine(new Line(minPosition.add(0, size.y(), size.z()), minPosition.add(0, 0, size.z()), colour)); - addLine(new Line(minPosition.add(0, size.y(), size.z()), minPosition.add(0, size.y(), 0), colour)); - addLine(new Line(minPosition.add(0, size.y(), size.z()), minPosition.add(size.x(), size.y(), size.z()), colour)); + posBatch.forEach(pos -> { + Vec3 minPosition = new Vec3(pos); + Vec3 size = new Vec3(1, 1, 1); + addLine(new Line(minPosition, minPosition.add(size.x(), 0, 0), colour), lines); + addLine(new Line(minPosition, minPosition.add(0, size.y(), 0), colour), lines); + addLine(new Line(minPosition, minPosition.add(0, 0, size.z()), colour), lines); + addLine(new Line(minPosition.add(size.x(), 0, size.z()), minPosition.add(size.x(), 0, 0), colour), lines); + addLine(new Line(minPosition.add(size.x(), 0, size.z()), minPosition.add(size.x(), size.y(), size.z()), colour), lines); + addLine(new Line(minPosition.add(size.x(), 0, size.z()), minPosition.add(0, 0, size.z()), colour), lines); + addLine(new Line(minPosition.add(size.x(), size.y(), 0), minPosition.add(size.x(), 0, 0), colour), lines); + addLine(new Line(minPosition.add(size.x(), size.y(), 0), minPosition.add(0, size.y(), 0), colour), lines); + addLine(new Line(minPosition.add(size.x(), size.y(), 0), minPosition.add(size.x(), size.y(), size.z()), colour), lines); + addLine(new Line(minPosition.add(0, size.y(), size.z()), minPosition.add(0, 0, size.z()), colour), lines); + addLine(new Line(minPosition.add(0, size.y(), size.z()), minPosition.add(0, size.y(), 0), colour), lines); + addLine(new Line(minPosition.add(0, size.y(), size.z()), minPosition.add(size.x(), size.y(), size.z()), colour), lines); + }); + RenderManager.lines.addAll(lines); } - public static int clear() { - int size = boxCount.getAndSet(0); + public static void clear() { lines.clear(); - return size; } - private static void addLine(Line line) { + private static void addLine(Line line, Set lines) { if (!lines.add(line)) { lines.remove(line); } diff --git a/src/main/resources/assets/seedmapper/lang/en_us.json b/src/main/resources/assets/seedmapper/lang/en_us.json index 2cecb2f0..3e91b985 100644 --- a/src/main/resources/assets/seedmapper/lang/en_us.json +++ b/src/main/resources/assets/seedmapper/lang/en_us.json @@ -61,5 +61,5 @@ "command.highlight.success": "Highlighted %s ores.", - "command.clear.success": "Cleared %s renders." + "command.clear.success": "Cleared all renders." } From 6a6af6b11abb8587fcda1d954276bc3404bbe835 Mon Sep 17 00:00:00 2001 From: Frederik van der Els Date: Fri, 2 May 2025 00:31:22 +0200 Subject: [PATCH 08/15] Stop rendering lines in unloaded chunks --- .../java/dev/xpple/seedmapper/render/RenderManager.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/dev/xpple/seedmapper/render/RenderManager.java b/src/main/java/dev/xpple/seedmapper/render/RenderManager.java index 509defb8..dd803a3c 100644 --- a/src/main/java/dev/xpple/seedmapper/render/RenderManager.java +++ b/src/main/java/dev/xpple/seedmapper/render/RenderManager.java @@ -7,6 +7,8 @@ import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents; import net.minecraft.core.BlockPos; import net.minecraft.util.ARGB; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.phys.Vec3; import java.time.Duration; @@ -60,6 +62,10 @@ public static void registerEvents() { private static void renderLines(WorldRenderContext context) { lines.forEach(line -> { + ChunkPos chunkPos = new ChunkPos(BlockPos.containing(line.start())); + if (context.world().getChunk(chunkPos.x, chunkPos.z, ChunkStatus.FULL, false) == null) { + return; + } Line relativeLine = line.offset(context.camera().getPosition().scale(-1)); Vec3 start = relativeLine.start(); Vec3 end = relativeLine.end(); From b43d4eabe686081a87cf4b8ebde9292435a5ffe2 Mon Sep 17 00:00:00 2001 From: Frederik van der Els Date: Fri, 2 May 2025 00:32:29 +0200 Subject: [PATCH 09/15] Calculate and display ores gradually in separate thread --- .../seedmapper/command/CommandExceptions.java | 4 +- .../command/commands/HighlightCommand.java | 39 +++++++++---- .../command/commands/LocateCommand.java | 44 +------------- .../mixin/ClientPacketListenerMixin.java | 23 ++++++++ .../seedmapper/thread/ThreadingHelper.java | 57 +++++++++++++++++++ .../assets/seedmapper/lang/en_us.json | 3 +- src/main/resources/mixins.seedmapper.json | 1 + 7 files changed, 113 insertions(+), 58 deletions(-) create mode 100644 src/main/java/dev/xpple/seedmapper/mixin/ClientPacketListenerMixin.java create mode 100644 src/main/java/dev/xpple/seedmapper/thread/ThreadingHelper.java diff --git a/src/main/java/dev/xpple/seedmapper/command/CommandExceptions.java b/src/main/java/dev/xpple/seedmapper/command/CommandExceptions.java index 8df0600b..50049264 100644 --- a/src/main/java/dev/xpple/seedmapper/command/CommandExceptions.java +++ b/src/main/java/dev/xpple/seedmapper/command/CommandExceptions.java @@ -2,7 +2,7 @@ import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; -import dev.xpple.seedmapper.command.commands.LocateCommand; +import dev.xpple.seedmapper.thread.ThreadingHelper; import net.minecraft.network.chat.Component; public final class CommandExceptions { @@ -10,7 +10,7 @@ public final class CommandExceptions { private CommandExceptions() { } - public static final SimpleCommandExceptionType ALREADY_BUSY_LOCATING_EXCEPTION = new SimpleCommandExceptionType(Component.translatable("commands.exceptions.alreadyBusyLocating", LocateCommand.STOP_TASK_COMPONENT)); + public static final SimpleCommandExceptionType ALREADY_BUSY_LOCATING_EXCEPTION = new SimpleCommandExceptionType(Component.translatable("commands.exceptions.alreadyBusyLocating", ThreadingHelper.STOP_TASK_COMPONENT)); public static final DynamicCommandExceptionType UNKNOWN_DIMENSION_EXCEPTION = new DynamicCommandExceptionType(arg -> Component.translatable("commands.exceptions.unknownDimension", arg)); public static final DynamicCommandExceptionType UNKNOWN_VERSION_EXCEPTION = new DynamicCommandExceptionType(arg -> Component.translatable("commands.exceptions.unknownVersion", arg)); public static final DynamicCommandExceptionType UNKNOWN_BIOME_EXCEPTION = new DynamicCommandExceptionType(arg -> Component.translatable("commands.exceptions.unknownBiome", arg)); diff --git a/src/main/java/dev/xpple/seedmapper/command/commands/HighlightCommand.java b/src/main/java/dev/xpple/seedmapper/command/commands/HighlightCommand.java index dbcbf8e5..c07adf29 100644 --- a/src/main/java/dev/xpple/seedmapper/command/commands/HighlightCommand.java +++ b/src/main/java/dev/xpple/seedmapper/command/commands/HighlightCommand.java @@ -27,6 +27,8 @@ import static com.mojang.brigadier.arguments.IntegerArgumentType.*; import static dev.xpple.seedmapper.command.arguments.BlockArgument.*; +import static dev.xpple.seedmapper.thread.ThreadingHelper.*; +import static dev.xpple.seedmapper.util.ChatBuilder.*; import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.*; public class HighlightCommand { @@ -36,8 +38,8 @@ public static void register(CommandDispatcher dispatc .then(literal("block") .then(argument("block", block()) .executes(ctx -> highlightBlock(CustomClientCommandSource.of(ctx.getSource()), getBlock(ctx, "block"))) - .then(argument("chunks", integer(0)) - .executes(ctx -> highlightBlock(CustomClientCommandSource.of(ctx.getSource()), getBlock(ctx, "block"), getInteger(ctx, "chunks"))))))); + .then(argument("chunks", integer(0, 20)) + .executes(ctx -> submit(() -> highlightBlock(CustomClientCommandSource.of(ctx.getSource()), getBlock(ctx, "block"), getInteger(ctx, "chunks")))))))); } private static int highlightBlock(CustomClientCommandSource source, Pair blockPair) throws CommandSyntaxException { @@ -56,9 +58,10 @@ private static int highlightBlock(CustomClientCommandSource source, Pair generatedOres = new HashMap<>(); + int[] count = {0}; SpiralLoop.spiral(center.x, center.z, chunkRange, (chunkX, chunkZ) -> { + Map generatedOres = new HashMap<>(); // TODO: check biome at multiple altitudes (technically should check 3x3 square of chunks) int biome = Cubiomes.getBiomeForOreGen(generator, chunkX, chunkZ); OreTypes.ORE_TYPES.stream() @@ -98,18 +101,30 @@ private static int highlightBlock(CustomClientCommandSource source, Pair blockOres = generatedOres.entrySet().stream() + .filter(entry -> entry.getValue() == block) + .map(Map.Entry::getKey) + .toList(); + count[0] += blockOres.size(); + source.getClient().schedule(() -> { + RenderManager.drawBoxes(blockOres, colour); + source.sendFeedback(Component.translatable("command.highlight.chunkSuccess", accent(String.valueOf(blockOres.size())), copy( + hover( + accent("%d %d".formatted(chunkX, chunkZ)), + base(Component.translatable("chat.copy.click")) + ), + "%d %d".formatted(chunkX, chunkZ) + ))); + }); + return false; }); - int block = blockPair.getFirst(); - int colour = blockPair.getSecond(); - List blockOres = generatedOres.entrySet().stream() - .filter(entry -> entry.getValue() == block) - .map(Map.Entry::getKey) - .toList(); - RenderManager.drawBoxes(blockOres, colour); - source.sendFeedback(Component.translatable("command.highlight.success", blockOres.size())); - return blockOres.size(); + source.getClient().schedule(() -> source.sendFeedback(Component.translatable("command.highlight.success", accent(String.valueOf(count[0]))))); + return count[0]; } } } diff --git a/src/main/java/dev/xpple/seedmapper/command/commands/LocateCommand.java b/src/main/java/dev/xpple/seedmapper/command/commands/LocateCommand.java index 3ec2a4bd..043c61c7 100644 --- a/src/main/java/dev/xpple/seedmapper/command/commands/LocateCommand.java +++ b/src/main/java/dev/xpple/seedmapper/command/commands/LocateCommand.java @@ -16,19 +16,14 @@ import dev.xpple.seedmapper.command.CustomClientCommandSource; import dev.xpple.seedmapper.feature.StructureChecks; import dev.xpple.seedmapper.feature.StructureVariantFeedbackHelper; -import dev.xpple.seedmapper.util.CheckedSupplier; import dev.xpple.seedmapper.util.SpiralLoop; import dev.xpple.seedmapper.util.TwoDTree; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; -import net.minecraft.ChatFormatting; -import net.minecraft.client.Minecraft; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.MutableComponent; import net.minecraft.util.RandomSource; -import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.Level; import net.minecraft.world.level.levelgen.WorldgenRandom; @@ -36,14 +31,12 @@ import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; import java.util.List; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; import java.util.stream.IntStream; import static com.mojang.brigadier.arguments.BoolArgumentType.*; import static dev.xpple.seedmapper.command.arguments.BiomeArgument.*; import static dev.xpple.seedmapper.command.arguments.StructurePredicateArgument.*; +import static dev.xpple.seedmapper.thread.ThreadingHelper.*; import static dev.xpple.seedmapper.util.ChatBuilder.*; import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.*; @@ -53,22 +46,6 @@ public class LocateCommand { private static final Long2ObjectMap cachedStrongholds = new Long2ObjectOpenHashMap<>(); - private static final ExecutorService locatingExecutor = Executors.newCachedThreadPool(); - private static Future currentTask = null; - - public static final Component STOP_TASK_COMPONENT = run(hover(format(Component.translatable("commands.exceptions.alreadyBusyLocating.stopTask"), ChatFormatting.UNDERLINE), base(Component.translatable("commands.exceptions.alreadyBusyLocating.clickToStop"))), () -> { - if (currentTask != null && !currentTask.isDone()) { - currentTask.cancel(true); - Minecraft.getInstance().player.displayClientMessage(Component.translatable("command.locate.taskStopped"), false); - } else { - Minecraft.getInstance().player.displayClientMessage(format(Component.translatable("command.locate.noTaskRunning"), ChatFormatting.RED), false); - } - }); - - static { - Runtime.getRuntime().addShutdownHook(new Thread(locatingExecutor::shutdownNow)); - } - public static void register(CommandDispatcher dispatcher) { dispatcher.register(literal("sm:locate") .then(literal("biome") @@ -88,25 +65,6 @@ public static void register(CommandDispatcher dispatc .executes(ctx -> submit(() -> locateSpawn(CustomClientCommandSource.of(ctx.getSource())))))); } - private static int submit(CheckedSupplier task) throws CommandSyntaxException { - if (currentTask != null && !currentTask.isDone()) { - throw CommandExceptions.ALREADY_BUSY_LOCATING_EXCEPTION.create(); - } - currentTask = locatingExecutor.submit(() -> { - try { - return task.get(); - } catch (CommandSyntaxException e) { - Player player = Minecraft.getInstance().player; - if (player != null) { - Minecraft.getInstance().schedule(() -> player.displayClientMessage(format((MutableComponent) e.getRawMessage(), ChatFormatting.RED), false)); - } - return 0; - } - }); - Minecraft.getInstance().player.displayClientMessage(Component.translatable("command.locate.taskStarted"), false); - return Command.SINGLE_SUCCESS; - } - private static int locateBiome(CustomClientCommandSource source, int biome) throws CommandSyntaxException { int dimension = source.getDimension(); if (Cubiomes.getDimension(biome) != dimension) { diff --git a/src/main/java/dev/xpple/seedmapper/mixin/ClientPacketListenerMixin.java b/src/main/java/dev/xpple/seedmapper/mixin/ClientPacketListenerMixin.java new file mode 100644 index 00000000..641e2f6e --- /dev/null +++ b/src/main/java/dev/xpple/seedmapper/mixin/ClientPacketListenerMixin.java @@ -0,0 +1,23 @@ +package dev.xpple.seedmapper.mixin; + +import dev.xpple.seedmapper.render.RenderManager; +import net.minecraft.client.multiplayer.ClientPacketListener; +import net.minecraft.network.protocol.game.ClientboundLoginPacket; +import net.minecraft.network.protocol.game.ClientboundRespawnPacket; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(ClientPacketListener.class) +public class ClientPacketListenerMixin { + @Inject(method = "handleLogin", at = @At("HEAD")) + private void onHandleLogin(ClientboundLoginPacket packet, CallbackInfo ci) { + RenderManager.clear(); + } + + @Inject(method = "handleRespawn", at = @At("HEAD")) + private void onHandleRespawn(ClientboundRespawnPacket packet, CallbackInfo ci) { + RenderManager.clear(); + } +} diff --git a/src/main/java/dev/xpple/seedmapper/thread/ThreadingHelper.java b/src/main/java/dev/xpple/seedmapper/thread/ThreadingHelper.java new file mode 100644 index 00000000..aa979802 --- /dev/null +++ b/src/main/java/dev/xpple/seedmapper/thread/ThreadingHelper.java @@ -0,0 +1,57 @@ +package dev.xpple.seedmapper.thread; + +import com.mojang.brigadier.Command; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import dev.xpple.seedmapper.command.CommandExceptions; +import dev.xpple.seedmapper.util.CheckedSupplier; +import net.minecraft.ChatFormatting; +import net.minecraft.client.Minecraft; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.world.entity.player.Player; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +import static dev.xpple.seedmapper.util.ChatBuilder.*; + +public final class ThreadingHelper { + private ThreadingHelper() { + } + + private static final ExecutorService locatingExecutor = Executors.newCachedThreadPool(); + private static Future currentTask = null; + + public static final Component STOP_TASK_COMPONENT = run(hover(format(Component.translatable("commands.exceptions.alreadyBusyLocating.stopTask"), ChatFormatting.UNDERLINE), base(Component.translatable("commands.exceptions.alreadyBusyLocating.clickToStop"))), () -> { + if (currentTask != null && !currentTask.isDone()) { + currentTask.cancel(true); + Minecraft.getInstance().player.displayClientMessage(Component.translatable("command.locate.taskStopped"), false); + } else { + Minecraft.getInstance().player.displayClientMessage(format(Component.translatable("command.locate.noTaskRunning"), ChatFormatting.RED), false); + } + }); + + static { + Runtime.getRuntime().addShutdownHook(new Thread(locatingExecutor::shutdownNow)); + } + + public static int submit(CheckedSupplier task) throws CommandSyntaxException { + if (currentTask != null && !currentTask.isDone()) { + throw CommandExceptions.ALREADY_BUSY_LOCATING_EXCEPTION.create(); + } + currentTask = locatingExecutor.submit(() -> { + try { + return task.get(); + } catch (CommandSyntaxException e) { + Player player = Minecraft.getInstance().player; + if (player != null) { + Minecraft.getInstance().schedule(() -> player.displayClientMessage(format((MutableComponent) e.getRawMessage(), ChatFormatting.RED), false)); + } + return 0; + } + }); + Minecraft.getInstance().player.displayClientMessage(Component.translatable("command.locate.taskStarted"), false); + return Command.SINGLE_SUCCESS; + } +} diff --git a/src/main/resources/assets/seedmapper/lang/en_us.json b/src/main/resources/assets/seedmapper/lang/en_us.json index 3e91b985..ecf97dfd 100644 --- a/src/main/resources/assets/seedmapper/lang/en_us.json +++ b/src/main/resources/assets/seedmapper/lang/en_us.json @@ -59,7 +59,8 @@ "command.locate.feature.slimeChunk.copyChunk": "Click to copy chunk coordinates of this slime chunk", "command.locate.spawn.success": "Spawn point estimated to be at %s.", - "command.highlight.success": "Highlighted %s ores.", + "command.highlight.chunkSuccess": "Highlighted %s ores in chunk %s.", + "command.highlight.success": "Highlighted %s ores in total!", "command.clear.success": "Cleared all renders." } diff --git a/src/main/resources/mixins.seedmapper.json b/src/main/resources/mixins.seedmapper.json index 98277138..7c7274b4 100644 --- a/src/main/resources/mixins.seedmapper.json +++ b/src/main/resources/mixins.seedmapper.json @@ -5,6 +5,7 @@ "mixins": [ ], "client": [ + "ClientPacketListenerMixin", "ScreenMixin" ], "injectors": { From d8d45f8f3de4bc05b9319bb3a974a418fa4b4954 Mon Sep 17 00:00:00 2001 From: Frederik van der Els Date: Fri, 2 May 2025 14:22:11 +0200 Subject: [PATCH 10/15] Add in-game air check config --- .../seedmapper/command/commands/HighlightCommand.java | 8 ++++++++ src/main/java/dev/xpple/seedmapper/config/Configs.java | 3 +++ 2 files changed, 11 insertions(+) diff --git a/src/main/java/dev/xpple/seedmapper/command/commands/HighlightCommand.java b/src/main/java/dev/xpple/seedmapper/command/commands/HighlightCommand.java index c07adf29..c6dcf9a7 100644 --- a/src/main/java/dev/xpple/seedmapper/command/commands/HighlightCommand.java +++ b/src/main/java/dev/xpple/seedmapper/command/commands/HighlightCommand.java @@ -10,6 +10,7 @@ import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.datafixers.util.Pair; import dev.xpple.seedmapper.command.CustomClientCommandSource; +import dev.xpple.seedmapper.config.Configs; import dev.xpple.seedmapper.feature.OreTypes; import dev.xpple.seedmapper.render.RenderManager; import dev.xpple.seedmapper.util.SpiralLoop; @@ -17,6 +18,8 @@ import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.status.ChunkStatus; import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; @@ -61,6 +64,8 @@ private static int highlightBlock(CustomClientCommandSource source, Pair { + LevelChunk chunk = source.getWorld().getChunkSource().getChunk(chunkX, chunkZ, ChunkStatus.FULL, false); + boolean doAirCheck = Configs.OreAirCheck && chunk != null; Map generatedOres = new HashMap<>(); // TODO: check biome at multiple altitudes (technically should check 3x3 square of chunks) int biome = Cubiomes.getBiomeForOreGen(generator, chunkX, chunkZ); @@ -83,6 +88,9 @@ private static int highlightBlock(CustomClientCommandSource source, Pair Date: Mon, 5 May 2025 16:24:00 +0200 Subject: [PATCH 11/15] Update README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 27e4e449..61ed41b9 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Usage: `/sm:locate feature structure []{}`. Locates a given structure closest to the player. All structures in all dimensions are supported. However, due to limitations in the underlying library, some structures (in particular desert pyramids, jungle temples and woodland mansions) may result in occasional false positives. For more advanced querying you can also use piece and variant data to further restrict the search. For example, the following command will search for end cities with ships: `/sm:locate feature structure end_city[end_ship]`. ### Ore highlighting -Usage: `/sm:highlight block `. +Usage: `/sm:highlight block [chunks]`. Highlights the specified block in the world. All versions from 1.13 onwards are supported. Due to high dependence on the [`OCEAN_FLOOR_WG`](https://minecraft.wiki/w/Heightmap#OCEAN_FLOOR_WG) heightmap, coal, copper and emerald ore locations may be off. From 0203f700a1c83f1342e9686dd45a7dba304f29f1 Mon Sep 17 00:00:00 2001 From: Frederik van der Els Date: Mon, 5 May 2025 16:24:20 +0200 Subject: [PATCH 12/15] Move rendering after translucent --- src/main/java/dev/xpple/seedmapper/render/RenderManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/dev/xpple/seedmapper/render/RenderManager.java b/src/main/java/dev/xpple/seedmapper/render/RenderManager.java index dd803a3c..05ab5683 100644 --- a/src/main/java/dev/xpple/seedmapper/render/RenderManager.java +++ b/src/main/java/dev/xpple/seedmapper/render/RenderManager.java @@ -57,7 +57,7 @@ private static void addLine(Line line, Set lines) { } public static void registerEvents() { - WorldRenderEvents.AFTER_ENTITIES.register(RenderManager::renderLines); + WorldRenderEvents.AFTER_TRANSLUCENT.register(RenderManager::renderLines); } private static void renderLines(WorldRenderContext context) { From 08dde49854426efdbb2b63693fc3046cbc798c2b Mon Sep 17 00:00:00 2001 From: Frederik van der Els Date: Mon, 5 May 2025 16:57:56 +0200 Subject: [PATCH 13/15] Bump version --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index ef0b9789..908da2aa 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,7 @@ org.gradle.jvmargs=-Xmx1G org.gradle.parallel=true # Mod Properties -mod_version=2.4.0 +mod_version=2.5.0-beta.1 maven_group=dev.xpple archives_base_name=seedmapper From 51a73356ac72e04065c2d6c8307a9d86173a9dfb Mon Sep 17 00:00:00 2001 From: Frederik van der Els Date: Thu, 22 May 2025 21:11:50 +0200 Subject: [PATCH 14/15] Update Cubiomes --- src/main/c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/c b/src/main/c index 88a0d609..56e57a2f 160000 --- a/src/main/c +++ b/src/main/c @@ -1 +1 @@ -Subproject commit 88a0d609f554be539ff2dd7a6b62a2fffd3958e0 +Subproject commit 56e57a2fbc86079623fb659c4ef8010520c5b7f2 From 40867380b903948a53dff9f1b1b8d368d0f99aca Mon Sep 17 00:00:00 2001 From: Frederik van der Els Date: Thu, 22 May 2025 21:13:08 +0200 Subject: [PATCH 15/15] Bump version --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 908da2aa..3a15c933 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,7 @@ org.gradle.jvmargs=-Xmx1G org.gradle.parallel=true # Mod Properties -mod_version=2.5.0-beta.1 +mod_version=2.5.0-beta.2 maven_group=dev.xpple archives_base_name=seedmapper