11package dev .compactmods .machines .command ;
22
3- import java .io .IOException ;
4- import java .nio .file .Files ;
5- import java .time .ZonedDateTime ;
6- import java .time .format .DateTimeFormatter ;
7- import java .util .concurrent .Executor ;
8- import com .google .common .collect .ImmutableList ;
93import com .mojang .brigadier .builder .ArgumentBuilder ;
104import com .mojang .brigadier .context .CommandContext ;
115import com .mojang .brigadier .exceptions .CommandSyntaxException ;
12- import com .mojang .serialization .JsonOps ;
13- import com .mojang .serialization .Lifecycle ;
14- import dev .compactmods .machines .CompactMachines ;
156import dev .compactmods .machines .core .Registration ;
7+ import dev .compactmods .machines .util .DimensionUtil ;
168import dev .compactmods .machines .util .TranslationUtil ;
179import net .minecraft .ChatFormatting ;
1810import net .minecraft .commands .CommandSourceStack ;
1911import net .minecraft .commands .Commands ;
20- import net .minecraft .core .Registry ;
21- import net .minecraft .resources .RegistryReadOps ;
22- import net .minecraft .resources .RegistryResourceAccess ;
23- import net .minecraft .resources .ResourceKey ;
24- import net .minecraft .server .MinecraftServer ;
25- import net .minecraft .server .level .ServerLevel ;
26- import net .minecraft .server .level .progress .ChunkProgressListener ;
27- import net .minecraft .world .level .Level ;
28- import net .minecraft .world .level .border .BorderChangeListener ;
29- import net .minecraft .world .level .dimension .LevelStem ;
30- import net .minecraft .world .level .levelgen .WorldGenSettings ;
31- import net .minecraft .world .level .storage .DerivedLevelData ;
32- import net .minecraft .world .level .storage .LevelResource ;
33- import net .minecraft .world .level .storage .LevelStorageSource ;
34- import net .minecraft .world .level .storage .WorldData ;
35- import net .minecraftforge .common .MinecraftForge ;
36- import net .minecraftforge .event .world .WorldEvent ;
37- import net .minecraftforge .fml .loading .FMLEnvironment ;
3812
3913public class ReaddDimensionCommand {
4014 public static ArgumentBuilder <CommandSourceStack , ?> register () {
@@ -51,113 +25,13 @@ private static int exec(CommandContext<CommandSourceStack> ctx) throws CommandSy
5125 if (compactLevel == null ) {
5226 src .sendSuccess (TranslationUtil .command ("level_not_found" ).withStyle (ChatFormatting .RED ), false );
5327
54- createAndRegisterWorldAndDimension (serv );
28+ DimensionUtil . createAndRegisterWorldAndDimension (serv );
5529 } else {
5630 src .sendSuccess (TranslationUtil .command ("level_registered" ).withStyle (ChatFormatting .DARK_GREEN ), false );
5731 }
5832
5933 return 0 ;
6034 }
6135
62- @ SuppressWarnings ("deprecation" ) // because we call the forge internal method server#markWorldsDirty
63- private static void createAndRegisterWorldAndDimension (final MinecraftServer server ) {
64- final var map = server .forgeGetWorldMap ();
6536
66- // get everything we need to create the dimension and the level
67- final ServerLevel overworld = server .getLevel (Level .OVERWORLD );
68-
69- // dimension keys have a 1:1 relationship with level keys, they have the same IDs as well
70- final ResourceKey <LevelStem > dimensionKey = ResourceKey .create (Registry .LEVEL_STEM_REGISTRY , Registration .COMPACT_DIMENSION .location ());
71-
72- final var serverResources = server .getResourceManager ();
73-
74- // only back up level.dat in production
75- if (FMLEnvironment .production && !doLevelFileBackup (server )) return ;
76-
77- var reg = server .registryAccess ();
78- var cmDimType = reg .registryOrThrow (Registry .DIMENSION_TYPE_REGISTRY )
79- .get (Registration .COMPACT_DIMENSION_DIM_TYPE );
80-
81- var ops = RegistryReadOps .create (JsonOps .INSTANCE , serverResources , reg );
82-
83- var resourceAccess = RegistryResourceAccess .forResourceManager (serverResources );
84- var dims = resourceAccess .listResources (Registry .DIMENSION_REGISTRY );
85-
86- var cmDim = dims .stream ()
87- .filter (d -> d .location ().equals (Registration .COMPACT_DIMENSION .location ()))
88- .findFirst ();
89-
90- cmDim .ifPresent (lev -> {
91- var parsed = resourceAccess .parseElement (ops , Registry .LEVEL_STEM_REGISTRY , dimensionKey , LevelStem .CODEC );
92-
93- var stem = parsed .orElseThrow ()
94- .result ().orElseThrow ()
95- .value ();
96-
97- // the int in create() here is radius of chunks to watch, 11 is what the server uses when it initializes worlds
98- final ChunkProgressListener chunkProgressListener = server .progressListenerFactory .create (11 );
99- final Executor executor = server .executor ;
100- final LevelStorageSource .LevelStorageAccess anvilConverter = server .storageSource ;
101- final WorldData worldData = server .getWorldData ();
102- final WorldGenSettings worldGenSettings = worldData .worldGenSettings ();
103- final DerivedLevelData derivedLevelData = new DerivedLevelData (worldData , worldData .overworldData ());
104-
105- // now we have everything we need to create the dimension and the level
106- // this is the same order server init creates levels:
107- // the dimensions are already registered when levels are created, we'll do that first
108- // then instantiate level, add border listener, add to map, fire world load event
109-
110- // register the actual dimension
111- worldGenSettings .dimensions ().register (dimensionKey , stem , Lifecycle .experimental ());
112-
113- // create the world instance
114- final ServerLevel newWorld = new ServerLevel (
115- server ,
116- executor ,
117- anvilConverter ,
118- derivedLevelData ,
119- Registration .COMPACT_DIMENSION ,
120- cmDimType ,
121- chunkProgressListener ,
122- stem .generator (),
123- worldGenSettings .isDebug (),
124- net .minecraft .world .level .biome .BiomeManager .obfuscateSeed (worldGenSettings .seed ()),
125- ImmutableList .of (), // "special spawn list"
126- false // "tick time", true for overworld, always false for nether, end, and json dimensions
127- );
128-
129- /*
130- add world border listener, for parity with json dimensions
131- the vanilla behaviour is that world borders exist in every dimension simultaneously with the same size and position
132- these border listeners are automatically added to the overworld as worlds are loaded, so we should do that here too
133- TODO if world-specific world borders are ever added, change it here too
134- */
135- overworld .getWorldBorder ().addListener (new BorderChangeListener .DelegateBorderChangeListener (newWorld .getWorldBorder ()));
136-
137- // register level
138- map .put (Registration .COMPACT_DIMENSION , newWorld );
139-
140- // update forge's world cache so the new level can be ticked
141- server .markWorldsDirty ();
142-
143- // fire world load event
144- MinecraftForge .EVENT_BUS .post (new WorldEvent .Load (newWorld ));
145- });
146- }
147-
148- private static boolean doLevelFileBackup (MinecraftServer server ) {
149- var levelRoot = server .getWorldPath (LevelResource .ROOT );
150- var levelFile = server .getWorldPath (LevelResource .LEVEL_DATA_FILE );
151-
152- var formatter = DateTimeFormatter .ofPattern ("'cm4-level-'yyyyMMdd-HHmmss'.dat'" );
153- var timestamp = formatter .format (ZonedDateTime .now ());
154- try {
155- Files .copy (levelFile , levelRoot .resolve (timestamp ));
156- } catch (IOException e ) {
157- CompactMachines .LOGGER .error ("Failed to backup level.dat file before modification; canceling register dim attempt." );
158- return false ;
159- }
160-
161- return true ;
162- }
16337}
0 commit comments