Skip to content

Commit fc93d28

Browse files
committed
Next steps in chunkloading code
1 parent 4e8befb commit fc93d28

File tree

8 files changed

+213
-79
lines changed

8 files changed

+213
-79
lines changed

src/main/java/dev/compactmods/machines/CompactMachines.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import dev.compactmods.machines.config.EnableVanillaRecipesConfigCondition;
55
import dev.compactmods.machines.config.ServerConfig;
66
import dev.compactmods.machines.core.Registration;
7+
import dev.compactmods.machines.rooms.chunkloading.CMRoomChunkloadingManager;
78
import net.minecraft.item.ItemGroup;
89
import net.minecraft.item.ItemStack;
910
import net.minecraftforge.common.crafting.CraftingHelper;
@@ -29,6 +30,8 @@ public ItemStack makeIcon() {
2930
}
3031
};
3132

33+
public static CMRoomChunkloadingManager CHUNKLOAD_MANAGER;
34+
3235
public CompactMachines() {
3336
// Register blocks and items
3437
Registration.init();

src/main/java/dev/compactmods/machines/block/tiles/CompactMachineTile.java

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import java.util.Optional;
77
import java.util.Set;
88
import java.util.UUID;
9+
import dev.compactmods.machines.CompactMachines;
910
import dev.compactmods.machines.api.tunnels.ICapableTunnel;
1011
import dev.compactmods.machines.api.tunnels.TunnelDefinition;
1112
import dev.compactmods.machines.config.ServerConfig;
@@ -26,13 +27,15 @@
2627
import net.minecraft.tileentity.ITickableTileEntity;
2728
import net.minecraft.tileentity.TileEntity;
2829
import net.minecraft.util.Direction;
30+
import net.minecraft.util.concurrent.TickDelayedTask;
2931
import net.minecraft.util.math.BlockPos;
3032
import net.minecraft.util.math.ChunkPos;
3133
import net.minecraft.world.server.ServerWorld;
3234
import net.minecraftforge.common.capabilities.Capability;
3335
import net.minecraftforge.common.capabilities.ICapabilityProvider;
3436
import net.minecraftforge.common.util.Constants;
3537
import net.minecraftforge.common.util.LazyOptional;
38+
import net.minecraftforge.common.world.ForgeChunkManager;
3639

3740
public class CompactMachineTile extends TileEntity implements ICapabilityProvider, ITickableTileEntity {
3841
public int machineId = -1;
@@ -54,25 +57,37 @@ public CompactMachineTile() {
5457
@Override
5558
public void clearRemoved() {
5659
super.clearRemoved();
60+
}
5761

58-
if (ServerConfig.MACHINE_CHUNKLOADING.get())
59-
doChunkload(true);
62+
@Override
63+
public void onLoad() {
64+
super.onLoad();
65+
66+
if(level == null || level.isClientSide)
67+
return;
68+
69+
if (ServerConfig.MACHINE_CHUNKLOADING.get()) {
70+
final MinecraftServer server = ((ServerWorld) level).getServer();
71+
server.submitAsync(new TickDelayedTask(server.getTickCount() + 5, () -> {
72+
CompactMachines.CHUNKLOAD_MANAGER.onMachineChunkLoad(machineId);
73+
}));
74+
}
6075
}
6176

6277
@Override
6378
public void onChunkUnloaded() {
6479
super.onChunkUnloaded();
6580

6681
if (ServerConfig.MACHINE_CHUNKLOADING.get())
67-
doChunkload(false);
82+
CompactMachines.CHUNKLOAD_MANAGER.onMachineChunkUnload(machineId);
6883
}
6984

7085
@Override
7186
public void setRemoved() {
7287
super.setRemoved();
7388

7489
if (ServerConfig.MACHINE_CHUNKLOADING.get())
75-
doChunkload(false);
90+
CompactMachines.CHUNKLOAD_MANAGER.onMachineChunkUnload(machineId);
7691
}
7792

7893
@Override
@@ -275,17 +290,6 @@ public boolean hasPlayersInside() {
275290
// .orElse(false);
276291
}
277292

278-
protected void doChunkload(boolean force) {
279-
if (level == null || level.isClientSide)
280-
return;
281-
282-
getInternalChunkPos().ifPresent(chunk -> {
283-
ServerWorld compact = this.level.getServer().getLevel(Registration.COMPACT_DIMENSION);
284-
compact.setChunkForced(chunk.x, chunk.z, force);
285-
286-
});
287-
}
288-
289293
public void doPostPlaced() {
290294
if (this.level == null || this.level.isClientSide)
291295
return;
@@ -302,7 +306,8 @@ public void doPostPlaced() {
302306
CompactMachineData extern = CompactMachineData.get(serv);
303307
extern.setMachineLocation(this.machineId, dp);
304308

305-
doChunkload(true);
309+
if(ServerConfig.MACHINE_CHUNKLOADING.get())
310+
CompactMachines.CHUNKLOAD_MANAGER.onMachineChunkLoad(machineId);
306311
}
307312

308313
public void handlePlayerLeft(UUID playerID) {

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import dev.compactmods.machines.CompactMachines;
44
import dev.compactmods.machines.command.CMCommandRoot;
5+
import dev.compactmods.machines.rooms.chunkloading.CMRoomChunkloadingManager;
56
import net.minecraft.server.MinecraftServer;
67
import net.minecraftforge.event.RegisterCommandsEvent;
78
import net.minecraftforge.eventbus.api.SubscribeEvent;
@@ -14,6 +15,8 @@ public class ServerEventHandler {
1415
@SubscribeEvent
1516
public static void onServerStarting(final FMLServerStartingEvent evt) {
1617
MinecraftServer server = evt.getServer();
18+
19+
CompactMachines.CHUNKLOAD_MANAGER = new CMRoomChunkloadingManager(server);
1720
// SavedMachineDataMigrator.migrate(server);
1821
}
1922

src/main/java/dev/compactmods/machines/data/player/theory.txt

Lines changed: 0 additions & 60 deletions
This file was deleted.
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
package dev.compactmods.machines.rooms.chunkloading;
2+
3+
import java.util.*;
4+
import com.google.common.collect.ImmutableList;
5+
import dev.compactmods.machines.CompactMachines;
6+
import dev.compactmods.machines.core.Registration;
7+
import dev.compactmods.machines.data.graph.CompactMachineConnectionGraph;
8+
import dev.compactmods.machines.data.persistent.CompactMachineData;
9+
import dev.compactmods.machines.data.persistent.MachineConnections;
10+
import dev.compactmods.machines.teleportation.DimensionalPosition;
11+
import net.minecraft.server.MinecraftServer;
12+
import net.minecraft.util.math.ChunkPos;
13+
import net.minecraft.world.Dimension;
14+
import net.minecraft.world.server.ServerWorld;
15+
import net.minecraftforge.common.world.ForgeChunkManager;
16+
17+
public class CMRoomChunkloadingManager implements IRoomChunkloadingManager {
18+
19+
private final MinecraftServer server;
20+
private final Map<ChunkPos, UUID> tickets;
21+
22+
// TODO - Finish and serialize data
23+
// see ForcedChunksSaveData
24+
25+
public CMRoomChunkloadingManager(MinecraftServer server) {
26+
this.server = server;
27+
this.tickets = new HashMap<>();
28+
}
29+
30+
@Override
31+
public boolean roomIsLoaded(ChunkPos room) {
32+
return tickets.containsKey(room);
33+
}
34+
35+
@Override
36+
public boolean hasAnyMachinesLoaded() {
37+
return !tickets.isEmpty();
38+
}
39+
40+
@Override
41+
public void onMachineChunkUnload(int machine) {
42+
final Optional<ChunkPos> attachedRoom = getConnectedRoom(machine);
43+
attachedRoom.ifPresent(room -> {
44+
final Collection<Integer> machines = getConnectedMachines(room);
45+
switch (machines.size()) {
46+
case 0:
47+
case 1:
48+
// No siblings or this is the only machine connected - unload the room
49+
setChunkForced(room, false);
50+
break;
51+
52+
default:
53+
// More than one machine attached to the room
54+
// Need to see if any other machine is still loaded before decision
55+
final CompactMachineData machData = CompactMachineData.get(server);
56+
if (machData == null) {
57+
// ohshi-
58+
return;
59+
}
60+
61+
// true if any connected machine is loaded; false otherwise
62+
boolean anyRoomMachineLoaded = machines.stream()
63+
.map(machData::getMachineLocation)
64+
.anyMatch(machLocation -> machLocation.map(d -> d.isLoaded(server)).orElse(false));
65+
66+
if(!anyRoomMachineLoaded) {
67+
setChunkForced(room, false);
68+
}
69+
break;
70+
}
71+
});
72+
}
73+
74+
@Override
75+
public void onMachineChunkLoad(int machine) {
76+
final Optional<ChunkPos> attachedRoom = getConnectedRoom(machine);
77+
attachedRoom.ifPresent(room -> {
78+
// If there's already a ticket for the room, early exit - another machine has it loaded
79+
if (tickets.containsKey(room))
80+
return;
81+
82+
setChunkForced(room, true);
83+
});
84+
}
85+
86+
private Optional<CompactMachineConnectionGraph> getGraph() {
87+
final MachineConnections conns = MachineConnections.get(server);
88+
if (conns == null)
89+
return Optional.empty();
90+
91+
return Optional.of(conns.graph);
92+
}
93+
94+
private Optional<ChunkPos> getConnectedRoom(int machine) {
95+
return getGraph().flatMap(graph -> graph.getConnectedRoom(machine));
96+
}
97+
98+
99+
private Collection<Integer> getConnectedMachines(ChunkPos room) {
100+
return getGraph().map(graph -> graph.getMachinesFor(room))
101+
.map(connectedMachines -> {
102+
switch (connectedMachines.size()) {
103+
case 0:
104+
case 1:
105+
// release ticket
106+
return Collections.<Integer>emptySet();
107+
108+
default:
109+
// scan connected machines, if at least one is loaded then do not release
110+
return ImmutableList.copyOf(connectedMachines);
111+
}
112+
}).orElse(Collections.emptySet());
113+
}
114+
115+
private Collection<Integer> getRoomConnectedMachines(int machine) {
116+
final CompactMachineConnectionGraph graph = getGraph().orElse(null);
117+
if (graph == null)
118+
return Collections.emptySet();
119+
120+
return getConnectedRoom(machine)
121+
.map(this::getConnectedMachines)
122+
.orElse(Collections.emptySet());
123+
}
124+
125+
private void setChunkForced(ChunkPos room, boolean force) {
126+
// If trying to force and room was not previously set up
127+
if (force && !tickets.containsKey(room)) {
128+
UUID newTicket = UUID.randomUUID();
129+
tickets.put(room, newTicket);
130+
}
131+
132+
UUID ticket = tickets.get(room);
133+
134+
ServerWorld compact = server.getLevel(Registration.COMPACT_DIMENSION);
135+
136+
if (compact != null) {
137+
boolean alreadyForced = compact.getForcedChunks().stream()
138+
.anyMatch(chunkLong -> chunkLong.equals(room.toLong()));
139+
140+
// if force status requires change
141+
if(alreadyForced != force) {
142+
// prevent deadlock?
143+
compact.getChunk(room.x, room.z);
144+
145+
boolean changed = ForgeChunkManager.forceChunk(compact, CompactMachines.MOD_ID,
146+
ticket, room.x, room.z, force, true);
147+
148+
if (!force && changed) {
149+
tickets.remove(room);
150+
}
151+
}
152+
}
153+
154+
}
155+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package dev.compactmods.machines.rooms.chunkloading;
2+
3+
import net.minecraft.server.MinecraftServer;
4+
import net.minecraft.util.math.ChunkPos;
5+
6+
public interface IRoomChunkloadingManager {
7+
8+
boolean roomIsLoaded(ChunkPos room);
9+
10+
boolean hasAnyMachinesLoaded();
11+
12+
void onMachineChunkUnload(int machine);
13+
14+
void onMachineChunkLoad(int machine);
15+
}

0 commit comments

Comments
 (0)