Skip to content

Commit 07a4fee

Browse files
authored
Fix unloaded postbox voiding packages (#8553)
There seems to be an area of chunks where `Level.isLoaded` returns `false`, but `PostboxBlockEntity.onChunkUnloaded` has not yet been called. Any trains delivering to that area will use the offline buffer, but when the block entity is eventually unloaded, it will overwrite the delivered packages with an older version of the inventory, causing them to be lost. I made the following changes to fix this: - Sync the offline buffer whenever the inventory changes, rather than in `onChunkUnloaded`. - Fix `StationBlockEntity.attachPackagePort` incorrectly replacing `GlobalPackagePort` instances with new ones, resetting their data. - During mail transfer, get the `Level` from `ServerLifecycleHooks` rather than `CarriageContraptionEntity`: this ensures a loaded postbox will always be discovered, regardless of whether the train itself is loaded. Fixes #7491
1 parent 5f9289f commit 07a4fee

File tree

6 files changed

+84
-51
lines changed

6 files changed

+84
-51
lines changed

src/main/java/com/simibubi/create/content/logistics/packagePort/postbox/PostboxBlockEntity.java

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
import com.simibubi.create.compat.computercraft.AbstractComputerBehaviour;
99
import com.simibubi.create.compat.computercraft.ComputerCraftProxy;
1010
import com.simibubi.create.content.logistics.packagePort.PackagePortBlockEntity;
11+
import com.simibubi.create.content.trains.station.GlobalPackagePort;
1112
import com.simibubi.create.content.trains.station.GlobalStation;
12-
import com.simibubi.create.content.trains.station.GlobalStation.GlobalPackagePort;
1313

1414
import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour;
1515

@@ -117,29 +117,29 @@ protected void read(CompoundTag tag, boolean clientPacket) {
117117
}
118118

119119
@Override
120-
public void onChunkUnloaded() {
120+
public void setChanged() {
121+
saveOfflineBuffer();
122+
super.setChanged();
123+
}
124+
125+
private void saveOfflineBuffer() {
121126
if (level == null || level.isClientSide)
122127
return;
128+
123129
GlobalStation station = trackedGlobalStation.get();
124130
if (station == null)
125131
return;
126-
if (!station.connectedPorts.containsKey(worldPosition))
127-
return;
132+
128133
GlobalPackagePort globalPackagePort = station.connectedPorts.get(worldPosition);
129-
for (int i = 0; i < inventory.getSlots(); i++) {
130-
globalPackagePort.offlineBuffer.setStackInSlot(i, inventory.getStackInSlot(i));
131-
inventory.setStackInSlot(i, ItemStack.EMPTY);
132-
}
134+
if (globalPackagePort == null)
135+
return;
133136

134-
globalPackagePort.primed = true;
135-
Create.RAILWAYS.markTracksDirty();
136-
super.onChunkUnloaded();
137+
globalPackagePort.saveOfflineBuffer(inventory);
137138
}
138139

139140
@Override
140141
public void invalidateCaps() {
141142
super.invalidate();
142143
computerBehaviour.removePeripheral();
143144
}
144-
145145
}

src/main/java/com/simibubi/create/content/trains/schedule/destination/DeliverPackagesInstruction.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
import com.simibubi.create.content.trains.graph.EdgePointType;
1717
import com.simibubi.create.content.trains.schedule.ScheduleRuntime;
1818
import com.simibubi.create.content.trains.schedule.ScheduleRuntime.State;
19+
import com.simibubi.create.content.trains.station.GlobalPackagePort;
1920
import com.simibubi.create.content.trains.station.GlobalStation;
20-
import com.simibubi.create.content.trains.station.GlobalStation.GlobalPackagePort;
2121
import com.simibubi.create.foundation.utility.CreateLang;
2222

2323
import net.createmod.catnip.data.Pair;

src/main/java/com/simibubi/create/content/trains/schedule/destination/FetchPackagesInstruction.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717
import com.simibubi.create.content.trains.graph.EdgePointType;
1818
import com.simibubi.create.content.trains.schedule.ScheduleRuntime;
1919
import com.simibubi.create.content.trains.schedule.ScheduleRuntime.State;
20+
import com.simibubi.create.content.trains.station.GlobalPackagePort;
2021
import com.simibubi.create.content.trains.station.GlobalStation;
21-
import com.simibubi.create.content.trains.station.GlobalStation.GlobalPackagePort;
2222
import com.simibubi.create.foundation.utility.CreateLang;
2323

2424
import net.createmod.catnip.data.Glob;
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package com.simibubi.create.content.trains.station;
2+
3+
import com.simibubi.create.Create;
4+
5+
import net.minecraftforge.items.IItemHandlerModifiable;
6+
import net.minecraftforge.items.ItemStackHandler;
7+
8+
public class GlobalPackagePort {
9+
public String address = "";
10+
public ItemStackHandler offlineBuffer = new ItemStackHandler(18);
11+
public boolean primed = false;
12+
private boolean restoring = false;
13+
14+
public void restoreOfflineBuffer(IItemHandlerModifiable inventory) {
15+
if (!primed) return;
16+
17+
restoring = true;
18+
19+
for (int slot = 0; slot < offlineBuffer.getSlots(); slot++) {
20+
inventory.setStackInSlot(slot, offlineBuffer.getStackInSlot(slot));
21+
}
22+
23+
restoring = false;
24+
primed = false;
25+
}
26+
27+
public void saveOfflineBuffer(IItemHandlerModifiable inventory) {
28+
/*
29+
* Each time restoreOfflineBuffer changes a slot, the inventory
30+
* calls this method. We must filter out those calls to prevent
31+
* overwriting later slots which haven't been restored yet, and
32+
* to avoid unnecessary work.
33+
*/
34+
if (restoring) return;
35+
36+
// TODO: Call save method on individual slots rather than iterating
37+
for (int slot = 0; slot < inventory.getSlots(); slot++) {
38+
offlineBuffer.setStackInSlot(slot, inventory.getStackInSlot(slot));
39+
}
40+
41+
Create.RAILWAYS.markTracksDirty();
42+
}
43+
}

src/main/java/com/simibubi/create/content/trains/station/GlobalStation.java

Lines changed: 19 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
import com.simibubi.create.content.logistics.box.PackageItem;
1212
import com.simibubi.create.content.logistics.packagePort.postbox.PostboxBlockEntity;
1313
import com.simibubi.create.content.trains.entity.Carriage;
14-
import com.simibubi.create.content.trains.entity.CarriageContraptionEntity;
1514
import com.simibubi.create.content.trains.entity.Train;
1615
import com.simibubi.create.content.trains.graph.DimensionPalette;
1716
import com.simibubi.create.content.trains.graph.TrackNode;
@@ -24,7 +23,7 @@
2423
import net.minecraft.nbt.NbtUtils;
2524
import net.minecraft.nbt.Tag;
2625
import net.minecraft.network.FriendlyByteBuf;
27-
import net.minecraft.server.level.ServerLevel;
26+
import net.minecraft.server.MinecraftServer;
2827
import net.minecraft.world.item.ItemStack;
2928
import net.minecraft.world.level.Level;
3029
import net.minecraft.world.level.block.entity.BlockEntity;
@@ -33,7 +32,7 @@
3332
import net.minecraftforge.items.IItemHandler;
3433
import net.minecraftforge.items.IItemHandlerModifiable;
3534
import net.minecraftforge.items.ItemHandlerHelper;
36-
import net.minecraftforge.items.ItemStackHandler;
35+
import net.minecraftforge.server.ServerLifecycleHooks;
3736

3837
public class GlobalStation extends SingleBlockEntityEdgePoint {
3938

@@ -162,27 +161,15 @@ public Train getNearestTrain() {
162161
return this.nearestTrain.get();
163162
}
164163

165-
// Package Port integration
166-
public static class GlobalPackagePort {
167-
public String address = "";
168-
public ItemStackHandler offlineBuffer = new ItemStackHandler(18);
169-
public boolean primed = false;
170-
}
171-
172164
public void runMailTransfer() {
173165
Train train = getPresentTrain();
174166
if (train == null || connectedPorts.isEmpty())
175167
return;
176-
Level level = null;
177168

178-
for (Carriage carriage : train.carriages) {
179-
if (level == null) {
180-
CarriageContraptionEntity entity = carriage.anyAvailableEntity();
181-
if (entity != null && entity.level() instanceof ServerLevel sl)
182-
level = sl.getServer()
183-
.getLevel(getBlockEntityDimension());
184-
}
169+
MinecraftServer server = ServerLifecycleHooks.getCurrentServer();
170+
Level level = server.getLevel(getBlockEntityDimension());
185171

172+
for (Carriage carriage : train.carriages) {
186173
IItemHandlerModifiable carriageInventory = carriage.storage.getAllItems();
187174
if (carriageInventory == null)
188175
continue;
@@ -212,9 +199,14 @@ public void runMailTransfer() {
212199
continue;
213200

214201
postboxInventory.setStackInSlot(slot, ItemStack.EMPTY);
215-
Create.RAILWAYS.markTracksDirty();
216-
if (box != null)
202+
203+
if (box == null) {
204+
port.primed = true;
205+
} else {
217206
box.spawnParticles();
207+
}
208+
209+
Create.RAILWAYS.markTracksDirty();
218210
}
219211
}
220212

@@ -243,10 +235,15 @@ public void runMailTransfer() {
243235
if (!result.isEmpty())
244236
continue;
245237

246-
Create.RAILWAYS.markTracksDirty();
247238
carriageInventory.setStackInSlot(slot, ItemStack.EMPTY);
248-
if (box != null)
239+
240+
if (box == null) {
241+
port.primed = true;
242+
} else {
249243
box.spawnParticles();
244+
}
245+
246+
Create.RAILWAYS.markTracksDirty();
250247

251248
break;
252249
}

src/main/java/com/simibubi/create/content/trains/station/StationBlockEntity.java

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
import com.simibubi.create.content.trains.graph.TrackNodeLocation.DiscoveredLocation;
5151
import com.simibubi.create.content.trains.schedule.Schedule;
5252
import com.simibubi.create.content.trains.schedule.ScheduleItem;
53-
import com.simibubi.create.content.trains.station.GlobalStation.GlobalPackagePort;
53+
import com.simibubi.create.content.trains.station.GlobalPackagePort;
5454
import com.simibubi.create.content.trains.track.ITrackBlock;
5555
import com.simibubi.create.content.trains.track.TrackTargetingBehaviour;
5656
import com.simibubi.create.foundation.advancement.AllAdvancements;
@@ -985,22 +985,15 @@ public void attachPackagePort(PackagePortBlockEntity ppbe) {
985985
if (ppbe instanceof PostboxBlockEntity pbe)
986986
pbe.trackedGlobalStation = new WeakReference<>(station);
987987

988-
if (station.connectedPorts.containsKey(ppbe.getBlockPos()))
989-
restoreOfflineBuffer(ppbe, station.connectedPorts.get(ppbe.getBlockPos()));
988+
GlobalPackagePort globalPackagePort = station.connectedPorts.get(ppbe.getBlockPos());
990989

991-
GlobalPackagePort globalPackagePort = new GlobalPackagePort();
992-
globalPackagePort.address = ppbe.addressFilter;
993-
station.connectedPorts.put(ppbe.getBlockPos(), globalPackagePort);
994-
}
995-
996-
private void restoreOfflineBuffer(PackagePortBlockEntity ppbe, GlobalPackagePort globalPackagePort) {
997-
if (!globalPackagePort.primed)
998-
return;
999-
for (int i = 0; i < globalPackagePort.offlineBuffer.getSlots(); i++) {
1000-
ppbe.inventory.setStackInSlot(i, globalPackagePort.offlineBuffer.getStackInSlot(i));
1001-
globalPackagePort.offlineBuffer.setStackInSlot(i, ItemStack.EMPTY);
990+
if (globalPackagePort == null) {
991+
globalPackagePort = new GlobalPackagePort();
992+
globalPackagePort.address = ppbe.addressFilter;
993+
station.connectedPorts.put(ppbe.getBlockPos(), globalPackagePort);
994+
} else {
995+
globalPackagePort.restoreOfflineBuffer(ppbe.inventory);
1002996
}
1003-
globalPackagePort.primed = false;
1004997
}
1005998

1006999
public void removePackagePort(PackagePortBlockEntity ppbe) {

0 commit comments

Comments
 (0)