Skip to content
9 changes: 9 additions & 0 deletions common/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand All @@ -28,4 +29,12 @@ dependencies {

// loom expects some loader classes to exist, provides mixin and mixin-extras too
modCompileOnly("net.fabricmc:fabric-loader:${fabricLoader}")

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")
}
Comment thread
maxryan008 marked this conversation as resolved.
Outdated
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* 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;

/**
* 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();
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Comment thread
maxryan008 marked this conversation as resolved.
*/
@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.
Expand All @@ -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.
*
* <p>If the dimension is already loaded, compatible backends such as Sable
* may apply these immediately.</p>
*
* @since 0.10.0
*/
void setDimensionProperties(@NotNull ResourceKey<Level> 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<Level> 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.
*
* <p>If the dimension has been applied to a compatible backend such as Sable,
* this should also remove those backend properties.</p>
*
* @since 0.10.0
*/
void clearDimensionProperties(@NotNull ResourceKey<Level> 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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 {
Expand All @@ -69,6 +73,8 @@ public class DynamicDimensionRegistryImpl implements DynamicDimensionRegistry {
private final Registry<DimensionType> dimTypes;
private final Registry<LevelStem> stems;

private final Map<ResourceKey<Level>, DynamicDimensionProperties> dimensionProperties = new HashMap<>();

public DynamicDimensionRegistryImpl(MinecraftServer server) {
this.server = server;
this.dimTypes = server.registryAccess().registryOrThrow(Registries.DIMENSION_TYPE);
Expand All @@ -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<Level> 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<Level> 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<Level> 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<Level> key) {
return this.dimensionProperties.get(key);
}


@Override
public void clearDimensionProperties(@NotNull ResourceKey<Level> key) {
this.dimensionProperties.remove(key);
DynamicDimensionPhysicsCompat.remove(key);
}

@Override
public boolean dynamicDimensionExists(@NotNull ResourceKey<Level> key) {
return this.dynamicDimensions.contains(key) || ((DynamicDimensionProvider) this.server).dynamicdimensions$isIdPendingCreation(key);
Expand Down Expand Up @@ -125,7 +178,9 @@ public boolean deleteDynamicDimension(@NotNull ResourceLocation id, @Nullable Pl
ResourceKey<Level> 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;
}
Expand All @@ -136,7 +191,9 @@ public boolean unloadDynamicDimension(@NotNull ResourceLocation id, @Nullable Pl
ResourceKey<Level> 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;
}

Expand Down Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +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<Level> key, DynamicDimensionProperties properties) {
if (Services.PLATFORM.isModLoaded(SABLE_MOD_ID)) {
SableDimensionPhysicsCompat.apply(key, properties);
}
}

public static void remove(ResourceKey<Level> key) {
if (Services.PLATFORM.isModLoaded(SABLE_MOD_ID)) {
SableDimensionPhysicsCompat.remove(key);
}
}
}
Loading