Skip to content

Commit

Permalink
Fix #693 - cgive creating ghost items
Browse files Browse the repository at this point in the history
  • Loading branch information
Earthcomputer committed Dec 9, 2024
1 parent 5a1e635 commit b9ad1a6
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,16 @@
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList;
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
import net.minecraft.client.multiplayer.MultiPlayerGameMode;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.commands.CommandBuildContext;
import net.minecraft.commands.arguments.item.ItemInput;
import net.minecraft.network.chat.Component;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.inventory.InventoryMenu;
import net.minecraft.world.item.ItemStack;

import static com.mojang.brigadier.arguments.IntegerArgumentType.*;
Expand All @@ -17,6 +23,7 @@
public class CGiveCommand {

private static final SimpleCommandExceptionType NOT_CREATIVE_EXCEPTION = new SimpleCommandExceptionType(Component.translatable("commands.cgive.notCreative"));
private static final SimpleCommandExceptionType NO_SPACE_EXCEPTION = new SimpleCommandExceptionType(Component.translatable("commands.cgive.noSpace"));

public static void register(CommandDispatcher<FabricClientCommandSource> dispatcher, CommandBuildContext context) {
dispatcher.register(literal("cgive")
Expand All @@ -27,15 +34,67 @@ public static void register(CommandDispatcher<FabricClientCommandSource> dispatc
}

private static int give(FabricClientCommandSource source, ItemInput itemInput, int count) throws CommandSyntaxException {
if (!source.getPlayer().getAbilities().instabuild) {
LocalPlayer player = source.getPlayer();
if (!player.getAbilities().instabuild) {
throw NOT_CREATIVE_EXCEPTION.create();
}
MultiPlayerGameMode interactionManager = source.getClient().gameMode;
assert interactionManager != null;

ItemStack stack = itemInput.createItemStack(count, false);
source.getClient().gameMode.handleCreativeModeItemAdd(stack, 36 + source.getPlayer().getInventory().selected);
source.getPlayer().inventoryMenu.broadcastChanges();

source.sendFeedback(Component.translatable("commands.cgive.success", stack.getCount(), stack.getDisplayName()));
IntList changedSlots = new IntArrayList();
int simulatedCount = stack.getCount();
int prevCount;
do {
prevCount = simulatedCount;
int slot = getSlotWithRemainingSpace(player.getInventory(), stack, changedSlots);
if (slot == -1) {
slot = player.getInventory().getFreeSlot();
}
if (slot != -1) {
ItemStack stackInSlot = player.getInventory().getItem(slot);
simulatedCount = Math.clamp(simulatedCount - (player.getInventory().getMaxStackSize(stackInSlot) - stackInSlot.getCount()), 0, simulatedCount);
changedSlots.add(slot);
}
} while (simulatedCount != 0 && simulatedCount != prevCount);

if (simulatedCount != 0) {
throw NO_SPACE_EXCEPTION.create();
}

for (int i = 0; i < changedSlots.size(); i++) {
int slot = changedSlots.getInt(i);
stack.setCount(player.getInventory().addResource(slot, stack));
interactionManager.handleCreativeModeItemAdd(player.getInventory().getItem(slot), inventoryToSlotId(slot));
}

player.inventoryMenu.broadcastChanges();

// recreate the stack, otherwise it shows that the player was given air
stack = itemInput.createItemStack(count, false);
source.sendFeedback(Component.translatable("commands.cgive.success", count, stack.getDisplayName()));
return Command.SINGLE_SUCCESS;
}

private static int getSlotWithRemainingSpace(Inventory inventory, ItemStack stack, IntList fullSlots) {
if (inventory.hasRemainingSpaceForItem(inventory.getItem(inventory.selected), stack) && !fullSlots.contains(inventory.selected)) {
return inventory.selected;
} else if (inventory.hasRemainingSpaceForItem(inventory.getItem(Inventory.SLOT_OFFHAND), stack) && !fullSlots.contains(Inventory.SLOT_OFFHAND)) {
return inventory.selected;
} else {
for (int slot = 0; slot < Inventory.INVENTORY_SIZE; slot++) {
if (inventory.hasRemainingSpaceForItem(inventory.getItem(slot), stack) && !fullSlots.contains(slot)) {
return slot;
}
}
return -1;
}
}

private static int inventoryToSlotId(int inventoryId) {
return inventoryId < Inventory.SELECTION_SIZE
? InventoryMenu.USE_ROW_SLOT_START + inventoryId
: InventoryMenu.INV_SLOT_START - Inventory.SELECTION_SIZE + inventoryId;
}
}
1 change: 1 addition & 0 deletions src/main/resources/assets/clientcommands/lang/en_us.json
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@
"commands.cghostblock.fill.success": "%s ghost blocks filled",
"commands.cghostblock.set.success": "Ghost block placed",

"commands.cgive.noSpace": "There is no space in your inventory for that item",
"commands.cgive.notCreative": "Player must be in creative mode to give items to self",
"commands.cgive.success": "Gave %s %s to self",

Expand Down
4 changes: 4 additions & 0 deletions src/main/resources/clientcommands.aw
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ accessible method net/minecraft/world/level/block/ShulkerBoxBlock canOpen (Lnet/
# cfish
accessible method net/minecraft/world/entity/projectile/FishingHook canHitEntity (Lnet/minecraft/world/entity/Entity;)Z

# cgive
accessible method net/minecraft/world/entity/player/Inventory addResource (ILnet/minecraft/world/item/ItemStack;)I
accessible method net/minecraft/world/entity/player/Inventory hasRemainingSpaceForItem (Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/item/ItemStack;)Z

# chat
accessible method net/minecraft/client/Minecraft openChatScreen (Ljava/lang/String;)V

Expand Down

0 comments on commit b9ad1a6

Please sign in to comment.