Add FTB NBT editor shortcuts
This commit is contained in:
parent
7041633e1b
commit
30f4dc4933
9 changed files with 263 additions and 0 deletions
|
|
@ -2,6 +2,10 @@ version = '0.1.0'
|
||||||
base.archivesName = 'saltatory-client'
|
base.archivesName = 'saltatory-client'
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
|
maven {
|
||||||
|
url = 'https://maven.ftb.dev/releases'
|
||||||
|
content { includeGroup 'dev.ftb.mods' }
|
||||||
|
}
|
||||||
maven {
|
maven {
|
||||||
url = 'https://api.modrinth.com/maven'
|
url = 'https://api.modrinth.com/maven'
|
||||||
content { includeGroup 'maven.modrinth' }
|
content { includeGroup 'maven.modrinth' }
|
||||||
|
|
@ -20,6 +24,7 @@ def createLibs = tasks.register('createLibs', Sync) {
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
compileOnly('dev.ftb.mods:ftb-library-neoforge:2101.1.37') { transitive = false }
|
||||||
createBundle('maven.modrinth:create:UjX6dr61') { transitive = false }
|
createBundle('maven.modrinth:create:UjX6dr61') { transitive = false }
|
||||||
compileOnly files(createLibs).asFileTree.matching { include '**/*.jar' }
|
compileOnly files(createLibs).asFileTree.matching { include '**/*.jar' }
|
||||||
compileOnly('maven.modrinth:iris:t3ruzodq') { transitive = false }
|
compileOnly('maven.modrinth:iris:t3ruzodq') { transitive = false }
|
||||||
|
|
|
||||||
59
client/src/main/java/dev/quorate/client/nbt/NbtKeys.java
Normal file
59
client/src/main/java/dev/quorate/client/nbt/NbtKeys.java
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
package dev.quorate.client.nbt;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.platform.InputConstants;
|
||||||
|
|
||||||
|
import net.minecraft.client.KeyMapping;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.phys.BlockHitResult;
|
||||||
|
import net.minecraft.world.phys.EntityHitResult;
|
||||||
|
import net.neoforged.api.distmarker.Dist;
|
||||||
|
import net.neoforged.bus.api.SubscribeEvent;
|
||||||
|
import net.neoforged.fml.common.EventBusSubscriber;
|
||||||
|
import net.neoforged.neoforge.client.event.ClientTickEvent;
|
||||||
|
import net.neoforged.neoforge.client.event.RegisterKeyMappingsEvent;
|
||||||
|
|
||||||
|
import org.lwjgl.glfw.GLFW;
|
||||||
|
|
||||||
|
public final class NbtKeys {
|
||||||
|
private static final KeyMapping OPEN =
|
||||||
|
new KeyMapping(
|
||||||
|
"key.saltatory_client.nbt",
|
||||||
|
InputConstants.Type.KEYSYM,
|
||||||
|
GLFW.GLFW_KEY_N,
|
||||||
|
"key.categories.misc");
|
||||||
|
|
||||||
|
private NbtKeys() {}
|
||||||
|
|
||||||
|
@EventBusSubscriber(modid = "saltatory_client", value = Dist.CLIENT)
|
||||||
|
public static final class ModEvents {
|
||||||
|
@SubscribeEvent
|
||||||
|
public static void register(RegisterKeyMappingsEvent event) {
|
||||||
|
if (NbtPlugin.supported()) event.register(OPEN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventBusSubscriber(modid = "saltatory_client", value = Dist.CLIENT)
|
||||||
|
public static final class GameEvents {
|
||||||
|
@SubscribeEvent
|
||||||
|
public static void tick(ClientTickEvent.Post event) {
|
||||||
|
Minecraft mc = Minecraft.getInstance();
|
||||||
|
while (OPEN.consumeClick()) {
|
||||||
|
if (!NbtPlugin.supported()
|
||||||
|
|| mc.player == null
|
||||||
|
|| mc.screen != null
|
||||||
|
|| mc.getConnection() == null) continue;
|
||||||
|
String target = "item";
|
||||||
|
if (mc.hitResult instanceof EntityHitResult hit) {
|
||||||
|
String kind = hit.getEntity() instanceof Player ? "player " : "entity ";
|
||||||
|
target = kind + hit.getEntity().getStringUUID();
|
||||||
|
} else if (mc.hitResult instanceof BlockHitResult hit
|
||||||
|
&& mc.level.getBlockEntity(hit.getBlockPos()) != null) {
|
||||||
|
var pos = hit.getBlockPos();
|
||||||
|
target = "block " + pos.getX() + " " + pos.getY() + " " + pos.getZ();
|
||||||
|
}
|
||||||
|
mc.getConnection().sendCommand("ftblibrary nbtedit " + target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
45
client/src/main/java/dev/quorate/client/nbt/NbtPlugin.java
Normal file
45
client/src/main/java/dev/quorate/client/nbt/NbtPlugin.java
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
package dev.quorate.client.nbt;
|
||||||
|
|
||||||
|
import dev.quorate.client.mixin.ModRanges;
|
||||||
|
|
||||||
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
|
import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin;
|
||||||
|
import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public final class NbtPlugin implements IMixinConfigPlugin {
|
||||||
|
static final String FTB = "[2101.1.37]";
|
||||||
|
|
||||||
|
public static boolean supported() {
|
||||||
|
return ModRanges.loaded("ftblibrary", FTB);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoad(String mixinPackage) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getRefMapperConfig() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean shouldApplyMixin(String target, String mixin) {
|
||||||
|
return supported();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void acceptTargets(Set<String> targets, Set<String> others) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getMixins() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void preApply(String target, ClassNode node, String mixin, IMixinInfo info) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void postApply(String target, ClassNode node, String mixin, IMixinInfo info) {}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,105 @@
|
||||||
|
package dev.quorate.client.nbt.mixin;
|
||||||
|
|
||||||
|
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||||
|
|
||||||
|
import dev.ftb.mods.ftblibrary.nbtedit.NBTEditorScreen;
|
||||||
|
import dev.ftb.mods.ftblibrary.nbtedit.NBTEditorScreen.ButtonNBT;
|
||||||
|
import dev.ftb.mods.ftblibrary.nbtedit.NBTEditorScreen.ButtonNBTCollection;
|
||||||
|
import dev.ftb.mods.ftblibrary.nbtedit.NBTEditorScreen.ButtonNBTMap;
|
||||||
|
import dev.ftb.mods.ftblibrary.ui.input.Key;
|
||||||
|
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.nbt.Tag;
|
||||||
|
import net.minecraft.nbt.TagParser;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
|
||||||
|
import org.lwjgl.glfw.GLFW;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
|
@Mixin(value = NBTEditorScreen.class, remap = false)
|
||||||
|
public abstract class EditorMixin {
|
||||||
|
@Shadow private ButtonNBT selected;
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
private void setSelected(ButtonNBT node) {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "keyPressed", at = @At("RETURN"), cancellable = true)
|
||||||
|
private void saltatory$keys(Key key, CallbackInfoReturnable<Boolean> result) {
|
||||||
|
if (result.getReturnValue() || !key.modifiers.control()) return;
|
||||||
|
if (key.is(GLFW.GLFW_KEY_C)) {
|
||||||
|
saltatory$copy();
|
||||||
|
result.setReturnValue(true);
|
||||||
|
} else if (key.is(GLFW.GLFW_KEY_V)) {
|
||||||
|
saltatory$paste();
|
||||||
|
result.setReturnValue(true);
|
||||||
|
} else if (key.is(GLFW.GLFW_KEY_D) || key.is(GLFW.GLFW_KEY_X)) {
|
||||||
|
NodeAccess node = (NodeAccess) selected;
|
||||||
|
ButtonNBTCollection parent = node.saltatory$parent();
|
||||||
|
if (parent != null) {
|
||||||
|
if (key.is(GLFW.GLFW_KEY_X)) saltatory$copy();
|
||||||
|
parent.setTag(node.saltatory$key(), null);
|
||||||
|
parent.updateChildren(false);
|
||||||
|
setSelected(parent);
|
||||||
|
parent.getGui().refreshWidgets();
|
||||||
|
}
|
||||||
|
result.setReturnValue(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private void saltatory$copy() {
|
||||||
|
NodeAccess node = (NodeAccess) selected;
|
||||||
|
ButtonNBTCollection parent = node.saltatory$parent();
|
||||||
|
CompoundTag copied = new CompoundTag();
|
||||||
|
if (parent == null && selected instanceof ButtonNBTMap root) {
|
||||||
|
for (String name : root.children.keySet()) {
|
||||||
|
copied.put(name, root.getTag(name).copy());
|
||||||
|
}
|
||||||
|
} else if (parent != null) {
|
||||||
|
copied.put(node.saltatory$key(), parent.getTag(node.saltatory$key()).copy());
|
||||||
|
}
|
||||||
|
Minecraft.getInstance().keyboardHandler.setClipboard(copied.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private void saltatory$paste() {
|
||||||
|
if (!(selected instanceof ButtonNBTCollection target)) return;
|
||||||
|
CompoundTag copied;
|
||||||
|
try {
|
||||||
|
copied = TagParser.parseTag(Minecraft.getInstance().keyboardHandler.getClipboard());
|
||||||
|
} catch (CommandSyntaxException e) {
|
||||||
|
Minecraft.getInstance()
|
||||||
|
.player
|
||||||
|
.displayClientMessage(Component.literal("Invalid NBT clipboard"), true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
byte elementType = 0;
|
||||||
|
for (String name : copied.getAllKeys()) {
|
||||||
|
Tag tag = copied.get(name);
|
||||||
|
if (!target.canCreateNew(tag.getId())
|
||||||
|
|| (!(target instanceof ButtonNBTMap)
|
||||||
|
&& elementType != 0
|
||||||
|
&& elementType != tag.getId())) {
|
||||||
|
Minecraft.getInstance()
|
||||||
|
.player
|
||||||
|
.displayClientMessage(
|
||||||
|
Component.literal("NBT type does not fit selection"), true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
elementType = tag.getId();
|
||||||
|
}
|
||||||
|
for (String name : copied.getAllKeys()) {
|
||||||
|
target.setTag(target instanceof ButtonNBTMap ? name : "-1", copied.get(name).copy());
|
||||||
|
}
|
||||||
|
target.updateChildren(false);
|
||||||
|
target.getGui().refreshWidgets();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
package dev.quorate.client.nbt.mixin;
|
||||||
|
|
||||||
|
import dev.ftb.mods.ftblibrary.nbtedit.NBTEditorScreen.ButtonNBT;
|
||||||
|
import dev.ftb.mods.ftblibrary.nbtedit.NBTEditorScreen.ButtonNBTCollection;
|
||||||
|
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||||
|
|
||||||
|
@Mixin(value = ButtonNBT.class, remap = false)
|
||||||
|
public interface NodeAccess {
|
||||||
|
@Accessor("parent")
|
||||||
|
ButtonNBTCollection saltatory$parent();
|
||||||
|
|
||||||
|
@Accessor("key")
|
||||||
|
String saltatory$key();
|
||||||
|
}
|
||||||
|
|
@ -14,6 +14,9 @@ config="client.mixins.json"
|
||||||
[[mixins]]
|
[[mixins]]
|
||||||
config="client.jemi.mixins.json"
|
config="client.jemi.mixins.json"
|
||||||
|
|
||||||
|
[[mixins]]
|
||||||
|
config="client.nbt.mixins.json"
|
||||||
|
|
||||||
[[dependencies.saltatory_client]]
|
[[dependencies.saltatory_client]]
|
||||||
modId="neoforge"
|
modId="neoforge"
|
||||||
type="required"
|
type="required"
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"key.saltatory_client.nbt": "Edit targeted NBT"
|
||||||
|
}
|
||||||
9
client/src/main/resources/client.nbt.mixins.json
Normal file
9
client/src/main/resources/client.nbt.mixins.json
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"required": true,
|
||||||
|
"minVersion": "0.8.7",
|
||||||
|
"package": "dev.quorate.client.nbt.mixin",
|
||||||
|
"compatibilityLevel": "JAVA_21",
|
||||||
|
"plugin": "dev.quorate.client.nbt.NbtPlugin",
|
||||||
|
"client": ["NodeAccess", "EditorMixin"],
|
||||||
|
"injectors": {"defaultRequire": 1}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
package dev.quorate.client.nbt;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
import dev.quorate.client.mixin.ModRanges;
|
||||||
|
|
||||||
|
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
final class NbtPluginTest {
|
||||||
|
@Test
|
||||||
|
void targetsOnlyInspectedFtbVersion() {
|
||||||
|
assertTrue(ModRanges.contains(new DefaultArtifactVersion("2101.1.37"), NbtPlugin.FTB));
|
||||||
|
assertFalse(ModRanges.contains(new DefaultArtifactVersion("2101.1.36"), NbtPlugin.FTB));
|
||||||
|
assertFalse(ModRanges.contains(new DefaultArtifactVersion("2101.1.38"), NbtPlugin.FTB));
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue