2323package dev .galacticraft .dynamicdimensions .impl ;
2424
2525import com .google .common .collect .ImmutableList ;
26+ import dev .galacticraft .dynamicdimensions .api .DynamicDimensionProperties ;
2627import dev .galacticraft .dynamicdimensions .api .DynamicDimensionRegistry ;
2728import dev .galacticraft .dynamicdimensions .api .PlayerRemover ;
2829import dev .galacticraft .dynamicdimensions .api .event .DynamicDimensionLoadCallback ;
2930import dev .galacticraft .dynamicdimensions .impl .accessor .DynamicDimensionProvider ;
3031import dev .galacticraft .dynamicdimensions .impl .accessor .PrimaryLevelDataAccessor ;
32+ import dev .galacticraft .dynamicdimensions .impl .compat .DynamicDimensionPhysicsCompat ;
3133import dev .galacticraft .dynamicdimensions .impl .mixin .*;
3234import dev .galacticraft .dynamicdimensions .impl .network .S2CPackets ;
3335import dev .galacticraft .dynamicdimensions .impl .registry .RegistryUtil ;
6062import org .jetbrains .annotations .NotNull ;
6163import org .jetbrains .annotations .Nullable ;
6264
65+ import java .util .HashMap ;
6366import java .util .List ;
67+ import java .util .Map ;
6468import java .util .stream .Collectors ;
6569
6670public class DynamicDimensionRegistryImpl implements DynamicDimensionRegistry {
@@ -69,6 +73,8 @@ public class DynamicDimensionRegistryImpl implements DynamicDimensionRegistry {
6973 private final Registry <DimensionType > dimTypes ;
7074 private final Registry <LevelStem > stems ;
7175
76+ private final Map <ResourceKey <Level >, DynamicDimensionProperties > dimensionProperties = new HashMap <>();
77+
7278 public DynamicDimensionRegistryImpl (MinecraftServer server ) {
7379 this .server = server ;
7480 this .dimTypes = server .registryAccess ().registryOrThrow (Registries .DIMENSION_TYPE );
@@ -81,6 +87,13 @@ public void loadDynamicDimensions() {
8187 Constants .LOGGER .debug ("Loading dynamic dimension '{}'" , id );
8288 ResourceKey <Level > key = ResourceKey .create (Registries .DIMENSION , id );
8389
90+ // If properties were already registered before this callback fires
91+ // (e.g. by the caller calling setDimensionProperties first), stage them now.
92+ DynamicDimensionProperties properties = this .dimensionProperties .get (key );
93+ if (properties != null ) {
94+ DynamicDimensionPhysicsCompat .stage (key , properties );
95+ }
96+
8497 return this .createDynamicLevel (id , chunkGenerator , type , key );
8598 });
8699
@@ -92,11 +105,58 @@ public void loadDynamicDimensions() {
92105 return this .createDynamicLevel (id , generator , type , true );
93106 }
94107
108+ @ Override
109+ public @ Nullable ServerLevel createDynamicDimension (@ NotNull ResourceLocation id , @ NotNull ChunkGenerator generator , @ NotNull DimensionType type , @ NotNull DynamicDimensionProperties properties ) {
110+ ResourceKey <Level > key = ResourceKey .create (Registries .DIMENSION , id );
111+ this .setDimensionProperties (key , properties );
112+
113+ ServerLevel level = this .createDynamicLevel (id , generator , type , true );
114+ if (level == null ) {
115+ this .clearDimensionProperties (key );
116+ }
117+
118+ return level ;
119+ }
120+
95121 @ Override
96122 public @ Nullable ServerLevel loadDynamicDimension (@ NotNull ResourceLocation id , @ NotNull ChunkGenerator generator , @ NotNull DimensionType type ) {
97123 return this .createDynamicLevel (id , generator , type , false );
98124 }
99125
126+ @ Override
127+ public @ Nullable ServerLevel loadDynamicDimension (@ NotNull ResourceLocation id , @ NotNull ChunkGenerator generator , @ NotNull DimensionType type , @ NotNull DynamicDimensionProperties properties ) {
128+ ResourceKey <Level > key = ResourceKey .create (Registries .DIMENSION , id );
129+ this .setDimensionProperties (key , properties );
130+
131+ ServerLevel level = this .createDynamicLevel (id , generator , type , false );
132+ if (level == null ) {
133+ this .clearDimensionProperties (key );
134+ }
135+
136+ return level ;
137+ }
138+
139+ @ Override
140+ public void setDimensionProperties (@ NotNull ResourceKey <Level > key , @ NotNull DynamicDimensionProperties properties ) {
141+ this .dimensionProperties .put (key , properties );
142+
143+ if (this .server .getLevel (key ) != null ) {
144+ DynamicDimensionPhysicsCompat .apply (key , properties );
145+ }
146+ }
147+
148+ @ Override
149+ public @ Nullable DynamicDimensionProperties getDimensionProperties (@ NotNull ResourceKey <Level > key ) {
150+ return this .dimensionProperties .get (key );
151+ }
152+
153+
154+ @ Override
155+ public void clearDimensionProperties (@ NotNull ResourceKey <Level > key ) {
156+ this .dimensionProperties .remove (key );
157+ DynamicDimensionPhysicsCompat .remove (key );
158+ }
159+
100160 @ Override
101161 public boolean dynamicDimensionExists (@ NotNull ResourceKey <Level > key ) {
102162 return this .dynamicDimensions .contains (key ) || ((DynamicDimensionProvider ) this .server ).dynamicdimensions$isIdPendingCreation (key );
@@ -125,7 +185,9 @@ public boolean deleteDynamicDimension(@NotNull ResourceLocation id, @Nullable Pl
125185 ResourceKey <Level > key = ResourceKey .create (Registries .DIMENSION , id );
126186 if (!this .canDeleteDimension (key )) return false ;
127187
188+ DynamicDimensionPhysicsCompat .remove (key );
128189 ((DynamicDimensionProvider ) this .server ).dynamicdimensions$removeLevel (key , remover , true );
190+ this .dimensionProperties .remove (key );
129191
130192 return true ;
131193 }
@@ -136,7 +198,9 @@ public boolean unloadDynamicDimension(@NotNull ResourceLocation id, @Nullable Pl
136198 ResourceKey <Level > key = ResourceKey .create (Registries .DIMENSION , id );
137199 if (!this .canDeleteDimension (key )) return false ;
138200
201+ DynamicDimensionPhysicsCompat .remove (key );
139202 ((DynamicDimensionProvider ) this .server ).dynamicdimensions$removeLevel (key , remover , false );
203+
140204 return true ;
141205 }
142206
@@ -162,8 +226,14 @@ public boolean unloadDynamicDimension(@NotNull ResourceLocation id, @Nullable Pl
162226 }
163227
164228 private @ NotNull ServerLevel createDynamicLevel (ResourceKey <Level > key , WorldData worldData , LevelStem stem , ServerLevel overworld ) {
165- // -- start createLevels --
166- final DerivedLevelData data = new DerivedLevelData (worldData , worldData .overworldData ()); //todo: do we want separate data?
229+ // Stage physics properties before ServerLevel construction so Sable's
230+ // SubLevelPhysicsSystem.initialize() mixin can flush them before reading gravity.
231+ DynamicDimensionProperties pendingProperties = this .dimensionProperties .get (key );
232+ if (pendingProperties != null ) {
233+ DynamicDimensionPhysicsCompat .stage (key , pendingProperties );
234+ }
235+
236+ final DerivedLevelData data = new DerivedLevelData (worldData , worldData .overworldData ());
167237 final ServerLevel level = new ServerLevel (
168238 this .server ,
169239 ((MinecraftServerAccessor ) this .server ).getExecutor (),
@@ -179,17 +249,13 @@ public boolean unloadDynamicDimension(@NotNull ResourceLocation id, @Nullable Pl
179249 null
180250 );
181251 overworld .getWorldBorder ().addListener (new BorderChangeListener .DelegateBorderChangeListener (level .getWorldBorder ()));
182- // -- end createLevels --
183252
184- // see PlayerList
185253 level .getChunkSource ().setSimulationDistance (((DistanceManagerAccessor ) ((ServerChunkCacheAccessor ) overworld .getChunkSource ()).getDistanceManager ()).getSimulationDistance ());
186254 level .getChunkSource ().setViewDistance (((ChunkMapAccessor ) overworld .getChunkSource ().chunkMap ).getViewDistance ());
187255
188- // -- start prepareLevels --
189256 ForcedChunksSavedData forcedChunksSavedData = level .getDataStorage ().get (ForcedChunksSavedData .factory (), "chunks" );
190257 if (forcedChunksSavedData != null ) {
191258 LongIterator longIterator = forcedChunksSavedData .getChunks ().iterator ();
192-
193259 while (longIterator .hasNext ()) {
194260 long l = longIterator .nextLong ();
195261 ChunkPos chunkPos = new ChunkPos (l );
@@ -198,10 +264,14 @@ public boolean unloadDynamicDimension(@NotNull ResourceLocation id, @Nullable Pl
198264 }
199265
200266 level .setSpawnSettings (this .server .isSpawningMonsters (), this .server .isSpawningAnimals ());
201- // -- end prepareLevels --
202267
203268 ((DynamicDimensionProvider ) this .server ).dynamicdimensions$registerLevel (level );
204269
270+ // Belt-and-suspenders apply after level exists, covers setDimensionProperties called post-creation.
271+ if (pendingProperties != null ) {
272+ DynamicDimensionPhysicsCompat .apply (key , pendingProperties );
273+ }
274+
205275 final var serializedType = ((CompoundTag ) DimensionType .DIRECT_CODEC .encode (stem .type ().value (), RegistryOps .create (NbtOps .INSTANCE , this .server .registryAccess ()), new CompoundTag ()).getOrThrow ());
206276 for (ServerPlayer player : this .server .getPlayerList ().getPlayers ()) {
207277 S2CPackets .sendCreateDimension (player , key .location (), serializedType );
0 commit comments