Skip to content

Commit 4c7fc2f

Browse files
authored
Add the ckit command (#227)
* Simplify code and handle duplicate kit names * Implement most requested changes * Simplify code and fix --override * Store ListTags instead of PlayerInventories to prevent memory leaks + re-change static imports to wildcard imports * Remove redundant line + optimise a bit * Implement last requested changes * Resolve conflicts * Resolve conflicts 2 * Resolve conflicts 3 * Implement requested changes * Fix removed line
1 parent eb9897e commit 4c7fc2f

File tree

4 files changed

+215
-19
lines changed

4 files changed

+215
-19
lines changed

src/main/java/net/earthcomputer/clientcommands/ClientCommands.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22

33
import com.mojang.brigadier.CommandDispatcher;
44
import net.earthcomputer.clientcommands.command.*;
5-
import net.earthcomputer.clientcommands.features.ChorusManipulation;
6-
import net.earthcomputer.clientcommands.render.RenderQueue;
75
import net.earthcomputer.clientcommands.script.ScriptManager;
86
import net.fabricmc.api.ClientModInitializer;
97
import net.fabricmc.loader.api.FabricLoader;
@@ -57,6 +55,7 @@ public static void registerCommands(CommandDispatcher<ServerCommandSource> dispa
5755
CStopSoundCommand.register(dispatcher);
5856
FovCommand.register(dispatcher);
5957
HotbarCommand.register(dispatcher);
58+
KitCommand.register(dispatcher);
6059

6160
CrackRNGCommand.register(dispatcher);
6261

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,19 @@
11
package net.earthcomputer.clientcommands.command;
22

3-
import static com.mojang.brigadier.arguments.IntegerArgumentType.*;
4-
import static net.earthcomputer.clientcommands.command.ClientCommandManager.*;
5-
import static net.minecraft.command.argument.ItemStackArgumentType.*;
6-
import static net.minecraft.server.command.CommandManager.*;
7-
83
import com.mojang.brigadier.CommandDispatcher;
9-
import com.mojang.brigadier.exceptions.*;
10-
4+
import com.mojang.brigadier.exceptions.CommandSyntaxException;
5+
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
116
import net.minecraft.client.MinecraftClient;
12-
import net.minecraft.client.network.ClientPlayerEntity;
137
import net.minecraft.command.argument.ItemStackArgument;
14-
import net.minecraft.entity.player.PlayerInventory;
158
import net.minecraft.item.ItemStack;
169
import net.minecraft.server.command.ServerCommandSource;
1710
import net.minecraft.text.TranslatableText;
1811

12+
import static com.mojang.brigadier.arguments.IntegerArgumentType.*;
13+
import static net.earthcomputer.clientcommands.command.ClientCommandManager.*;
14+
import static net.minecraft.command.argument.ItemStackArgumentType.*;
15+
import static net.minecraft.server.command.CommandManager.*;
16+
1917
public class CGiveCommand {
2018

2119
private static final SimpleCommandExceptionType NOT_CREATIVE_EXCEPTION = new SimpleCommandExceptionType(new TranslatableText("commands.cgive.notCreative"));
@@ -31,20 +29,16 @@ public static void register(CommandDispatcher<ServerCommandSource> dispatcher) {
3129
}
3230

3331
private static int give(ServerCommandSource source, ItemStackArgument itemArgument, int count) throws CommandSyntaxException {
34-
ClientPlayerEntity player = MinecraftClient.getInstance().player;
35-
if (!player.abilities.creativeMode) {
32+
final MinecraftClient client = MinecraftClient.getInstance();
33+
if (!client.player.abilities.creativeMode) {
3634
throw NOT_CREATIVE_EXCEPTION.create();
3735
}
3836

3937
ItemStack stack = itemArgument.createStack(Math.min(count, itemArgument.getItem().getMaxCount()), false);
40-
41-
PlayerInventory inventory = player.inventory;
42-
inventory.setStack(inventory.selectedSlot, stack);
43-
MinecraftClient.getInstance().interactionManager.clickCreativeStack(stack, 36 + inventory.selectedSlot);
44-
player.playerScreenHandler.sendContentUpdates();
38+
client.interactionManager.clickCreativeStack(stack, 36 + client.player.inventory.selectedSlot);
39+
client.player.playerScreenHandler.sendContentUpdates();
4540

4641
sendFeedback(new TranslatableText("commands.cgive.success", count, stack.toHoverableText()));
4742
return 0;
4843
}
49-
5044
}
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
package net.earthcomputer.clientcommands.command;
2+
3+
import com.mojang.brigadier.CommandDispatcher;
4+
import com.mojang.brigadier.arguments.StringArgumentType;
5+
import com.mojang.brigadier.exceptions.CommandSyntaxException;
6+
import com.mojang.brigadier.exceptions.DynamicCommandExceptionType;
7+
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
8+
import com.mojang.brigadier.tree.LiteralCommandNode;
9+
import com.mojang.serialization.Dynamic;
10+
import net.earthcomputer.clientcommands.interfaces.ISlot;
11+
import net.fabricmc.fabric.api.util.NbtType;
12+
import net.fabricmc.loader.api.FabricLoader;
13+
import net.minecraft.SharedConstants;
14+
import net.minecraft.client.MinecraftClient;
15+
import net.minecraft.command.CommandSource;
16+
import net.minecraft.datafixer.TypeReferences;
17+
import net.minecraft.entity.player.PlayerInventory;
18+
import net.minecraft.item.ItemStack;
19+
import net.minecraft.nbt.*;
20+
import net.minecraft.screen.slot.Slot;
21+
import net.minecraft.server.command.ServerCommandSource;
22+
import net.minecraft.text.TranslatableText;
23+
import net.minecraft.util.Util;
24+
25+
import java.io.File;
26+
import java.io.IOException;
27+
import java.nio.file.Path;
28+
import java.util.HashMap;
29+
import java.util.List;
30+
import java.util.Map;
31+
32+
import static net.earthcomputer.clientcommands.command.ClientCommandManager.*;
33+
import static net.minecraft.server.command.CommandManager.*;
34+
35+
public class KitCommand {
36+
37+
private static final SimpleCommandExceptionType SAVE_FAILED_EXCEPTION = new SimpleCommandExceptionType(new TranslatableText("commands.ckit.saveFile.failed"));
38+
private static final SimpleCommandExceptionType LOAD_FAILED_EXCEPTION = new SimpleCommandExceptionType(new TranslatableText("commands.ckit.loadFile.failed"));
39+
40+
private static final DynamicCommandExceptionType ALREADY_EXISTS_EXCEPTION = new DynamicCommandExceptionType(arg -> new TranslatableText("commands.ckit.create.alreadyExists", arg));
41+
42+
private static final SimpleCommandExceptionType NOT_CREATIVE_EXCEPTION = new SimpleCommandExceptionType(new TranslatableText("commands.ckit.load.notCreative"));
43+
private static final DynamicCommandExceptionType NOT_FOUND_EXCEPTION = new DynamicCommandExceptionType(arg -> new TranslatableText("commands.ckit.notFound", arg));
44+
45+
private static final Path configPath = FabricLoader.getInstance().getConfigDir().resolve("clientcommands");
46+
47+
private static final MinecraftClient client = MinecraftClient.getInstance();
48+
49+
private static final Map<String, ListTag> kits = new HashMap<>();
50+
51+
public static void register(CommandDispatcher<ServerCommandSource> dispatcher) {
52+
addClientSideCommand("ckit");
53+
54+
LiteralCommandNode<ServerCommandSource> ckit = dispatcher.register(literal("ckit"));
55+
dispatcher.register(literal("ckit")
56+
.then(literal("create")
57+
.then(argument("name", StringArgumentType.string())
58+
.executes(ctx -> create(ctx.getSource(), StringArgumentType.getString(ctx, "name")))))
59+
.then(literal("delete")
60+
.then(argument("name", StringArgumentType.string())
61+
.suggests((ctx, builder) -> CommandSource.suggestMatching(kits.keySet(), builder))
62+
.executes(ctx -> delete(ctx.getSource(), StringArgumentType.getString(ctx, "name")))))
63+
.then(literal("edit")
64+
.then(argument("name", StringArgumentType.string())
65+
.suggests((ctx, builder) -> CommandSource.suggestMatching(kits.keySet(), builder))
66+
.executes(ctx -> edit(ctx.getSource(), StringArgumentType.getString(ctx, "name")))))
67+
.then(literal("load")
68+
.then(argument("name", StringArgumentType.string())
69+
.suggests((ctx, builder) -> CommandSource.suggestMatching(kits.keySet(), builder))
70+
.then(literal("--override")
71+
.executes(ctx -> load(ctx.getSource(), StringArgumentType.getString(ctx, "name"), true)))
72+
.executes(ctx -> load(ctx.getSource(), StringArgumentType.getString(ctx, "name"), false))))
73+
.then(literal("list")
74+
.executes(ctx -> list(ctx.getSource()))));
75+
}
76+
77+
private static int create(ServerCommandSource source, String name) throws CommandSyntaxException {
78+
loadFile();
79+
80+
if (kits.containsKey(name)) {
81+
throw ALREADY_EXISTS_EXCEPTION.create(name);
82+
}
83+
kits.put(name, client.player.inventory.serialize(new ListTag()));
84+
saveFile();
85+
sendFeedback("commands.ckit.create.success", name);
86+
return 0;
87+
}
88+
89+
private static int delete(ServerCommandSource source, String name) throws CommandSyntaxException {
90+
loadFile();
91+
92+
if (kits.remove(name) == null) {
93+
throw NOT_FOUND_EXCEPTION.create(name);
94+
}
95+
saveFile();
96+
sendFeedback("commands.ckit.delete.success", name);
97+
return 0;
98+
}
99+
100+
private static int edit(ServerCommandSource source, String name) throws CommandSyntaxException {
101+
loadFile();
102+
103+
if (!kits.containsKey(name)) {
104+
throw NOT_FOUND_EXCEPTION.create(name);
105+
}
106+
kits.put(name, client.player.inventory.serialize(new ListTag()));
107+
saveFile();
108+
sendFeedback("commands.ckit.edit.success", name);
109+
return 0;
110+
}
111+
112+
private static int load(ServerCommandSource source, String name, boolean override) throws CommandSyntaxException {
113+
if (!client.player.abilities.creativeMode) {
114+
throw NOT_CREATIVE_EXCEPTION.create();
115+
}
116+
117+
loadFile();
118+
119+
ListTag kit = kits.get(name);
120+
if (kit == null) {
121+
throw NOT_FOUND_EXCEPTION.create(name);
122+
}
123+
124+
PlayerInventory tempInv = new PlayerInventory(client.player);
125+
tempInv.deserialize(kit);
126+
List<Slot> slots = client.player.playerScreenHandler.slots;
127+
for (int i = 0; i < slots.size(); i++) {
128+
if (slots.get(i).inventory == client.player.inventory) {
129+
ItemStack itemStack = tempInv.getStack(((ISlot) slots.get(i)).getIndex());
130+
if (!itemStack.isEmpty() || override) {
131+
client.interactionManager.clickCreativeStack(itemStack, i);
132+
}
133+
}
134+
}
135+
136+
client.player.playerScreenHandler.sendContentUpdates();
137+
sendFeedback("commands.ckit.load.success", name);
138+
return 0;
139+
}
140+
141+
private static int list(ServerCommandSource source) throws CommandSyntaxException {
142+
loadFile();
143+
144+
String list = String.join(", ", kits.keySet());
145+
sendFeedback(list.equals("") ? "No available kits" : "Available kits: " + list);
146+
return kits.size();
147+
}
148+
149+
private static void saveFile() throws CommandSyntaxException {
150+
try {
151+
CompoundTag rootTag = new CompoundTag();
152+
CompoundTag compoundTag = new CompoundTag();
153+
kits.forEach(compoundTag::put);
154+
rootTag.putInt("DataVersion", SharedConstants.getGameVersion().getWorldVersion());
155+
rootTag.put("Kits", compoundTag);
156+
File newFile = File.createTempFile("kits", ".dat", configPath.toFile());
157+
NbtIo.write(rootTag, newFile);
158+
File backupFile = new File(configPath.toFile(), "kits.dat_old");
159+
File currentFile = new File(configPath.toFile(), "kits.dat");
160+
Util.backupAndReplace(currentFile, newFile, backupFile);
161+
} catch (IOException e) {
162+
throw SAVE_FAILED_EXCEPTION.create();
163+
}
164+
}
165+
166+
private static void loadFile() throws CommandSyntaxException {
167+
try {
168+
kits.clear();
169+
CompoundTag rootTag = NbtIo.read(new File(configPath.toFile(), "kits.dat"));
170+
if (rootTag == null) {
171+
return;
172+
}
173+
final int currentVersion = SharedConstants.getGameVersion().getWorldVersion();
174+
final int fileVersion = rootTag.getInt("DataVersion");
175+
CompoundTag compoundTag = rootTag.getCompound("Kits");
176+
if (fileVersion >= currentVersion) {
177+
compoundTag.getKeys().forEach(key -> kits.put(key, compoundTag.getList(key, NbtType.COMPOUND)));
178+
} else {
179+
compoundTag.getKeys().forEach(key -> {
180+
ListTag updatedListTag = new ListTag();
181+
compoundTag.getList(key, NbtType.COMPOUND).forEach(tag -> {
182+
Dynamic<Tag> oldTagDynamic = new Dynamic<>(NbtOps.INSTANCE, tag);
183+
Dynamic<Tag> newTagDynamic = client.getDataFixer().update(TypeReferences.ITEM_STACK, oldTagDynamic, fileVersion, currentVersion);
184+
updatedListTag.add(newTagDynamic.getValue());
185+
});
186+
kits.put(key, updatedListTag);
187+
});
188+
}
189+
} catch (IOException e) {
190+
throw LOAD_FAILED_EXCEPTION.create();
191+
}
192+
}
193+
}

src/main/resources/assets/clientcommands/lang/en_us.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,16 @@
7979
"commands.chotbar.notCreative": "Player must be in creative mode to restore item hotbars",
8080
"commands.chotbar.restoredHotbar": "Restored item hotbar %d",
8181

82+
"commands.ckit.notFound": "Kit \"%s\" not found",
83+
"commands.ckit.saveFile.failed": "Could not save kits file",
84+
"commands.ckit.loadFile.failed": "Could not load kits file",
85+
"commands.ckit.load.success": "Successfully gave kit \"%s\" to self",
86+
"commands.ckit.load.notCreative": "Player must be in creative mode to give items to self",
87+
"commands.ckit.create.success": "Successfully created kit \"%s\"",
88+
"commands.ckit.create.alreadyExists": "Kit \"%s\" already exists",
89+
"commands.ckit.delete.success": "Successfully deleted kit \"%s\"",
90+
"commands.ckit.edit.success": "Successfully edited kit \"%s\"",
91+
8292
"commands.cplaysound.success": "Played sound %s to self",
8393

8494
"commands.crelog.failed": "Failed to relog",

0 commit comments

Comments
 (0)