Skip to content

Commit

Permalink
fix: dropping items from the belt no longer sends them to the aether
Browse files Browse the repository at this point in the history
  • Loading branch information
Jamalam360 committed Apr 20, 2024
1 parent 5e3f18d commit 773cb40
Show file tree
Hide file tree
Showing 8 changed files with 231 additions and 202 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1 +1 @@
- Re-release due to Curseforge being jank?
- Fix item-loss when dropping an item from the belt.
Original file line number Diff line number Diff line change
@@ -1,12 +1,25 @@
package io.github.jamalam360.utility_belt;

public class Config {
import io.github.jamalam360.jamlib.config.ConfigExtensions;
import java.util.List;
import net.minecraft.network.chat.Component;

public class Config implements ConfigExtensions<Config> {
public boolean displayUtilityBeltWhenNotSelected = true;
public boolean invertScrolling = false;
public boolean useSneakSwapping = true;
public HotbarKeyBehaviour hotbarKeyBehaviour = HotbarKeyBehaviour.SWITCH_BELT_SLOT;
public Position hotbarPosition = Position.MIDDLE_LEFT;

@Override
public List<Link> getLinks() {
return List.of(
new Link(Link.DISCORD, "https://jamalam.tech/discord", Component.translatable("config.utility_belt.discord")),
new Link(Link.GITHUB, "https://github.com/JamCoreModding/utility-belt", Component.translatable("config.utility_belt.github")),
new Link(Link.GENERIC_LINK, "https://modrinth.com/mod/utility-belt", Component.translatable("config.utility_belt.modrinth"))
);
}

public enum HotbarKeyBehaviour {
SWITCH_BACK_TO_HOTBAR,
SWITCH_BELT_SLOT
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,184 +10,195 @@
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.state.BlockState;
import org.spongepowered.asm.mixin.*;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

@Mixin(Inventory.class)
public class InventoryMixin {
@Shadow
@Final
public Player player;

@Inject(
method = "getSelected",
at = @At("HEAD"),
cancellable = true
)
private void utilitybelt$getSelectedInUtilityBelt(CallbackInfoReturnable<ItemStack> cir) {
StateManager stateManager = StateManager.getServerInstance();
if (stateManager.isInBelt(this.player)) {
ItemStack belt = UtilityBeltItem.getBelt(this.player);
assert belt != null;
UtilityBeltInventory inv = stateManager.getInventory(this.player);
cir.setReturnValue(inv.getItem(stateManager.getSelectedBeltSlot(this.player)));
}
}

/**
* Necessary because Mojank does not use getSelected in this method.
*/
@Inject(
method = "getDestroySpeed",
at = @At("HEAD"),
cancellable = true
)
private void utilitybelt$getDestroySpeed(BlockState blockState, CallbackInfoReturnable<Float> cir) {
StateManager stateManager = StateManager.getServerInstance();
if (stateManager.isInBelt(this.player)) {
ItemStack belt = UtilityBeltItem.getBelt(this.player);
assert belt != null;
UtilityBeltInventory inv = stateManager.getInventory(this.player);
cir.setReturnValue(inv.getItem(stateManager.getSelectedBeltSlot(this.player)).getDestroySpeed(blockState));
}
}

@Inject(
method = "tick",
at = @At("RETURN")
)
private void utilitybelt$tick(CallbackInfo ci) {
ItemStack belt = UtilityBeltItem.getBelt(this.player);
StateManager stateManager = StateManager.getServerInstance();
if (stateManager.isInBelt(this.player)) {
assert belt != null;
UtilityBeltInventory inv = stateManager.getInventory(this.player);
int selectedSlot = stateManager.getSelectedBeltSlot(this.player);

for (int i = 0; i < inv.getContainerSize(); i++) {
ItemStack stack = inv.getItem(i);
if (!stack.isEmpty()) {
stack.inventoryTick(this.player.level(), this.player, i, i == selectedSlot);
}
}
}
}

@Inject(method = "removeItem(Lnet/minecraft/world/item/ItemStack;)V", at = @At("HEAD"), cancellable = true)
private void utilitybelt$patchRemoveOneForHeldItems(ItemStack stack, CallbackInfo ci) {
ItemStack belt = UtilityBeltItem.getBelt(this.player);
if (belt != null) {
UtilityBeltInventory inv = StateManager.getServerInstance().getInventory(this.player);
int found = -1;

for (int i = 0; i < inv.getContainerSize(); i++) {
if (ItemStack.matches(stack, inv.getItem(i))) {
found = i;
break;
}
}

if (found != -1) {
inv.setItem(found, ItemStack.EMPTY);
ci.cancel();
}
}
}

@Inject(method = "fillStackedContents", at = @At("HEAD"))
private void utilitybelt$recipeFinderPatch(StackedContents contents, CallbackInfo ci) {
ItemStack belt = UtilityBeltItem.getBelt(this.player);
if (belt != null) {
UtilityBeltInventory inv = StateManager.getServerInstance().getInventory(this.player);

for (int i = 0; i < inv.getContainerSize(); i++) {
contents.accountSimpleStack(inv.getItem(i));
}
}
}

@Inject(method = "removeFromSelected", at = @At("HEAD"), cancellable = true)
private void utilitybelt$dropStackIfUsingUtilityBelt(boolean entireStack, CallbackInfoReturnable<ItemStack> cir) {
StateManager stateManager = StateManager.getServerInstance();
if (stateManager.isInBelt(this.player)) {
int slot = stateManager.getSelectedBeltSlot(this.player);
UtilityBeltInventory inv = stateManager.getInventory(this.player);
ItemStack removed = inv.removeItemNoUpdate(slot);
cir.setReturnValue(removed);
}
}

@Inject(method = "clearContent", at = @At("HEAD"))
private void utilitybelt$clearUtilityBelt(CallbackInfo ci) {
ItemStack belt = UtilityBeltItem.getBelt(this.player);
if (belt != null) {
UtilityBeltInventory inv = StateManager.getServerInstance().getInventory(this.player);
inv.clearContent();
}
}

@Inject(method = "contains(Lnet/minecraft/world/item/ItemStack;)Z", at = @At("HEAD"), cancellable = true)
private void utilitybelt$patchContainsStack(ItemStack stack, CallbackInfoReturnable<Boolean> cir) {
ItemStack belt = UtilityBeltItem.getBelt(this.player);
if (belt != null) {
UtilityBeltInventory inv = StateManager.getServerInstance().getInventory(this.player);

for (int i = 0; i < inv.getContainerSize(); i++) {
if (!inv.getItem(i).isEmpty() && ItemStack.matches(inv.getItem(i), stack)) {
cir.setReturnValue(true);
}
}
}
}

@Inject(method = "contains(Lnet/minecraft/tags/TagKey;)Z", at = @At("HEAD"), cancellable = true)
private void utilitybelt$patchContainsStack(TagKey<Item> key, CallbackInfoReturnable<Boolean> cir) {
ItemStack belt = UtilityBeltItem.getBelt(this.player);
if (belt != null) {
UtilityBeltInventory inv = StateManager.getServerInstance().getInventory(this.player);

for (int i = 0; i < inv.getContainerSize(); i++) {
if (!inv.getItem(i).isEmpty() && inv.getItem(i).is(key)) {
cir.setReturnValue(true);
}
}
}
}

@Inject(method = "dropAll", at = @At("HEAD"))
private void utilitybelt$dropAllFromUtilityBelt(CallbackInfo ci) {
ItemStack belt = UtilityBeltItem.getBelt(this.player);
if (belt != null) {
UtilityBeltInventory inv = StateManager.getServerInstance().getInventory(this.player);

for (int i = 0; i < inv.getContainerSize(); i++) {
ItemStack itemStack = inv.getItem(i);
if (!itemStack.isEmpty()) {
this.player.drop(itemStack, true, false);
inv.setItem(i, ItemStack.EMPTY);
}
}
}
}

@Inject(
method = "isEmpty",
at = @At("HEAD"),
cancellable = true
)
private void utilitybelt$patchIsEmpty(CallbackInfoReturnable<Boolean> cir) {
ItemStack belt = UtilityBeltItem.getBelt(this.player);
if (belt != null) {
UtilityBeltInventory inv = StateManager.getServerInstance().getInventory(this.player);

for (int i = 0; i < inv.getContainerSize(); i++) {
if (!inv.getItem(i).isEmpty()) {
cir.setReturnValue(false);
}
}
}
}
public abstract class InventoryMixin {

@Shadow
@Final
public Player player;

@Inject(
method = "getSelected",
at = @At("HEAD"),
cancellable = true
)
private void utilitybelt$getSelectedInUtilityBelt(CallbackInfoReturnable<ItemStack> cir) {
StateManager stateManager = StateManager.getServerInstance();
if (stateManager.isInBelt(this.player)) {
ItemStack belt = UtilityBeltItem.getBelt(this.player);
assert belt != null;
UtilityBeltInventory inv = stateManager.getInventory(this.player);
cir.setReturnValue(inv.getItem(stateManager.getSelectedBeltSlot(this.player)));
}
}

/**
* Necessary because Mojank does not use getSelected in this method.
*/
@Inject(
method = "getDestroySpeed",
at = @At("HEAD"),
cancellable = true
)
private void utilitybelt$getDestroySpeed(BlockState blockState, CallbackInfoReturnable<Float> cir) {
StateManager stateManager = StateManager.getServerInstance();
if (stateManager.isInBelt(this.player)) {
ItemStack belt = UtilityBeltItem.getBelt(this.player);
assert belt != null;
UtilityBeltInventory inv = stateManager.getInventory(this.player);
cir.setReturnValue(inv.getItem(stateManager.getSelectedBeltSlot(this.player)).getDestroySpeed(blockState));
}
}

@Inject(
method = "tick",
at = @At("RETURN")
)
private void utilitybelt$tick(CallbackInfo ci) {
ItemStack belt = UtilityBeltItem.getBelt(this.player);
StateManager stateManager = StateManager.getServerInstance();
if (stateManager.isInBelt(this.player)) {
assert belt != null;
UtilityBeltInventory inv = stateManager.getInventory(this.player);
int selectedSlot = stateManager.getSelectedBeltSlot(this.player);

for (int i = 0; i < inv.getContainerSize(); i++) {
ItemStack stack = inv.getItem(i);
if (!stack.isEmpty()) {
stack.inventoryTick(this.player.level(), this.player, i, i == selectedSlot);
}
}
}
}

@Inject(method = "removeItem(Lnet/minecraft/world/item/ItemStack;)V", at = @At("HEAD"), cancellable = true)
private void utilitybelt$patchRemoveOneForHeldItems(ItemStack stack, CallbackInfo ci) {
ItemStack belt = UtilityBeltItem.getBelt(this.player);
if (belt != null) {
UtilityBeltInventory inv = StateManager.getServerInstance().getInventory(this.player);
int found = -1;

for (int i = 0; i < inv.getContainerSize(); i++) {
if (ItemStack.matches(stack, inv.getItem(i))) {
found = i;
break;
}
}

if (found != -1) {
inv.setItem(found, ItemStack.EMPTY);
ci.cancel();
}
}
}

@Inject(method = "fillStackedContents", at = @At("HEAD"))
private void utilitybelt$recipeFinderPatch(StackedContents contents, CallbackInfo ci) {
ItemStack belt = UtilityBeltItem.getBelt(this.player);
if (belt != null) {
UtilityBeltInventory inv = StateManager.getServerInstance().getInventory(this.player);

for (int i = 0; i < inv.getContainerSize(); i++) {
contents.accountSimpleStack(inv.getItem(i));
}
}
}

@Inject(method = "removeFromSelected", at = @At("HEAD"), cancellable = true)
private void utilitybelt$dropStackIfUsingUtilityBelt(boolean entireStack, CallbackInfoReturnable<ItemStack> cir) {
StateManager stateManager = StateManager.getServerInstance();
if (stateManager.isInBelt(this.player)) {
int slot = stateManager.getSelectedBeltSlot(this.player);
UtilityBeltInventory inv = stateManager.getInventory(this.player);
ItemStack selected = inv.getItem(slot);

if (this.player.isLocalPlayer()) {
// Because of how the inventory is synced, we fake the return value on the clientside (not actually removing it)
ItemStack fakeReturn = selected.copy();
fakeReturn.setCount(entireStack ? selected.getCount() : 1);
cir.setReturnValue(selected.isEmpty() ? ItemStack.EMPTY : fakeReturn);
} else {
cir.setReturnValue(selected.isEmpty() ? ItemStack.EMPTY : inv.removeItem(slot, entireStack ? selected.getCount() : 1));
}
}
}

@Inject(method = "clearContent", at = @At("HEAD"))
private void utilitybelt$clearUtilityBelt(CallbackInfo ci) {
ItemStack belt = UtilityBeltItem.getBelt(this.player);
if (belt != null) {
UtilityBeltInventory inv = StateManager.getServerInstance().getInventory(this.player);
inv.clearContent();
}
}

@Inject(method = "contains(Lnet/minecraft/world/item/ItemStack;)Z", at = @At("HEAD"), cancellable = true)
private void utilitybelt$patchContainsStack(ItemStack stack, CallbackInfoReturnable<Boolean> cir) {
ItemStack belt = UtilityBeltItem.getBelt(this.player);
if (belt != null) {
UtilityBeltInventory inv = StateManager.getServerInstance().getInventory(this.player);

for (int i = 0; i < inv.getContainerSize(); i++) {
if (!inv.getItem(i).isEmpty() && ItemStack.matches(inv.getItem(i), stack)) {
cir.setReturnValue(true);
}
}
}
}

@Inject(method = "contains(Lnet/minecraft/tags/TagKey;)Z", at = @At("HEAD"), cancellable = true)
private void utilitybelt$patchContainsStack(TagKey<Item> key, CallbackInfoReturnable<Boolean> cir) {
ItemStack belt = UtilityBeltItem.getBelt(this.player);
if (belt != null) {
UtilityBeltInventory inv = StateManager.getServerInstance().getInventory(this.player);

for (int i = 0; i < inv.getContainerSize(); i++) {
if (!inv.getItem(i).isEmpty() && inv.getItem(i).is(key)) {
cir.setReturnValue(true);
}
}
}
}

@Inject(method = "dropAll", at = @At("HEAD"))
private void utilitybelt$dropAllFromUtilityBelt(CallbackInfo ci) {
ItemStack belt = UtilityBeltItem.getBelt(this.player);
if (belt != null) {
UtilityBeltInventory inv = StateManager.getServerInstance().getInventory(this.player);

for (int i = 0; i < inv.getContainerSize(); i++) {
ItemStack itemStack = inv.getItem(i);
if (!itemStack.isEmpty()) {
this.player.drop(itemStack, true, false);
inv.setItem(i, ItemStack.EMPTY);
}
}
}
}

@Inject(
method = "isEmpty",
at = @At("HEAD"),
cancellable = true
)
private void utilitybelt$patchIsEmpty(CallbackInfoReturnable<Boolean> cir) {
ItemStack belt = UtilityBeltItem.getBelt(this.player);
if (belt != null) {
UtilityBeltInventory inv = StateManager.getServerInstance().getInventory(this.player);

for (int i = 0; i < inv.getContainerSize(); i++) {
if (!inv.getItem(i).isEmpty()) {
cir.setReturnValue(false);
}
}
}
}
}
Loading

0 comments on commit 773cb40

Please sign in to comment.