Skip to content

Commit 2ee5b63

Browse files
committed
Improved Loot Locating, Crash Fixes, UI Fixes (No Seed Fix), New Config
Folder, Stronghold Support (Beta).
1 parent dd17bdf commit 2ee5b63

15 files changed

Lines changed: 292 additions & 117 deletions

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ org.gradle.parallel=true
44

55
# Mod Properties
66
mod_version=2.22.3-CevAPI
7-
fork_release_version=v0.19
7+
fork_release_version=v0.20
88
maven_group=dev.xpple
99
archives_base_name=SeedMapper
1010

src/main/java/dev/xpple/seedmapper/SeedMapper.java

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,11 @@
5555
public class SeedMapper implements ClientModInitializer {
5656

5757
public static final String MOD_ID = "seedmapper";
58+
public static final String CONFIG_ID = "seedmapper_cevapi";
59+
public static final String LEGACY_CONFIG_ID = MOD_ID;
5860

59-
public static final Path modConfigPath = FabricLoader.getInstance().getConfigDir().resolve(MOD_ID);
61+
public static final Path modConfigPath = FabricLoader.getInstance().getConfigDir().resolve(CONFIG_ID);
62+
public static final Path legacyModConfigPath = FabricLoader.getInstance().getConfigDir().resolve(LEGACY_CONFIG_ID);
6063

6164
private static final Logger LOGGER = LogUtils.getLogger();
6265

@@ -78,8 +81,9 @@ public class SeedMapper implements ClientModInitializer {
7881
@Override
7982
public void onInitializeClient() {
8083
CubiomesNative.ensureLoaded();
84+
migrateLegacyConfigIfNeeded();
8185

82-
new ModConfigBuilder<>(MOD_ID, Configs.class)
86+
new ModConfigBuilder<>(CONFIG_ID, Configs.class)
8387
.registerType(SeedIdentifier.class, new SeedIdentifierAdapter(), SeedIdentifierArgument::seedIdentifier)
8488
.registerType(SeedResolutionArgument.SeedResolution.class, new SeedResolutionAdapter(), SeedResolutionArgument::seedResolution)
8589
.registerTypeHierarchy(MapFeature.class, new MapFeatureAdapter(), MapFeatureArgument::mapFeature)
@@ -118,6 +122,21 @@ public void onInitializeClient() {
118122
}
119123
}
120124

125+
private static void migrateLegacyConfigIfNeeded() {
126+
Path legacyConfigFile = legacyModConfigPath.resolve("config.json");
127+
Path forkConfigFile = modConfigPath.resolve("config.json");
128+
try {
129+
if (Files.exists(forkConfigFile) || !Files.exists(legacyConfigFile)) {
130+
return;
131+
}
132+
Files.createDirectories(modConfigPath);
133+
Files.copy(legacyConfigFile, forkConfigFile, StandardCopyOption.COPY_ATTRIBUTES);
134+
LOGGER.info("Copied legacy SeedMapper config from '{}' to '{}'", legacyConfigFile, forkConfigFile);
135+
} catch (IOException e) {
136+
LOGGER.warn("Failed to copy legacy SeedMapper config from '{}' to '{}'", legacyConfigFile, forkConfigFile, e);
137+
}
138+
}
139+
121140
private static void registerCommands(CommandDispatcher<FabricClientCommandSource> dispatcher, CommandBuildContext context) {
122141
LocateCommand.register(dispatcher);
123142
SourceCommand.register(dispatcher);

src/main/java/dev/xpple/seedmapper/command/arguments/ItemAndEnchantmentsPredicateArgument.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,15 @@
1313
import com.mojang.brigadier.suggestion.Suggestions;
1414
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
1515
import dev.xpple.seedmapper.command.CommandExceptions;
16+
import dev.xpple.seedmapper.util.CubiomesCompat;
1617
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
1718
import net.minecraft.commands.SharedSuggestionProvider;
1819
import net.minecraft.core.registries.BuiltInRegistries;
1920
import net.minecraft.network.chat.Component;
2021
import net.minecraft.resources.Identifier;
2122
import net.minecraft.resources.ResourceKey;
2223
import net.minecraft.world.item.Item;
24+
import net.minecraft.world.item.Items;
2325
import net.minecraft.world.item.enchantment.Enchantment;
2426
import net.minecraft.world.item.enchantment.Enchantments;
2527

@@ -42,17 +44,17 @@ public class ItemAndEnchantmentsPredicateArgument implements ArgumentType<ItemAn
4244

4345
private static final Map<String, Integer> ITEMS = IntStream.range(0, Cubiomes.NUM_ITEMS()).boxed()
4446
.collect(Collectors.toUnmodifiableMap(item -> {
45-
String name = Cubiomes.global_id2item_name(item, Cubiomes.MC_NEWEST()).getString(0);
47+
String name = CubiomesCompat.itemName(item, Cubiomes.MC_NEWEST());
4648
String prefix = Identifier.DEFAULT_NAMESPACE + ':';
4749
return name.startsWith(prefix) ? name.substring(prefix.length()) : name;
4850
}, item -> item));
4951

5052
public static final Map<Integer, Item> ITEM_ID_TO_MC = IntStream.range(0, Cubiomes.NUM_ITEMS()).boxed()
5153
.collect(Collectors.toUnmodifiableMap(item -> item, item -> {
52-
String name = Cubiomes.global_id2item_name(item, Cubiomes.MC_NEWEST()).getString(0);
54+
String name = CubiomesCompat.itemName(item, Cubiomes.MC_NEWEST());
5355
Identifier identifier = Identifier.parse(name);
5456
Optional<Item> optionalItem = BuiltInRegistries.ITEM.getOptional(identifier);
55-
return optionalItem.orElseThrow();
57+
return optionalItem.orElse(Items.AIR);
5658
}));
5759

5860
//<editor-fold defaultstate="collapsed" desc="private static final Map<String, Integer> ENCHANTMENTS;">

src/main/java/dev/xpple/seedmapper/command/commands/EspConfigCommand.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,10 @@ public static void register(CommandDispatcher<FabricClientCommandSource> dispatc
6060
return;
6161
}
6262

63-
CommandNode<FabricClientCommandSource> modRoot = cconfigRoot.getChild(SeedMapper.MOD_ID);
63+
CommandNode<FabricClientCommandSource> modRoot = cconfigRoot.getChild(SeedMapper.CONFIG_ID);
64+
if (modRoot == null) {
65+
modRoot = cconfigRoot.getChild(SeedMapper.MOD_ID);
66+
}
6467
if (modRoot == null) {
6568
// Mod-specific cconfig node missing: register direct fallback.
6669
registerDirectSmConfig(dispatcher);
@@ -75,7 +78,8 @@ private static void registerDirectSmConfig(CommandDispatcher<FabricClientCommand
7578
LiteralArgumentBuilder<FabricClientCommandSource> smRoot = literal("sm:config");
7679
smRoot.then(buildEspLiteral("ESP"));
7780
ZoomConfigCommand.register(smRoot);
78-
dispatcher.register(smRoot);
81+
CommandNode<FabricClientCommandSource> registeredSmRoot = dispatcher.register(smRoot);
82+
dispatcher.register(literal("smconfig").redirect(registeredSmRoot));
7983
}
8084

8185
private static LiteralArgumentBuilder<FabricClientCommandSource> buildEspLiteral(String literalName) {

src/main/java/dev/xpple/seedmapper/command/commands/ExportLootCommand.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import dev.xpple.seedmapper.command.CustomClientCommandSource;
1414
import dev.xpple.seedmapper.command.arguments.DimensionArgument;
1515
import dev.xpple.seedmapper.feature.StructureChecks;
16+
import dev.xpple.seedmapper.util.CubiomesCompat;
1617
import dev.xpple.seedmapper.util.LootExportHelper;
1718
import dev.xpple.seedmapper.util.SeedIdentifier;
1819
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
@@ -194,7 +195,7 @@ private static Set<Integer> parseStructureFilter(String filter, int version) {
194195
if (Cubiomes.getStructureConfig(structure, version, config) == 0) {
195196
continue;
196197
}
197-
String name = Cubiomes.struct2str(StructureConfig.structType(config)).getString(0);
198+
String name = CubiomesCompat.structureName(StructureConfig.structType(config));
198199
if (wanted.contains(name.toLowerCase())) {
199200
matches.add((int) StructureConfig.structType(config));
200201
}

src/main/java/dev/xpple/seedmapper/command/commands/LocateCommand.java

Lines changed: 146 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import dev.xpple.seedmapper.feature.StructureVariantFeedbackHelper;
2525
import dev.xpple.seedmapper.seedmap.SeedMapScreen;
2626
import dev.xpple.seedmapper.util.ComponentUtils;
27+
import dev.xpple.seedmapper.util.CubiomesCompat;
2728
import dev.xpple.seedmapper.util.SeedIdentifier;
2829
import dev.xpple.seedmapper.util.SpiralLoop;
2930
import dev.xpple.seedmapper.util.SpiralSpliterator;
@@ -376,7 +377,7 @@ record StructureIterationState(MemorySegment structureConfig, StructureChecks.Ge
376377
*/
377378
for (int stateIndex = 0, radius = 0;; stateIndex++) {
378379
if (structureStates.isEmpty()) {
379-
throw CommandExceptions.LOOT_NOT_AVAILABLE_EXCEPTION.create();
380+
break;
380381
}
381382
if (stateIndex >= structureStates.size()) {
382383
stateIndex = 0;
@@ -424,6 +425,9 @@ record StructureIterationState(MemorySegment structureConfig, StructureChecks.Ge
424425
MemorySegment lootSeeds = Piece.lootSeeds(piece);
425426
for (int j = 0; j < chestCount; j++) {
426427
MemorySegment lootTable = lootTables.getAtIndex(ValueLayout.ADDRESS, j).reinterpret(Long.MAX_VALUE);
428+
if (lootTable.equals(MemorySegment.NULL)) {
429+
continue;
430+
}
427431
MemorySegment lootTableContext;
428432
if (Cubiomes.init_loot_table_name(ltcPtr, lootTable, version) == 0) {
429433
lootTableContext = null;
@@ -432,9 +436,11 @@ record StructureIterationState(MemorySegment structureConfig, StructureChecks.Ge
432436
}
433437
if (lootTableContext == null || Cubiomes.has_item(lootTableContext, itemPredicate.item()) == 0) {
434438
Set<String> structureIgnoredLootTables = ignoredLootTables.computeIfAbsent(structure, _ -> new HashSet<>());
435-
structureIgnoredLootTables.add(lootTable.getString(0));
436-
// if structure has no loot tables with the desired item, remove structure from state loop
437-
if (structureIgnoredLootTables.size() == lootTableCount.get(structure)) {
439+
structureIgnoredLootTables.add(CubiomesCompat.safeCString(lootTable, "unknown_loot_table"));
440+
// If cubiomes reports a known positive loot-table count for this structure,
441+
// we can prune it once all loot tables are known misses for the requested item.
442+
int knownLootTableCount = lootTableCount.getOrDefault(structure, 0);
443+
if (knownLootTableCount > 0 && structureIgnoredLootTables.size() == knownLootTableCount) {
438444
return;
439445
}
440446
continue;
@@ -462,7 +468,9 @@ record StructureIterationState(MemorySegment structureConfig, StructureChecks.Ge
462468
structureStates.remove(stateIndex);
463469
break;
464470
}
465-
if (ignoredLootTables.getOrDefault(structure, Collections.emptySet()).size() == lootTableCount.get(structure)) {
471+
int knownLootTableCount = lootTableCount.getOrDefault(structure, 0);
472+
if (knownLootTableCount > 0
473+
&& ignoredLootTables.getOrDefault(structure, Collections.emptySet()).size() == knownLootTableCount) {
466474
structureStates.remove(stateIndex);
467475
break;
468476
}
@@ -472,18 +480,149 @@ record StructureIterationState(MemorySegment structureConfig, StructureChecks.Ge
472480
}
473481
int newlyFound = found[0] - previouslyFound;
474482
if (newlyFound > 0) {
475-
String structureName = Cubiomes.struct2str(StructureConfig.structType(structureConfig)).getString(0);
483+
String structureName = CubiomesCompat.structureName(StructureConfig.structType(structureConfig));
476484
structureResults.add(new LootStructureResult(structureName, newlyFound, List.copyOf(aggregatedLootPositions)));
477485
}
478486
if (found[0] >= amount) {
479487
break;
480488
}
481489
}
482-
String itemName = Cubiomes.global_id2item_name(itemPredicate.item(), version).getString(0);
490+
491+
if (found[0] < amount && dimension == Cubiomes.DIM_OVERWORLD()) {
492+
int newlyFound = scanStrongholdLoot(center, seed, version, generator, amount - found[0], itemPredicate, found, primaryPos, structureResults, arena);
493+
if (newlyFound > 0 && primaryPos[0] == null && !structureResults.isEmpty()) {
494+
LootStructureResult last = structureResults.getLast();
495+
if (!last.positions().isEmpty()) {
496+
primaryPos[0] = last.positions().getFirst();
497+
}
498+
}
499+
}
500+
501+
if (found[0] <= 0) {
502+
throw CommandExceptions.LOOT_NOT_AVAILABLE_EXCEPTION.create();
503+
}
504+
505+
String itemName = CubiomesCompat.itemName(itemPredicate.item(), version);
483506
return new LootLocateResult(found[0], itemName, primaryPos[0] == null ? center : primaryPos[0], center, List.copyOf(structureResults));
484507
}
485508
}
486509

510+
private static int scanStrongholdLoot(
511+
BlockPos center,
512+
long seed,
513+
int version,
514+
MemorySegment generator,
515+
int amountNeeded,
516+
EnchantedItem itemPredicate,
517+
int[] foundTotal,
518+
BlockPos[] primaryPos,
519+
List<LootStructureResult> structureResults,
520+
Arena arena
521+
) {
522+
if (amountNeeded <= 0) {
523+
return 0;
524+
}
525+
526+
List<BlockPos> strongholds = new ArrayList<>();
527+
TwoDTree strongholdTree = calculateStrongholds(seed, Cubiomes.DIM_OVERWORLD(), version, Generator.flags(generator));
528+
for (BlockPos pos : strongholdTree) {
529+
strongholds.add(pos);
530+
}
531+
strongholds.sort(Comparator.comparingDouble(pos -> pos.distSqr(center.atY(0))));
532+
533+
int structure = Cubiomes.Stronghold();
534+
List<BlockPos> aggregatedLootPositions = new ArrayList<>();
535+
int foundInStrongholds = 0;
536+
537+
MemorySegment structureVariant = StructureVariant.allocate(arena);
538+
MemorySegment structureSaltConfig = StructureSaltConfig.allocate(arena);
539+
MemorySegment pieces = Piece.allocateArray(StructureChecks.MAX_END_CITY_AND_FORTRESS_PIECES, arena);
540+
MemorySegment ltcPtr = arena.allocate(Cubiomes.C_POINTER);
541+
542+
for (BlockPos strongholdPos : strongholds) {
543+
int posX = strongholdPos.getX();
544+
int posZ = strongholdPos.getZ();
545+
546+
int biome = Cubiomes.getBiomeAt(generator, 4, posX >> 2, 320 >> 2, posZ >> 2);
547+
Cubiomes.getVariant(structureVariant, structure, version, seed, posX, posZ, biome);
548+
biome = StructureVariant.biome(structureVariant) != -1 ? StructureVariant.biome(structureVariant) : biome;
549+
if (Cubiomes.getStructureSaltConfig(structure, version, biome, structureSaltConfig) == 0) {
550+
continue;
551+
}
552+
int numPieces = Cubiomes.getStructurePieces(
553+
pieces,
554+
StructureChecks.MAX_END_CITY_AND_FORTRESS_PIECES,
555+
structure,
556+
structureSaltConfig,
557+
structureVariant,
558+
version,
559+
seed,
560+
posX,
561+
posZ
562+
);
563+
if (numPieces <= 0) {
564+
continue;
565+
}
566+
567+
int foundAtThisStronghold = 0;
568+
for (int i = 0; i < numPieces; i++) {
569+
MemorySegment piece = Piece.asSlice(pieces, i);
570+
int chestCount = Piece.chestCount(piece);
571+
if (chestCount == 0) {
572+
continue;
573+
}
574+
MemorySegment lootTables = Piece.lootTables(piece);
575+
MemorySegment lootSeeds = Piece.lootSeeds(piece);
576+
for (int j = 0; j < chestCount; j++) {
577+
MemorySegment lootTable = lootTables.getAtIndex(ValueLayout.ADDRESS, j).reinterpret(Long.MAX_VALUE);
578+
if (lootTable.equals(MemorySegment.NULL)) {
579+
continue;
580+
}
581+
if (Cubiomes.init_loot_table_name(ltcPtr, lootTable, version) == 0) {
582+
continue;
583+
}
584+
MemorySegment lootTableContext = ltcPtr.get(ValueLayout.ADDRESS, 0).reinterpret(LootTableContext.sizeof());
585+
if (Cubiomes.has_item(lootTableContext, itemPredicate.item()) == 0) {
586+
continue;
587+
}
588+
Cubiomes.set_loot_seed(lootTableContext, lootSeeds.getAtIndex(Cubiomes.C_LONG_LONG, j));
589+
Cubiomes.generate_loot(lootTableContext);
590+
int lootCount = LootTableContext.generated_item_count(lootTableContext);
591+
for (int k = 0; k < lootCount; k++) {
592+
MemorySegment itemStack = ItemStack.asSlice(LootTableContext.generated_items(lootTableContext), k);
593+
if (Cubiomes.get_global_item_id(lootTableContext, ItemStack.item(itemStack)) == itemPredicate.item()
594+
&& itemPredicate.enchantmensPredicate().test(itemStack)) {
595+
int stackCount = ItemStack.count(itemStack);
596+
foundAtThisStronghold += stackCount;
597+
foundTotal[0] += stackCount;
598+
}
599+
}
600+
}
601+
}
602+
603+
if (foundAtThisStronghold > 0) {
604+
foundInStrongholds += foundAtThisStronghold;
605+
aggregatedLootPositions.add(new BlockPos(posX, 0, posZ));
606+
if (primaryPos[0] == null) {
607+
primaryPos[0] = new BlockPos(posX, 0, posZ);
608+
}
609+
}
610+
611+
if (foundInStrongholds >= amountNeeded) {
612+
break;
613+
}
614+
}
615+
616+
if (foundInStrongholds > 0) {
617+
structureResults.add(new LootStructureResult(
618+
CubiomesCompat.structureName(structure),
619+
foundInStrongholds,
620+
List.copyOf(aggregatedLootPositions)
621+
));
622+
}
623+
return foundInStrongholds;
624+
}
625+
487626
private static int locateSpawn(CustomClientCommandSource source) throws CommandSyntaxException {
488627
SeedIdentifier seed = source.getSeed().getSecond();
489628
try (Arena arena = Arena.ofConfined()) {

0 commit comments

Comments
 (0)