Skip to content

Commit

Permalink
feat: internal rework
Browse files Browse the repository at this point in the history
  • Loading branch information
Jamalam360 committed Jun 7, 2024
1 parent 7944b58 commit a09a4cc
Show file tree
Hide file tree
Showing 20 changed files with 395 additions and 291 deletions.
12 changes: 11 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1 +1,11 @@
- Fix a dupe exploit (#44)
This release brings about a significant internal rework with should make Utility Belt significantly
less buggy. I have conducted a long play testing session before this release to try to verify
everything works as intended.

## Closed Issues

- #47: fishing rod flickering
- #46: dupe bug
- #45: dupe bug

Alongside the issues that were reported, many others have been fixed.
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,6 @@ public boolean hasBelt(Player player) {
return belt != null && belt.is(UtilityBelt.UTILITY_BELT_ITEM.get());
}

public void onStartTick(Player player) {
}

public abstract boolean isInBelt(Player player);

public abstract void setInBelt(Player player, boolean inBelt);
Expand All @@ -40,4 +37,10 @@ public void onStartTick(Player player) {
public abstract void setSelectedBeltSlot(Player player, int slot);

public abstract UtilityBeltInventory getInventory(Player player);

public UtilityBeltInventory.Mutable getMutableInventory(Player player) {
return new UtilityBeltInventory.Mutable(this.getInventory(player));
}

public abstract void setInventory(Player player, UtilityBeltInventory.Mutable inventory);
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public class UtilityBelt {
public static final RegistrySupplier<Item> UTILITY_BELT_ITEM = ITEMS.register("utility_belt", UtilityBeltItem::new);
public static final RegistrySupplier<MenuType<UtilityBeltMenu>> MENU_TYPE = MENUS.register("utility_belt", () -> new MenuType<>(UtilityBeltMenu::new, FeatureFlagSet.of()));
public static final RegistrySupplier<DataComponentType<UtilityBeltInventory>> UTILITY_BELT_INVENTORY_COMPONENT_TYPE = COMPONENT_TYPES.register("utility_belt_inventory", () ->
DataComponentType.<UtilityBeltInventory>builder().persistent(UtilityBeltInventory.CODEC).networkSynchronized(UtilityBeltInventory.STREAM_CODEC).build()
DataComponentType.<UtilityBeltInventory>builder().persistent(UtilityBeltInventory.CODEC).cacheEncoding().build()
);

public static void init() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,73 +1,110 @@
package io.github.jamalam360.utility_belt;

import com.mojang.serialization.Codec;
import java.util.ArrayList;
import java.util.List;
import net.minecraft.core.NonNullList;
import net.minecraft.core.component.DataComponents;
import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.codec.ByteBufCodecs;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.world.SimpleContainer;
import net.minecraft.world.item.ItemStack;

public class UtilityBeltInventory extends SimpleContainer {
public record UtilityBeltInventory(List<ItemStack> items) {

public static final UtilityBeltInventory EMPTY = new UtilityBeltInventory(NonNullList.withSize(4, ItemStack.EMPTY));
public static final Codec<UtilityBeltInventory> CODEC = Codec
.list(ItemStack.CODEC)
.xmap(UtilityBeltInventory::new, UtilityBeltInventory::getItems);
.list(ItemStack.OPTIONAL_CODEC)
.xmap(UtilityBeltInventory::new, UtilityBeltInventory::items);

public static final StreamCodec<RegistryFriendlyByteBuf, UtilityBeltInventory> STREAM_CODEC = StreamCodec
.composite(
ItemStack.STREAM_CODEC.apply(ByteBufCodecs.list(4)),
UtilityBeltInventory::getItems,
ItemStack.OPTIONAL_STREAM_CODEC.apply(ByteBufCodecs.list(4)),
UtilityBeltInventory::items,
UtilityBeltInventory::new
);

public UtilityBeltInventory {
if (items.size() != 4) {
throw new IllegalArgumentException("Utility belt inventory must have exactly 4 items");
}
}

public UtilityBeltInventory() {
super(4);
public ItemStack getItem(int index) {
return items.get(index);
}

private UtilityBeltInventory(List<ItemStack> stacks) {
super(4);
public int getContainerSize() {
return 4;
}

for (int i = 0; i < stacks.size(); i++) {
this.setItem(i, stacks.get(i));
}
public UtilityBeltInventory clone() {
return new UtilityBeltInventory(new ArrayList<>(items));
}

@Override
public boolean equals(Object obj) {
if (obj instanceof UtilityBeltInventory other) {
if (other.getContainerSize() == this.getContainerSize()) {
for (int i = 0; i < this.getContainerSize(); i++) {
if (!ItemStack.matches(this.getItem(i), other.getItem(i))) {
return false;
}
}

return true;
}
return ItemStack.listMatches(items, other.items);
}

return false;
}

@SuppressWarnings("deprecation")
@Override
public int hashCode() {
int hash = 0;
for (int i = 0; i < this.getContainerSize(); i++) {
hash += this.getItem(i).hashCode();
return ItemStack.hashStackList(items);
}

@Override
public String toString() {
return invToString("UtilityBeltInventory[", items);
}

public static class Mutable extends SimpleContainer {

public Mutable(UtilityBeltInventory inv) {
super(4);

for (int i = 0; i < inv.getContainerSize(); i++) {
this.setItem(i, inv.getItem(i));
}
}

public UtilityBeltInventory toImmutable() {
return new UtilityBeltInventory(new ArrayList<>(this.getItems()));
}

@Override
public boolean equals(Object obj) {
if (obj instanceof UtilityBeltInventory other) {
return ItemStack.listMatches(this.getItems(), other.items);
}

return false;
}

return hash;
@Override
public String toString() {
return invToString("UtilityBeltInventory$Mutable[", this.getItems());
}
}

@Override
public UtilityBeltInventory clone() {
UtilityBeltInventory inv = new UtilityBeltInventory();
for (int i = 0; i < this.getContainerSize(); i++) {
inv.setItem(i, this.getItem(i).copy());
private static String invToString(String prefix, List<ItemStack> items) {
StringBuilder string = new StringBuilder(prefix);

for (int i = 0; i < items.size(); i++) {
string.append(items.get(i));
string.append(" {");
string.append(items.get(i).getComponents().get(DataComponents.DAMAGE));
string.append("}");
if (i < items.size() - 1) {
string.append(", ");
}
}

return inv;
return string.toString();
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package io.github.jamalam360.utility_belt;

import io.github.jamalam360.utility_belt.UtilityBeltInventory.Mutable;
import io.github.jamalam360.utility_belt.client.ClientNetworking;
import java.util.List;
import java.util.function.Consumer;
import net.minecraft.network.chat.Component;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.SlotAccess;
import net.minecraft.world.entity.player.Player;
Expand All @@ -30,11 +32,11 @@ public class UtilityBeltItem extends Item {
private static final int BAR_COLOR = Mth.color(0.4F, 0.4F, 1.0F);

public UtilityBeltItem() {
super(new Item.Properties().stacksTo(1).component(UtilityBelt.UTILITY_BELT_INVENTORY_COMPONENT_TYPE.get(), new UtilityBeltInventory()));
super(new Item.Properties().stacksTo(1).component(UtilityBelt.UTILITY_BELT_INVENTORY_COMPONENT_TYPE.get(), UtilityBeltInventory.EMPTY));
}

@SuppressWarnings("BooleanMethodIsAlwaysInverted")
private static boolean handleStack(ItemStack stack, UtilityBeltInventory inv, Consumer<ItemStack> slotAccess) {
private static boolean handleStack(ItemStack stack, UtilityBeltInventory.Mutable inv, Consumer<ItemStack> slotAccess) {
if (stack.isEmpty()) {
for (int i = 0; i < inv.getContainerSize(); i++) {
if (!inv.getItem(i).isEmpty()) {
Expand Down Expand Up @@ -67,12 +69,13 @@ public static boolean isValidItem(ItemStack stack) {
// Going to keep this name as is until 1.20.4 support is dropped, to keep the diffs smaller
public static UtilityBeltInventory getInventoryFromTag(ItemStack stack) {
if (!stack.has(UtilityBelt.UTILITY_BELT_INVENTORY_COMPONENT_TYPE.get())) {
stack.set(UtilityBelt.UTILITY_BELT_INVENTORY_COMPONENT_TYPE.get(), new UtilityBeltInventory());
stack.set(UtilityBelt.UTILITY_BELT_INVENTORY_COMPONENT_TYPE.get(), UtilityBeltInventory.EMPTY);
}

return stack.get(UtilityBelt.UTILITY_BELT_INVENTORY_COMPONENT_TYPE.get());
}

// This should only be called by the state managers, or when the belt is NOT equipped
public static void setInventory(ItemStack stack, UtilityBeltInventory inv) {
stack.set(UtilityBelt.UTILITY_BELT_INVENTORY_COMPONENT_TYPE.get(), inv);
}
Expand All @@ -90,12 +93,12 @@ public static ItemStack getBelt(Player player) {

@Override
public boolean isBarVisible(ItemStack itemStack) {
return getInventoryFromTag(itemStack).hasAnyMatching(s -> !s.isEmpty());
return getInventoryFromTag(itemStack).items().stream().anyMatch(s -> !s.isEmpty());
}

@Override
public int getBarWidth(ItemStack itemStack) {
long size = getInventoryFromTag(itemStack).getItems().stream().filter((s) -> !s.isEmpty()).count();
long size = getInventoryFromTag(itemStack).items().stream().filter((s) -> !s.isEmpty()).count();
return size == 4L ? 13 : (int) (size * 3);
}

Expand Down Expand Up @@ -123,14 +126,13 @@ public boolean overrideStackedOnOther(ItemStack belt, Slot slot, ClickAction cli
}

ItemStack slotStack = slot.getItem();
UtilityBeltInventory inv = getInventoryFromTag(belt);
UtilityBeltInventory.Mutable inv = new Mutable(getInventoryFromTag(belt));

if (!handleStack(slotStack, inv, slot::set)) {
return false;
}

playInsertSound(player);
setInventory(belt, inv);
setInventory(belt, inv.toImmutable());
return true;
}

Expand All @@ -140,17 +142,23 @@ public boolean overrideOtherStackedOnMe(ItemStack belt, ItemStack otherStack, Sl
return false;
}

UtilityBeltInventory inv = getInventoryFromTag(belt);
UtilityBeltInventory.Mutable inv = new Mutable(getInventoryFromTag(belt));

if (!handleStack(otherStack, inv, slotAccess::set)) {
return false;
}

playInsertSound(player);
setInventory(belt, inv);
setInventory(belt, inv.toImmutable());
return true;
}

public void onEquip(LivingEntity wearer, ItemStack belt) {
if (wearer instanceof Player player && !player.level().isClientSide) {
StateManager.getServerInstance().setInventory(player, new Mutable(getInventoryFromTag(belt)));
}
}

public void onUnequip(LivingEntity wearer) {
if (wearer instanceof Player player && player.level().isClientSide) {
StateManager.getClientInstance().setInBelt(player, false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ public class UtilityBeltPackets {
public static final CustomPacketPayload.Type<C2SOpenScreen> C2S_OPEN_SCREEN = new CustomPacketPayload.Type<>(UtilityBelt.id("open_screen"));
public static final CustomPacketPayload.Type<S2CSetBeltSlot> S2C_SET_BELT_SLOT = new CustomPacketPayload.Type<>(UtilityBelt.id("set_belt_slot"));
public static final CustomPacketPayload.Type<S2CSetHotbarSlot> S2C_SET_HOTBAR_SLOT = new CustomPacketPayload.Type<>(UtilityBelt.id("set_hotbar_slot"));
public static final CustomPacketPayload.Type<S2CUpdateBeltInventory> S2C_UPDATE_BELT_INVENTORY = new CustomPacketPayload.Type<>(UtilityBelt.id("update_belt_inventory"));

public record C2SUpdateState(boolean inBelt, int slot, boolean swapItems) implements CustomPacketPayload {

Expand Down Expand Up @@ -67,4 +68,14 @@ public Type<? extends CustomPacketPayload> type() {
return S2C_SET_HOTBAR_SLOT;
}
}

public record S2CUpdateBeltInventory(UtilityBeltInventory inventory) implements CustomPacketPayload {

public static final StreamCodec<RegistryFriendlyByteBuf, S2CUpdateBeltInventory> STREAM_CODEC = UtilityBeltInventory.STREAM_CODEC.map(S2CUpdateBeltInventory::new, S2CUpdateBeltInventory::inventory);

@Override
public Type<? extends CustomPacketPayload> type() {
return new CustomPacketPayload.Type<>(UtilityBelt.id("update_belt_inventory"));
}
}
}
Loading

0 comments on commit a09a4cc

Please sign in to comment.