glimmer reed, tuft recipes, dimensional tear sounds, nyxium roots, many missing tags, configured support

This commit is contained in:
craisinlord committed 2026-09-02 22:18:24 -05:00
1 parent 4ecd7906d6
commit 867fef9d0a
148 files changed
+1832 -79

No files matched your search

+16 -1
View File
@@ -48,9 +48,24 @@ dependencies {
compileOnly(files("$rootDir/infinite_dimensions_jars/infinity-2.7.2+1.21.1-neoforge.jar"))
runtimeOnly(files("$rootDir/infinite_dimensions_jars/infinity-2.7.2+1.21.1-fabric.jar"))
compileOnly(files("$rootDir/infinite_dimensions_jars/gravity-api-1.0.7-1.20.1.jar"))
compileOnly(files("$rootDir/infinite_dimensions_jars/cloth-config-15.0.140-fabric.jar"))
compileOnly(files("$rootDir/infinite_dimensions_jars/sable-neoforge-1.21.1-2.0.3.jar"))
// Cloth Config — optional, powers the in-game settings screen (AntarchyClothConfigScreenBuilder)
// via the Mod Menu integration below. compileOnly + modLocalRuntime only: never bundled or
// required at runtime in the shipped jar. Guarded by FabricLoader.isModLoaded("cloth-config")
// in AntarchyModMenuIntegration before any Cloth Config class is touched. Reuses the
// clothconfig_curseforge_id/clothconfig_curseforge_file_id pin already in gradle.properties.
modCompileOnly("curse.maven:cloth-config-${clothconfig_curseforge_id}:${clothconfig_curseforge_file_id}")
modLocalRuntime("curse.maven:cloth-config-${clothconfig_curseforge_id}:${clothconfig_curseforge_file_id}")
// Mod Menu — optional, provides the "modmenu" fabric.mod.json entrypoint
// (AntarchyModMenuIntegration). Same soft-dependency treatment as Cloth Config above; Fabric
// Loader only ever resolves the "modmenu" entrypoint if Mod Menu itself is installed and asks
// for it, so nothing here is touched when it's absent. Reuses the mod_menu version already
// pinned in gradle.properties.
modCompileOnly "com.terraformersmc:modmenu:${mod_menu}"
modLocalRuntime "com.terraformersmc:modmenu:${mod_menu}"
// Compile against the NeoForge jar (official Mojang mappings, matches this module's compile
// space) but load the real Fabric jar at runtime — sizeable_foliage's Fabric jar ships
// intermediary-mapped, which this compileOnly classpath can't resolve directly.
@@ -70,6 +70,40 @@ public final class AntarchyConfigModuleFabric {
}
}
/**
* Exposes the reflection-based getter/setter binding map (see {@link #buildBindings()}) so
* other Fabric-side code — namely the optional Cloth Config screen builder — can reuse the
* exact same set of persisted settings the JSON files already round-trip, instead of
* hand-authoring a separate list. Read-only: callers get/set individual values through
* {@link SettingBinding#getValue()} / {@link SettingBinding#setValue(Object)}.
*/
public static Map<String, SettingBinding> getBindings() {
return SETTINGS;
}
/**
* Re-serializes the current live value of every binding back to its JSON file. Intended for
* the optional Cloth Config screen's save handler: entries there update the live
* {@link AntarchySettings} fields immediately through their own save consumers (same as
* {@link SettingBinding#apply(Object)} does below), but nothing writes those changes to disk
* until this runs — mirrors the persistence tail of {@link #init()} above.
*/
public static void persist() {
Map<ConfigSection, JsonObject> normalized = new LinkedHashMap<>();
for (ConfigSection section : ConfigSection.values()) {
normalized.put(section, new JsonObject());
}
for (Map.Entry<String, SettingBinding> entry : SETTINGS.entrySet()) {
SettingBinding binding = entry.getValue();
normalized.get(binding.section).add(entry.getKey(), binding.toJson(binding.getCurrentValue()));
}
for (Map.Entry<ConfigSection, JsonObject> entry : normalized.entrySet()) {
writeConfig(entry.getKey().path, entry.getValue());
}
}
private static JsonObject readConfig(Path path) {
if (!Files.exists(path)) {
return null;
@@ -145,7 +179,11 @@ public final class AntarchyConfigModuleFabric {
return Character.toLowerCase(value.charAt(0)) + value.substring(1);
}
private enum ConfigSection {
/**
* Public so the optional Cloth Config screen builder (fabric.client package) can group
* entries into the same Mobs/Tools/Misc categories the JSON files already use.
*/
public enum ConfigSection {
MOBS("antarchy_mobs.json"),
TOOLS("antarchy_tools.json"),
MISC("antarchy_misc.json");
@@ -222,7 +260,15 @@ public final class AntarchyConfigModuleFabric {
}
}
private static final class SettingBinding {
/**
* Public so the optional Cloth Config screen builder (fabric.client package) can reuse this
* exact binding — the same getter/setter pair and JSON section the persistence layer above
* already drives — instead of a separate hand-authored entry list. The JSON-specific
* machinery (readValue/apply/toJson/getCurrentValue) stays private and is reused internally
* by the public getValue()/setValue() wrappers below, so there's exactly one code path for
* "what is this setting's current value" and "how do I change it".
*/
public static final class SettingBinding {
private final String name;
private final Method getter;
private final Method setter;
@@ -237,6 +283,31 @@ public final class AntarchyConfigModuleFabric {
this.section = section;
}
/** The AntarchySettings property name, e.g. {@code krakenHealth}. */
public String getName() {
return name;
}
/** Which of the three JSON files (Mobs/Tools/Misc) this setting persists to. */
public ConfigSection getSection() {
return section;
}
/** The primitive/String type of the setter's single parameter (boolean/int/double/float/String). */
public Class<?> getType() {
return setterType;
}
/** The setting's current live value, boxed (Boolean/Integer/Double/Float/String). */
public Object getValue() {
return getCurrentValue();
}
/** Applies a new value immediately via reflection, same as the JSON loader does at startup. */
public void setValue(Object value) {
apply(value);
}
private Object readValue(JsonElement element) {
Object defaultValue = getCurrentValue();
if (element == null || element.isJsonNull()) {
@@ -335,6 +335,12 @@ public final class AntarchyFabricContent {
AntarchyFabricSounds.PRINCESS_FLY,
AntarchyFabricSounds.PRINCESS_STEP
);
AntarchySoundEvents.bindDimensionalTearSounds(
AntarchyFabricSounds.DIMENSIONAL_TEAR_OPEN,
AntarchyFabricSounds.DIMENSIONAL_TEAR_IDLE,
AntarchyFabricSounds.DIMENSIONAL_TEAR_CREATURE_LEAVES,
AntarchyFabricSounds.DIMENSIONAL_TEAR_CLOSE
);
AntarchyObjects.setOctopusBomb(AntarchyFabricEntities.OCTOPUS_BOMB);
AntarchyObjects.setTentacle(AntarchyFabricEntities.TENTACLE);
@@ -387,6 +393,7 @@ public final class AntarchyFabricContent {
AntarchyObjects.setLumenBucket(() -> AntarchyFabricItems.LUMEN_BUCKET.get());
AntarchyObjects.setLumenBlock(() -> AntarchyFabricBlocks.LUMEN_BLOCK.get());
AntarchyObjects.setLumenFroglight(() -> AntarchyFabricBlocks.LUMEN_FROGLIGHT.get());
AntarchyObjects.setGlimmeringReed(() -> AntarchyFabricBlocks.GLIMMERING_REED.get());
AntarchyObjects.setPeachLeavesParticle(() -> AntarchyFabricMisc.PEACH_LEAVES_PARTICLE.get());
AntarchyObjects.setLotusPollen(() -> AntarchyFabricMisc.LOTUS_POLLEN.get());
AntarchyObjects.setNightmareFireFlame(() -> AntarchyFabricMisc.NIGHTMARE_FIRE_FLAME.get());
@@ -0,0 +1,91 @@
package com.craisinlord.antarchy.fabric.client;
import com.craisinlord.antarchy.fabric.AntarchyConfigModuleFabric;
import com.craisinlord.antarchy.fabric.AntarchyConfigModuleFabric.ConfigSection;
import com.craisinlord.antarchy.fabric.AntarchyConfigModuleFabric.SettingBinding;
import me.shedaniel.clothconfig2.api.ConfigBuilder;
import me.shedaniel.clothconfig2.api.ConfigCategory;
import me.shedaniel.clothconfig2.api.ConfigEntryBuilder;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.Component;
import java.util.EnumMap;
import java.util.Map;
/**
* Builds a Cloth Config screen directly from {@link AntarchyConfigModuleFabric}'s existing
* reflection-based binding map, so the screen and the on-disk JSON files stay in sync
* automatically — no separate hand-authored list of 350+ entries.
*
* <p>Only ever reached from {@link AntarchyModMenuIntegration#getModConfigScreenFactory()} after
* it has already confirmed Cloth Config is present, so every Cloth Config class referenced here
* is safe to touch.
*
* <p>Phase 1 scope (see the implementation plan): raw field names as labels, no min/max bounds,
* no tooltips, and fields backed by {@code ResourceKey<Level>} (the four dimension-identity
* settings) are skipped entirely rather than exposed with a widget that doesn't fit them.
*/
public final class AntarchyClothConfigScreenBuilder {
private AntarchyClothConfigScreenBuilder() {
}
public static Screen build(Screen parent) {
ConfigBuilder builder = ConfigBuilder.create()
.setParentScreen(parent)
.setTitle(Component.translatable("antarchy.config.title"));
// Entry save consumers (below) already update the live AntarchySettings fields the
// instant the player edits a widget, matching how the game normally behaves. This runs
// last, once, when the player clicks "Save" — it's what actually writes those changes
// back to the three JSON files, since AntarchyConfigModuleFabric only reads+writes them
// at startup otherwise.
builder.setSavingRunnable(AntarchyConfigModuleFabric::persist);
ConfigEntryBuilder entryBuilder = builder.entryBuilder();
Map<ConfigSection, ConfigCategory> categories = new EnumMap<>(ConfigSection.class);
for (ConfigSection section : ConfigSection.values()) {
categories.put(section, builder.getOrCreateCategory(Component.literal(displayName(section))));
}
for (SettingBinding binding : AntarchyConfigModuleFabric.getBindings().values()) {
addEntry(entryBuilder, categories.get(binding.getSection()), binding);
}
return builder.build();
}
private static void addEntry(ConfigEntryBuilder entryBuilder, ConfigCategory category, SettingBinding binding) {
Class<?> type = binding.getType();
Component label = Component.literal(binding.getName());
if (type == boolean.class) {
category.addEntry(entryBuilder.startBooleanToggle(label, (Boolean) binding.getValue())
.setSaveConsumer(binding::setValue)
.build());
} else if (type == int.class) {
category.addEntry(entryBuilder.startIntField(label, (Integer) binding.getValue())
.setSaveConsumer(binding::setValue)
.build());
} else if (type == double.class) {
category.addEntry(entryBuilder.startDoubleField(label, (Double) binding.getValue())
.setSaveConsumer(binding::setValue)
.build());
} else if (type == float.class) {
category.addEntry(entryBuilder.startFloatField(label, (Float) binding.getValue())
.setSaveConsumer(binding::setValue)
.build());
}
// String-typed bindings back the ResourceKey<Level> dimension fields (see
// AntarchyConfigModuleFabric.isSupported) and are intentionally skipped here — they're
// structural dimension identity, not a tuning knob, and Cloth Config has no natural
// widget for them. Every other supported type is exactly what's already persisted to
// JSON today, so nothing shown here can drift from what the JSON files contain.
}
private static String displayName(ConfigSection section) {
return switch (section) {
case MOBS -> "Mobs";
case TOOLS -> "Tools";
case MISC -> "Misc";
};
}
}
@@ -351,6 +351,7 @@ public final class AntarchyFabricClientBootstrap {
BlockRenderLayerMap.INSTANCE.putBlock(AntarchyFabricBlocks.DUPLICATOR_SAPLING.get(), RenderType.cutout());
BlockRenderLayerMap.INSTANCE.putBlock(AntarchyFabricBlocks.ORANGE_MILKWEED.get(), RenderType.cutout());
BlockRenderLayerMap.INSTANCE.putBlock(AntarchyFabricBlocks.PINK_MILKWEED.get(), RenderType.cutout());
BlockRenderLayerMap.INSTANCE.putBlock(AntarchyFabricBlocks.GLIMMERING_REED.get(), RenderType.cutout());
BlockRenderLayerMap.INSTANCE.putBlock(AntarchyFabricBlocks.AMBER_LICHEN.get(), RenderType.cutout());
BlockRenderLayerMap.INSTANCE.putBlock(AntarchyFabricBlocks.MUCUS.get(), RenderType.cutout());
BlockRenderLayerMap.INSTANCE.putBlock(AntarchyFabricBlocks.CREEPVINE.get(), RenderType.cutout());
@@ -378,6 +379,8 @@ public final class AntarchyFabricClientBootstrap {
BlockRenderLayerMap.INSTANCE.putBlock(AntarchyFabricBlocks.NADIR_FERN.get(), RenderType.cutout());
BlockRenderLayerMap.INSTANCE.putBlock(AntarchyFabricBlocks.LARGE_NADIR_FERN.get(), RenderType.cutout());
BlockRenderLayerMap.INSTANCE.putBlock(AntarchyFabricBlocks.DUSKBELL.get(), RenderType.cutout());
BlockRenderLayerMap.INSTANCE.putBlock(AntarchyFabricBlocks.NADIR_ROOTS.get(), RenderType.cutout());
BlockRenderLayerMap.INSTANCE.putBlock(AntarchyFabricBlocks.VERDANT_ROOTS.get(), RenderType.cutout());
BlockRenderLayerMap.INSTANCE.putBlock(AntarchyFabricBlocks.STAR_CORAL.get(), RenderType.cutout());
BlockRenderLayerMap.INSTANCE.putBlock(AntarchyFabricBlocks.STAR_CORAL_FAN.get(), RenderType.cutout());
BlockRenderLayerMap.INSTANCE.putBlock(AntarchyFabricBlocks.STAR_CORAL_WALL_FAN.get(), RenderType.cutout());
@@ -0,0 +1,37 @@
package com.craisinlord.antarchy.fabric.client;
import com.terraformersmc.modmenu.api.ConfigScreenFactory;
import com.terraformersmc.modmenu.api.ModMenuApi;
import net.fabricmc.loader.api.FabricLoader;
/**
* Optional Mod Menu integration entrypoint — declared under the "modmenu" key in
* fabric.mod.json, never referenced anywhere else in Antarchy's own code.
*
* <p>This class is only ever loaded/instantiated by Mod Menu itself. Fabric Loader resolves
* entrypoints lazily: it reads every mod's fabric.mod.json at startup, but a class named under
* "entrypoints" is not loaded until something explicitly calls
* {@code FabricLoader.getInstance().getEntrypointContainers("modmenu", ModMenuApi.class)} for
* that key — and only Mod Menu does that. So if Mod Menu isn't installed, this class is never
* touched at all, and "modmenu" is declared as a "suggests" (not "depends") dependency in
* fabric.mod.json precisely so Antarchy loads identically either way.
*
* <p>Mod Menu and Cloth Config are independently optional, so the one runtime guard this
* integration does need is below: if Mod Menu is present but Cloth Config isn't, building the
* real screen would touch Cloth Config classes that aren't on the classpath.
*/
public final class AntarchyModMenuIntegration implements ModMenuApi {
@Override
public ConfigScreenFactory<?> getModConfigScreenFactory() {
if (!FabricLoader.getInstance().isModLoaded("cloth-config")) {
// Mod Menu always shows the config button once a non-null factory is returned, so
// there's no clean way to hide it conditionally — handing back the screen that was
// already open is the safest no-op fallback when Cloth Config isn't installed.
return parent -> parent;
}
// Method reference, not a direct call: this does not load AntarchyClothConfigScreenBuilder
// or touch any Cloth Config class until the player actually clicks the config button,
// which only happens after the isModLoaded check above has already passed.
return AntarchyClothConfigScreenBuilder::build;
}
}
@@ -137,6 +137,8 @@ public final class AntarchyFabricBlocks {
public static final DeferredBlock<MilkweedBlock> PINK_MILKWEED = BLOCKS.register("pink_milkweed",
() -> new MilkweedBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.PEONY)));
public static final DeferredBlock<com.craisinlord.antarchy.content.block.GlimmeringReedBlock> GLIMMERING_REED = BLOCKS.register("glimmering_reed",
() -> new com.craisinlord.antarchy.content.block.GlimmeringReedBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.SUNFLOWER).lightLevel(state -> 8)));
public static final DeferredBlock<com.craisinlord.antarchy.content.block.CamelliaBlock> CAMELLIA = BLOCKS.register("camellia",
@@ -1389,6 +1391,10 @@ public final class AntarchyFabricBlocks {
() -> new LargeNadirFernBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.LARGE_FERN).noCollission()));
public static final DeferredBlock<DirectionalThoraxisFlowerBlock> DUSKBELL = BLOCKS.register("duskbell",
() -> new DirectionalThoraxisFlowerBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.ALLIUM).lightLevel(state -> 4)));
public static final DeferredBlock<DirectionalThoraxisFlowerBlock> NADIR_ROOTS = BLOCKS.register("nadir_roots",
() -> new DirectionalThoraxisFlowerBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.CRIMSON_ROOTS)));
public static final DeferredBlock<DirectionalThoraxisFlowerBlock> VERDANT_ROOTS = BLOCKS.register("verdant_roots",
() -> new DirectionalThoraxisFlowerBlock(BlockBehaviour.Properties.ofFullCopy(Blocks.WARPED_ROOTS)));
public static final DeferredBlock<Block> DEAD_STAR_CORAL_BLOCK = BLOCKS.register("dead_star_coral_block",
() -> new Block(BlockBehaviour.Properties.ofFullCopy(Blocks.TUBE_CORAL_BLOCK)));
@@ -246,6 +246,7 @@ public final class AntarchyFabricItems {
public static final DeferredItem<net.minecraft.world.item.BlockItem> PINK_MILKWEED_ITEM = ITEMS.registerSimpleBlockItem(AntarchyFabricBlocks.PINK_MILKWEED);
public static final DeferredItem<net.minecraft.world.item.BlockItem> GLIMMERING_REED_ITEM = ITEMS.registerSimpleBlockItem(AntarchyFabricBlocks.GLIMMERING_REED);
public static final DeferredItem<net.minecraft.world.item.BlockItem> CAMELLIA_ITEM = ITEMS.registerSimpleBlockItem(AntarchyFabricBlocks.CAMELLIA);
@@ -710,6 +711,8 @@ public final class AntarchyFabricItems {
public static final DeferredItem<net.minecraft.world.item.BlockItem> NADIR_FERN_ITEM = ITEMS.registerSimpleBlockItem(AntarchyFabricBlocks.NADIR_FERN);
public static final DeferredItem<net.minecraft.world.item.BlockItem> LARGE_NADIR_FERN_ITEM = ITEMS.registerSimpleBlockItem(AntarchyFabricBlocks.LARGE_NADIR_FERN);
public static final DeferredItem<net.minecraft.world.item.BlockItem> DUSKBELL_ITEM = ITEMS.registerSimpleBlockItem(AntarchyFabricBlocks.DUSKBELL);
public static final DeferredItem<net.minecraft.world.item.BlockItem> NADIR_ROOTS_ITEM = ITEMS.registerSimpleBlockItem(AntarchyFabricBlocks.NADIR_ROOTS);
public static final DeferredItem<net.minecraft.world.item.BlockItem> VERDANT_ROOTS_ITEM = ITEMS.registerSimpleBlockItem(AntarchyFabricBlocks.VERDANT_ROOTS);
public static final DeferredItem<net.minecraft.world.item.BlockItem> DEAD_STAR_CORAL_BLOCK_ITEM = ITEMS.registerSimpleBlockItem(AntarchyFabricBlocks.DEAD_STAR_CORAL_BLOCK);
@@ -79,7 +79,6 @@ import com.craisinlord.antarchy.content.worldgen.thoraxis.ThoraxisFissureFeature
import com.craisinlord.antarchy.content.worldgen.thoraxis.ThoraxisBloodCrystalConfiguration;
import com.craisinlord.antarchy.content.worldgen.thoraxis.ThoraxisBloodCrystalFeature;
import com.craisinlord.antarchy.content.worldgen.thoraxis.ThoraxisAntiwaterPoolConfiguration;
import com.craisinlord.antarchy.content.worldgen.thoraxis.ThoraxisAntiwaterPoolFeature;
import com.craisinlord.antarchy.content.worldgen.thoraxis.ThoraxisRibColumnsConfiguration;
import com.craisinlord.antarchy.content.worldgen.thoraxis.ThoraxisRibColumnsFeature;
import com.craisinlord.antarchy.content.worldgen.thoraxis.ThoraxisSpikeConfiguration;
@@ -695,6 +694,8 @@ public final class AntarchyFabricMisc {
public static final DeferredHolder<Feature<?>, LumenLilyPadFeature> LUMEN_LILY_PADS = FEATURES.register("lumen_lily_pads",
() -> new LumenLilyPadFeature(NoneFeatureConfiguration.CODEC));
public static final DeferredHolder<Feature<?>, com.craisinlord.antarchy.content.worldgen.elythia.GlimmeringReedFeature> GLIMMERING_REEDS = FEATURES.register("glimmering_reeds",
() -> new com.craisinlord.antarchy.content.worldgen.elythia.GlimmeringReedFeature(NoneFeatureConfiguration.CODEC));
public static final DeferredHolder<Feature<?>, com.craisinlord.antarchy.content.worldgen.elythia.GiantLilyPadPatchFeature> GIANT_LILY_PAD_PATCH = FEATURES.register("giant_lily_pad_patch",
() -> new com.craisinlord.antarchy.content.worldgen.elythia.GiantLilyPadPatchFeature(NoneFeatureConfiguration.CODEC));
@@ -814,9 +815,6 @@ public final class AntarchyFabricMisc {
() -> new com.craisinlord.antarchy.content.worldgen.mushroom.GlowcapHugeMushroomWorldgenFeature(NoneFeatureConfiguration.CODEC));
public static final DeferredHolder<Feature<?>, ThoraxisAntiwaterPoolFeature> THORAXIS_ANTIWATER_POOL = FEATURES.register("thoraxis_antiwater_pool",
() -> new ThoraxisAntiwaterPoolFeature(ThoraxisAntiwaterPoolConfiguration.CODEC));
public static final DeferredHolder<Feature<?>, LucidAntiwaterPoolFeature> LUCID_ANTIWATER_POOL = FEATURES.register("lucid_antiwater_pool",
() -> new LucidAntiwaterPoolFeature(ThoraxisAntiwaterPoolConfiguration.CODEC));
@@ -188,6 +188,10 @@ public final class AntarchyFabricSounds {
public static final DeferredHolder<SoundEvent, SoundEvent> MUSIC_GAME_THORAXIS = registerSoundEvent("music.game.thoraxis");
public static final DeferredHolder<SoundEvent, SoundEvent> DIMENSIONAL_TEAR_OPEN = registerSoundEvent("dimensional_tear_open");
public static final DeferredHolder<SoundEvent, SoundEvent> DIMENSIONAL_TEAR_IDLE = registerSoundEvent("dimensional_tear_idle");
public static final DeferredHolder<SoundEvent, SoundEvent> DIMENSIONAL_TEAR_CREATURE_LEAVES = registerSoundEvent("dimensional_tear_creature_leaves");
public static final DeferredHolder<SoundEvent, SoundEvent> DIMENSIONAL_TEAR_CLOSE = registerSoundEvent("dimensional_tear_close");
public static final DeferredHolder<SoundEvent, SoundEvent> MUSIC_GAME_CAVARYN = registerSoundEvent("music.game.cavaryn");
@@ -21,6 +21,9 @@
],
"client": [
"com.craisinlord.antarchy.fabric.client.AntarchyFabricClient"
],
"modmenu": [
"com.craisinlord.antarchy.fabric.client.AntarchyModMenuIntegration"
]
},
"mixins": [
@@ -38,5 +41,9 @@
},
"breaks": {
"infinity": "<2.7.2"
},
"suggests": {
"modmenu": "*",
"cloth-config": "*"
}
}