Fixed cases where Refined Storage unwillingly acts like a chunkloader.

This commit is contained in:
raoulvdberge
2020-07-17 02:58:43 +02:00
parent b0200f457c
commit e78cadec2a
18 changed files with 102 additions and 27 deletions

View File

@@ -2,6 +2,7 @@
### 1.9.2 ### 1.9.2
- Fixed crash with Forge version 67 (Darkere) - Fixed crash with Forge version 67 (Darkere)
- Fixed cases where Refined Storage unwillingly acts like a chunkloader (raoulvdberge)
- Networks that are in a chunk that isn't loaded will no longer work, they will turn off. Chunkload the Controller to maintain a functioning network over long distances (Darkere/raoulvdberge) - Networks that are in a chunk that isn't loaded will no longer work, they will turn off. Chunkload the Controller to maintain a functioning network over long distances (Darkere/raoulvdberge)
- Re-added interdimensional networks with the Network Transmitter and Network Receiver (raoulvdberge) - Re-added interdimensional networks with the Network Transmitter and Network Receiver (raoulvdberge)

View File

@@ -21,12 +21,12 @@ public interface IExternalStorageProvider<T> {
/** /**
* @param context the context of the external storage * @param context the context of the external storage
* @param tile the tile supplier * @param tile the tile
* @param direction the direction of the external storage * @param direction the direction of the external storage
* @return the external storage handler * @return the external storage handler
*/ */
@Nonnull @Nonnull
IExternalStorage<T> provide(IExternalStorageContext context, Supplier<TileEntity> tile, Direction direction); IExternalStorage<T> provide(IExternalStorageContext context, TileEntity tile, Direction direction);
/** /**
* Returns the priority of this external storage provider. * Returns the priority of this external storage provider.

View File

@@ -80,11 +80,13 @@ public class Network implements INetwork, IRedstoneConfigurable {
private ControllerBlock.EnergyType lastEnergyType = ControllerBlock.EnergyType.OFF; private ControllerBlock.EnergyType lastEnergyType = ControllerBlock.EnergyType.OFF;
private int lastEnergyUsage; private int lastEnergyUsage;
private RedstoneMode redstoneMode = RedstoneMode.IGNORE; private RedstoneMode redstoneMode = RedstoneMode.IGNORE;
private boolean redstonePowered = false;
private boolean amILoaded = false; private boolean amILoaded = false;
private boolean throttlingDisabled = true; // Will be enabled after first update private boolean throttlingDisabled = true; // Will be enabled after first update
private boolean couldRun; private boolean couldRun;
private int ticksSinceUpdateChanged; private int ticksSinceUpdateChanged;
private int ticks;
public Network(World world, BlockPos pos, NetworkType type) { public Network(World world, BlockPos pos, NetworkType type) {
this.pos = pos; this.pos = pos;
@@ -115,7 +117,11 @@ public class Network implements INetwork, IRedstoneConfigurable {
@Override @Override
public boolean canRun() { public boolean canRun() {
return amILoaded && energy.getEnergyStored() >= getEnergyUsage() && redstoneMode.isEnabled(world, pos); return amILoaded && energy.getEnergyStored() >= getEnergyUsage() && redstoneMode.isEnabled(redstonePowered);
}
public void setRedstonePowered(boolean redstonePowered) {
this.redstonePowered = redstonePowered;
} }
@Override @Override
@@ -136,6 +142,12 @@ public class Network implements INetwork, IRedstoneConfigurable {
@Override @Override
public void update() { public void update() {
if (!world.isRemote) { if (!world.isRemote) {
if (ticks == 0) {
redstonePowered = world.isBlockPowered(pos);
}
++ticks;
amILoaded = world.isBlockPresent(pos); amILoaded = world.isBlockPresent(pos);
updateEnergyUsage(); updateEnergyUsage();
@@ -498,7 +510,7 @@ public class Network implements INetwork, IRedstoneConfigurable {
} }
public ControllerBlock.EnergyType getEnergyType() { public ControllerBlock.EnergyType getEnergyType() {
if (!redstoneMode.isEnabled(world, pos)) { if (!redstoneMode.isEnabled(redstonePowered)) {
return ControllerBlock.EnergyType.OFF; return ControllerBlock.EnergyType.OFF;
} }
@@ -532,7 +544,7 @@ public class Network implements INetwork, IRedstoneConfigurable {
} }
private void updateEnergyUsage() { private void updateEnergyUsage() {
if (!redstoneMode.isEnabled(world, pos)) { if (!redstoneMode.isEnabled(redstonePowered)) {
this.lastEnergyUsage = 0; this.lastEnergyUsage = 0;
return; return;
} }

View File

@@ -77,7 +77,7 @@ public class ConstructorNetworkNode extends NetworkNode implements IComparable,
public void update() { public void update() {
super.update(); super.update();
if (canUpdate() && ticks % upgrades.getSpeed(BASE_SPEED, 4) == 0) { if (canUpdate() && ticks % upgrades.getSpeed(BASE_SPEED, 4) == 0 && world.isBlockPresent(pos)) {
if (type == IType.ITEMS && !itemFilters.getStackInSlot(0).isEmpty()) { if (type == IType.ITEMS && !itemFilters.getStackInSlot(0).isEmpty()) {
ItemStack stack = itemFilters.getStackInSlot(0); ItemStack stack = itemFilters.getStackInSlot(0);

View File

@@ -84,7 +84,7 @@ public class DestructorNetworkNode extends NetworkNode implements IComparable, I
public void update() { public void update() {
super.update(); super.update();
if (canUpdate() && ticks % upgrades.getSpeed(BASE_SPEED, 4) == 0) { if (canUpdate() && ticks % upgrades.getSpeed(BASE_SPEED, 4) == 0 && world.isBlockPresent(pos)) {
if (type == IType.ITEMS) { if (type == IType.ITEMS) {
if (pickupItem) { if (pickupItem) {
pickupItems(); pickupItems();

View File

@@ -61,7 +61,7 @@ public class DetectorNetworkNode extends NetworkNode implements IComparable, ITy
public void update() { public void update() {
super.update(); super.update();
if (powered != wasPowered) { if (powered != wasPowered && world.isBlockPresent(pos)) {
wasPowered = powered; wasPowered = powered;
world.setBlockState(pos, world.getBlockState(pos).with(DetectorBlock.POWERED, powered)); world.setBlockState(pos, world.getBlockState(pos).with(DetectorBlock.POWERED, powered));

View File

@@ -85,7 +85,7 @@ public class ExporterNetworkNode extends NetworkNode implements IComparable, ITy
public void update() { public void update() {
super.update(); super.update();
if (canUpdate() && ticks % upgrades.getSpeed() == 0) { if (canUpdate() && ticks % upgrades.getSpeed() == 0 && world.isBlockPresent(pos)) {
if (type == IType.ITEMS) { if (type == IType.ITEMS) {
IItemHandler handler = WorldUtils.getItemHandler(getFacingTile(), getDirection().getOpposite()); IItemHandler handler = WorldUtils.getItemHandler(getFacingTile(), getDirection().getOpposite());
@@ -236,7 +236,6 @@ public class ExporterNetworkNode extends NetworkNode implements IComparable, ITy
markDirty(); markDirty();
} }
@Override @Override
public ResourceLocation getId() { public ResourceLocation getId() {
return ID; return ID;

View File

@@ -85,7 +85,7 @@ public class ExternalStorageNetworkNode extends NetworkNode implements IStorageP
public void update() { public void update() {
super.update(); super.update();
if (canUpdate()) { if (canUpdate() && world.isBlockPresent(pos)) {
if (networkTicks++ == 0) { if (networkTicks++ == 0) {
updateStorage(network, InvalidateCause.INITIAL_TICK_INVALIDATION); updateStorage(network, InvalidateCause.INITIAL_TICK_INVALIDATION);
@@ -214,7 +214,7 @@ public class ExternalStorageNetworkNode extends NetworkNode implements IStorageP
if (type == IType.ITEMS) { if (type == IType.ITEMS) {
for (IExternalStorageProvider<ItemStack> provider : API.instance().getExternalStorageProviders(StorageType.ITEM)) { for (IExternalStorageProvider<ItemStack> provider : API.instance().getExternalStorageProviders(StorageType.ITEM)) {
if (provider.canProvide(facing, getDirection())) { if (provider.canProvide(facing, getDirection())) {
itemStorages.add(provider.provide(this, this::getFacingTile, getDirection())); itemStorages.add(provider.provide(this, getFacingTile(), getDirection()));
break; break;
} }
@@ -222,7 +222,7 @@ public class ExternalStorageNetworkNode extends NetworkNode implements IStorageP
} else if (type == IType.FLUIDS) { } else if (type == IType.FLUIDS) {
for (IExternalStorageProvider<FluidStack> provider : API.instance().getExternalStorageProviders(StorageType.FLUID)) { for (IExternalStorageProvider<FluidStack> provider : API.instance().getExternalStorageProviders(StorageType.FLUID)) {
if (provider.canProvide(facing, getDirection())) { if (provider.canProvide(facing, getDirection())) {
fluidStorages.add(provider.provide(this, this::getFacingTile, getDirection())); fluidStorages.add(provider.provide(this, getFacingTile(), getDirection()));
break; break;
} }

View File

@@ -250,7 +250,7 @@ public class FluidInterfaceNetworkNode extends NetworkNode {
} }
private void onTankOutChanged() { private void onTankOutChanged() {
if (!world.isRemote) { if (!world.isRemote && world.isBlockPresent(pos)) {
((FluidInterfaceTile) world.getTileEntity(pos)).getDataManager().sendParameterToWatchers(FluidInterfaceTile.TANK_OUT); ((FluidInterfaceTile) world.getTileEntity(pos)).getDataManager().sendParameterToWatchers(FluidInterfaceTile.TANK_OUT);
} }

View File

@@ -60,7 +60,7 @@ public class ImporterNetworkNode extends NetworkNode implements IComparable, IWh
public void update() { public void update() {
super.update(); super.update();
if (!canUpdate()) { if (!canUpdate() || !world.isBlockPresent(pos)) {
return; return;
} }

View File

@@ -30,10 +30,21 @@ public abstract class NetworkNode implements INetworkNode, INetworkNodeVisitor {
@Nullable @Nullable
protected INetwork network; protected INetwork network;
// @Volatile: Mental note. At this moment world instances are retained in Minecraft (since 1.16).
// This means that during the entire server lifetime, all worlds are present and will not change their instance.
// However, due to the memory footprint of worlds and modded minecraft having the tendency to have lots of worlds,
// Forge is planning to unload (aka remove) worlds so their instances will change.
// This is problematic as this attribute will target the wrong world in that case.
// Idea: possibly change to a getter based on RegistryKey<World>?
// Another note: this attribute isn't the *real* problem. Because network nodes are in WorldSavedData in a tick handler,
// new instances of network nodes will be created when the world refreshes (causing this field to be different too).
// However, network nodes in the network graph *AREN'T* recreated when the world refreshes, causing the graph to have the incorrect instance, and even worse,
// having multiple different instances of the same network node.
protected World world; protected World world;
protected BlockPos pos; protected BlockPos pos;
protected int ticks; protected int ticks;
protected RedstoneMode redstoneMode = RedstoneMode.IGNORE; protected RedstoneMode redstoneMode = RedstoneMode.IGNORE;
private boolean redstonePowered = false;
@Nullable @Nullable
protected UUID owner; protected UUID owner;
protected String version; protected String version;
@@ -102,7 +113,7 @@ public abstract class NetworkNode implements INetworkNode, INetworkNodeVisitor {
@Override @Override
public boolean isActive() { public boolean isActive() {
return redstoneMode.isEnabled(world, pos); return redstoneMode.isEnabled(redstonePowered);
} }
protected final boolean canUpdate() { protected final boolean canUpdate() {
@@ -121,8 +132,16 @@ public abstract class NetworkNode implements INetworkNode, INetworkNodeVisitor {
return 4; return 4;
} }
public void setRedstonePowered(boolean redstonePowered) {
this.redstonePowered = redstonePowered;
}
@Override @Override
public void update() { public void update() {
if (ticks == 0) {
redstonePowered = world.isBlockPowered(pos);
}
++ticks; ++ticks;
boolean canUpdate = canUpdate(); boolean canUpdate = canUpdate();

View File

@@ -20,8 +20,14 @@ public class FluidExternalStorageProvider implements IExternalStorageProvider<Fl
@Nonnull @Nonnull
@Override @Override
public IExternalStorage<FluidStack> provide(IExternalStorageContext context, Supplier<TileEntity> tile, Direction direction) { public IExternalStorage<FluidStack> provide(IExternalStorageContext context, TileEntity tile, Direction direction) {
return new FluidExternalStorage(context, () -> WorldUtils.getFluidHandler(tile.get(), direction.getOpposite()), tile.get() instanceof FluidInterfaceTile); return new FluidExternalStorage(context, () -> {
if (!tile.getWorld().isBlockPresent(tile.getPos())) {
return null;
}
return WorldUtils.getFluidHandler(tile, direction.getOpposite());
}, tile instanceof FluidInterfaceTile);
} }
@Override @Override

View File

@@ -29,8 +29,14 @@ public class ItemExternalStorageProvider implements IExternalStorageProvider<Ite
@Nonnull @Nonnull
@Override @Override
public IExternalStorage<ItemStack> provide(IExternalStorageContext context, Supplier<TileEntity> tile, Direction direction) { public IExternalStorage<ItemStack> provide(IExternalStorageContext context, TileEntity tile, Direction direction) {
return new ItemExternalStorage(context, () -> WorldUtils.getItemHandler(tile.get(), direction.getOpposite()), tile.get() instanceof InterfaceTile); return new ItemExternalStorage(context, () -> {
if (!tile.getWorld().isBlockPresent(tile.getPos())) {
return null;
}
return WorldUtils.getItemHandler(tile, direction.getOpposite());
}, tile instanceof InterfaceTile);
} }
@Override @Override

View File

@@ -1,7 +1,10 @@
package com.refinedmods.refinedstorage.block; package com.refinedmods.refinedstorage.block;
import com.refinedmods.refinedstorage.RS; import com.refinedmods.refinedstorage.RS;
import com.refinedmods.refinedstorage.api.network.INetwork;
import com.refinedmods.refinedstorage.api.network.NetworkType; import com.refinedmods.refinedstorage.api.network.NetworkType;
import com.refinedmods.refinedstorage.apiimpl.API;
import com.refinedmods.refinedstorage.apiimpl.network.Network;
import com.refinedmods.refinedstorage.container.ControllerContainer; import com.refinedmods.refinedstorage.container.ControllerContainer;
import com.refinedmods.refinedstorage.tile.ControllerTile; import com.refinedmods.refinedstorage.tile.ControllerTile;
import com.refinedmods.refinedstorage.util.BlockUtils; import com.refinedmods.refinedstorage.util.BlockUtils;
@@ -27,6 +30,7 @@ import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TranslationTextComponent; import net.minecraft.util.text.TranslationTextComponent;
import net.minecraft.world.IBlockReader; import net.minecraft.world.IBlockReader;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraft.world.server.ServerWorld;
import net.minecraftforge.energy.CapabilityEnergy; import net.minecraftforge.energy.CapabilityEnergy;
import net.minecraftforge.fml.network.NetworkHooks; import net.minecraftforge.fml.network.NetworkHooks;
@@ -105,6 +109,19 @@ public class ControllerBlock extends BaseBlock {
} }
} }
@Override
@SuppressWarnings("deprecation")
public void neighborChanged(BlockState state, World world, BlockPos pos, Block blockIn, BlockPos fromPos, boolean isMoving) {
super.neighborChanged(state, world, pos, blockIn, fromPos, isMoving);
if (!world.isRemote) {
INetwork network = API.instance().getNetworkManager((ServerWorld) world).getNetwork(pos);
if (network instanceof Network) {
((Network) network).setRedstonePowered(world.isBlockPowered(pos));
}
}
}
@Override @Override
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public ActionResultType onBlockActivated(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult hit) { public ActionResultType onBlockActivated(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult hit) {

View File

@@ -2,6 +2,7 @@ package com.refinedmods.refinedstorage.block;
import com.refinedmods.refinedstorage.api.network.node.INetworkNode; import com.refinedmods.refinedstorage.api.network.node.INetworkNode;
import com.refinedmods.refinedstorage.api.network.node.INetworkNodeProxy; import com.refinedmods.refinedstorage.api.network.node.INetworkNodeProxy;
import com.refinedmods.refinedstorage.apiimpl.API;
import com.refinedmods.refinedstorage.apiimpl.network.node.NetworkNode; import com.refinedmods.refinedstorage.apiimpl.network.node.NetworkNode;
import com.refinedmods.refinedstorage.tile.NetworkNodeTile; import com.refinedmods.refinedstorage.tile.NetworkNodeTile;
import net.minecraft.block.Block; import net.minecraft.block.Block;
@@ -15,6 +16,7 @@ import net.minecraft.util.Direction;
import net.minecraft.util.NonNullList; import net.minecraft.util.NonNullList;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraft.world.server.ServerWorld;
import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.IItemHandler;
public abstract class NetworkNodeBlock extends BaseBlock { public abstract class NetworkNodeBlock extends BaseBlock {
@@ -28,6 +30,19 @@ public abstract class NetworkNodeBlock extends BaseBlock {
} }
} }
@Override
@SuppressWarnings("deprecation")
public void neighborChanged(BlockState state, World world, BlockPos pos, Block blockIn, BlockPos fromPos, boolean isMoving) {
super.neighborChanged(state, world, pos, blockIn, fromPos, isMoving);
if (!world.isRemote) {
INetworkNode node = API.instance().getNetworkNodeManager((ServerWorld) world).getNode(pos);
if (node instanceof NetworkNode) {
((NetworkNode) node).setRedstonePowered(world.isBlockPowered(pos));
}
}
}
@Override @Override
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public void onReplaced(BlockState state, World worldIn, BlockPos pos, BlockState newState, boolean isMoving) { public void onReplaced(BlockState state, World worldIn, BlockPos pos, BlockState newState, boolean isMoving) {
@@ -80,7 +95,7 @@ public abstract class NetworkNodeBlock extends BaseBlock {
public boolean hasTileEntity(BlockState state) { public boolean hasTileEntity(BlockState state) {
return true; return true;
} }
public boolean hasConnectedState() { public boolean hasConnectedState() {
return false; return false;
} }

View File

@@ -12,14 +12,14 @@ public enum RedstoneMode {
private static final String NBT = "RedstoneMode"; private static final String NBT = "RedstoneMode";
public boolean isEnabled(World world, BlockPos pos) { public boolean isEnabled(boolean powered) {
switch (this) { switch (this) {
case IGNORE: case IGNORE:
return true; return true;
case HIGH: case HIGH:
return world.isBlockPowered(pos); return powered;
case LOW: case LOW:
return !world.isBlockPowered(pos); return !powered;
default: default:
return false; return false;
} }

View File

@@ -541,7 +541,7 @@ public class PortableGridTile extends BaseTile implements IGrid, IPortableGrid,
return false; return false;
} }
return redstoneMode.isEnabled(world, pos); return redstoneMode.isEnabled(world.isBlockPowered(pos));
} }
@Override @Override
@@ -565,7 +565,7 @@ public class PortableGridTile extends BaseTile implements IGrid, IPortableGrid,
public void drainEnergy(int energy) { public void drainEnergy(int energy) {
if (RS.SERVER_CONFIG.getPortableGrid().getUseEnergy() && if (RS.SERVER_CONFIG.getPortableGrid().getUseEnergy() &&
type != PortableGridBlockItem.Type.CREATIVE && type != PortableGridBlockItem.Type.CREATIVE &&
redstoneMode.isEnabled(world, pos)) { redstoneMode.isEnabled(world.isBlockPowered(pos))) {
energyStorage.extractEnergy(energy, false); energyStorage.extractEnergy(energy, false);
updateState(); updateState();

View File

@@ -31,7 +31,7 @@ import java.util.UUID;
public final class WorldUtils { public final class WorldUtils {
public static void updateBlock(@Nullable World world, BlockPos pos) { public static void updateBlock(@Nullable World world, BlockPos pos) {
if (world != null) { if (world != null && world.isBlockPresent(pos)) {
BlockState state = world.getBlockState(pos); BlockState state = world.getBlockState(pos);
world.notifyBlockUpdate(pos, state, state, 1 | 2); world.notifyBlockUpdate(pos, state, state, 1 | 2);