From dbe32f3a8621193ef95ac2c73c4b5e5f2dca187a Mon Sep 17 00:00:00 2001 From: maxryan008 Date: Fri, 24 Apr 2026 09:50:02 +1000 Subject: [PATCH 1/9] feature: Sable compatability with Dynamic Dimensions. When Sable is installed the DynamicDimensionProperties.java can be used to define certain dimension specific properties for Sable's physics engine to use. --- .../api/DynamicDimensionProperties.java | 21 +++ .../api/DynamicDimensionRegistry.java | 68 ++++++++++ .../impl/DynamicDimensionRegistryImpl.java | 62 +++++++++ .../compat/DynamicDimensionPhysicsCompat.java | 18 +++ .../compat/SableDimensionPhysicsCompat.java | 122 ++++++++++++++++++ 5 files changed, 291 insertions(+) create mode 100644 common/src/main/java/dev/galacticraft/dynamicdimensions/api/DynamicDimensionProperties.java create mode 100644 common/src/main/java/dev/galacticraft/dynamicdimensions/impl/compat/DynamicDimensionPhysicsCompat.java create mode 100644 common/src/main/java/dev/galacticraft/dynamicdimensions/impl/compat/SableDimensionPhysicsCompat.java diff --git a/common/src/main/java/dev/galacticraft/dynamicdimensions/api/DynamicDimensionProperties.java b/common/src/main/java/dev/galacticraft/dynamicdimensions/api/DynamicDimensionProperties.java new file mode 100644 index 0000000..4f3d2c3 --- /dev/null +++ b/common/src/main/java/dev/galacticraft/dynamicdimensions/api/DynamicDimensionProperties.java @@ -0,0 +1,21 @@ +package dev.galacticraft.dynamicdimensions.api; + +import org.joml.Vector3f; + +/** + * Generic physics/environment properties for a dynamic dimension. + * + * DynamicDimensions does not decide what these values mean. + * Optional compat layers, such as Sable compat, may consume them. + */ +public abstract class DynamicDimensionProperties { + public abstract int priority(); + + public abstract Vector3f baseGravity(); + + public abstract double basePressure(); + + public abstract float universalDrag(); + + public abstract Vector3f magneticNorth(); +} \ No newline at end of file diff --git a/common/src/main/java/dev/galacticraft/dynamicdimensions/api/DynamicDimensionRegistry.java b/common/src/main/java/dev/galacticraft/dynamicdimensions/api/DynamicDimensionRegistry.java index b5ecfa4..ff4ecbe 100644 --- a/common/src/main/java/dev/galacticraft/dynamicdimensions/api/DynamicDimensionRegistry.java +++ b/common/src/main/java/dev/galacticraft/dynamicdimensions/api/DynamicDimensionRegistry.java @@ -122,6 +122,13 @@ default boolean canDeleteDimension(@NotNull ResourceLocation id) { */ @Nullable ServerLevel createDynamicDimension(@NotNull ResourceLocation id, @NotNull ChunkGenerator chunkGenerator, @NotNull DimensionType type); + /** + * Registers a new dimension and applies optional dynamic-dimension properties. + * + * @since 0.10.0 + */ + @Nullable ServerLevel createDynamicDimension(@NotNull ResourceLocation id, @NotNull ChunkGenerator chunkGenerator, @NotNull DimensionType type, @NotNull DynamicDimensionProperties properties); + /** * Registers a new dimension and updates all clients with the new dimension. * If world data already exists for this dimension it will be used, otherwise it will be created. @@ -137,6 +144,67 @@ default boolean canDeleteDimension(@NotNull ResourceLocation id) { */ @Nullable ServerLevel loadDynamicDimension(@NotNull ResourceLocation id, @NotNull ChunkGenerator chunkGenerator, @NotNull DimensionType type); + /** + * Loads a dynamic dimension and applies optional dynamic-dimension properties. + * + * @since 0.10.0 + */ + @Nullable ServerLevel loadDynamicDimension(@NotNull ResourceLocation id, @NotNull ChunkGenerator chunkGenerator, @NotNull DimensionType type, @NotNull DynamicDimensionProperties properties); + + /** + * Sets properties for a dynamic dimension. + * + *

If the dimension is already loaded, compatible backends such as Sable + * may apply these immediately.

+ * + * @since 0.10.0 + */ + void setDimensionProperties(@NotNull ResourceKey key, @NotNull DynamicDimensionProperties properties); + + /** + * Sets properties for a dynamic dimension. + * + * @since 0.10.0 + */ + default void setDimensionProperties(@NotNull ResourceLocation id, @NotNull DynamicDimensionProperties properties) { + this.setDimensionProperties(ResourceKey.create(Registries.DIMENSION, id), properties); + } + + /** + * Gets the currently stored properties for a dynamic dimension. + * + * @since 0.10.0 + */ + @Nullable DynamicDimensionProperties getDimensionProperties(@NotNull ResourceKey key); + + /** + * Gets the currently stored properties for a dynamic dimension. + * + * @since 0.10.0 + */ + default @Nullable DynamicDimensionProperties getDimensionProperties(@NotNull ResourceLocation id) { + return this.getDimensionProperties(ResourceKey.create(Registries.DIMENSION, id)); + } + + /** + * Clears stored properties for a dynamic dimension. + * + *

If the dimension has been applied to a compatible backend such as Sable, + * this should also remove those backend properties.

+ * + * @since 0.10.0 + */ + void clearDimensionProperties(@NotNull ResourceKey key); + + /** + * Clears stored properties for a dynamic dimension. + * + * @since 0.10.0 + */ + default void clearDimensionProperties(@NotNull ResourceLocation id) { + this.clearDimensionProperties(ResourceKey.create(Registries.DIMENSION, id)); + } + /** * Deletes a dynamic dimension from the server. * This may delete the dimension files permanently. diff --git a/common/src/main/java/dev/galacticraft/dynamicdimensions/impl/DynamicDimensionRegistryImpl.java b/common/src/main/java/dev/galacticraft/dynamicdimensions/impl/DynamicDimensionRegistryImpl.java index 0c22171..3b0ffdf 100644 --- a/common/src/main/java/dev/galacticraft/dynamicdimensions/impl/DynamicDimensionRegistryImpl.java +++ b/common/src/main/java/dev/galacticraft/dynamicdimensions/impl/DynamicDimensionRegistryImpl.java @@ -23,11 +23,13 @@ package dev.galacticraft.dynamicdimensions.impl; import com.google.common.collect.ImmutableList; +import dev.galacticraft.dynamicdimensions.api.DynamicDimensionProperties; import dev.galacticraft.dynamicdimensions.api.DynamicDimensionRegistry; import dev.galacticraft.dynamicdimensions.api.PlayerRemover; import dev.galacticraft.dynamicdimensions.api.event.DynamicDimensionLoadCallback; import dev.galacticraft.dynamicdimensions.impl.accessor.DynamicDimensionProvider; import dev.galacticraft.dynamicdimensions.impl.accessor.PrimaryLevelDataAccessor; +import dev.galacticraft.dynamicdimensions.impl.compat.DynamicDimensionPhysicsCompat; import dev.galacticraft.dynamicdimensions.impl.mixin.*; import dev.galacticraft.dynamicdimensions.impl.network.S2CPackets; import dev.galacticraft.dynamicdimensions.impl.registry.RegistryUtil; @@ -60,7 +62,9 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; public class DynamicDimensionRegistryImpl implements DynamicDimensionRegistry { @@ -69,6 +73,8 @@ public class DynamicDimensionRegistryImpl implements DynamicDimensionRegistry { private final Registry dimTypes; private final Registry stems; + private final Map, DynamicDimensionProperties> dimensionProperties = new HashMap<>(); + public DynamicDimensionRegistryImpl(MinecraftServer server) { this.server = server; this.dimTypes = server.registryAccess().registryOrThrow(Registries.DIMENSION_TYPE); @@ -92,11 +98,58 @@ public void loadDynamicDimensions() { return this.createDynamicLevel(id, generator, type, true); } + @Override + public @Nullable ServerLevel createDynamicDimension(@NotNull ResourceLocation id, @NotNull ChunkGenerator generator, @NotNull DimensionType type, @NotNull DynamicDimensionProperties properties) { + ResourceKey key = ResourceKey.create(Registries.DIMENSION, id); + this.setDimensionProperties(key, properties); + + ServerLevel level = this.createDynamicLevel(id, generator, type, true); + if (level == null) { + this.clearDimensionProperties(key); + } + + return level; + } + @Override public @Nullable ServerLevel loadDynamicDimension(@NotNull ResourceLocation id, @NotNull ChunkGenerator generator, @NotNull DimensionType type) { return this.createDynamicLevel(id, generator, type, false); } + @Override + public @Nullable ServerLevel loadDynamicDimension(@NotNull ResourceLocation id, @NotNull ChunkGenerator generator, @NotNull DimensionType type, @NotNull DynamicDimensionProperties properties) { + ResourceKey key = ResourceKey.create(Registries.DIMENSION, id); + this.setDimensionProperties(key, properties); + + ServerLevel level = this.createDynamicLevel(id, generator, type, false); + if (level == null) { + this.clearDimensionProperties(key); + } + + return level; + } + + @Override + public void setDimensionProperties(@NotNull ResourceKey key, @NotNull DynamicDimensionProperties properties) { + this.dimensionProperties.put(key, properties); + + if (this.server.getLevel(key) != null) { + DynamicDimensionPhysicsCompat.apply(key, properties); + } + } + + @Override + public @Nullable DynamicDimensionProperties getDimensionProperties(@NotNull ResourceKey key) { + return this.dimensionProperties.get(key); + } + + + @Override + public void clearDimensionProperties(@NotNull ResourceKey key) { + this.dimensionProperties.remove(key); + DynamicDimensionPhysicsCompat.remove(key); + } + @Override public boolean dynamicDimensionExists(@NotNull ResourceKey key) { return this.dynamicDimensions.contains(key) || ((DynamicDimensionProvider) this.server).dynamicdimensions$isIdPendingCreation(key); @@ -125,7 +178,9 @@ public boolean deleteDynamicDimension(@NotNull ResourceLocation id, @Nullable Pl ResourceKey key = ResourceKey.create(Registries.DIMENSION, id); if (!this.canDeleteDimension(key)) return false; + DynamicDimensionPhysicsCompat.remove(key); ((DynamicDimensionProvider) this.server).dynamicdimensions$removeLevel(key, remover, true); + this.dimensionProperties.remove(key); return true; } @@ -136,7 +191,9 @@ public boolean unloadDynamicDimension(@NotNull ResourceLocation id, @Nullable Pl ResourceKey key = ResourceKey.create(Registries.DIMENSION, id); if (!this.canDeleteDimension(key)) return false; + DynamicDimensionPhysicsCompat.remove(key); ((DynamicDimensionProvider) this.server).dynamicdimensions$removeLevel(key, remover, false); + return true; } @@ -202,6 +259,11 @@ public boolean unloadDynamicDimension(@NotNull ResourceLocation id, @Nullable Pl ((DynamicDimensionProvider) this.server).dynamicdimensions$registerLevel(level); + DynamicDimensionProperties properties = this.dimensionProperties.get(key); + if (properties != null) { + DynamicDimensionPhysicsCompat.apply(key, properties); + } + final var serializedType = ((CompoundTag) DimensionType.DIRECT_CODEC.encode(stem.type().value(), RegistryOps.create(NbtOps.INSTANCE, this.server.registryAccess()), new CompoundTag()).getOrThrow()); for (ServerPlayer player : this.server.getPlayerList().getPlayers()) { S2CPackets.sendCreateDimension(player, key.location(), serializedType); diff --git a/common/src/main/java/dev/galacticraft/dynamicdimensions/impl/compat/DynamicDimensionPhysicsCompat.java b/common/src/main/java/dev/galacticraft/dynamicdimensions/impl/compat/DynamicDimensionPhysicsCompat.java new file mode 100644 index 0000000..e382ed2 --- /dev/null +++ b/common/src/main/java/dev/galacticraft/dynamicdimensions/impl/compat/DynamicDimensionPhysicsCompat.java @@ -0,0 +1,18 @@ +package dev.galacticraft.dynamicdimensions.impl.compat; + +import dev.galacticraft.dynamicdimensions.api.DynamicDimensionProperties; +import net.minecraft.resources.ResourceKey; +import net.minecraft.world.level.Level; + +public final class DynamicDimensionPhysicsCompat { + private DynamicDimensionPhysicsCompat() { + } + + public static void apply(ResourceKey key, DynamicDimensionProperties properties) { + SableDimensionPhysicsCompat.apply(key, properties); + } + + public static void remove(ResourceKey key) { + SableDimensionPhysicsCompat.remove(key); + } +} \ No newline at end of file diff --git a/common/src/main/java/dev/galacticraft/dynamicdimensions/impl/compat/SableDimensionPhysicsCompat.java b/common/src/main/java/dev/galacticraft/dynamicdimensions/impl/compat/SableDimensionPhysicsCompat.java new file mode 100644 index 0000000..2b520f9 --- /dev/null +++ b/common/src/main/java/dev/galacticraft/dynamicdimensions/impl/compat/SableDimensionPhysicsCompat.java @@ -0,0 +1,122 @@ +package dev.galacticraft.dynamicdimensions.impl.compat; + +import dev.galacticraft.dynamicdimensions.api.DynamicDimensionProperties; +import dev.galacticraft.dynamicdimensions.impl.Constants; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.Level; +import org.joml.Vector3f; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.Map; +import java.util.Optional; + +final class SableDimensionPhysicsCompat { + private static final String DATA_CLASS = + "dev.ryanhcode.sable.physics.config.dimension_physics.DimensionPhysicsData"; + + private static final String PHYSICS_CLASS = + "dev.ryanhcode.sable.physics.config.dimension_physics.DimensionPhysics"; + + private static Boolean loaded; + + private SableDimensionPhysicsCompat() { + } + + private static boolean isLoaded() { + if (loaded != null) { + return loaded; + } + + try { + Class.forName(DATA_CLASS); + Class.forName(PHYSICS_CLASS); + loaded = true; + } catch (Throwable ignored) { + loaded = false; + } + + return loaded; + } + + static void apply(ResourceKey key, DynamicDimensionProperties properties) { + if (!isLoaded()) { + return; + } + + try { + Class dataClass = Class.forName(DATA_CLASS); + Class physicsClass = Class.forName(PHYSICS_CLASS); + + Field mapField = dataClass.getDeclaredField("DIMENSION_PHYSICS_DATA"); + mapField.setAccessible(true); + + @SuppressWarnings("unchecked") + Map, Object> map = + (Map, Object>) mapField.get(null); + + Constructor constructor = physicsClass.getConstructor( + ResourceLocation.class, + int.class, + Optional.class, + Optional.class, + Optional.class, + Optional.class, + Optional.class + ); + + Object physics = constructor.newInstance( + key.location(), + properties.priority(), + Optional.of(properties.universalDrag()), + Optional.of(copy(properties.baseGravity())), + Optional.of(properties.basePressure()), + Optional.empty(), + Optional.of(copy(properties.magneticNorth())) + ); + + Object existing = map.get(key); + if (existing == null || priorityOf(existing) <= properties.priority()) { + map.put(key, physics); + } + } catch (Throwable throwable) { + Constants.LOGGER.warn("Failed to apply Sable physics properties for dynamic dimension '{}'", key.location(), throwable); + } + } + + static void remove(ResourceKey key) { + if (!isLoaded()) { + return; + } + + try { + Class dataClass = Class.forName(DATA_CLASS); + + Field mapField = dataClass.getDeclaredField("DIMENSION_PHYSICS_DATA"); + mapField.setAccessible(true); + + @SuppressWarnings("unchecked") + Map, Object> map = + (Map, Object>) mapField.get(null); + + map.remove(key); + } catch (Throwable throwable) { + Constants.LOGGER.warn("Failed to remove Sable physics properties for dynamic dimension '{}'", key.location(), throwable); + } + } + + private static int priorityOf(Object physics) { + try { + Method method = physics.getClass().getMethod("priority"); + return (int) method.invoke(physics); + } catch (Throwable ignored) { + return Integer.MIN_VALUE; + } + } + + private static Vector3f copy(Vector3f vector) { + return new Vector3f(vector.x(), vector.y(), vector.z()); + } +} \ No newline at end of file From 52090c9ffcca5b67e7d49ecee3f66c207ab294a1 Mon Sep 17 00:00:00 2001 From: maxryan008 Date: Tue, 28 Apr 2026 11:27:12 +1000 Subject: [PATCH 2/9] Fixed all review issues and ran spotless apply --- common/build.gradle.kts | 9 ++ .../api/DynamicDimensionProperties.java | 22 ++++ .../compat/DynamicDimensionPhysicsCompat.java | 33 ++++- .../compat/SableDimensionPhysicsCompat.java | 118 ++++++++---------- .../platform/services/PlatformHelper.java | 2 + fabric/build.gradle.kts | 10 ++ .../fabric/platform/FabricPlatformHelper.java | 6 + gradle.properties | 5 +- neoforge/build.gradle.kts | 9 ++ .../forge/platform/ForgePlatformHelper.java | 6 + 10 files changed, 148 insertions(+), 72 deletions(-) diff --git a/common/build.gradle.kts b/common/build.gradle.kts index 4ecd318..540b758 100644 --- a/common/build.gradle.kts +++ b/common/build.gradle.kts @@ -2,6 +2,7 @@ val modId = project.property("mod.id").toString() val minecraft = project.property("minecraft.version").toString() val yarn = project.property("fabric.yarn.build").toString() val fabricLoader = project.property("fabric.loader.version").toString() +val sable = project.property("sable.version").toString() plugins { id("fabric-loom") @@ -28,4 +29,12 @@ dependencies { // loom expects some loader classes to exist, provides mixin and mixin-extras too modCompileOnly("net.fabricmc:fabric-loader:${fabricLoader}") + + compileOnlyApi("dev.ryanhcode.sable:sable-common-$minecraft:$sable") +} + +repositories { + maven("https://maven.ryanhcode.dev/releases") + maven("https://raw.githubusercontent.com/Fuzss/modresources/main/maven/") + maven("https://maven.blamejared.com") } diff --git a/common/src/main/java/dev/galacticraft/dynamicdimensions/api/DynamicDimensionProperties.java b/common/src/main/java/dev/galacticraft/dynamicdimensions/api/DynamicDimensionProperties.java index 4f3d2c3..ca9512c 100644 --- a/common/src/main/java/dev/galacticraft/dynamicdimensions/api/DynamicDimensionProperties.java +++ b/common/src/main/java/dev/galacticraft/dynamicdimensions/api/DynamicDimensionProperties.java @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2021-2025 Team Galacticraft + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package dev.galacticraft.dynamicdimensions.api; import org.joml.Vector3f; diff --git a/common/src/main/java/dev/galacticraft/dynamicdimensions/impl/compat/DynamicDimensionPhysicsCompat.java b/common/src/main/java/dev/galacticraft/dynamicdimensions/impl/compat/DynamicDimensionPhysicsCompat.java index e382ed2..58c376a 100644 --- a/common/src/main/java/dev/galacticraft/dynamicdimensions/impl/compat/DynamicDimensionPhysicsCompat.java +++ b/common/src/main/java/dev/galacticraft/dynamicdimensions/impl/compat/DynamicDimensionPhysicsCompat.java @@ -1,18 +1,47 @@ +/* + * Copyright (c) 2021-2025 Team Galacticraft + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package dev.galacticraft.dynamicdimensions.impl.compat; import dev.galacticraft.dynamicdimensions.api.DynamicDimensionProperties; +import dev.galacticraft.dynamicdimensions.impl.platform.Services; import net.minecraft.resources.ResourceKey; import net.minecraft.world.level.Level; +import static dev.galacticraft.dynamicdimensions.impl.compat.SableDimensionPhysicsCompat.SABLE_MOD_ID; + public final class DynamicDimensionPhysicsCompat { private DynamicDimensionPhysicsCompat() { } public static void apply(ResourceKey key, DynamicDimensionProperties properties) { - SableDimensionPhysicsCompat.apply(key, properties); + if (Services.PLATFORM.isModLoaded(SABLE_MOD_ID)) { + SableDimensionPhysicsCompat.apply(key, properties); + } } public static void remove(ResourceKey key) { - SableDimensionPhysicsCompat.remove(key); + if (Services.PLATFORM.isModLoaded(SABLE_MOD_ID)) { + SableDimensionPhysicsCompat.remove(key); + } } } \ No newline at end of file diff --git a/common/src/main/java/dev/galacticraft/dynamicdimensions/impl/compat/SableDimensionPhysicsCompat.java b/common/src/main/java/dev/galacticraft/dynamicdimensions/impl/compat/SableDimensionPhysicsCompat.java index 2b520f9..7b09253 100644 --- a/common/src/main/java/dev/galacticraft/dynamicdimensions/impl/compat/SableDimensionPhysicsCompat.java +++ b/common/src/main/java/dev/galacticraft/dynamicdimensions/impl/compat/SableDimensionPhysicsCompat.java @@ -1,73 +1,55 @@ +/* + * Copyright (c) 2021-2025 Team Galacticraft + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package dev.galacticraft.dynamicdimensions.impl.compat; import dev.galacticraft.dynamicdimensions.api.DynamicDimensionProperties; import dev.galacticraft.dynamicdimensions.impl.Constants; +import dev.galacticraft.dynamicdimensions.impl.platform.Services; +import dev.ryanhcode.sable.physics.config.dimension_physics.DimensionPhysics; +import dev.ryanhcode.sable.physics.config.dimension_physics.DimensionPhysicsData; import net.minecraft.resources.ResourceKey; -import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.Level; import org.joml.Vector3f; -import java.lang.reflect.Constructor; import java.lang.reflect.Field; -import java.lang.reflect.Method; import java.util.Map; import java.util.Optional; final class SableDimensionPhysicsCompat { - private static final String DATA_CLASS = - "dev.ryanhcode.sable.physics.config.dimension_physics.DimensionPhysicsData"; - - private static final String PHYSICS_CLASS = - "dev.ryanhcode.sable.physics.config.dimension_physics.DimensionPhysics"; - - private static Boolean loaded; + static final String SABLE_MOD_ID = "sable"; private SableDimensionPhysicsCompat() { } - private static boolean isLoaded() { - if (loaded != null) { - return loaded; - } - - try { - Class.forName(DATA_CLASS); - Class.forName(PHYSICS_CLASS); - loaded = true; - } catch (Throwable ignored) { - loaded = false; - } - - return loaded; - } - static void apply(ResourceKey key, DynamicDimensionProperties properties) { - if (!isLoaded()) { + if (!Services.PLATFORM.isModLoaded(SABLE_MOD_ID)) { return; } try { - Class dataClass = Class.forName(DATA_CLASS); - Class physicsClass = Class.forName(PHYSICS_CLASS); - - Field mapField = dataClass.getDeclaredField("DIMENSION_PHYSICS_DATA"); - mapField.setAccessible(true); - - @SuppressWarnings("unchecked") - Map, Object> map = - (Map, Object>) mapField.get(null); + Map, DimensionPhysics> map = physicsMap(); - Constructor constructor = physicsClass.getConstructor( - ResourceLocation.class, - int.class, - Optional.class, - Optional.class, - Optional.class, - Optional.class, - Optional.class - ); - - Object physics = constructor.newInstance( + DimensionPhysics physics = new DimensionPhysics( key.location(), properties.priority(), Optional.of(properties.universalDrag()), @@ -77,43 +59,41 @@ static void apply(ResourceKey key, DynamicDimensionProperties properties) Optional.of(copy(properties.magneticNorth())) ); - Object existing = map.get(key); - if (existing == null || priorityOf(existing) <= properties.priority()) { + DimensionPhysics existing = map.get(key); + + if (existing == null || existing.priority() <= properties.priority()) { map.put(key, physics); } } catch (Throwable throwable) { - Constants.LOGGER.warn("Failed to apply Sable physics properties for dynamic dimension '{}'", key.location(), throwable); + Constants.LOGGER.warn( + "Failed to apply Sable physics properties for dynamic dimension '{}'", + key.location(), + throwable + ); } } static void remove(ResourceKey key) { - if (!isLoaded()) { + if (!Services.PLATFORM.isModLoaded(SABLE_MOD_ID)) { return; } try { - Class dataClass = Class.forName(DATA_CLASS); - - Field mapField = dataClass.getDeclaredField("DIMENSION_PHYSICS_DATA"); - mapField.setAccessible(true); - - @SuppressWarnings("unchecked") - Map, Object> map = - (Map, Object>) mapField.get(null); - - map.remove(key); + physicsMap().remove(key); } catch (Throwable throwable) { - Constants.LOGGER.warn("Failed to remove Sable physics properties for dynamic dimension '{}'", key.location(), throwable); + Constants.LOGGER.warn( + "Failed to remove Sable physics properties for dynamic dimension '{}'", + key.location(), + throwable + ); } } - private static int priorityOf(Object physics) { - try { - Method method = physics.getClass().getMethod("priority"); - return (int) method.invoke(physics); - } catch (Throwable ignored) { - return Integer.MIN_VALUE; - } + @SuppressWarnings("unchecked") + private static Map, DimensionPhysics> physicsMap() throws ReflectiveOperationException { + Field field = DimensionPhysicsData.class.getDeclaredField("DIMENSION_PHYSICS_DATA"); + field.setAccessible(true); + return (Map, DimensionPhysics>) field.get(null); } private static Vector3f copy(Vector3f vector) { diff --git a/common/src/main/java/dev/galacticraft/dynamicdimensions/impl/platform/services/PlatformHelper.java b/common/src/main/java/dev/galacticraft/dynamicdimensions/impl/platform/services/PlatformHelper.java index 1b5d031..07f77bc 100644 --- a/common/src/main/java/dev/galacticraft/dynamicdimensions/impl/platform/services/PlatformHelper.java +++ b/common/src/main/java/dev/galacticraft/dynamicdimensions/impl/platform/services/PlatformHelper.java @@ -46,4 +46,6 @@ public interface PlatformHelper { void invokeAddedEvent(@NotNull ResourceKey key, @NotNull ServerLevel level); void invokeLoadEvent(MinecraftServer server, DynamicDimensionLoadCallback.DynamicDimensionLoader loader); + + boolean isModLoaded(String modId); } diff --git a/fabric/build.gradle.kts b/fabric/build.gradle.kts index fd9840e..fbb8028 100644 --- a/fabric/build.gradle.kts +++ b/fabric/build.gradle.kts @@ -5,6 +5,8 @@ val fabricLoader = project.property("fabric.loader.version").toString() val fabricAPI = project.property("fabric.api.version").toString() val fabricModules = project.property("fabric.api.modules").toString().split(',') val badpackets = project.property("badpackets.version").toString() +val sable = project.property("sable.version").toString() +val veil = project.property("veil.version").toString() plugins { id("fabric-loom") @@ -60,6 +62,8 @@ dependencies { } modRuntimeOnly("net.fabricmc.fabric-api:fabric-api:$fabricAPI") modRuntimeOnly("lol.bai:badpackets:fabric-$badpackets") + compileOnlyApi("dev.ryanhcode.sable:sable-fabric-$minecraft:$sable") + compileOnlyApi("foundry.veil:veil-fabric-$veil") } tasks.compileJava { @@ -77,3 +81,9 @@ tasks.javadoc { tasks.validateAccessWidener { enabled = false // access widener validated by :common } + +repositories { + maven("https://maven.ryanhcode.dev/releases") + maven("https://raw.githubusercontent.com/Fuzss/modresources/main/maven/") + maven("https://maven.blamejared.com") +} diff --git a/fabric/src/main/java/dev/galacticraft/dynamicdimensions/impl/fabric/platform/FabricPlatformHelper.java b/fabric/src/main/java/dev/galacticraft/dynamicdimensions/impl/fabric/platform/FabricPlatformHelper.java index ca3d689..91227c3 100644 --- a/fabric/src/main/java/dev/galacticraft/dynamicdimensions/impl/fabric/platform/FabricPlatformHelper.java +++ b/fabric/src/main/java/dev/galacticraft/dynamicdimensions/impl/fabric/platform/FabricPlatformHelper.java @@ -29,6 +29,7 @@ import dev.galacticraft.dynamicdimensions.impl.fabric.DynamicDimensionsFabric; import dev.galacticraft.dynamicdimensions.impl.fabric.config.DynamicDimensionsConfigImpl; import dev.galacticraft.dynamicdimensions.impl.platform.services.PlatformHelper; +import net.fabricmc.loader.api.FabricLoader; import net.minecraft.resources.ResourceKey; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; @@ -72,4 +73,9 @@ public void invokeAddedEvent(@NotNull ResourceKey key, @NotNull ServerLev public void invokeLoadEvent(MinecraftServer server, DynamicDimensionLoadCallback.DynamicDimensionLoader loader) { DynamicDimensionsFabric.DIMENSION_LOAD_EVENT.invoker().loadDimensions(server, loader); } + + @Override + public boolean isModLoaded(String modId) { + return FabricLoader.getInstance().isModLoaded(modId); + } } diff --git a/gradle.properties b/gradle.properties index b973903..1bd9f73 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,7 +5,7 @@ mod.id=dynamicdimensions mod.name=Dynamic Dimensions mod.description=Library to facilitate the runtime addition and removal of Minecraft dimensions. mod.license=MIT -mod.version=0.9.1 +mod.version=0.10.0 # Minecraft setup minecraft.version=1.21.1 @@ -34,3 +34,6 @@ fabric.api.modules=\ fabric-command-api-v2,\ fabric-lifecycle-events-v1,\ fabric-resource-loader-v0 + +sable.version=1.1.3 +veil.version=1.21.1:3.6.2 \ No newline at end of file diff --git a/neoforge/build.gradle.kts b/neoforge/build.gradle.kts index ea932ac..789ebc8 100644 --- a/neoforge/build.gradle.kts +++ b/neoforge/build.gradle.kts @@ -11,6 +11,8 @@ val parchmentVersion = project.property("parchment.version").toString() val badpackets = project.property("badpackets.version").toString() +val sable = project.property("sable.version").toString() + plugins { `java-library` `maven-publish` @@ -61,6 +63,7 @@ neoForge { dependencies { compileOnly(project(":common", "namedElements")) runtimeOnly("lol.bai:badpackets:neo-$badpackets") + compileOnlyApi("dev.ryanhcode.sable:sable-neoforge-$minecraft:$sable") } tasks.compileJava { @@ -83,3 +86,9 @@ tasks.processResources { tasks.javadoc { source(project(":common").sourceSets.main.get().allJava) } + +repositories { + maven("https://maven.ryanhcode.dev/releases") + maven("https://raw.githubusercontent.com/Fuzss/modresources/main/maven/") + maven("https://maven.blamejared.com") +} \ No newline at end of file diff --git a/neoforge/src/main/java/dev/galacticraft/dynamicdimensions/impl/forge/platform/ForgePlatformHelper.java b/neoforge/src/main/java/dev/galacticraft/dynamicdimensions/impl/forge/platform/ForgePlatformHelper.java index c293e64..334b0fd 100644 --- a/neoforge/src/main/java/dev/galacticraft/dynamicdimensions/impl/forge/platform/ForgePlatformHelper.java +++ b/neoforge/src/main/java/dev/galacticraft/dynamicdimensions/impl/forge/platform/ForgePlatformHelper.java @@ -32,6 +32,7 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.Level; +import net.neoforged.fml.ModList; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; @@ -84,4 +85,9 @@ public void invokeLoadEvent(MinecraftServer server, DynamicDimensionLoadCallback loadCallback.loadDimensions(server, loader); } } + + @Override + public boolean isModLoaded(String modId) { + return ModList.get().isLoaded(modId); + } } From 107884e36d1285181af81470cf01f41ed60acab7 Mon Sep 17 00:00:00 2001 From: maxryan008 Date: Tue, 28 Apr 2026 13:06:30 +1000 Subject: [PATCH 3/9] Small fixes --- common/build.gradle.kts | 2 +- fabric/build.gradle.kts | 2 -- neoforge/build.gradle.kts | 1 - 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/common/build.gradle.kts b/common/build.gradle.kts index 540b758..26039c7 100644 --- a/common/build.gradle.kts +++ b/common/build.gradle.kts @@ -30,7 +30,7 @@ dependencies { // loom expects some loader classes to exist, provides mixin and mixin-extras too modCompileOnly("net.fabricmc:fabric-loader:${fabricLoader}") - compileOnlyApi("dev.ryanhcode.sable:sable-common-$minecraft:$sable") + modCompileOnly("dev.ryanhcode.sable:sable-common-$minecraft:$sable") } repositories { diff --git a/fabric/build.gradle.kts b/fabric/build.gradle.kts index fbb8028..5d1b40f 100644 --- a/fabric/build.gradle.kts +++ b/fabric/build.gradle.kts @@ -62,8 +62,6 @@ dependencies { } modRuntimeOnly("net.fabricmc.fabric-api:fabric-api:$fabricAPI") modRuntimeOnly("lol.bai:badpackets:fabric-$badpackets") - compileOnlyApi("dev.ryanhcode.sable:sable-fabric-$minecraft:$sable") - compileOnlyApi("foundry.veil:veil-fabric-$veil") } tasks.compileJava { diff --git a/neoforge/build.gradle.kts b/neoforge/build.gradle.kts index 789ebc8..5e37db9 100644 --- a/neoforge/build.gradle.kts +++ b/neoforge/build.gradle.kts @@ -63,7 +63,6 @@ neoForge { dependencies { compileOnly(project(":common", "namedElements")) runtimeOnly("lol.bai:badpackets:neo-$badpackets") - compileOnlyApi("dev.ryanhcode.sable:sable-neoforge-$minecraft:$sable") } tasks.compileJava { From 543e7ae47e8897d5dfe364de6e735609a10b7b7d Mon Sep 17 00:00:00 2001 From: maxryan008 Date: Tue, 28 Apr 2026 13:09:54 +1000 Subject: [PATCH 4/9] Add back dependencies for common --- fabric/build.gradle.kts | 1 + neoforge/build.gradle.kts | 1 + 2 files changed, 2 insertions(+) diff --git a/fabric/build.gradle.kts b/fabric/build.gradle.kts index 5d1b40f..8a29126 100644 --- a/fabric/build.gradle.kts +++ b/fabric/build.gradle.kts @@ -62,6 +62,7 @@ dependencies { } modRuntimeOnly("net.fabricmc.fabric-api:fabric-api:$fabricAPI") modRuntimeOnly("lol.bai:badpackets:fabric-$badpackets") + compileOnlyApi("dev.ryanhcode.sable:sable-common-$minecraft:$sable") } tasks.compileJava { diff --git a/neoforge/build.gradle.kts b/neoforge/build.gradle.kts index 5e37db9..789ebc8 100644 --- a/neoforge/build.gradle.kts +++ b/neoforge/build.gradle.kts @@ -63,6 +63,7 @@ neoForge { dependencies { compileOnly(project(":common", "namedElements")) runtimeOnly("lol.bai:badpackets:neo-$badpackets") + compileOnlyApi("dev.ryanhcode.sable:sable-neoforge-$minecraft:$sable") } tasks.compileJava { From 233dc00ee509842ff354f32f39a20bbd44a1c6d9 Mon Sep 17 00:00:00 2001 From: maxryan008 Date: Tue, 28 Apr 2026 13:39:15 +1000 Subject: [PATCH 5/9] Removed api dependency into normal compile only --- common/build.gradle.kts | 2 +- fabric/build.gradle.kts | 2 +- neoforge/build.gradle.kts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/common/build.gradle.kts b/common/build.gradle.kts index 26039c7..75a37fd 100644 --- a/common/build.gradle.kts +++ b/common/build.gradle.kts @@ -30,7 +30,7 @@ dependencies { // loom expects some loader classes to exist, provides mixin and mixin-extras too modCompileOnly("net.fabricmc:fabric-loader:${fabricLoader}") - modCompileOnly("dev.ryanhcode.sable:sable-common-$minecraft:$sable") + compileOnly("dev.ryanhcode.sable:sable-common-$minecraft:$sable") } repositories { diff --git a/fabric/build.gradle.kts b/fabric/build.gradle.kts index 8a29126..5c0b933 100644 --- a/fabric/build.gradle.kts +++ b/fabric/build.gradle.kts @@ -62,7 +62,7 @@ dependencies { } modRuntimeOnly("net.fabricmc.fabric-api:fabric-api:$fabricAPI") modRuntimeOnly("lol.bai:badpackets:fabric-$badpackets") - compileOnlyApi("dev.ryanhcode.sable:sable-common-$minecraft:$sable") + compileOnly("dev.ryanhcode.sable:sable-common-$minecraft:$sable") } tasks.compileJava { diff --git a/neoforge/build.gradle.kts b/neoforge/build.gradle.kts index 789ebc8..adc70b3 100644 --- a/neoforge/build.gradle.kts +++ b/neoforge/build.gradle.kts @@ -63,7 +63,7 @@ neoForge { dependencies { compileOnly(project(":common", "namedElements")) runtimeOnly("lol.bai:badpackets:neo-$badpackets") - compileOnlyApi("dev.ryanhcode.sable:sable-neoforge-$minecraft:$sable") + compileOnly("dev.ryanhcode.sable:sable-neoforge-$minecraft:$sable") } tasks.compileJava { From abbfc6c0fa3f77672d88577383bbca8951e81c55 Mon Sep 17 00:00:00 2001 From: maxryan008 Date: Fri, 1 May 2026 22:34:58 +1000 Subject: [PATCH 6/9] Fixed issues with compatability. --- .../event/DynamicDimensionLoadCallback.java | 16 +++ .../impl/DynamicDimensionRegistryImpl.java | 28 +++-- .../compat/DynamicDimensionPhysicsCompat.java | 6 ++ .../compat/SableDimensionPhysicsCompat.java | 100 +++++++++++++++--- .../mixin/compat/sable/SableMixinPlugin.java | 45 ++++++++ .../sable/SubLevelPhysicsSystemMixin.java | 21 ++++ .../dynamicdimensions.sable.mixins.json | 12 +++ fabric/src/main/resources/fabric.mod.json | 3 +- neoforge/build.gradle.kts | 13 ++- .../resources/META-INF/neoforge.mods.toml | 2 + 10 files changed, 214 insertions(+), 32 deletions(-) create mode 100644 common/src/main/java/dev/galacticraft/dynamicdimensions/impl/mixin/compat/sable/SableMixinPlugin.java create mode 100644 common/src/main/java/dev/galacticraft/dynamicdimensions/impl/mixin/compat/sable/SubLevelPhysicsSystemMixin.java create mode 100644 common/src/main/resources/dynamicdimensions.sable.mixins.json diff --git a/common/src/main/java/dev/galacticraft/dynamicdimensions/api/event/DynamicDimensionLoadCallback.java b/common/src/main/java/dev/galacticraft/dynamicdimensions/api/event/DynamicDimensionLoadCallback.java index 4e9b807..4a7567d 100644 --- a/common/src/main/java/dev/galacticraft/dynamicdimensions/api/event/DynamicDimensionLoadCallback.java +++ b/common/src/main/java/dev/galacticraft/dynamicdimensions/api/event/DynamicDimensionLoadCallback.java @@ -22,6 +22,7 @@ package dev.galacticraft.dynamicdimensions.api.event; +import dev.galacticraft.dynamicdimensions.api.DynamicDimensionRegistry; import dev.galacticraft.dynamicdimensions.impl.platform.Services; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; @@ -58,5 +59,20 @@ interface DynamicDimensionLoader { * @return the newly loaded level */ @NotNull ServerLevel loadDynamicDimension(@NotNull ResourceLocation id, @NotNull ChunkGenerator chunkGenerator, @NotNull DimensionType type); + + /** + * Creates/loads a new dynamic dimension and applies the given properties before level construction, + * so that compatible backends (e.g. Sable) receive the correct physics data from the start. + * @param id the id of the dimension. Must be free in the level stem, dimension type, and level registries. + * @param chunkGenerator the chunk generator to generate the dimension with + * @param type the dimension type + * @param properties the dimension properties to apply + * @param server the current minecraft server + * @return the newly loaded level + */ + default @NotNull ServerLevel loadDynamicDimension(@NotNull ResourceLocation id, @NotNull ChunkGenerator chunkGenerator, @NotNull DimensionType type, @NotNull dev.galacticraft.dynamicdimensions.api.DynamicDimensionProperties properties, @NotNull MinecraftServer server) { + DynamicDimensionRegistry.from(server).setDimensionProperties(net.minecraft.resources.ResourceKey.create(net.minecraft.core.registries.Registries.DIMENSION, id), properties); + return this.loadDynamicDimension(id, chunkGenerator, type); + } } } diff --git a/common/src/main/java/dev/galacticraft/dynamicdimensions/impl/DynamicDimensionRegistryImpl.java b/common/src/main/java/dev/galacticraft/dynamicdimensions/impl/DynamicDimensionRegistryImpl.java index 3b0ffdf..967bce5 100644 --- a/common/src/main/java/dev/galacticraft/dynamicdimensions/impl/DynamicDimensionRegistryImpl.java +++ b/common/src/main/java/dev/galacticraft/dynamicdimensions/impl/DynamicDimensionRegistryImpl.java @@ -87,6 +87,13 @@ public void loadDynamicDimensions() { Constants.LOGGER.debug("Loading dynamic dimension '{}'", id); ResourceKey key = ResourceKey.create(Registries.DIMENSION, id); + // If properties were already registered before this callback fires + // (e.g. by the caller calling setDimensionProperties first), stage them now. + DynamicDimensionProperties properties = this.dimensionProperties.get(key); + if (properties != null) { + DynamicDimensionPhysicsCompat.stage(key, properties); + } + return this.createDynamicLevel(id, chunkGenerator, type, key); }); @@ -219,8 +226,14 @@ public boolean unloadDynamicDimension(@NotNull ResourceLocation id, @Nullable Pl } private @NotNull ServerLevel createDynamicLevel(ResourceKey key, WorldData worldData, LevelStem stem, ServerLevel overworld) { - // -- start createLevels -- - final DerivedLevelData data = new DerivedLevelData(worldData, worldData.overworldData()); //todo: do we want separate data? + // Stage physics properties before ServerLevel construction so Sable's + // SubLevelPhysicsSystem.initialize() mixin can flush them before reading gravity. + DynamicDimensionProperties pendingProperties = this.dimensionProperties.get(key); + if (pendingProperties != null) { + DynamicDimensionPhysicsCompat.stage(key, pendingProperties); + } + + final DerivedLevelData data = new DerivedLevelData(worldData, worldData.overworldData()); final ServerLevel level = new ServerLevel( this.server, ((MinecraftServerAccessor) this.server).getExecutor(), @@ -236,17 +249,13 @@ public boolean unloadDynamicDimension(@NotNull ResourceLocation id, @Nullable Pl null ); overworld.getWorldBorder().addListener(new BorderChangeListener.DelegateBorderChangeListener(level.getWorldBorder())); - // -- end createLevels -- - // see PlayerList level.getChunkSource().setSimulationDistance(((DistanceManagerAccessor) ((ServerChunkCacheAccessor) overworld.getChunkSource()).getDistanceManager()).getSimulationDistance()); level.getChunkSource().setViewDistance(((ChunkMapAccessor) overworld.getChunkSource().chunkMap).getViewDistance()); - // -- start prepareLevels -- ForcedChunksSavedData forcedChunksSavedData = level.getDataStorage().get(ForcedChunksSavedData.factory(), "chunks"); if (forcedChunksSavedData != null) { LongIterator longIterator = forcedChunksSavedData.getChunks().iterator(); - while (longIterator.hasNext()) { long l = longIterator.nextLong(); ChunkPos chunkPos = new ChunkPos(l); @@ -255,13 +264,12 @@ public boolean unloadDynamicDimension(@NotNull ResourceLocation id, @Nullable Pl } level.setSpawnSettings(this.server.isSpawningMonsters(), this.server.isSpawningAnimals()); - // -- end prepareLevels -- ((DynamicDimensionProvider) this.server).dynamicdimensions$registerLevel(level); - DynamicDimensionProperties properties = this.dimensionProperties.get(key); - if (properties != null) { - DynamicDimensionPhysicsCompat.apply(key, properties); + // Belt-and-suspenders apply after level exists, covers setDimensionProperties called post-creation. + if (pendingProperties != null) { + DynamicDimensionPhysicsCompat.apply(key, pendingProperties); } final var serializedType = ((CompoundTag) DimensionType.DIRECT_CODEC.encode(stem.type().value(), RegistryOps.create(NbtOps.INSTANCE, this.server.registryAccess()), new CompoundTag()).getOrThrow()); diff --git a/common/src/main/java/dev/galacticraft/dynamicdimensions/impl/compat/DynamicDimensionPhysicsCompat.java b/common/src/main/java/dev/galacticraft/dynamicdimensions/impl/compat/DynamicDimensionPhysicsCompat.java index 58c376a..9bd1977 100644 --- a/common/src/main/java/dev/galacticraft/dynamicdimensions/impl/compat/DynamicDimensionPhysicsCompat.java +++ b/common/src/main/java/dev/galacticraft/dynamicdimensions/impl/compat/DynamicDimensionPhysicsCompat.java @@ -44,4 +44,10 @@ public static void remove(ResourceKey key) { SableDimensionPhysicsCompat.remove(key); } } + + public static void stage(final ResourceKey key, final DynamicDimensionProperties properties) { + if (Services.PLATFORM.isModLoaded(SABLE_MOD_ID)) { + SableDimensionPhysicsCompat.stage(key, properties); + } + } } \ No newline at end of file diff --git a/common/src/main/java/dev/galacticraft/dynamicdimensions/impl/compat/SableDimensionPhysicsCompat.java b/common/src/main/java/dev/galacticraft/dynamicdimensions/impl/compat/SableDimensionPhysicsCompat.java index 7b09253..7387062 100644 --- a/common/src/main/java/dev/galacticraft/dynamicdimensions/impl/compat/SableDimensionPhysicsCompat.java +++ b/common/src/main/java/dev/galacticraft/dynamicdimensions/impl/compat/SableDimensionPhysicsCompat.java @@ -32,39 +32,81 @@ import org.joml.Vector3f; import java.lang.reflect.Field; +import java.util.HashMap; import java.util.Map; import java.util.Optional; -final class SableDimensionPhysicsCompat { +public final class SableDimensionPhysicsCompat { static final String SABLE_MOD_ID = "sable"; + /** + * Properties staged before SubLevelPhysicsSystem.initialize() runs for a newly created dynamic dimension. + * Flushed into DIMENSION_PHYSICS_DATA by the mixin at the HEAD of initialize(), before gravity is ever read. + */ + private static final Map, DynamicDimensionProperties> PENDING_PROPERTIES = new HashMap<>(); + private SableDimensionPhysicsCompat() { } - static void apply(ResourceKey key, DynamicDimensionProperties properties) { + /** + * Call this synchronously at the very start of createDynamicDimension, before any deferred work is queued. + * Ensures properties are present in PENDING_PROPERTIES before SubLevelPhysicsSystem.initialize() fires. + */ + static void stage(final ResourceKey key, final DynamicDimensionProperties properties) { if (!Services.PLATFORM.isModLoaded(SABLE_MOD_ID)) { return; } + PENDING_PROPERTIES.put(key, properties); + } + + /** + * Called from the mixin on SubLevelPhysicsSystem.initialize() at HEAD. + * Drains the pending entry for this dimension into DIMENSION_PHYSICS_DATA before gravity is read. + */ + public static void flushForLevel(final ResourceKey key) { + final DynamicDimensionProperties pending = PENDING_PROPERTIES.remove(key); + if (pending == null || !Services.PLATFORM.isModLoaded(SABLE_MOD_ID)) { + return; + } try { - Map, DimensionPhysics> map = physicsMap(); + final Map, DimensionPhysics> map = physicsMap(); + final DimensionPhysics physics = buildPhysics(key, pending); + final DimensionPhysics existing = map.get(key); - DimensionPhysics physics = new DimensionPhysics( + if (existing == null || existing.priority() <= pending.priority()) { + map.put(key, physics); + clearDefault(key); + } + } catch (final Throwable throwable) { + Constants.LOGGER.warn( + "Failed to flush staged Sable physics for dynamic dimension '{}'", key.location(), - properties.priority(), - Optional.of(properties.universalDrag()), - Optional.of(copy(properties.baseGravity())), - Optional.of(properties.basePressure()), - Optional.empty(), - Optional.of(copy(properties.magneticNorth())) + throwable ); + } + } + + /** + * Directly writes properties into DIMENSION_PHYSICS_DATA. + * Safe to call after the level exists, but on its own is insufficient — Rapier reads gravity only once + * at initialize() time. Use stage() + the mixin flush to cover that window instead. + */ + static void apply(final ResourceKey key, final DynamicDimensionProperties properties) { + if (!Services.PLATFORM.isModLoaded(SABLE_MOD_ID)) { + return; + } - DimensionPhysics existing = map.get(key); + try { + final Map, DimensionPhysics> map = physicsMap(); + final DimensionPhysics physics = buildPhysics(key, properties); + final DimensionPhysics existing = map.get(key); if (existing == null || existing.priority() <= properties.priority()) { map.put(key, physics); + clearDefault(key); } - } catch (Throwable throwable) { + } catch (final Throwable throwable) { Constants.LOGGER.warn( "Failed to apply Sable physics properties for dynamic dimension '{}'", key.location(), @@ -73,14 +115,17 @@ static void apply(ResourceKey key, DynamicDimensionProperties properties) } } - static void remove(ResourceKey key) { + static void remove(final ResourceKey key) { if (!Services.PLATFORM.isModLoaded(SABLE_MOD_ID)) { return; } + // Clear any staged-but-not-yet-flushed entry so it doesn't leak into a future dimension with the same key. + PENDING_PROPERTIES.remove(key); + try { physicsMap().remove(key); - } catch (Throwable throwable) { + } catch (final Throwable throwable) { Constants.LOGGER.warn( "Failed to remove Sable physics properties for dynamic dimension '{}'", key.location(), @@ -89,14 +134,37 @@ static void remove(ResourceKey key) { } } + private static DimensionPhysics buildPhysics(final ResourceKey key, final DynamicDimensionProperties properties) { + return new DimensionPhysics( + key.location(), + properties.priority(), + Optional.of(properties.universalDrag()), + Optional.of(copy(properties.baseGravity())), + Optional.of(properties.basePressure()), + Optional.empty(), + Optional.of(copy(properties.magneticNorth())) + ); + } + + private static void clearDefault(final ResourceKey key) throws ReflectiveOperationException { + final Field field = DimensionPhysicsData.class.getDeclaredField("DEFAULT_DIMENSION_PHYSICS_DATA"); + field.setAccessible(true); + + @SuppressWarnings("unchecked") + final Map, DimensionPhysics> defaults = + (Map, DimensionPhysics>) field.get(null); + + defaults.remove(key); + } + @SuppressWarnings("unchecked") private static Map, DimensionPhysics> physicsMap() throws ReflectiveOperationException { - Field field = DimensionPhysicsData.class.getDeclaredField("DIMENSION_PHYSICS_DATA"); + final Field field = DimensionPhysicsData.class.getDeclaredField("DIMENSION_PHYSICS_DATA"); field.setAccessible(true); return (Map, DimensionPhysics>) field.get(null); } - private static Vector3f copy(Vector3f vector) { + private static Vector3f copy(final Vector3f vector) { return new Vector3f(vector.x(), vector.y(), vector.z()); } } \ No newline at end of file diff --git a/common/src/main/java/dev/galacticraft/dynamicdimensions/impl/mixin/compat/sable/SableMixinPlugin.java b/common/src/main/java/dev/galacticraft/dynamicdimensions/impl/mixin/compat/sable/SableMixinPlugin.java new file mode 100644 index 0000000..f8b2e54 --- /dev/null +++ b/common/src/main/java/dev/galacticraft/dynamicdimensions/impl/mixin/compat/sable/SableMixinPlugin.java @@ -0,0 +1,45 @@ +package dev.galacticraft.dynamicdimensions.impl.mixin.compat.sable; + +import org.objectweb.asm.tree.ClassNode; +import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; +import org.spongepowered.asm.mixin.extensibility.IMixinInfo; + +import java.util.List; +import java.util.Set; + +public class SableMixinPlugin implements IMixinConfigPlugin { + + private boolean sableLoaded; + + @Override + public void onLoad(final String mixinPackage) { + try { + Class loaderClass = Class.forName("net.fabricmc.loader.api.FabricLoader"); + Object instance = loaderClass.getMethod("getInstance").invoke(null); + this.sableLoaded = (boolean) loaderClass.getMethod("isModLoaded", String.class).invoke(instance, "sable"); + System.out.println("[DynDims/SableMixin] Sable detected via FabricLoader: " + this.sableLoaded); + } catch (final Exception e) { + // Not on Fabric, fall back to checking for NeoForge mod list + try { + Class modListClass = Class.forName("net.neoforged.fml.ModList"); + Object modList = modListClass.getMethod("get").invoke(null); + this.sableLoaded = (boolean) modListClass.getMethod("isLoaded", String.class).invoke(modList, "sable"); + System.out.println("[DynDims/SableMixin] Sable detected via ModList: " + this.sableLoaded); + } catch (final Exception ex) { + this.sableLoaded = false; + System.out.println("[DynDims/SableMixin] Could not determine if Sable is loaded: " + ex.getMessage()); + } + } + } + + @Override + public boolean shouldApplyMixin(final String targetClassName, final String mixinClassName) { + return this.sableLoaded; + } + + @Override public String getRefMapperConfig() { return null; } + @Override public void acceptTargets(Set myTargets, Set otherTargets) {} + @Override public List getMixins() { return null; } + @Override public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {} + @Override public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {} +} \ No newline at end of file diff --git a/common/src/main/java/dev/galacticraft/dynamicdimensions/impl/mixin/compat/sable/SubLevelPhysicsSystemMixin.java b/common/src/main/java/dev/galacticraft/dynamicdimensions/impl/mixin/compat/sable/SubLevelPhysicsSystemMixin.java new file mode 100644 index 0000000..339dca2 --- /dev/null +++ b/common/src/main/java/dev/galacticraft/dynamicdimensions/impl/mixin/compat/sable/SubLevelPhysicsSystemMixin.java @@ -0,0 +1,21 @@ +package dev.galacticraft.dynamicdimensions.impl.mixin.compat.sable; + +import dev.galacticraft.dynamicdimensions.impl.compat.SableDimensionPhysicsCompat; +import net.minecraft.server.level.ServerLevel; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(targets = "dev.ryanhcode.sable.sublevel.system.SubLevelPhysicsSystem", remap = false) +public class SubLevelPhysicsSystemMixin { + + @Shadow + private ServerLevel level; + + @Inject(method = "initialize", at = @At("HEAD")) + private void dynamicdimensions$flushPendingPhysics(final CallbackInfo ci) { + SableDimensionPhysicsCompat.flushForLevel(this.level.dimension()); + } +} \ No newline at end of file diff --git a/common/src/main/resources/dynamicdimensions.sable.mixins.json b/common/src/main/resources/dynamicdimensions.sable.mixins.json new file mode 100644 index 0000000..1a1600e --- /dev/null +++ b/common/src/main/resources/dynamicdimensions.sable.mixins.json @@ -0,0 +1,12 @@ +{ + "required": false, + "package": "dev.galacticraft.dynamicdimensions.impl.mixin.compat.sable", + "compatibilityLevel": "JAVA_21", + "plugin": "dev.galacticraft.dynamicdimensions.impl.mixin.compat.sable.SableMixinPlugin", + "mixins": [ + "SubLevelPhysicsSystemMixin" + ], + "injectors": { + "defaultRequire": 0 + } +} \ No newline at end of file diff --git a/fabric/src/main/resources/fabric.mod.json b/fabric/src/main/resources/fabric.mod.json index b2b6860..0e4986c 100644 --- a/fabric/src/main/resources/fabric.mod.json +++ b/fabric/src/main/resources/fabric.mod.json @@ -41,7 +41,8 @@ ] }, "mixins": [ - "${mod_id}.mixins.json" + "${mod_id}.mixins.json", + "${mod_id}.sable.mixins.json" ], "accessWidener": "${mod_id}.accesswidener", "depends": { diff --git a/neoforge/build.gradle.kts b/neoforge/build.gradle.kts index adc70b3..a481ca7 100644 --- a/neoforge/build.gradle.kts +++ b/neoforge/build.gradle.kts @@ -75,11 +75,14 @@ tasks.processResources { // remove refmap on neoforge doLast { - file(outputs.files.asFileTree.first { it.name.equals("dynamicdimensions.mixins.json") }.apply { - val parse = groovy.json.JsonSlurper().parse(this)!! as MutableMap<*, *> - parse.remove("refmap") - writeText(groovy.json.JsonOutput.toJson(parse)) - }) + listOf("dynamicdimensions.mixins.json", "dynamicdimensions.sable.mixins.json").forEach { configName -> + val configFile = outputs.files.asFileTree.find { it.name == configName } + if (configFile != null) { + val parse = groovy.json.JsonSlurper().parse(configFile)!! as MutableMap<*, *> + parse.remove("refmap") + configFile.writeText(groovy.json.JsonOutput.toJson(parse)) + } + } } } diff --git a/neoforge/src/main/resources/META-INF/neoforge.mods.toml b/neoforge/src/main/resources/META-INF/neoforge.mods.toml index a2fa5ed..0863bd4 100644 --- a/neoforge/src/main/resources/META-INF/neoforge.mods.toml +++ b/neoforge/src/main/resources/META-INF/neoforge.mods.toml @@ -16,6 +16,8 @@ ${mod_description} [[mixins]] config="${mod_id}.mixins.json" +[[mixins]] +config = "${mod_id}.sable.mixins.json" [[dependencies.${mod_id}]] modId = "badpackets" From f6f15d9f4465f7c5d184df15177ccd1a74388f33 Mon Sep 17 00:00:00 2001 From: maxryan008 Date: Fri, 1 May 2026 23:21:00 +1000 Subject: [PATCH 7/9] Run spotless apply for licence headers --- .../mixin/compat/sable/SableMixinPlugin.java | 22 +++++++++++++++++++ .../sable/SubLevelPhysicsSystemMixin.java | 22 +++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/common/src/main/java/dev/galacticraft/dynamicdimensions/impl/mixin/compat/sable/SableMixinPlugin.java b/common/src/main/java/dev/galacticraft/dynamicdimensions/impl/mixin/compat/sable/SableMixinPlugin.java index f8b2e54..7814846 100644 --- a/common/src/main/java/dev/galacticraft/dynamicdimensions/impl/mixin/compat/sable/SableMixinPlugin.java +++ b/common/src/main/java/dev/galacticraft/dynamicdimensions/impl/mixin/compat/sable/SableMixinPlugin.java @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2021-2025 Team Galacticraft + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package dev.galacticraft.dynamicdimensions.impl.mixin.compat.sable; import org.objectweb.asm.tree.ClassNode; diff --git a/common/src/main/java/dev/galacticraft/dynamicdimensions/impl/mixin/compat/sable/SubLevelPhysicsSystemMixin.java b/common/src/main/java/dev/galacticraft/dynamicdimensions/impl/mixin/compat/sable/SubLevelPhysicsSystemMixin.java index 339dca2..27149b9 100644 --- a/common/src/main/java/dev/galacticraft/dynamicdimensions/impl/mixin/compat/sable/SubLevelPhysicsSystemMixin.java +++ b/common/src/main/java/dev/galacticraft/dynamicdimensions/impl/mixin/compat/sable/SubLevelPhysicsSystemMixin.java @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2021-2025 Team Galacticraft + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package dev.galacticraft.dynamicdimensions.impl.mixin.compat.sable; import dev.galacticraft.dynamicdimensions.impl.compat.SableDimensionPhysicsCompat; From 6a0405d99bfc7853ec807534ba523000bf8ba439 Mon Sep 17 00:00:00 2001 From: maxryan008 Date: Tue, 5 May 2026 20:11:25 +1000 Subject: [PATCH 8/9] Update sable version --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 1bd9f73..3e3bb5d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -35,5 +35,5 @@ fabric.api.modules=\ fabric-lifecycle-events-v1,\ fabric-resource-loader-v0 -sable.version=1.1.3 +sable.version=1.2.2 veil.version=1.21.1:3.6.2 \ No newline at end of file From 7125d5d086e84fc9fdbc451e6de1372adefba5b2 Mon Sep 17 00:00:00 2001 From: maxryan008 Date: Fri, 8 May 2026 09:47:15 +1000 Subject: [PATCH 9/9] Fix small nitpicks and run spotless --- build.gradle.kts | 4 ++++ common/build.gradle.kts | 6 ------ .../api/event/DynamicDimensionLoadCallback.java | 7 +++++-- .../impl/mixin/compat/sable/SableMixinPlugin.java | 7 ++++--- fabric/build.gradle.kts | 6 ------ neoforge/build.gradle.kts | 6 ------ 6 files changed, 13 insertions(+), 23 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 6e38347..1aedac3 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -90,6 +90,10 @@ subprojects { includeGroup("lol.bai") } } + + maven("https://maven.ryanhcode.dev/releases") + maven("https://raw.githubusercontent.com/Fuzss/modresources/main/maven/") + maven("https://maven.blamejared.com") } dependencies { diff --git a/common/build.gradle.kts b/common/build.gradle.kts index 75a37fd..c6c29da 100644 --- a/common/build.gradle.kts +++ b/common/build.gradle.kts @@ -32,9 +32,3 @@ dependencies { compileOnly("dev.ryanhcode.sable:sable-common-$minecraft:$sable") } - -repositories { - maven("https://maven.ryanhcode.dev/releases") - maven("https://raw.githubusercontent.com/Fuzss/modresources/main/maven/") - maven("https://maven.blamejared.com") -} diff --git a/common/src/main/java/dev/galacticraft/dynamicdimensions/api/event/DynamicDimensionLoadCallback.java b/common/src/main/java/dev/galacticraft/dynamicdimensions/api/event/DynamicDimensionLoadCallback.java index 4a7567d..6e9b849 100644 --- a/common/src/main/java/dev/galacticraft/dynamicdimensions/api/event/DynamicDimensionLoadCallback.java +++ b/common/src/main/java/dev/galacticraft/dynamicdimensions/api/event/DynamicDimensionLoadCallback.java @@ -22,8 +22,11 @@ package dev.galacticraft.dynamicdimensions.api.event; +import dev.galacticraft.dynamicdimensions.api.DynamicDimensionProperties; import dev.galacticraft.dynamicdimensions.api.DynamicDimensionRegistry; import dev.galacticraft.dynamicdimensions.impl.platform.Services; +import net.minecraft.core.registries.Registries; +import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; @@ -70,8 +73,8 @@ interface DynamicDimensionLoader { * @param server the current minecraft server * @return the newly loaded level */ - default @NotNull ServerLevel loadDynamicDimension(@NotNull ResourceLocation id, @NotNull ChunkGenerator chunkGenerator, @NotNull DimensionType type, @NotNull dev.galacticraft.dynamicdimensions.api.DynamicDimensionProperties properties, @NotNull MinecraftServer server) { - DynamicDimensionRegistry.from(server).setDimensionProperties(net.minecraft.resources.ResourceKey.create(net.minecraft.core.registries.Registries.DIMENSION, id), properties); + default @NotNull ServerLevel loadDynamicDimension(@NotNull ResourceLocation id, @NotNull ChunkGenerator chunkGenerator, @NotNull DimensionType type, @NotNull DynamicDimensionProperties properties, @NotNull MinecraftServer server) { + DynamicDimensionRegistry.from(server).setDimensionProperties(ResourceKey.create(Registries.DIMENSION, id), properties); return this.loadDynamicDimension(id, chunkGenerator, type); } } diff --git a/common/src/main/java/dev/galacticraft/dynamicdimensions/impl/mixin/compat/sable/SableMixinPlugin.java b/common/src/main/java/dev/galacticraft/dynamicdimensions/impl/mixin/compat/sable/SableMixinPlugin.java index 7814846..45878ad 100644 --- a/common/src/main/java/dev/galacticraft/dynamicdimensions/impl/mixin/compat/sable/SableMixinPlugin.java +++ b/common/src/main/java/dev/galacticraft/dynamicdimensions/impl/mixin/compat/sable/SableMixinPlugin.java @@ -22,6 +22,7 @@ package dev.galacticraft.dynamicdimensions.impl.mixin.compat.sable; +import dev.galacticraft.dynamicdimensions.impl.Constants; import org.objectweb.asm.tree.ClassNode; import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; import org.spongepowered.asm.mixin.extensibility.IMixinInfo; @@ -39,17 +40,17 @@ public void onLoad(final String mixinPackage) { Class loaderClass = Class.forName("net.fabricmc.loader.api.FabricLoader"); Object instance = loaderClass.getMethod("getInstance").invoke(null); this.sableLoaded = (boolean) loaderClass.getMethod("isModLoaded", String.class).invoke(instance, "sable"); - System.out.println("[DynDims/SableMixin] Sable detected via FabricLoader: " + this.sableLoaded); + Constants.LOGGER.info("Sable detected via FabricLoader: {}", this.sableLoaded); } catch (final Exception e) { // Not on Fabric, fall back to checking for NeoForge mod list try { Class modListClass = Class.forName("net.neoforged.fml.ModList"); Object modList = modListClass.getMethod("get").invoke(null); this.sableLoaded = (boolean) modListClass.getMethod("isLoaded", String.class).invoke(modList, "sable"); - System.out.println("[DynDims/SableMixin] Sable detected via ModList: " + this.sableLoaded); + Constants.LOGGER.info("Sable detected via ModList: {}", this.sableLoaded); } catch (final Exception ex) { this.sableLoaded = false; - System.out.println("[DynDims/SableMixin] Could not determine if Sable is loaded: " + ex.getMessage()); + Constants.LOGGER.info("Could not determine if Sable is loaded: {}", ex.getMessage()); } } } diff --git a/fabric/build.gradle.kts b/fabric/build.gradle.kts index 5c0b933..5b4d2da 100644 --- a/fabric/build.gradle.kts +++ b/fabric/build.gradle.kts @@ -80,9 +80,3 @@ tasks.javadoc { tasks.validateAccessWidener { enabled = false // access widener validated by :common } - -repositories { - maven("https://maven.ryanhcode.dev/releases") - maven("https://raw.githubusercontent.com/Fuzss/modresources/main/maven/") - maven("https://maven.blamejared.com") -} diff --git a/neoforge/build.gradle.kts b/neoforge/build.gradle.kts index a481ca7..b36271d 100644 --- a/neoforge/build.gradle.kts +++ b/neoforge/build.gradle.kts @@ -88,10 +88,4 @@ tasks.processResources { tasks.javadoc { source(project(":common").sourceSets.main.get().allJava) -} - -repositories { - maven("https://maven.ryanhcode.dev/releases") - maven("https://raw.githubusercontent.com/Fuzss/modresources/main/maven/") - maven("https://maven.blamejared.com") } \ No newline at end of file