From f0c02356d315f0861aa57f5ebed8b76599850ffe Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Tue, 10 Jun 2025 13:18:43 -0700 Subject: [PATCH 1/3] make neighbor cache use weak refs --- .../NeighborCacheTileEntityBase.java | 42 ++++++++++++++----- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/src/main/java/gregtech/api/metatileentity/NeighborCacheTileEntityBase.java b/src/main/java/gregtech/api/metatileentity/NeighborCacheTileEntityBase.java index 97200ab8518..c345c768ac4 100644 --- a/src/main/java/gregtech/api/metatileentity/NeighborCacheTileEntityBase.java +++ b/src/main/java/gregtech/api/metatileentity/NeighborCacheTileEntityBase.java @@ -11,11 +11,16 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.lang.ref.WeakReference; import java.util.Arrays; public abstract class NeighborCacheTileEntityBase extends SyncedTileEntityBase implements INeighborCache { - private final TileEntity[] neighbors = new TileEntity[6]; + private static final WeakReference NULL = new WeakReference<>(null); + private static final WeakReference INVALID = new WeakReference<>(null); + + @SuppressWarnings("rawtypes") + private final WeakReference[] neighbors = new WeakReference[6]; private boolean neighborsInvalidated = false; public NeighborCacheTileEntityBase() { @@ -24,7 +29,7 @@ public NeighborCacheTileEntityBase() { protected void invalidateNeighbors() { if (!this.neighborsInvalidated) { - Arrays.fill(this.neighbors, this); + Arrays.fill(this.neighbors, INVALID); this.neighborsInvalidated = true; } } @@ -60,17 +65,32 @@ public void onChunkUnload() { @Override public @Nullable TileEntity getNeighbor(@NotNull EnumFacing facing) { if (world == null || pos == null) return null; - int i = facing.getIndex(); - TileEntity neighbor = this.neighbors[i]; - if (neighbor == this || (neighbor != null && neighbor.isInvalid())) { - neighbor = world.getTileEntity(pos.offset(facing)); - this.neighbors[i] = neighbor; - this.neighborsInvalidated = false; - } - return neighbor; + WeakReference ref = invalidRef(facing) ? computeNeighbor(facing) : getRef(facing); + return ref.get(); + } + + // if true, compute neighbor, if false, return TE or null + private boolean invalidRef(EnumFacing facing) { + WeakReference ref = getRef(facing); + if (ref == INVALID) return true; + TileEntity te = ref.get(); + return te != null && te.isInvalid(); + } + + private WeakReference computeNeighbor(EnumFacing facing) { + TileEntity te = super.getNeighbor(facing); + // avoid making new references to null TEs + this.neighbors[facing.ordinal()] = te == null ? NULL : new WeakReference<>(te); + this.neighborsInvalidated = false; + return getRef(facing); + } + + @SuppressWarnings("unchecked") + private WeakReference getRef(EnumFacing facing) { + return (WeakReference) this.neighbors[facing.ordinal()]; } public void onNeighborChanged(@NotNull EnumFacing facing) { - this.neighbors[facing.getIndex()] = this; + this.neighbors[facing.ordinal()] = INVALID; } } From a5b266d98b7c2139341dff83a95a2418560580a8 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Tue, 10 Jun 2025 22:33:40 -0700 Subject: [PATCH 2/3] use list instead of rawtype array --- .../NeighborCacheTileEntityBase.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/main/java/gregtech/api/metatileentity/NeighborCacheTileEntityBase.java b/src/main/java/gregtech/api/metatileentity/NeighborCacheTileEntityBase.java index c345c768ac4..80c3d2d5ac1 100644 --- a/src/main/java/gregtech/api/metatileentity/NeighborCacheTileEntityBase.java +++ b/src/main/java/gregtech/api/metatileentity/NeighborCacheTileEntityBase.java @@ -13,14 +13,15 @@ import java.lang.ref.WeakReference; import java.util.Arrays; +import java.util.List; public abstract class NeighborCacheTileEntityBase extends SyncedTileEntityBase implements INeighborCache { private static final WeakReference NULL = new WeakReference<>(null); private static final WeakReference INVALID = new WeakReference<>(null); - @SuppressWarnings("rawtypes") - private final WeakReference[] neighbors = new WeakReference[6]; + private final List> neighbors = Arrays.asList( + INVALID, INVALID, INVALID, INVALID, INVALID, INVALID); private boolean neighborsInvalidated = false; public NeighborCacheTileEntityBase() { @@ -29,7 +30,9 @@ public NeighborCacheTileEntityBase() { protected void invalidateNeighbors() { if (!this.neighborsInvalidated) { - Arrays.fill(this.neighbors, INVALID); + for (EnumFacing value : EnumFacing.VALUES) { + this.neighbors.set(value.getIndex(), INVALID); + } this.neighborsInvalidated = true; } } @@ -80,17 +83,16 @@ private boolean invalidRef(EnumFacing facing) { private WeakReference computeNeighbor(EnumFacing facing) { TileEntity te = super.getNeighbor(facing); // avoid making new references to null TEs - this.neighbors[facing.ordinal()] = te == null ? NULL : new WeakReference<>(te); + this.neighbors.set(facing.getIndex(), te == null ? NULL : new WeakReference<>(te)); this.neighborsInvalidated = false; return getRef(facing); } - @SuppressWarnings("unchecked") private WeakReference getRef(EnumFacing facing) { - return (WeakReference) this.neighbors[facing.ordinal()]; + return this.neighbors.get(facing.getIndex()); } public void onNeighborChanged(@NotNull EnumFacing facing) { - this.neighbors[facing.ordinal()] = INVALID; + this.neighbors.set(facing.getIndex(), INVALID); } } From 9706d67bf8a46d9228663b049c7c388504591291 Mon Sep 17 00:00:00 2001 From: Ghzdude <44148655+ghzdude@users.noreply.github.com> Date: Wed, 18 Jun 2025 01:21:27 -0700 Subject: [PATCH 3/3] fix possible loss of referent (?) move comment to more appropriate place mark certain methods as not null --- .../api/metatileentity/NeighborCacheTileEntityBase.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/gregtech/api/metatileentity/NeighborCacheTileEntityBase.java b/src/main/java/gregtech/api/metatileentity/NeighborCacheTileEntityBase.java index 80c3d2d5ac1..dac9672978a 100644 --- a/src/main/java/gregtech/api/metatileentity/NeighborCacheTileEntityBase.java +++ b/src/main/java/gregtech/api/metatileentity/NeighborCacheTileEntityBase.java @@ -68,11 +68,11 @@ public void onChunkUnload() { @Override public @Nullable TileEntity getNeighbor(@NotNull EnumFacing facing) { if (world == null || pos == null) return null; + // if the ref is INVALID, compute neighbor, otherwise, return TE or null WeakReference ref = invalidRef(facing) ? computeNeighbor(facing) : getRef(facing); return ref.get(); } - // if true, compute neighbor, if false, return TE or null private boolean invalidRef(EnumFacing facing) { WeakReference ref = getRef(facing); if (ref == INVALID) return true; @@ -80,14 +80,17 @@ private boolean invalidRef(EnumFacing facing) { return te != null && te.isInvalid(); } + @NotNull private WeakReference computeNeighbor(EnumFacing facing) { TileEntity te = super.getNeighbor(facing); // avoid making new references to null TEs - this.neighbors.set(facing.getIndex(), te == null ? NULL : new WeakReference<>(te)); + WeakReference ref = te == null ? NULL : new WeakReference<>(te); + this.neighbors.set(facing.getIndex(), ref); this.neighborsInvalidated = false; - return getRef(facing); + return ref; } + @NotNull private WeakReference getRef(EnumFacing facing) { return this.neighbors.get(facing.getIndex()); }