Skip to content

Commit 23c0ef8

Browse files
committed
Fix equals and hashCode implementations for various data components
1 parent ef3c8ce commit 23c0ef8

File tree

8 files changed

+138
-67
lines changed

8 files changed

+138
-67
lines changed

src/main/java/mekanism/client/render/transmitter/RenderMechanicalPipe.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ public class RenderMechanicalPipe extends RenderTransmitterBase<TileEntityMechan
4343
private static final float offset = 0.02F;
4444
//Note: this is basically used as an enum map (Direction), but null key is possible, which EnumMap doesn't support.
4545
// 6 is used for null side, and 7 is used for null side but flowing vertically
46+
//TODO - 1.20.5: Look at all maps and sets that use FluidStacks as keys as they no longer are hashed
4647
private static final Int2ObjectMap<Map<FluidStack, Int2ObjectMap<Model3D>>> cachedLiquids = new Int2ObjectArrayMap<>(8);
4748

4849
public RenderMechanicalPipe(BlockEntityRendererProvider.Context context) {

src/main/java/mekanism/common/attachments/FormulaAttachment.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,4 +67,21 @@ public boolean isEmpty() {
6767
public boolean hasItems() {
6868
return inventory.stream().anyMatch(slot -> !slot.isEmpty());
6969
}
70+
71+
@Override
72+
public boolean equals(Object o) {
73+
if (this == o) {
74+
return true;
75+
} else if (o == null || getClass() != o.getClass()) {
76+
return false;
77+
}
78+
FormulaAttachment other = (FormulaAttachment) o;
79+
return invalid == other.invalid && ItemStack.listMatches(inventory, other.inventory);
80+
}
81+
82+
@Override
83+
public int hashCode() {
84+
int hash = ItemStack.hashStackList(inventory);
85+
return 31 * hash + Boolean.hashCode(invalid);
86+
}
7087
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package mekanism.common.attachments;
2+
3+
import com.mojang.serialization.Codec;
4+
import io.netty.buffer.ByteBuf;
5+
import java.util.ArrayList;
6+
import java.util.Arrays;
7+
import java.util.List;
8+
import mekanism.api.annotations.NothingNullByDefault;
9+
import mekanism.common.tile.machine.TileEntityDimensionalStabilizer;
10+
import net.minecraft.network.codec.ByteBufCodecs;
11+
import net.minecraft.network.codec.StreamCodec;
12+
13+
@NothingNullByDefault
14+
public record StabilizedChunks(byte[] chunks) {
15+
16+
private static final int ARRAY_SIZE = TileEntityDimensionalStabilizer.MAX_LOAD_DIAMETER * TileEntityDimensionalStabilizer.MAX_LOAD_DIAMETER;
17+
18+
public static final Codec<StabilizedChunks> CODEC = Codec.BYTE.listOf(ARRAY_SIZE, ARRAY_SIZE).xmap(bytes -> {
19+
byte[] chunks = new byte[ARRAY_SIZE];
20+
for (int i = 0; i < ARRAY_SIZE; i++) {
21+
chunks[i] = bytes.get(i);
22+
}
23+
return new StabilizedChunks(chunks);
24+
}, chunks -> {
25+
List<Byte> list = new ArrayList<>(ARRAY_SIZE);
26+
for (byte chunk : chunks.chunks()) {
27+
list.add(chunk);
28+
}
29+
return list;
30+
});
31+
public static final StreamCodec<ByteBuf, StabilizedChunks> STREAM_CODEC = ByteBufCodecs.byteArray(ARRAY_SIZE)
32+
.map(StabilizedChunks::new, StabilizedChunks::chunks);
33+
34+
public StabilizedChunks {
35+
if (chunks.length != ARRAY_SIZE) {
36+
throw new IllegalArgumentException("Expected to have " + ARRAY_SIZE + " chunks, but got " + chunks.length);
37+
}
38+
}
39+
40+
public static StabilizedChunks create(TileEntityDimensionalStabilizer stabilizer) {
41+
byte[] chunksToLoad = new byte[ARRAY_SIZE];
42+
for (int x = 0; x < TileEntityDimensionalStabilizer.MAX_LOAD_DIAMETER; x++) {
43+
for (int z = 0; z < TileEntityDimensionalStabilizer.MAX_LOAD_DIAMETER; z++) {
44+
chunksToLoad[x * TileEntityDimensionalStabilizer.MAX_LOAD_DIAMETER + z] = stabilizer.isChunkLoadingAt(x, z) ? (byte) 1 : 0;
45+
}
46+
}
47+
return new StabilizedChunks(chunksToLoad);
48+
}
49+
50+
public boolean loaded(int chunk) {
51+
return chunks[chunk] == 1;
52+
}
53+
54+
//Note: We have to override equals and hashCode as the default implementation for records doesn't handle arrays properly
55+
@Override
56+
public boolean equals(Object o) {
57+
if (this == o) {
58+
return true;
59+
} else if (o == null || getClass() != o.getClass()) {
60+
return false;
61+
}
62+
return Arrays.equals(chunks, ((StabilizedChunks) o).chunks);
63+
}
64+
65+
@Override
66+
public int hashCode() {
67+
return Arrays.hashCode(chunks);
68+
}
69+
}

src/main/java/mekanism/common/attachments/component/UpgradeAware.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import java.util.EnumSet;
88
import java.util.List;
99
import java.util.Map;
10+
import java.util.Objects;
1011
import java.util.Set;
1112
import mekanism.api.JsonConstants;
1213
import mekanism.api.NBTConstants;
@@ -62,4 +63,22 @@ public List<IInventorySlot> asInventorySlots(Set<Upgrade> supportedUpgrades) {
6263
output.setStack(outputSlot);
6364
return List.of(input, output);
6465
}
66+
67+
@Override
68+
public boolean equals(Object o) {
69+
if (this == o) {
70+
return true;
71+
} if (o == null || getClass() != o.getClass()) {
72+
return false;
73+
}
74+
UpgradeAware other = (UpgradeAware) o;
75+
return ItemStack.matches(inputSlot, other.inputSlot) && ItemStack.matches(outputSlot, other.outputSlot) && Objects.equals(upgrades, other.upgrades);
76+
}
77+
78+
@Override
79+
public int hashCode() {
80+
int hash = upgrades.hashCode();
81+
hash = 31 * hash + ItemStack.hashItemAndComponents(inputSlot);
82+
return 31 * hash + ItemStack.hashItemAndComponents(outputSlot);
83+
}
6584
}

src/main/java/mekanism/common/attachments/qio/PortableDashboardContents.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,19 @@ public record PortableDashboardContents(List<ItemStack> contents) {
2424
//Make the list unmodifiable to ensure we don't accidentally mutate it
2525
contents = Collections.unmodifiableList(contents);
2626
}
27+
28+
@Override
29+
public boolean equals(Object o) {
30+
if (this == o) {
31+
return true;
32+
} else if (o == null || getClass() != o.getClass()) {
33+
return false;
34+
}
35+
return ItemStack.listMatches(contents, ((PortableDashboardContents) o).contents);
36+
}
37+
38+
@Override
39+
public int hashCode() {
40+
return ItemStack.hashStackList(contents);
41+
}
2742
}

src/main/java/mekanism/common/registries/MekanismDataComponents.java

Lines changed: 11 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
package mekanism.common.registries;
22

33
import com.mojang.serialization.Codec;
4-
import java.util.ArrayList;
5-
import java.util.List;
64
import java.util.UUID;
75
import mekanism.api.MekanismAPI;
86
import mekanism.api.annotations.NothingNullByDefault;
@@ -17,6 +15,7 @@
1715
import mekanism.common.attachments.FormulaAttachment;
1816
import mekanism.common.attachments.FrequencyAware;
1917
import mekanism.common.attachments.OverflowAware;
18+
import mekanism.common.attachments.StabilizedChunks;
2019
import mekanism.common.attachments.component.AttachedEjector;
2120
import mekanism.common.attachments.component.AttachedSideConfig;
2221
import mekanism.common.attachments.component.UpgradeAware;
@@ -44,14 +43,14 @@
4443
import mekanism.common.item.interfaces.IJetpackItem.JetpackMode;
4544
import mekanism.common.lib.frequency.Frequency;
4645
import mekanism.common.lib.frequency.FrequencyType;
46+
import mekanism.common.lib.inventory.HashedItem;
4747
import mekanism.common.registration.MekanismDeferredHolder;
4848
import mekanism.common.registration.impl.DataComponentDeferredRegister;
4949
import mekanism.common.tile.TileEntityChemicalTank.GasMode;
5050
import mekanism.common.tile.interfaces.IFluidContainerManager.ContainerEditMode;
5151
import mekanism.common.tile.interfaces.IRedstoneControl.RedstoneControl;
5252
import mekanism.common.tile.laser.TileEntityLaserAmplifier.RedstoneOutput;
5353
import mekanism.common.tile.machine.TileEntityDigitalMiner;
54-
import mekanism.common.tile.machine.TileEntityDimensionalStabilizer;
5554
import net.minecraft.core.component.DataComponentType;
5655
import net.minecraft.core.registries.BuiltInRegistries;
5756
import net.minecraft.core.registries.Registries;
@@ -60,7 +59,6 @@
6059
import net.minecraft.network.codec.ByteBufCodecs;
6160
import net.minecraft.resources.ResourceKey;
6261
import net.minecraft.world.item.Item;
63-
import net.minecraft.world.item.ItemStack;
6462
import org.jetbrains.annotations.Nullable;
6563

6664
@NothingNullByDefault
@@ -216,42 +214,16 @@ private MekanismDataComponents() {
216214
);
217215

218216
//TODO - 1.20.5: Validate this doesn't have to be optional
219-
public static final MekanismDeferredHolder<DataComponentType<?>, DataComponentType<ItemStack>> ITEM_TARGET = DATA_COMPONENTS.simple("item_target",
220-
builder -> builder.persistent(ItemStack.CODEC)
221-
.networkSynchronized(ItemStack.STREAM_CODEC)
217+
//Note: We can't directly use ItemStack as it needs to override equals and hashcode, but as our only use case converts it to a HashedItem, we just use that
218+
public static final MekanismDeferredHolder<DataComponentType<?>, DataComponentType<HashedItem>> ITEM_TARGET = DATA_COMPONENTS.simple("item_target",
219+
builder -> builder.persistent(HashedItem.CODEC)
220+
.networkSynchronized(HashedItem.STREAM_CODEC)
222221
);
223222

224-
//TODO - 1.20.5: Re-evaluate this, it is kind of messy
225-
public static final MekanismDeferredHolder<DataComponentType<?>, DataComponentType<boolean[]>> STABILIZER_CHUNKS = DATA_COMPONENTS.simple("stabilzer_chunks",
226-
builder -> {
227-
int size = TileEntityDimensionalStabilizer.MAX_LOAD_DIAMETER * TileEntityDimensionalStabilizer.MAX_LOAD_DIAMETER;
228-
return builder.persistent(Codec.BOOL.listOf(size, size).xmap(booleans -> {
229-
boolean[] booleanArray = new boolean[booleans.size()];
230-
for (int i = 0; i < booleans.size(); i++) {
231-
booleanArray[i] = booleans.get(i);
232-
}
233-
return booleanArray;
234-
}, booleans -> {
235-
List<Boolean> booleanList = new ArrayList<>(booleans.length);
236-
for (boolean bool : booleans) {
237-
booleanList.add(bool);
238-
}
239-
return booleanList;
240-
}))
241-
.networkSynchronized(ByteBufCodecs.byteArray(size).map(bytes -> {
242-
boolean[] booleans = new boolean[bytes.length];
243-
for (int i = 0; i < bytes.length; i++) {
244-
booleans[i] = bytes[i] == 1;
245-
}
246-
return booleans;
247-
}, booleans -> {
248-
byte[] bytes = new byte[booleans.length];
249-
for (int i = 0; i < booleans.length; i++) {
250-
bytes[i] = booleans[i] ? (byte) 1 : 0;
251-
}
252-
return bytes;
253-
}));
254-
});
223+
public static final MekanismDeferredHolder<DataComponentType<?>, DataComponentType<StabilizedChunks>> STABILIZER_CHUNKS = DATA_COMPONENTS.simple("stabilzer_chunks",
224+
builder -> builder.persistent(StabilizedChunks.CODEC)
225+
.networkSynchronized(StabilizedChunks.STREAM_CODEC)
226+
);
255227

256228
public static final MekanismDeferredHolder<DataComponentType<?>, DataComponentType<FrequencyAware<TeleporterFrequency>>> TELEPORTER_FREQUENCY = DATA_COMPONENTS.registerFrequencyAware("teleporter_frequency", () -> FrequencyType.TELEPORTER);
257229
public static final MekanismDeferredHolder<DataComponentType<?>, DataComponentType<FrequencyAware<InventoryFrequency>>> INVENTORY_FREQUENCY = DATA_COMPONENTS.registerFrequencyAware("inventory_frequency", () -> FrequencyType.INVENTORY);
@@ -292,7 +264,7 @@ public static <FREQ extends Frequency> DataComponentType<FrequencyAware<FREQ>> g
292264
);
293265
public static final MekanismDeferredHolder<DataComponentType<?>, DataComponentType<MergedChemicalTank>> CHEMICAL_TANK_CONTENTS_HANDLER = DATA_COMPONENTS.simple("chemical_tank_contents_handler",
294266
builder -> {
295-
//TODO - 1.20.5: Figure out how to implement containers
267+
//TODO - 1.20.5: Figure out how to implement containers
296268
/*if (holder instanceof ItemStack stack && !stack.isEmpty() && stack.getItem() instanceof ItemBlockChemicalTank tank) {
297269
ChemicalTankTier tier = Objects.requireNonNull(tank.getTier(), "Chemical tank tier cannot be null");
298270
return MergedChemicalTank.create(

src/main/java/mekanism/common/tile/machine/TileEntityDimensionalStabilizer.java

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
package mekanism.common.tile.machine;
22

33
import java.util.HashSet;
4-
import java.util.List;
5-
import java.util.Map;
64
import java.util.Set;
75
import java.util.function.BiFunction;
86
import mekanism.api.Action;
@@ -11,6 +9,7 @@
119
import mekanism.api.NBTConstants;
1210
import mekanism.api.RelativeSide;
1311
import mekanism.api.math.FloatingLong;
12+
import mekanism.common.attachments.StabilizedChunks;
1413
import mekanism.common.attachments.containers.ContainerType;
1514
import mekanism.common.capabilities.energy.FixedUsageEnergyContainer;
1615
import mekanism.common.capabilities.holder.energy.EnergyContainerHelper;
@@ -32,11 +31,9 @@
3231
import mekanism.common.tile.component.TileComponentChunkLoader;
3332
import mekanism.common.tile.interfaces.IHasVisualization;
3433
import net.minecraft.core.BlockPos;
35-
import net.minecraft.core.Holder;
3634
import net.minecraft.core.HolderLookup;
3735
import net.minecraft.core.SectionPos;
3836
import net.minecraft.core.component.DataComponentMap;
39-
import net.minecraft.core.component.DataComponentType;
4037
import net.minecraft.nbt.CompoundTag;
4138
import net.minecraft.world.level.ChunkPos;
4239
import net.minecraft.world.level.block.entity.BlockEntity;
@@ -261,19 +258,14 @@ protected void applyImplicitComponents(@NotNull BlockEntity.DataComponentInput i
261258
//TODO - 1.20.4: Deduplicate this and the from nbt
262259
boolean changed = false;
263260
int lastChunksLoaded = chunksLoaded;
264-
boolean[] chunksToLoad = input.get(MekanismDataComponents.STABILIZER_CHUNKS);
261+
StabilizedChunks chunksToLoad = input.get(MekanismDataComponents.STABILIZER_CHUNKS);
265262
if (chunksToLoad == null) {
266263
//Skip if we don't have any data
267264
return;
268265
}
269-
if (chunksToLoad.length != MAX_LOAD_DIAMETER * MAX_LOAD_DIAMETER) {
270-
//If it is the wrong size dummy it to all zeros so things get set to false as we don't know
271-
// where to position our values
272-
chunksToLoad = new boolean[MAX_LOAD_DIAMETER * MAX_LOAD_DIAMETER];
273-
}
274266
for (int x = 0; x < MAX_LOAD_DIAMETER; x++) {
275267
for (int z = 0; z < MAX_LOAD_DIAMETER; z++) {
276-
changed |= setChunkLoadingAt(x, z, chunksToLoad[x * MAX_LOAD_DIAMETER + z]);
268+
changed |= setChunkLoadingAt(x, z, chunksToLoad.loaded(x * MAX_LOAD_DIAMETER + z));
277269
}
278270
}
279271
if (changed) {
@@ -291,13 +283,7 @@ protected void applyImplicitComponents(@NotNull BlockEntity.DataComponentInput i
291283
@Override
292284
protected void collectImplicitComponents(@NotNull DataComponentMap.Builder builder) {
293285
super.collectImplicitComponents(builder);
294-
boolean[] chunksToLoad = new boolean[MAX_LOAD_DIAMETER * MAX_LOAD_DIAMETER];
295-
for (int x = 0; x < MAX_LOAD_DIAMETER; x++) {
296-
for (int z = 0; z < MAX_LOAD_DIAMETER; z++) {
297-
chunksToLoad[x * MAX_LOAD_DIAMETER + z] = isChunkLoadingAt(x, z);
298-
}
299-
}
300-
builder.set(MekanismDataComponents.STABILIZER_CHUNKS, chunksToLoad);
286+
builder.set(MekanismDataComponents.STABILIZER_CHUNKS, StabilizedChunks.create(this));
301287
}
302288

303289
@Override

src/main/java/mekanism/common/tile/qio/TileEntityQIORedstoneAdapter.java

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package mekanism.common.tile.qio;
22

3-
import java.util.List;
43
import mekanism.api.NBTConstants;
54
import mekanism.client.model.data.DataBasedModelLoader;
65
import mekanism.common.content.qio.QIOFrequency;
@@ -16,10 +15,8 @@
1615
import mekanism.common.util.NBTUtils;
1716
import net.minecraft.core.BlockPos;
1817
import net.minecraft.core.Direction;
19-
import net.minecraft.core.Holder;
2018
import net.minecraft.core.HolderLookup;
2119
import net.minecraft.core.component.DataComponentMap;
22-
import net.minecraft.core.component.DataComponentType;
2320
import net.minecraft.core.registries.BuiltInRegistries;
2421
import net.minecraft.nbt.CompoundTag;
2522
import net.minecraft.resources.ResourceLocation;
@@ -163,7 +160,7 @@ public void handleUpdateTag(@NotNull CompoundTag tag, @NotNull HolderLookup.Prov
163160
protected void collectImplicitComponents(@NotNull DataComponentMap.Builder builder) {
164161
super.collectImplicitComponents(builder);
165162
if (itemType != null) {
166-
builder.set(MekanismDataComponents.ITEM_TARGET, itemType.getInternalStack());
163+
builder.set(MekanismDataComponents.ITEM_TARGET, itemType);
167164
}
168165
builder.set(MekanismDataComponents.LONG_AMOUNT, count);
169166
builder.set(MekanismDataComponents.FUZZY, fuzzy);
@@ -173,12 +170,7 @@ protected void collectImplicitComponents(@NotNull DataComponentMap.Builder build
173170
@Override
174171
protected void applyImplicitComponents(@NotNull BlockEntity.DataComponentInput input) {
175172
super.applyImplicitComponents(input);
176-
ItemStack target = input.get(MekanismDataComponents.ITEM_TARGET);
177-
if (target != null && !target.isEmpty()) {
178-
itemType = HashedItem.create(target);
179-
} else {
180-
itemType = null;
181-
}
173+
itemType = input.get(MekanismDataComponents.ITEM_TARGET);
182174
count = input.getOrDefault(MekanismDataComponents.LONG_AMOUNT, count);
183175
fuzzy = input.getOrDefault(MekanismDataComponents.FUZZY, fuzzy);
184176
inverted = input.getOrDefault(MekanismDataComponents.INVERSE, inverted);

0 commit comments

Comments
 (0)