Skip to content

Commit d05c165

Browse files
committed
Simplify the custom clock implementation
1 parent bfb48e9 commit d05c165

25 files changed

Lines changed: 238 additions & 680 deletions

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ jobs:
2222
- name: Set up JDK
2323
uses: actions/setup-java@v1
2424
with:
25-
java-version: 21
25+
java-version: 25
2626

2727
- name: Grant execute permission for gradlew
2828
run: chmod +x gradlew

.github/workflows/release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ jobs:
2424
- name: Set up JDK
2525
uses: actions/setup-java@v1
2626
with:
27-
java-version: 21
27+
java-version: 25
2828

2929
- name: Grant execute permission for gradlew
3030
run: chmod +x gradlew

gradle.properties

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@ org.gradle.jvmargs=-Xmx2G
33

44
# Fabric Properties
55

6-
minecraft_version=26.1
6+
minecraft_version=26.1.1
77
loader_version=0.18.5
88
loom_version=1.15-SNAPSHOT
99

1010
# Mod Properties
11-
mod_version=0.8.0
11+
mod_version=0.8.0-beta.1
1212
maven_group=xyz.nucleoid
1313
archives_base_name=fantasy
1414

src/main/java/xyz/nucleoid/fantasy/Fantasy.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,6 @@ public final class Fantasy {
4343
public static final Logger LOGGER = LogManager.getLogger(Fantasy.class);
4444
public static final String ID = "fantasy";
4545
public static final ResourceKey<DimensionType> DEFAULT_DIM_TYPE = ResourceKey.create(Registries.DIMENSION_TYPE, Identifier.fromNamespaceAndPath(Fantasy.ID, "default"));
46-
public static final ResourceKey<Timeline> DEFAULT_TIMELINE = ResourceKey.create(Registries.TIMELINE, Identifier.fromNamespaceAndPath(ID, "default"));
47-
public static final ResourceKey<WorldClock> DEFAULT_WORLD_CLOCK = ResourceKey.create(Registries.WORLD_CLOCK, Identifier.fromNamespaceAndPath(ID, "default"));
48-
public static final TagKey<Timeline> DEFAULT_TIMELINES = TagKey.create(Registries.TIMELINE, Identifier.fromNamespaceAndPath(ID, "in_default"));
49-
5046
private static Fantasy instance;
5147

5248
private final MinecraftServer server;

src/main/java/xyz/nucleoid/fantasy/MinecraftServerExtension.java

Lines changed: 0 additions & 8 deletions
This file was deleted.
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package xyz.nucleoid.fantasy;
2+
3+
import net.minecraft.core.Holder;
4+
import net.minecraft.network.protocol.game.ClientboundSetTimePacket;
5+
import net.minecraft.server.MinecraftServer;
6+
import net.minecraft.server.level.ServerLevel;
7+
import net.minecraft.util.Util;
8+
import net.minecraft.world.clock.ClockNetworkState;
9+
import net.minecraft.world.clock.PackedClockStates;
10+
import net.minecraft.world.clock.ServerClockManager;
11+
import net.minecraft.world.clock.WorldClock;
12+
import xyz.nucleoid.fantasy.mixin.clock.ClockInstanceAccessor;
13+
14+
import java.util.Map;
15+
import java.util.function.BooleanSupplier;
16+
import java.util.function.Consumer;
17+
18+
public class RuntimeClockManager extends ServerClockManager {
19+
protected final BooleanSupplier advanceTime;
20+
protected MinecraftServer server;
21+
22+
public RuntimeClockManager(PackedClockStates packedClockStates, BooleanSupplier advanceTime) {
23+
super(packedClockStates);
24+
this.advanceTime = advanceTime;
25+
}
26+
27+
@Override
28+
public void init(MinecraftServer server) {
29+
super.init(server);
30+
this.server = server;
31+
}
32+
33+
@Override
34+
public void tick() {
35+
if (this.advanceTime.getAsBoolean()) {
36+
((ServerClockManagerExtension) this).fantasy$getClocks().values().forEach(ClockInstance::tick);
37+
this.setDirty();
38+
}
39+
}
40+
41+
@Override
42+
protected void modifyClock(final Holder<WorldClock> clock, final Consumer<? super ClockInstance> action) {
43+
ClockInstance instance = this.getInstance(clock);
44+
action.accept(instance);
45+
Map<Holder<WorldClock>, ClockNetworkState> updates = Map.of(clock, this.packNetworkState(instance, this.server));
46+
this.setDirty();
47+
48+
var packet = new ClientboundSetTimePacket(this.getGameTime(), updates);
49+
50+
for (ServerLevel level : this.server.getAllLevels()) {
51+
if (level.clockManager() == this) {
52+
for (var player : level.players()) {
53+
player.connection.send(packet);
54+
}
55+
56+
level.environmentAttributes().invalidateTickCache();
57+
}
58+
}
59+
}
60+
61+
@Override
62+
public ClientboundSetTimePacket createFullSyncPacket() {
63+
return new ClientboundSetTimePacket(this.getGameTime(), Util.mapValues(((ServerClockManagerExtension) this).fantasy$getClocks(), (clock) -> this.packNetworkState(clock, this.server)));
64+
}
65+
66+
protected ClockNetworkState packNetworkState(ClockInstance instance, final MinecraftServer server) {
67+
var i = (ClockInstanceAccessor) instance;
68+
boolean paused = i.isPaused() || !this.advanceTime.getAsBoolean();
69+
return new ClockNetworkState(i.getTotalTicks(), i.getPartialTick(), paused ? 0.0F : i.getRate());
70+
}
71+
72+
public void tickFromLevel(RuntimeLevel level) {
73+
this.tick();
74+
}
75+
}

src/main/java/xyz/nucleoid/fantasy/RuntimeLevel.java

Lines changed: 26 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -1,90 +1,46 @@
11
package xyz.nucleoid.fantasy;
22

33
import com.google.common.collect.ImmutableList;
4-
import net.minecraft.core.Holder;
5-
import net.minecraft.core.Registry;
6-
import net.minecraft.core.registries.Registries;
74
import net.minecraft.resources.ResourceKey;
85
import net.minecraft.server.MinecraftServer;
96
import net.minecraft.server.level.ServerLevel;
107
import net.minecraft.util.ProgressListener;
118
import net.minecraft.util.Util;
12-
import net.minecraft.util.profiling.Profiler;
13-
import net.minecraft.world.clock.WorldClock;
9+
import net.minecraft.world.clock.ServerClockManager;
1410
import net.minecraft.world.level.CustomSpawner;
1511
import net.minecraft.world.level.Level;
1612
import net.minecraft.world.level.biome.BiomeManager;
17-
import net.minecraft.world.level.dimension.DimensionType;
1813
import net.minecraft.world.level.dimension.LevelStem;
1914
import net.minecraft.world.level.gamerules.GameRules;
2015
import net.minecraft.world.level.storage.LevelStorageSource;
2116
import net.minecraft.world.level.storage.ServerLevelData;
22-
import net.minecraft.world.timeline.Timeline;
23-
import org.jetbrains.annotations.ApiStatus;
2417
import org.jetbrains.annotations.Nullable;
2518
import xyz.nucleoid.fantasy.mixin.MinecraftServerAccess;
2619

2720
import java.util.List;
2821
import java.util.concurrent.Executor;
2922

30-
import static xyz.nucleoid.fantasy.RuntimeServerClockManager.*;
31-
3223
public class RuntimeLevel extends ServerLevel {
3324
final Style style;
3425
private boolean flat;
3526
@Nullable
36-
private GameRules rules;
37-
@ApiStatus.Internal
38-
public final Holder<WorldClock> worldClock;
39-
@ApiStatus.Internal
40-
public final Holder<Timeline> timeline;
27+
private final GameRules rules;
28+
@Nullable
29+
private final ServerClockManager clockManager;
4130

4231
protected RuntimeLevel(MinecraftServer server, ResourceKey<Level> dimension, RuntimeLevelConfig config, Style style) {
43-
Registry<WorldClock> worldClockRegistry = server.registryAccess()
44-
.lookupOrThrow(Registries.WORLD_CLOCK);
45-
Registry<Timeline> timelineRegistry = server.registryAccess()
46-
.lookupOrThrow(Registries.TIMELINE);
47-
Holder<WorldClock> worldClock;
48-
Holder<Timeline> timeline;
49-
50-
try (var _ = RemoveFromRegistry.thaw(worldClockRegistry); var _ = RemoveFromRegistry.thaw(timelineRegistry)) {
51-
if (worldClockRegistry.containsKey(dimension.identifier())) {
52-
worldClock = worldClockRegistry.getOrThrow(ResourceKey.create(Registries.WORLD_CLOCK, dimension.identifier()));
53-
} else {
54-
worldClock = Registry.registerForHolder(
55-
worldClockRegistry,
56-
dimension.identifier(),
57-
new WorldClock()
58-
);
59-
}
60-
61-
if (timelineRegistry.containsKey(dimension.identifier())) {
62-
timeline = timelineRegistry.getOrThrow(ResourceKey.create(Registries.TIMELINE, dimension.identifier()));
63-
} else {
64-
timeline = Registry.registerForHolder(
65-
timelineRegistry,
66-
dimension.identifier(),
67-
RuntimeServerClockManager.createDefaultTimeline(timelineRegistry, worldClock)
68-
);
69-
}
32+
LevelStem dimensionOptions = config.createDimensionOptions(server);
33+
GameRules gameRules = null;
34+
if (!config.shouldMirrorOverworldGameRules()) {
35+
gameRules = new GameRules(server.getWorldData().enabledFeatures());
36+
config.getGameRules().applyTo(gameRules, null);
37+
} else {
38+
gameRules = null;
7039
}
7140

72-
LevelStem dimensionOptions = config.createDimensionOptions(server);
73-
DimensionType dimensionType = dimensionOptions.type().value();
74-
WORLD_CLOCKS.add(worldClock);
75-
DIMENSION_TYPE_2_WORLD_CLOCKS.put(dimensionType, worldClock);
76-
WORLD_CLOCKS_2_LEVEL.put(worldClock, dimension);
77-
@SuppressWarnings("unchecked") // Always the same, correct type
78-
Holder<Timeline>[] timelines = dimensionType.timelines().stream()
79-
.map(holder -> {
80-
if (holder.is(Fantasy.DEFAULT_TIMELINE)) {
81-
return timeline;
82-
} else {
83-
return holder;
84-
}
85-
})
86-
.toArray(Holder[]::new);
87-
DIMENSION_TYPE_2_TIMELINES.put(dimensionType, timelines);
41+
this.clockManager = config.getClockManager(server, gameRules != null ? gameRules : server.getGameRules());
42+
this.style = style;
43+
8844
super(
8945
server, Util.backgroundExecutor(), ((MinecraftServerAccess) server).getStorageSource(),
9046
new RuntimeLevelData(server.getWorldData(), config),
@@ -95,29 +51,17 @@ protected RuntimeLevel(MinecraftServer server, ResourceKey<Level> dimension, Run
9551
ImmutableList.of(),
9652
config.shouldTickTime()
9753
);
98-
this.style = style;
9954
this.flat = config.isFlat().orElse(super.isFlat());
100-
this.worldClock = worldClock;
101-
this.timeline = timeline;
102-
this.clockManager().registerClock(
103-
this.worldClock,
104-
this.timeline,
105-
this.style.equals(Style.TEMPORARY)
106-
);
107-
this.clockManager().unloadedClocks.remove(this.worldClock);
108-
this.getRuntimeLevelData().setGameTime(this.clockManager().getTotalTicks(this.worldClock) % this.timeline.value().periodTicks().orElse(24000));
109-
110-
if (!config.shouldMirrorOverworldGameRules()) {
111-
this.rules = new GameRules(server.getWorldData().enabledFeatures());
112-
config.getGameRules().applyTo(this.rules, null);
113-
}
55+
this.rules = gameRules;
11456
}
11557

116-
protected RuntimeLevel(MinecraftServer server, Executor executor, LevelStorageSource.LevelStorageAccess levelStorage, ServerLevelData levelData, ResourceKey<Level> dimension, LevelStem levelStem, boolean isDebug, long biomeZoomSeed, List<CustomSpawner> customSpawners, boolean tickTime, Style style, Holder<WorldClock> worldClock, Holder<Timeline> timeline) {
117-
super(server, executor, levelStorage, levelData, dimension, levelStem, isDebug, biomeZoomSeed, customSpawners, tickTime);
58+
protected RuntimeLevel(MinecraftServer server, Executor executor, LevelStorageSource.LevelStorageAccess levelStorage, ServerLevelData levelData, ResourceKey<Level> dimension,
59+
LevelStem levelStem, boolean isDebug, long biomeZoomSeed, List<CustomSpawner> customSpawners, boolean tickTime, Style style,
60+
@Nullable GameRules gameRules, @Nullable ServerClockManager clockManager) {
11861
this.style = style;
119-
this.worldClock = worldClock;
120-
this.timeline = timeline;
62+
this.rules = gameRules;
63+
this.clockManager = clockManager;
64+
super(server, executor, levelStorage, levelData, dimension, levelStem, isDebug, biomeZoomSeed, customSpawners, tickTime);
12165
}
12266

12367
@Override
@@ -135,12 +79,9 @@ public long getSeed() {
13579

13680
@Override
13781
protected void tickTime() {
138-
if (this.tickTime) {
139-
long time = this.getRuntimeLevelData().getGameTime() + 1L;
140-
this.getRuntimeLevelData().setGameTime(time);
141-
Profiler.get().push("scheduledFunctions");
142-
this.getServer().getScheduledEvents().tick(this.getServer(), time);
143-
Profiler.get().pop();
82+
this.getRuntimeLevelData().setGameTime(this.getServer().overworld().getGameTime());
83+
if (this.tickTime && this.clockManager instanceof RuntimeClockManager clockManager) {
84+
clockManager.tickFromLevel(this);
14485
}
14586
}
14687

@@ -161,8 +102,8 @@ private RuntimeLevelData getRuntimeLevelData() {
161102
}
162103

163104
@Override
164-
public RuntimeServerClockManager clockManager() {
165-
return ((MinecraftServerExtension) this.getServer()).fantasy$clockManager();
105+
public ServerClockManager clockManager() {
106+
return this.clockManager != null ? this.clockManager : super.clockManager();
166107
}
167108

168109
public enum Style {

0 commit comments

Comments
 (0)