Fixes #4747: The chunk unload event was triggering before the chunk was actually saved to disk, which means disconnecting grid connections at that point led to grid nodes not saving their data to the chunk.

This commit is contained in:
Sebastian Hartte
2020-09-19 16:54:30 +02:00
parent 4aa9c92a68
commit f2427ee347
2 changed files with 69 additions and 19 deletions
@@ -20,7 +20,6 @@ package appeng.tile;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -31,7 +30,6 @@ import javax.annotation.Nullable;
import io.netty.buffer.Unpooled;
import net.fabricmc.fabric.api.block.entity.BlockEntityClientSerializable;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerChunkEvents;
import net.fabricmc.fabric.api.rendering.data.v1.RenderAttachmentBlockEntity;
import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntity;
@@ -69,24 +67,8 @@ import appeng.util.SettingsFrom;
public class AEBaseBlockEntity extends BlockEntity implements IOrientable, ICommonTile, ICustomNameObject,
BlockEntityClientSerializable, RenderAttachmentBlockEntity, AttributeProvider {
// FIXME: should probably remove at start of next server tick!
static {
ServerChunkEvents.CHUNK_UNLOAD.register((serverWorld, worldChunk) -> {
List<AEBaseBlockEntity> entitiesToRemove = null;
for (BlockEntity value : worldChunk.getBlockEntities().values()) {
if (value instanceof AEBaseBlockEntity) {
if (entitiesToRemove == null) {
entitiesToRemove = new ArrayList<>();
}
entitiesToRemove.add((AEBaseBlockEntity) value);
}
}
if (entitiesToRemove != null) {
for (AEBaseBlockEntity blockEntity : entitiesToRemove) {
blockEntity.onChunkUnloaded();
}
}
});
DeferredTileEntityUnloader.register();
}
protected void onChunkUnloaded() {
@@ -0,0 +1,68 @@
/*
* This file is part of Applied Energistics 2.
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
*
* Applied Energistics 2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Applied Energistics 2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
*/
package appeng.tile;
import appeng.hooks.TickHandler;
import appeng.util.IWorldCallable;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerChunkEvents;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.world.World;
import java.util.ArrayList;
import java.util.List;
/**
* We need to defer actually unloading tile entities until the end of the tick,
* after the chunk has been saved to disk. The CHUNK_UNLOAD event runs before
* the chunk has been saved, and if we disconnect nodes at that point, the saved
* data will be missing information from the node (such as the player id).
*/
class DeferredTileEntityUnloader implements IWorldCallable<Void> {
public static void register() {
ServerChunkEvents.CHUNK_UNLOAD.register((serverWorld, worldChunk) -> {
List<AEBaseBlockEntity> entitiesToRemove = null;
for (BlockEntity value : worldChunk.getBlockEntities().values()) {
if (value instanceof AEBaseBlockEntity) {
if (entitiesToRemove == null) {
entitiesToRemove = new ArrayList<>();
}
entitiesToRemove.add((AEBaseBlockEntity) value);
}
}
if (entitiesToRemove != null) {
TickHandler.instance().addCallable(serverWorld, new DeferredTileEntityUnloader(entitiesToRemove));
}
});
}
private final List<AEBaseBlockEntity> entitiesToRemove;
public DeferredTileEntityUnloader(List<AEBaseBlockEntity> entitiesToRemove) {
this.entitiesToRemove = entitiesToRemove;
}
@Override
public Void call(World world) {
for (AEBaseBlockEntity blockEntity : entitiesToRemove) {
blockEntity.onChunkUnloaded();
}
return null;
}
}