Skip to content

Commit ab3130b

Browse files
committed
Bump to beta 6, add registerdim command.
1 parent 254c5a6 commit ab3130b

File tree

5 files changed

+203
-4
lines changed

5 files changed

+203
-4
lines changed

gradle.properties

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ org.gradle.jvmargs=-Xmx3G
44
org.gradle.daemon=false
55

66
minecraft_version=1.18.1
7-
forge_version=39.0.0
7+
forge_version=39.0.75
88

99
mod_id=compactmachines
10-
mod_version=4.0.0-beta.5
10+
mod_version=4.0.0-beta.6
1111

1212
# Dependencies and Libs
1313
jei_mc_version=1.18.1

src/main/java/dev/compactmods/machines/command/CMCommandRoot.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ public static void register(CommandDispatcher<CommandSourceStack> dispatcher) {
1111
final LiteralArgumentBuilder<CommandSourceStack> root = LiteralArgumentBuilder.literal(CompactMachines.MOD_ID);
1212
root.then(CMEjectSubcommand.register());
1313
root.then(CMSummarySubcommand.register());
14+
root.then(ReaddDimensionCommand.register());
1415
dispatcher.register(root);
1516
}
1617
}
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
package dev.compactmods.machines.command;
2+
3+
import java.io.IOException;
4+
import java.io.InputStreamReader;
5+
import java.nio.file.Files;
6+
import java.time.ZonedDateTime;
7+
import java.time.format.DateTimeFormatter;
8+
import java.util.concurrent.Executor;
9+
import com.google.common.collect.ImmutableList;
10+
import com.google.gson.Gson;
11+
import com.google.gson.JsonObject;
12+
import com.mojang.brigadier.builder.ArgumentBuilder;
13+
import com.mojang.brigadier.context.CommandContext;
14+
import com.mojang.brigadier.exceptions.CommandSyntaxException;
15+
import com.mojang.serialization.JsonOps;
16+
import com.mojang.serialization.Lifecycle;
17+
import dev.compactmods.machines.CompactMachines;
18+
import dev.compactmods.machines.core.Registration;
19+
import dev.compactmods.machines.util.TranslationUtil;
20+
import net.minecraft.ChatFormatting;
21+
import net.minecraft.commands.CommandSourceStack;
22+
import net.minecraft.commands.Commands;
23+
import net.minecraft.core.Registry;
24+
import net.minecraft.resources.RegistryReadOps;
25+
import net.minecraft.resources.RegistryResourceAccess;
26+
import net.minecraft.resources.ResourceKey;
27+
import net.minecraft.resources.ResourceLocation;
28+
import net.minecraft.server.MinecraftServer;
29+
import net.minecraft.server.level.ServerLevel;
30+
import net.minecraft.server.level.progress.ChunkProgressListener;
31+
import net.minecraft.server.packs.resources.Resource;
32+
import net.minecraft.world.level.Level;
33+
import net.minecraft.world.level.border.BorderChangeListener;
34+
import net.minecraft.world.level.dimension.LevelStem;
35+
import net.minecraft.world.level.levelgen.WorldGenSettings;
36+
import net.minecraft.world.level.storage.DerivedLevelData;
37+
import net.minecraft.world.level.storage.LevelResource;
38+
import net.minecraft.world.level.storage.LevelStorageSource;
39+
import net.minecraft.world.level.storage.WorldData;
40+
import net.minecraftforge.common.MinecraftForge;
41+
import net.minecraftforge.event.world.WorldEvent;
42+
import net.minecraftforge.fml.loading.FMLEnvironment;
43+
44+
public class ReaddDimensionCommand {
45+
public static ArgumentBuilder<CommandSourceStack, ?> register() {
46+
return Commands.literal("registerdim")
47+
.requires(cs -> cs.hasPermission(Commands.LEVEL_GAMEMASTERS))
48+
.executes(ReaddDimensionCommand::exec);
49+
}
50+
51+
private static int exec(CommandContext<CommandSourceStack> ctx) throws CommandSyntaxException {
52+
var src = ctx.getSource();
53+
var serv = src.getServer();
54+
55+
var compactLevel = serv.getLevel(Registration.COMPACT_DIMENSION);
56+
if (compactLevel == null) {
57+
src.sendSuccess(TranslationUtil.command("level_not_found").withStyle(ChatFormatting.RED), false);
58+
59+
createAndRegisterWorldAndDimension(serv);
60+
} else {
61+
src.sendSuccess(TranslationUtil.command("level_registered").withStyle(ChatFormatting.DARK_GREEN), false);
62+
}
63+
64+
return 0;
65+
}
66+
67+
@SuppressWarnings("deprecation") // because we call the forge internal method server#markWorldsDirty
68+
private static void createAndRegisterWorldAndDimension(final MinecraftServer server) {
69+
final var map = server.forgeGetWorldMap();
70+
71+
// get everything we need to create the dimension and the level
72+
final ServerLevel overworld = server.getLevel(Level.OVERWORLD);
73+
74+
// dimension keys have a 1:1 relationship with level keys, they have the same IDs as well
75+
final ResourceKey<LevelStem> dimensionKey = ResourceKey.create(Registry.LEVEL_STEM_REGISTRY, Registration.COMPACT_DIMENSION.location());
76+
77+
final var serverResources = server.getResourceManager();
78+
79+
Resource dimFile = null;
80+
try {
81+
dimFile = serverResources.getResource(new ResourceLocation(CompactMachines.MOD_ID, "dimension/compact_world.json"));
82+
} catch (IOException e) {
83+
CompactMachines.LOGGER.error("Failed to register dimension from datapack settings.", e);
84+
}
85+
86+
if (dimFile == null) {
87+
return;
88+
}
89+
90+
// only back up level.dat in production
91+
if (FMLEnvironment.production && !doLevelFileBackup(server)) return;
92+
93+
var g = new Gson();
94+
final var jsonDim = g.fromJson(new InputStreamReader(dimFile.getInputStream()), JsonObject.class);
95+
96+
var reg = server.registryAccess();
97+
var cmDimType = reg.registryOrThrow(Registry.DIMENSION_TYPE_REGISTRY)
98+
.get(Registration.COMPACT_DIMENSION_DIM_TYPE);
99+
100+
// TODO - Figure out how to either re-read dimension info from data structure, or kick the level.dat into behaving
101+
var ops = RegistryReadOps.create(JsonOps.INSTANCE, serverResources, reg);
102+
103+
var resourceAccess = RegistryResourceAccess.forResourceManager(serverResources);
104+
var dims = resourceAccess.listResources(Registry.DIMENSION_REGISTRY);
105+
106+
var cmDim = dims.stream()
107+
.filter(d -> d.location().equals(Registration.COMPACT_DIMENSION.location()))
108+
.findFirst();
109+
110+
cmDim.ifPresent(lev -> {
111+
var parsed = resourceAccess.parseElement(ops, Registry.LEVEL_STEM_REGISTRY, dimensionKey, LevelStem.CODEC);
112+
113+
var stem = parsed.orElseThrow()
114+
.result().orElseThrow()
115+
.value();
116+
117+
// the int in create() here is radius of chunks to watch, 11 is what the server uses when it initializes worlds
118+
final ChunkProgressListener chunkProgressListener = server.progressListenerFactory.create(11);
119+
final Executor executor = server.executor;
120+
final LevelStorageSource.LevelStorageAccess anvilConverter = server.storageSource;
121+
final WorldData worldData = server.getWorldData();
122+
final WorldGenSettings worldGenSettings = worldData.worldGenSettings();
123+
final DerivedLevelData derivedLevelData = new DerivedLevelData(worldData, worldData.overworldData());
124+
125+
// now we have everything we need to create the dimension and the level
126+
// this is the same order server init creates levels:
127+
// the dimensions are already registered when levels are created, we'll do that first
128+
// then instantiate level, add border listener, add to map, fire world load event
129+
130+
// register the actual dimension
131+
worldGenSettings.dimensions().register(dimensionKey, stem, Lifecycle.experimental());
132+
133+
// create the world instance
134+
final ServerLevel newWorld = new ServerLevel(
135+
server,
136+
executor,
137+
anvilConverter,
138+
derivedLevelData,
139+
Registration.COMPACT_DIMENSION,
140+
cmDimType,
141+
chunkProgressListener,
142+
stem.generator(),
143+
worldGenSettings.isDebug(),
144+
net.minecraft.world.level.biome.BiomeManager.obfuscateSeed(worldGenSettings.seed()),
145+
ImmutableList.of(), // "special spawn list"
146+
false // "tick time", true for overworld, always false for nether, end, and json dimensions
147+
);
148+
149+
/*
150+
add world border listener, for parity with json dimensions
151+
the vanilla behaviour is that world borders exist in every dimension simultaneously with the same size and position
152+
these border listeners are automatically added to the overworld as worlds are loaded, so we should do that here too
153+
TODO if world-specific world borders are ever added, change it here too
154+
*/
155+
overworld.getWorldBorder().addListener(new BorderChangeListener.DelegateBorderChangeListener(newWorld.getWorldBorder()));
156+
157+
// register level
158+
map.put(Registration.COMPACT_DIMENSION, newWorld);
159+
160+
// update forge's world cache so the new level can be ticked
161+
server.markWorldsDirty();
162+
163+
// fire world load event
164+
MinecraftForge.EVENT_BUS.post(new WorldEvent.Load(newWorld));
165+
});
166+
}
167+
168+
private static boolean doLevelFileBackup(MinecraftServer server) {
169+
var levelRoot = server.getWorldPath(LevelResource.ROOT);
170+
var levelFile = server.getWorldPath(LevelResource.LEVEL_DATA_FILE);
171+
172+
var formatter = DateTimeFormatter.ofPattern("'cm4-level-'yyyyMMdd-HHmmss'.dat'");
173+
var timestamp = formatter.format(ZonedDateTime.now());
174+
try {
175+
Files.copy(levelFile, levelRoot.resolve(timestamp));
176+
} catch (IOException e) {
177+
CompactMachines.LOGGER.error("Failed to backup level.dat file before modification; canceling register dim attempt.");
178+
return false;
179+
}
180+
181+
return true;
182+
}
183+
}

src/main/java/dev/compactmods/machines/core/Registration.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import net.minecraft.world.level.block.SoundType;
2121
import net.minecraft.world.level.block.entity.BlockEntityType;
2222
import net.minecraft.world.level.block.state.BlockBehaviour;
23+
import net.minecraft.world.level.dimension.DimensionType;
2324
import net.minecraft.world.level.material.Material;
2425
import net.minecraft.world.level.material.MaterialColor;
2526
import net.minecraftforge.eventbus.api.IEventBus;
@@ -30,6 +31,7 @@
3031

3132
@Mod.EventBusSubscriber(modid = MOD_ID)
3233
public class Registration {
34+
3335
// ================================================================================================================
3436
// REGISTRIES
3537
// ================================================================================================================
@@ -124,7 +126,11 @@ public class Registration {
124126
// ================================================================================================================
125127
// DIMENSION
126128
// ================================================================================================================
127-
public static final ResourceKey<Level> COMPACT_DIMENSION = ResourceKey.create(Registry.DIMENSION_REGISTRY, new ResourceLocation("compactmachines:compact_world"));
129+
public static final ResourceKey<Level> COMPACT_DIMENSION = ResourceKey
130+
.create(Registry.DIMENSION_REGISTRY, new ResourceLocation(MOD_ID, "compact_world"));
131+
132+
public static final ResourceKey<DimensionType> COMPACT_DIMENSION_DIM_TYPE = ResourceKey
133+
.create(Registry.DIMENSION_TYPE_REGISTRY, new ResourceLocation(MOD_ID, "compact_world"));
128134

129135
// ================================================================================================================
130136
// INITIALIZATION
Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,10 @@
1-
public net.minecraft.world.level.chunk.ChunkBiomeContainer f_62112_ # biomes
1+
public net.minecraft.world.level.chunk.ChunkBiomeContainer f_62112_ # biomes
2+
3+
# Fix Dimension Command
4+
public net.minecraft.server.MinecraftServer f_129738_ # executor
5+
public net.minecraft.server.MinecraftServer f_129744_ # storageSource
6+
public net.minecraft.server.MinecraftServer f_129756_ # progressListenerFactory
7+
public net.minecraft.world.level.border.WorldBorder f_61905_ # listeners
8+
public-f net.minecraft.world.level.levelgen.WorldGenSettings f_64605_ # dimensions
9+
public net.minecraft.world.level.border.BorderChangeListener$DelegateBorderChangeListener f_61864_ # worldBorder
10+
public-f net.minecraft.client.renderer.DimensionSpecialEffects f_108857_ # EFFECTS

0 commit comments

Comments
 (0)