diff --git a/README.md b/README.md index ed8a37d..e0e86b4 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@
-Logo +Logo # No More Useless Keys diff --git a/build.gradle b/build.gradle index 7f71904..e6d5388 100644 --- a/build.gradle +++ b/build.gradle @@ -1,174 +1,79 @@ plugins { - id 'fabric-loom' version '1.4-SNAPSHOT' - id 'maven-publish' - id 'com.matthewprenger.cursegradle' version '1.4.0' - id 'com.modrinth.minotaur' version '2.1.1' - id 'org.cadixdev.licenser' version '0.6.1' + id 'dev.architectury.loom' version '1.6-SNAPSHOT' apply false + id 'architectury-plugin' version '3.4-SNAPSHOT' + id 'com.github.johnrengelman.shadow' version '8.1.1' apply false } -sourceCompatibility = JavaVersion.VERSION_1_8 -targetCompatibility = JavaVersion.VERSION_16 +architectury { + minecraft = project.minecraft_version +} -archivesBaseName = project.archives_base_name -version = "${project.mod_version}+mc${project.minecraft_version}" -group = project.maven_group +allprojects { + version = "${project.mod_version}+mc${project.minecraft_version}" + group = project.maven_group +} -loom { - accessWidenerPath = file("src/main/resources/nmuk.accesswidener") +subprojects { + apply plugin: 'dev.architectury.loom' + apply plugin: 'architectury-plugin' + apply plugin: 'maven-publish' + + base { + archivesName = rootProject.archives_base_name + } + + repositories { + maven { + name "Siphalor's Maven" + url "https://maven.siphalor.de" + } + maven { url "https://jitpack.io" } + mavenLocal() + } + + dependencies { + minecraft "net.minecraft:minecraft:$rootProject.minecraft_version" + mappings "net.fabricmc:yarn:$rootProject.yarn_mappings:v2" + } + + java { + withSourcesJar() + + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + + processResources { + def substitutions = [ + "mod_id": mod_id, + "mod_version": mod_version, + "mod_name": mod_name, + "mod_authors": mod_authors, + "mod_description": mod_description, + "forge_version": forge_version, + "minecraft_version_range": minecraft_version_range + ] + inputs.properties(substitutions) + + filesMatching(['fabric.mod.json', 'META-INF/mods.toml', 'pack.mcmeta']) { + expand(substitutions) + } + } } +/* + sourceSets { testmod { compileClasspath += main.compileClasspath runtimeClasspath += main.runtimeClasspath } -} +}*/ -repositories { - maven { - name "Siphalor's Maven" - url "https://maven.siphalor.de" - } - maven { url "https://jitpack.io" } - mavenLocal() -} - -dependencies { - //to change the versions see the gradle.properties file - minecraft "com.mojang:minecraft:${project.minecraft_version}" - mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" - modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" - - modImplementation("de.siphalor:amecsapi-${project.minecraft_major_version}:1.4.0+mc1.20-pre1") { - exclude group: "net.fabricmc.fabric-api" - exclude module: "nmuk-${project.minecraft_major_version}" - } - - [ - "fabric-api-base", - "fabric-key-binding-api-v1", - "fabric-resource-loader-v0" - ].each { - include(modApi(fabricApi.module(it, project.fabric_api_version))) - } - - testmodImplementation sourceSets.main.output -} - -license { - header = project.file('LICENSE_HEADER') - - include '**/*.java' -} - -processResources { - inputs.property "version", version - - afterEvaluate { - from(sourceSets.main.resources.srcDirs) { - exclude "*.svg" - include "fabric.mod.json" - expand "version": version - duplicatesStrategy DuplicatesStrategy.INCLUDE - } - } -} // ensure that the encoding is set to UTF-8, no matter what the system default is // this fixes some edge cases with special characters not displaying correctly // see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html tasks.withType(JavaCompile).configureEach { - options.encoding = "UTF-8" -} - -// Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task -// if it is present. -// If you remove this task, sources will not be generated. -tasks.register('sourcesJar', Jar) { - dependsOn classes - archiveClassifier.set("sources") - from sourceSets.main.allSource -} - -jar { - from "LICENSE" -} - -// configure the maven publication -publishing { - publications { - create("fabricMod", MavenPublication) { - artifactId = project.archives_base_name + '-' + project.minecraft_major_version - // add all the jars that should be included when publishing to maven - - from components.java - java.withSourcesJar() - } - } - - // select the repositories you want to publish to - repositories { - if (project.hasProperty("siphalorMavenUser")) { - maven { - name = "Siphalor" - url = "https://maven.siphalor.de/upload.php" - credentials { - username = siphalorMavenUser - password = siphalorMavenPassword - } - } - } - } -} - -// Mod sites - -static def getChangelog() { - return 'git log -1 --format=format:##%x20%s%n%n%b%nRelease%x20by%x20%an --grep Version'.execute().text.trim() -} - -tasks.register('uploadToModSites') { - dependsOn build - group = "upload" -} - -if (project.hasProperty("curseforgeToken")) { - curseforge { - apiKey project.curseforgeToken - project { - id = "438172" - releaseType = project.mod_release - changelogType = "markdown" - changelog = project.getChangelog() - addGameVersion("Fabric") - String mcVersions = project.hasProperty("curseforge_mc_versions") ? project.curseforge_mc_versions : project.mod_mc_versions - for (version in mcVersions.split(";")) { - addGameVersion(version) - } - relations { - embeddedLibrary "fabric-api" - optionalDependency "amecs" - } - mainArtifact(remapJar) { - displayName = "[${project.mod_mc_version_specifier}] ${project.mod_version}" - } - } - } - uploadToModSites.finalizedBy(tasks.curseforge) -} - -modrinth { - if (project.hasProperty("modrinthToken")) { - token = project.modrinthToken - uploadToModSites.finalizedBy(tasks.modrinth) - } - - projectId = "YCcdA1Lp" - versionName = "[${project.mod_mc_version_specifier}] ${project.mod_version}" - versionType = project.mod_release - changelog = project.getChangelog() - uploadFile = remapJar - gameVersions.set(project.mod_mc_versions.split(";") as List) - loaders.set(["fabric"]) + options.encoding = "UTF-8" } -tasks.modrinth.group = "upload" diff --git a/common/build.gradle b/common/build.gradle new file mode 100644 index 0000000..219d974 --- /dev/null +++ b/common/build.gradle @@ -0,0 +1,17 @@ +architectury { + common rootProject.enabled_platforms.split(',') +} + +dependencies { + // We depend on Fabric Loader here to use the Fabric @Environment annotations, + // which get remapped to the correct annotations on each platform. + // Do NOT use other classes from Fabric Loader. + modImplementation "net.fabricmc:fabric-loader:$rootProject.fabric_loader_version" + + // Architectury API. This is optional, and you can comment it out if you don't need it. + modImplementation "dev.architectury:architectury:$rootProject.architectury_api_version" +} + +loom { + accessWidenerPath = file("src/main/resources/nmuk.accesswidener") +} \ No newline at end of file diff --git a/src/main/java/de/siphalor/nmuk/NMUK.java b/common/src/main/java/de/siphalor/nmuk/NMUK.java similarity index 100% rename from src/main/java/de/siphalor/nmuk/NMUK.java rename to common/src/main/java/de/siphalor/nmuk/NMUK.java diff --git a/src/main/java/de/siphalor/nmuk/api/NMUKAlternatives.java b/common/src/main/java/de/siphalor/nmuk/api/NMUKAlternatives.java similarity index 89% rename from src/main/java/de/siphalor/nmuk/api/NMUKAlternatives.java rename to common/src/main/java/de/siphalor/nmuk/api/NMUKAlternatives.java index 563f89a..38c320f 100644 --- a/src/main/java/de/siphalor/nmuk/api/NMUKAlternatives.java +++ b/common/src/main/java/de/siphalor/nmuk/api/NMUKAlternatives.java @@ -17,7 +17,7 @@ package de.siphalor.nmuk.api; -import de.siphalor.nmuk.impl.IKeyBinding; +import de.siphalor.nmuk.impl.NMUKKeyBinding; import de.siphalor.nmuk.impl.NMUKKeyBindingHelper; import de.siphalor.nmuk.impl.mixin.KeyBindingAccessor; import net.minecraft.client.option.KeyBinding; @@ -64,10 +64,10 @@ public static void create(KeyBinding base, InputUtil.Type inputType, int code) { * @param alternative The alternative keybinding. This keybinding MUST NOT be registered yet */ public static void create(KeyBinding base, KeyBinding alternative) { - ((KeyBindingAccessor) alternative).setTranslationKey(base.getTranslationKey() + "%" + ((IKeyBinding) base).nmuk_getNextChildId()); + ((KeyBindingAccessor) alternative).setTranslationKey(base.getTranslationKey() + "%" + ((NMUKKeyBinding) base).nmuk_getNextChildId()); ((KeyBindingAccessor) alternative).setCategory(base.getCategory()); - ((IKeyBinding) base).nmuk_addAlternative(alternative); - ((IKeyBinding) alternative).nmuk_setParent(base); + ((NMUKKeyBinding) base).nmuk_addAlternative(alternative); + ((NMUKKeyBinding) alternative).nmuk_setParent(base); NMUKKeyBindingHelper.registerKeyBinding(alternative); NMUKKeyBindingHelper.defaultAlternatives.put(base, alternative); } @@ -79,7 +79,7 @@ public static void create(KeyBinding base, KeyBinding alternative) { * @return Whether the given keybinding is an alternative */ public static boolean isAlternative(KeyBinding binding) { - return ((IKeyBinding) binding).nmuk_isAlternative(); + return ((NMUKKeyBinding) binding).nmuk_isAlternative(); } /** @@ -90,7 +90,7 @@ public static boolean isAlternative(KeyBinding binding) { */ @Nullable public static List getAlternatives(KeyBinding binding) { - return ((IKeyBinding) binding).nmuk_getAlternatives(); + return ((NMUKKeyBinding) binding).nmuk_getAlternatives(); } /** @@ -100,6 +100,6 @@ public static List getAlternatives(KeyBinding binding) { * @return The base keyinding or null if the given keybinding is no alternative */ public static KeyBinding getBase(KeyBinding binding) { - return ((IKeyBinding) binding).nmuk_getParent(); + return ((NMUKKeyBinding) binding).nmuk_getParent(); } } diff --git a/src/main/java/de/siphalor/nmuk/impl/AlternativeKeyBinding.java b/common/src/main/java/de/siphalor/nmuk/impl/AlternativeKeyBinding.java similarity index 55% rename from src/main/java/de/siphalor/nmuk/impl/AlternativeKeyBinding.java rename to common/src/main/java/de/siphalor/nmuk/impl/AlternativeKeyBinding.java index a577f6d..9107567 100644 --- a/src/main/java/de/siphalor/nmuk/impl/AlternativeKeyBinding.java +++ b/common/src/main/java/de/siphalor/nmuk/impl/AlternativeKeyBinding.java @@ -17,24 +17,20 @@ package de.siphalor.nmuk.impl; -import net.fabricmc.loader.api.FabricLoader; import net.minecraft.client.option.KeyBinding; import net.minecraft.client.util.InputUtil; import org.jetbrains.annotations.ApiStatus; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; - @ApiStatus.Internal public class AlternativeKeyBinding extends KeyBinding { public AlternativeKeyBinding(KeyBinding parent, String translationKey, int code, String category) { super(translationKey, code, category); - ((IKeyBinding) this).nmuk_setParent(parent); + ((NMUKKeyBinding) this).nmuk_setParent(parent); } public AlternativeKeyBinding(KeyBinding parent, String translationKey, InputUtil.Type type, int code, String category) { super(translationKey, type, code, category); - ((IKeyBinding) this).nmuk_setParent(parent); + ((NMUKKeyBinding) this).nmuk_setParent(parent); } @Override @@ -44,24 +40,4 @@ public boolean isDefault() { } return super.isDefault(); } - - private static final MethodHandle INCREMENT_TIMES_PRESSED_SUPER; - static { - MethodHandle methodHandle; - try { - methodHandle = MethodHandles.lookup().unreflectSpecial(KeyBinding.class.getDeclaredMethod("amecs$incrementTimesPressed"), AlternativeKeyBinding.class); - } catch (NoSuchMethodException | IllegalAccessException e) { - if (FabricLoader.getInstance().isModLoaded("amecsapi")) { - throw new RuntimeException("Failed to initialize NMUK compatibility with Amecs", e); - } - methodHandle = null; - } - INCREMENT_TIMES_PRESSED_SUPER = methodHandle; - } - public void amecs$incrementTimesPressed() throws Throwable { - INCREMENT_TIMES_PRESSED_SUPER.invoke(this); - - KeyBinding parent = ((IKeyBinding) this).nmuk_getParent(); - ((de.siphalor.amecs.impl.duck.IKeyBinding) parent).amecs$incrementTimesPressed(); - } } diff --git a/common/src/main/java/de/siphalor/nmuk/impl/ModifierHandle.java b/common/src/main/java/de/siphalor/nmuk/impl/ModifierHandle.java new file mode 100644 index 0000000..779611b --- /dev/null +++ b/common/src/main/java/de/siphalor/nmuk/impl/ModifierHandle.java @@ -0,0 +1,13 @@ +package de.siphalor.nmuk.impl; + +import dev.architectury.injectables.annotations.ExpectPlatform; +import net.minecraft.client.option.KeyBinding; +import org.jetbrains.annotations.ApiStatus; + +@ApiStatus.Internal +public class ModifierHandle { + @ExpectPlatform + public static void resetKeyModifiers(KeyBinding keyBinding) { + throw new AssertionError(); + } +} diff --git a/src/main/java/de/siphalor/nmuk/impl/IKeyBinding.java b/common/src/main/java/de/siphalor/nmuk/impl/NMUKKeyBinding.java similarity index 97% rename from src/main/java/de/siphalor/nmuk/impl/IKeyBinding.java rename to common/src/main/java/de/siphalor/nmuk/impl/NMUKKeyBinding.java index c1caf47..9f1a6d8 100644 --- a/src/main/java/de/siphalor/nmuk/impl/IKeyBinding.java +++ b/common/src/main/java/de/siphalor/nmuk/impl/NMUKKeyBinding.java @@ -23,7 +23,7 @@ import java.util.List; @ApiStatus.Internal -public interface IKeyBinding { +public interface NMUKKeyBinding { short nmuk_getNextChildId(); void nmuk_setNextChildId(short nextChildId); diff --git a/common/src/main/java/de/siphalor/nmuk/impl/NMUKKeyBindingHelper.java b/common/src/main/java/de/siphalor/nmuk/impl/NMUKKeyBindingHelper.java new file mode 100644 index 0000000..f571a63 --- /dev/null +++ b/common/src/main/java/de/siphalor/nmuk/impl/NMUKKeyBindingHelper.java @@ -0,0 +1,124 @@ +/* + * Copyright 2021 Siphalor + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. + * See the License for the specific language governing + * permissions and limitations under the License. + */ + +package de.siphalor.nmuk.impl; + +import com.google.common.collect.Multimap; +import com.google.common.collect.Multimaps; +import de.siphalor.nmuk.impl.mixin.EntryListWidgetAccessor; +import de.siphalor.nmuk.impl.mixin.GameOptionsAccessor; +import de.siphalor.nmuk.impl.mixin.KeybindsScreenAccessor; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.screen.option.ControlsListWidget; +import net.minecraft.client.option.GameOptions; +import net.minecraft.client.option.KeyBinding; +import net.minecraft.client.util.InputUtil; +import net.minecraft.text.Text; +import org.apache.commons.lang3.ArrayUtils; +import org.jetbrains.annotations.ApiStatus; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; + +@ApiStatus.Internal +public class NMUKKeyBindingHelper { + public static final Multimap defaultAlternatives = Multimaps.newSetMultimap(new HashMap<>(), HashSet::new); + + public static void removeKeyBinding(KeyBinding binding) { + GameOptionsAccessor options = (GameOptionsAccessor) MinecraftClient.getInstance().options; + KeyBinding[] keysAll = options.getAllKeys(); + int index = ArrayUtils.indexOf(keysAll, binding); + KeyBinding[] newKeysAll = new KeyBinding[keysAll.length - 1]; + System.arraycopy(keysAll, 0, newKeysAll, 0, index); + System.arraycopy(keysAll, index + 1, newKeysAll, index, keysAll.length - index - 1); + options.setAllKeys(newKeysAll); + KeyBinding.updateKeysByCode(); + } + + public static void registerKeyBinding(KeyBinding binding) { + GameOptionsAccessor options = (GameOptionsAccessor) MinecraftClient.getInstance().options; + if (options != null) { // Game is during initialization - this is handled by Fapi already + KeyBinding[] keysAll = options.getAllKeys(); + KeyBinding[] newKeysAll = new KeyBinding[keysAll.length + 1]; + System.arraycopy(keysAll, 0, newKeysAll, 0, keysAll.length); + newKeysAll[keysAll.length] = binding; + options.setAllKeys(newKeysAll); + } + KeyBinding.updateKeysByCode(); + } + + public static void registerKeyBindings(GameOptions gameOptions, Collection bindings) { + GameOptionsAccessor options = (GameOptionsAccessor) gameOptions; + KeyBinding[] keysAll = options.getAllKeys(); + KeyBinding[] newKeysAll = new KeyBinding[keysAll.length + bindings.size()]; + System.arraycopy(keysAll, 0, newKeysAll, 0, keysAll.length); + int i = keysAll.length; + for (KeyBinding binding : bindings) { + newKeysAll[i] = binding; + i++; + } + options.setAllKeys(newKeysAll); + KeyBinding.updateKeysByCode(); + } + + public static void resetSingleKeyBinding(KeyBinding keyBinding) { + keyBinding.setBoundKey(keyBinding.getDefaultKey()); + ModifierHandle.resetKeyModifiers(keyBinding); + } + + public static KeyBinding createAlternativeKeyBinding(KeyBinding base) { + return createAlternativeKeyBinding(base, -1); + } + + public static KeyBinding createAlternativeKeyBinding(KeyBinding base, int code) { + return createAlternativeKeyBinding(base, InputUtil.Type.KEYSYM, code); + } + + public static KeyBinding createAlternativeKeyBinding(KeyBinding base, InputUtil.Type type, int code) { + NMUKKeyBinding parent = (NMUKKeyBinding) base; + KeyBinding alt = new AlternativeKeyBinding(base, base.getTranslationKey() + "%" + parent.nmuk_getNextChildId(), type, code, base.getCategory()); + parent.nmuk_addAlternative(alt); + return alt; + } + + public static List getControlsListWidgetEntries() { + Screen screen = MinecraftClient.getInstance().currentScreen; + if (screen instanceof KeybindsScreenAccessor) { + //noinspection unchecked + return (List) (Object) + ((EntryListWidgetAccessor) ((KeybindsScreenAccessor) screen).getControlsList()).getChildren(); + } + return null; + } + + public static ControlsListWidget.KeyBindingEntry createKeyBindingEntry(ControlsListWidget listWidget, KeyBinding binding, Text text) { + try { + // noinspection JavaReflectionMemberAccess,JavaReflectionMemberAccess + Constructor constructor = ControlsListWidget.KeyBindingEntry.class.getDeclaredConstructor(ControlsListWidget.class, KeyBinding.class, Text.class); + constructor.setAccessible(true); + return constructor.newInstance(listWidget, binding, text); + } catch (IllegalAccessException | InstantiationException | InvocationTargetException | NoSuchMethodException e) { + e.printStackTrace(); + } + return null; + } +} diff --git a/src/main/java/de/siphalor/nmuk/impl/mixin/EntryListWidgetAccessor.java b/common/src/main/java/de/siphalor/nmuk/impl/mixin/EntryListWidgetAccessor.java similarity index 100% rename from src/main/java/de/siphalor/nmuk/impl/mixin/EntryListWidgetAccessor.java rename to common/src/main/java/de/siphalor/nmuk/impl/mixin/EntryListWidgetAccessor.java diff --git a/src/main/java/de/siphalor/nmuk/impl/mixin/GameOptionsAccessor.java b/common/src/main/java/de/siphalor/nmuk/impl/mixin/GameOptionsAccessor.java similarity index 100% rename from src/main/java/de/siphalor/nmuk/impl/mixin/GameOptionsAccessor.java rename to common/src/main/java/de/siphalor/nmuk/impl/mixin/GameOptionsAccessor.java diff --git a/src/main/java/de/siphalor/nmuk/impl/mixin/KeyBindingAccessor.java b/common/src/main/java/de/siphalor/nmuk/impl/mixin/KeyBindingAccessor.java similarity index 100% rename from src/main/java/de/siphalor/nmuk/impl/mixin/KeyBindingAccessor.java rename to common/src/main/java/de/siphalor/nmuk/impl/mixin/KeyBindingAccessor.java diff --git a/src/main/java/de/siphalor/nmuk/impl/mixin/KeybindsScreenAccessor.java b/common/src/main/java/de/siphalor/nmuk/impl/mixin/KeybindsScreenAccessor.java similarity index 100% rename from src/main/java/de/siphalor/nmuk/impl/mixin/KeybindsScreenAccessor.java rename to common/src/main/java/de/siphalor/nmuk/impl/mixin/KeybindsScreenAccessor.java diff --git a/src/main/java/de/siphalor/nmuk/impl/mixin/MixinGameOptions.java b/common/src/main/java/de/siphalor/nmuk/impl/mixin/MixinGameOptions.java similarity index 80% rename from src/main/java/de/siphalor/nmuk/impl/mixin/MixinGameOptions.java rename to common/src/main/java/de/siphalor/nmuk/impl/mixin/MixinGameOptions.java index d703f47..c8b0055 100644 --- a/src/main/java/de/siphalor/nmuk/impl/mixin/MixinGameOptions.java +++ b/common/src/main/java/de/siphalor/nmuk/impl/mixin/MixinGameOptions.java @@ -18,7 +18,7 @@ package de.siphalor.nmuk.impl.mixin; import de.siphalor.nmuk.NMUK; -import de.siphalor.nmuk.impl.IKeyBinding; +import de.siphalor.nmuk.impl.NMUKKeyBinding; import de.siphalor.nmuk.impl.NMUKKeyBindingHelper; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; @@ -34,7 +34,6 @@ import java.io.*; import java.nio.charset.StandardCharsets; -import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Queue; @@ -44,32 +43,12 @@ public class MixinGameOptions { @Unique private File nmukOptionsFile; - @Unique - private KeyBinding[] tempKeysAll; @Mutable @Shadow @Final public KeyBinding[] allKeys; - // Prevent nmuk keybindings from getting saved to the Vanilla options file - @Inject( - method = "accept", - at = @At(value = "FIELD", target = "Lnet/minecraft/client/option/GameOptions;allKeys:[Lnet/minecraft/client/option/KeyBinding;") - ) - public void removeNMUKBindings(CallbackInfo ci) { - tempKeysAll = allKeys; - allKeys = Arrays.stream(allKeys).filter(binding -> !((IKeyBinding) binding).nmuk_isAlternative()).toArray(KeyBinding[]::new); - } - - @Inject( - method = "accept", - at = @At(value = "INVOKE", target = "Lnet/minecraft/sound/SoundCategory;values()[Lnet/minecraft/sound/SoundCategory;") - ) - public void resetAllKeys(CallbackInfo ci) { - allKeys = tempKeysAll; - } - @Inject( method = "write", at = @At("RETURN") @@ -77,7 +56,7 @@ public void resetAllKeys(CallbackInfo ci) { public void save(CallbackInfo ci) { try (PrintWriter printWriter = new PrintWriter(new OutputStreamWriter(new FileOutputStream(nmukOptionsFile), StandardCharsets.UTF_8))) { for (KeyBinding binding : allKeys) { - if (((IKeyBinding) binding).nmuk_isAlternative()) { + if (((NMUKKeyBinding) binding).nmuk_isAlternative()) { printWriter.println("key_" + binding.getTranslationKey() + ":" + binding.getBoundKeyTranslationKey()); } } @@ -129,8 +108,8 @@ public void load(CallbackInfo ci) { KeyBinding base = keyBindings.get(id); if (base != null) { int index = alternativeCountMap.getOrDefault(base, 0); - List children = ((IKeyBinding) base).nmuk_getAlternatives(); - ((IKeyBinding) base).nmuk_setNextChildId(altId); + List children = ((NMUKKeyBinding) base).nmuk_getAlternatives(); + ((NMUKKeyBinding) base).nmuk_setNextChildId(altId); if (children == null) { KeyBinding alternative = NMUKKeyBindingHelper.createAlternativeKeyBinding(base); alternative.setBoundKey(boundKey); @@ -157,9 +136,9 @@ public void load(CallbackInfo ci) { int newCount, oldCount; for (KeyBinding binding : allKeys) { newCount = alternativeCountMap.getOrDefault(binding, 0); - oldCount = ((IKeyBinding) binding).nmuk_getAlternativesCount(); + oldCount = ((NMUKKeyBinding) binding).nmuk_getAlternativesCount(); if (oldCount > newCount) { - List alternatives = ((IKeyBinding) binding).nmuk_getAlternatives(); + List alternatives = ((NMUKKeyBinding) binding).nmuk_getAlternatives(); alternatives.subList(newCount, oldCount).clear(); } } diff --git a/src/main/java/de/siphalor/nmuk/impl/mixin/MixinKeyBinding.java b/common/src/main/java/de/siphalor/nmuk/impl/mixin/MixinKeyBinding.java similarity index 84% rename from src/main/java/de/siphalor/nmuk/impl/mixin/MixinKeyBinding.java rename to common/src/main/java/de/siphalor/nmuk/impl/mixin/MixinKeyBinding.java index cf10b9a..c49a0af 100644 --- a/src/main/java/de/siphalor/nmuk/impl/mixin/MixinKeyBinding.java +++ b/common/src/main/java/de/siphalor/nmuk/impl/mixin/MixinKeyBinding.java @@ -17,11 +17,10 @@ package de.siphalor.nmuk.impl.mixin; -import de.siphalor.nmuk.impl.IKeyBinding; +import de.siphalor.nmuk.impl.NMUKKeyBinding; import de.siphalor.nmuk.impl.NMUKKeyBindingHelper; import net.minecraft.client.option.KeyBinding; import net.minecraft.client.resource.language.I18n; -import net.minecraft.client.util.InputUtil; import org.apache.commons.lang3.StringUtils; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; @@ -31,14 +30,13 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import org.spongepowered.asm.mixin.injection.callback.LocalCapture; import java.util.Collection; import java.util.LinkedList; import java.util.List; @Mixin(value = KeyBinding.class, priority = 800) -public abstract class MixinKeyBinding implements IKeyBinding { +public abstract class MixinKeyBinding implements NMUKKeyBinding { @Shadow private boolean pressed; @Shadow @@ -114,21 +112,7 @@ public int nmuk_getIndexInParent() { if (parent == null) { return 0; } - return ((IKeyBinding) parent).nmuk_getAlternatives().indexOf((KeyBinding) (Object) this); - } - - @Inject( - method = "onKeyPressed", - at = @At(value = "FIELD", target = "Lnet/minecraft/client/option/KeyBinding;timesPressed:I"), - cancellable = true, - locals = LocalCapture.CAPTURE_FAILSOFT - ) - private static void onKeyPressed(InputUtil.Key key, CallbackInfo callbackInfo, KeyBinding binding) { - KeyBinding parent = ((IKeyBinding) binding).nmuk_getParent(); - if (parent != null) { - ((KeyBindingAccessor) parent).setTimesPressed(((KeyBindingAccessor) parent).getTimesPressed() + 1); - callbackInfo.cancel(); - } + return ((NMUKKeyBinding) parent).nmuk_getAlternatives().indexOf((KeyBinding) (Object) this); } @Inject( @@ -168,9 +152,9 @@ public void compareToInjection(KeyBinding other, CallbackInfoReturnable if (other == parent) { cir.setReturnValue(1); } else if (category.equals(other.getCategory())) { - KeyBinding otherParent = ((IKeyBinding) other).nmuk_getParent(); + KeyBinding otherParent = ((NMUKKeyBinding) other).nmuk_getParent(); if (otherParent == parent) { - cir.setReturnValue(Integer.compare(nmuk_getIndexInParent(), ((IKeyBinding) other).nmuk_getIndexInParent())); + cir.setReturnValue(Integer.compare(nmuk_getIndexInParent(), ((NMUKKeyBinding) other).nmuk_getIndexInParent())); } else { cir.setReturnValue( I18n.translate(StringUtils.substringBeforeLast(translationKey, "%")) diff --git a/src/main/java/de/siphalor/nmuk/impl/mixin/MixinKeyBindingEntry.java b/common/src/main/java/de/siphalor/nmuk/impl/mixin/MixinKeyBindingEntry.java similarity index 90% rename from src/main/java/de/siphalor/nmuk/impl/mixin/MixinKeyBindingEntry.java rename to common/src/main/java/de/siphalor/nmuk/impl/mixin/MixinKeyBindingEntry.java index d36edd8..6326c82 100644 --- a/src/main/java/de/siphalor/nmuk/impl/mixin/MixinKeyBindingEntry.java +++ b/common/src/main/java/de/siphalor/nmuk/impl/mixin/MixinKeyBindingEntry.java @@ -18,7 +18,7 @@ package de.siphalor.nmuk.impl.mixin; import com.google.common.collect.ImmutableList; -import de.siphalor.nmuk.impl.IKeyBinding; +import de.siphalor.nmuk.impl.NMUKKeyBinding; import de.siphalor.nmuk.impl.NMUKKeyBindingHelper; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.DrawContext; @@ -48,27 +48,31 @@ public class MixinKeyBindingEntry { @Shadow @Final private ButtonWidget resetButton; + @Shadow @Final private ButtonWidget editButton; + @Mutable @Shadow @Final private Text bindingName; + // This is a synthetic field containing the outer class instance - @Shadow(aliases = "field_2742", remap = false) + @Shadow(aliases = {"field_2742", "this$0", "f_193909_"}, remap = false) @Final private ControlsListWidget listWidget; + @Unique private ButtonWidget alternativesButton; @Inject(method = "", at = @At("RETURN")) public void onConstruct(ControlsListWidget outer, KeyBinding binding, Text text, CallbackInfo ci) { - IKeyBinding iKeyBinding = (IKeyBinding) binding; - if (iKeyBinding.nmuk_isAlternative()) { + NMUKKeyBinding NMUKKeyBinding = (NMUKKeyBinding) binding; + if (NMUKKeyBinding.nmuk_isAlternative()) { bindingName = ENTRY_NAME; alternativesButton = ButtonWidget.builder(Text.literal("x"), button -> { - ((IKeyBinding) iKeyBinding.nmuk_getParent()).nmuk_removeAlternative(binding); + ((NMUKKeyBinding) NMUKKeyBinding.nmuk_getParent()).nmuk_removeAlternative(binding); NMUKKeyBindingHelper.removeKeyBinding(binding); List entries = NMUKKeyBindingHelper.getControlsListWidgetEntries(); if (entries != null) { @@ -86,7 +90,7 @@ public void onConstruct(ControlsListWidget outer, KeyBinding binding, Text text, for (int i = 0, entriesSize = entries.size(); i < entriesSize; i++) { //noinspection ConstantConditions,RedundantCast,RedundantCast if (entries.get(i) == (ControlsListWidget.KeyBindingEntry) (Object) this) { - i += ((IKeyBinding) binding).nmuk_getAlternativesCount(); + i += ((NMUKKeyBinding) binding).nmuk_getAlternativesCount(); entries.add(i, altEntry); break; } @@ -101,8 +105,8 @@ public void onConstruct(ControlsListWidget outer, KeyBinding binding, Text text, @SuppressWarnings("UnresolvedMixinReference") @Inject(method = "method_19870(Lnet/minecraft/client/option/KeyBinding;Lnet/minecraft/client/gui/widget/ButtonWidget;)V", at = @At("HEAD")) private void resetButtonPressed(KeyBinding keyBinding, ButtonWidget widget, CallbackInfo ci) { - if (((IKeyBinding) keyBinding).nmuk_getParent() == null && Screen.hasShiftDown()) { - List alternatives = ((IKeyBinding) keyBinding).nmuk_getAlternatives(); + if (((NMUKKeyBinding) keyBinding).nmuk_getParent() == null && Screen.hasShiftDown()) { + List alternatives = ((NMUKKeyBinding) keyBinding).nmuk_getAlternatives(); List defaultAlternatives = new ArrayList<>(NMUKKeyBindingHelper.defaultAlternatives.get(keyBinding)); List entries = NMUKKeyBindingHelper.getControlsListWidgetEntries(); // noinspection ConstantConditions @@ -113,7 +117,7 @@ private void resetButtonPressed(KeyBinding keyBinding, ButtonWidget widget, Call KeyBinding alternative = iterator.next(); index = defaultAlternatives.indexOf(alternative); if (index == -1) { - entries.remove(entryPos + 1 + ((IKeyBinding) alternative).nmuk_getIndexInParent()); + entries.remove(entryPos + 1 + ((NMUKKeyBinding) alternative).nmuk_getIndexInParent()); iterator.remove(); NMUKKeyBindingHelper.removeKeyBinding(alternative); continue; diff --git a/common/src/main/resources/architectury.common.json b/common/src/main/resources/architectury.common.json new file mode 100644 index 0000000..131c890 --- /dev/null +++ b/common/src/main/resources/architectury.common.json @@ -0,0 +1,4 @@ + +{ + "accessWidener": "nmuk.accesswidener" +} \ No newline at end of file diff --git a/src/main/resources/assets/nmuk/lang/de_de.json b/common/src/main/resources/assets/nmuk/lang/de_de.json similarity index 100% rename from src/main/resources/assets/nmuk/lang/de_de.json rename to common/src/main/resources/assets/nmuk/lang/de_de.json diff --git a/src/main/resources/assets/nmuk/lang/en_us.json b/common/src/main/resources/assets/nmuk/lang/en_us.json similarity index 100% rename from src/main/resources/assets/nmuk/lang/en_us.json rename to common/src/main/resources/assets/nmuk/lang/en_us.json diff --git a/src/main/resources/assets/nmuk/lang/et_ee.json b/common/src/main/resources/assets/nmuk/lang/et_ee.json similarity index 100% rename from src/main/resources/assets/nmuk/lang/et_ee.json rename to common/src/main/resources/assets/nmuk/lang/et_ee.json diff --git a/src/main/resources/assets/nmuk/lang/fi_fi.json b/common/src/main/resources/assets/nmuk/lang/fi_fi.json similarity index 100% rename from src/main/resources/assets/nmuk/lang/fi_fi.json rename to common/src/main/resources/assets/nmuk/lang/fi_fi.json diff --git a/src/main/resources/assets/nmuk/lang/it_it.json b/common/src/main/resources/assets/nmuk/lang/it_it.json similarity index 100% rename from src/main/resources/assets/nmuk/lang/it_it.json rename to common/src/main/resources/assets/nmuk/lang/it_it.json diff --git a/src/main/resources/assets/nmuk/lang/ko_kr.json b/common/src/main/resources/assets/nmuk/lang/ko_kr.json similarity index 100% rename from src/main/resources/assets/nmuk/lang/ko_kr.json rename to common/src/main/resources/assets/nmuk/lang/ko_kr.json diff --git a/src/main/resources/assets/nmuk/lang/pt_br.json b/common/src/main/resources/assets/nmuk/lang/pt_br.json similarity index 97% rename from src/main/resources/assets/nmuk/lang/pt_br.json rename to common/src/main/resources/assets/nmuk/lang/pt_br.json index 05d6668..ab50458 100644 --- a/src/main/resources/assets/nmuk/lang/pt_br.json +++ b/common/src/main/resources/assets/nmuk/lang/pt_br.json @@ -1,3 +1,3 @@ -{ - "nmuk.options.controls.reset.tooltip": "Segure Shift para redefinir todas as alternativas também" -} +{ + "nmuk.options.controls.reset.tooltip": "Segure Shift para redefinir todas as alternativas também" +} diff --git a/src/main/resources/assets/nmuk/lang/pt_pt.json b/common/src/main/resources/assets/nmuk/lang/pt_pt.json similarity index 100% rename from src/main/resources/assets/nmuk/lang/pt_pt.json rename to common/src/main/resources/assets/nmuk/lang/pt_pt.json diff --git a/src/main/resources/assets/nmuk/lang/ru_ru.json b/common/src/main/resources/assets/nmuk/lang/ru_ru.json similarity index 100% rename from src/main/resources/assets/nmuk/lang/ru_ru.json rename to common/src/main/resources/assets/nmuk/lang/ru_ru.json diff --git a/src/main/resources/assets/nmuk/lang/tr_tr.json b/common/src/main/resources/assets/nmuk/lang/tr_tr.json similarity index 100% rename from src/main/resources/assets/nmuk/lang/tr_tr.json rename to common/src/main/resources/assets/nmuk/lang/tr_tr.json diff --git a/src/main/resources/assets/nmuk/lang/zh_hans.json b/common/src/main/resources/assets/nmuk/lang/zh_hans.json similarity index 100% rename from src/main/resources/assets/nmuk/lang/zh_hans.json rename to common/src/main/resources/assets/nmuk/lang/zh_hans.json diff --git a/src/main/resources/assets/nmuk/icon.png b/common/src/main/resources/icon.png similarity index 100% rename from src/main/resources/assets/nmuk/icon.png rename to common/src/main/resources/icon.png diff --git a/src/main/resources/assets/nmuk/icon.svg b/common/src/main/resources/icon.svg similarity index 100% rename from src/main/resources/assets/nmuk/icon.svg rename to common/src/main/resources/icon.svg diff --git a/src/main/resources/nmuk.accesswidener b/common/src/main/resources/nmuk.accesswidener similarity index 100% rename from src/main/resources/nmuk.accesswidener rename to common/src/main/resources/nmuk.accesswidener diff --git a/src/main/resources/nmuk.mixins.json b/common/src/main/resources/nmuk.mixins.json similarity index 77% rename from src/main/resources/nmuk.mixins.json rename to common/src/main/resources/nmuk.mixins.json index bba8114..49a13b6 100644 --- a/src/main/resources/nmuk.mixins.json +++ b/common/src/main/resources/nmuk.mixins.json @@ -1,17 +1,17 @@ { "required": true, + "minVersion": "0.8", "package": "de.siphalor.nmuk.impl.mixin", "compatibilityLevel": "JAVA_8", - "mixins": [ - "KeybindsScreenAccessor", + "client": [ "EntryListWidgetAccessor", "GameOptionsAccessor", - "KeyBindingAccessor", "MixinGameOptions", "MixinKeyBinding", - "MixinKeyBindingEntry" + "MixinKeyBindingEntry", + "KeybindsScreenAccessor", + "KeyBindingAccessor" ], - "client": [], "server": [], "injectors": { "defaultRequire": 1 diff --git a/fabric/build.gradle b/fabric/build.gradle new file mode 100644 index 0000000..930af99 --- /dev/null +++ b/fabric/build.gradle @@ -0,0 +1,61 @@ +plugins { + id 'com.github.johnrengelman.shadow' +} + +architectury { + platformSetupLoomIde() + fabric() +} + +configurations { + common { + canBeResolved = true + canBeConsumed = false + } + compileClasspath.extendsFrom common + runtimeClasspath.extendsFrom common + developmentFabric.extendsFrom common + + // Files in this configuration will be bundled into your mod using the Shadow plugin. + // Don't use the `shadow` configuration from the plugin itself as it's meant for excluding files. + shadowBundle { + canBeResolved = true + canBeConsumed = false + } +} + +sourceSets { + testmod { + compileClasspath += main.compileClasspath + runtimeClasspath += main.runtimeClasspath + } +} + +dependencies { + modImplementation "net.fabricmc:fabric-loader:$project.fabric_loader_version" + + // Fabric API. This is technically optional, but you probably want it anyway. + modImplementation "net.fabricmc.fabric-api:fabric-api:$project.fabric_api_version" + + // Architectury API. This is optional, and you can comment it out if you don't need it. + modImplementation "dev.architectury:architectury-fabric:$project.architectury_api_version" + + modImplementation("de.siphalor:amecsapi-${project.minecraft_major_version}:1.4.0+mc1.20-pre1") { + exclude group: "net.fabricmc.fabric-api" + exclude module: "nmuk-${project.minecraft_major_version}" + } + + common(project(path: ':common', configuration: 'namedElements')) { transitive false } + shadowBundle project(path: ':common', configuration: 'transformProductionFabric') + + testmodImplementation sourceSets.main.output +} + +shadowJar { + configurations = [project.configurations.shadowBundle] + archiveClassifier = 'dev-shadow' +} + +remapJar { + input.set shadowJar.archiveFile +} diff --git a/src/main/java/de/siphalor/nmuk/impl/AmecsProxy.java b/fabric/src/main/java/de/siphalor/nmuk/impl/fabric/ModifierHandleImpl.java similarity index 74% rename from src/main/java/de/siphalor/nmuk/impl/AmecsProxy.java rename to fabric/src/main/java/de/siphalor/nmuk/impl/fabric/ModifierHandleImpl.java index 2ecbed1..da64ab4 100644 --- a/src/main/java/de/siphalor/nmuk/impl/AmecsProxy.java +++ b/fabric/src/main/java/de/siphalor/nmuk/impl/fabric/ModifierHandleImpl.java @@ -15,15 +15,19 @@ * permissions and limitations under the License. */ -package de.siphalor.nmuk.impl; +package de.siphalor.nmuk.impl.fabric; import de.siphalor.amecs.api.KeyBindingUtils; +import dev.architectury.platform.Platform; import net.minecraft.client.option.KeyBinding; import org.jetbrains.annotations.ApiStatus; @ApiStatus.Internal -public class AmecsProxy { +public class ModifierHandleImpl { + private static final boolean isAmecsLoaded = Platform.isModLoaded("amecsapi"); public static void resetKeyModifiers(KeyBinding keyBinding) { - KeyBindingUtils.resetBoundModifiers(keyBinding); + if (isAmecsLoaded) { + KeyBindingUtils.resetBoundModifiers(keyBinding); + } } } diff --git a/fabric/src/main/java/de/siphalor/nmuk/impl/fabric/mixin/MixinGameOptionsFabric.java b/fabric/src/main/java/de/siphalor/nmuk/impl/fabric/mixin/MixinGameOptionsFabric.java new file mode 100644 index 0000000..150f162 --- /dev/null +++ b/fabric/src/main/java/de/siphalor/nmuk/impl/fabric/mixin/MixinGameOptionsFabric.java @@ -0,0 +1,57 @@ +/* + * Copyright 2021 Siphalor + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. + * See the License for the specific language governing + * permissions and limitations under the License. + */ + +package de.siphalor.nmuk.impl.fabric.mixin; + +import de.siphalor.nmuk.impl.NMUKKeyBinding; +import net.minecraft.client.option.GameOptions; +import net.minecraft.client.option.KeyBinding; +import org.spongepowered.asm.mixin.*; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.Arrays; + +@Mixin(value = GameOptions.class, priority = 800) +public class MixinGameOptionsFabric { + @Unique + private KeyBinding[] tempKeysAll; + + @Mutable + @Shadow + @Final + public KeyBinding[] allKeys; + + // Prevent nmuk keybindings from getting saved to the Vanilla options file + @Inject( + method = "accept", + at = @At(value = "FIELD", target = "Lnet/minecraft/client/option/GameOptions;allKeys:[Lnet/minecraft/client/option/KeyBinding;") + ) + public void removeNMUKBindings(CallbackInfo ci) { + tempKeysAll = allKeys; + allKeys = Arrays.stream(allKeys).filter(binding -> !((NMUKKeyBinding) binding).nmuk_isAlternative()).toArray(KeyBinding[]::new); + } + + @Inject( + method = "accept", + at = @At(value = "INVOKE", target = "Lnet/minecraft/sound/SoundCategory;values()[Lnet/minecraft/sound/SoundCategory;") + ) + public void resetAllKeys(CallbackInfo ci) { + allKeys = tempKeysAll; + } +} diff --git a/fabric/src/main/java/de/siphalor/nmuk/impl/fabric/mixin/MixinKeyBindingFabric.java b/fabric/src/main/java/de/siphalor/nmuk/impl/fabric/mixin/MixinKeyBindingFabric.java new file mode 100644 index 0000000..14b4b7f --- /dev/null +++ b/fabric/src/main/java/de/siphalor/nmuk/impl/fabric/mixin/MixinKeyBindingFabric.java @@ -0,0 +1,44 @@ +/* + * Copyright 2021 Siphalor + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. + * See the License for the specific language governing + * permissions and limitations under the License. + */ + +package de.siphalor.nmuk.impl.fabric.mixin; + +import de.siphalor.nmuk.impl.NMUKKeyBinding; +import de.siphalor.nmuk.impl.mixin.KeyBindingAccessor; +import net.minecraft.client.option.KeyBinding; +import org.spongepowered.asm.mixin.Mixin; +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.LocalCapture; + +@Mixin(value = KeyBinding.class, priority = 800) +public abstract class MixinKeyBindingFabric implements NMUKKeyBinding { + @Inject( + method = "onKeyPressed", + at = @At(value = "FIELD", target = "Lnet/minecraft/client/option/KeyBinding;timesPressed:I"), + cancellable = true, + locals = LocalCapture.CAPTURE_FAILSOFT + ) + private static void onKeyPressed(CallbackInfo callbackInfo, KeyBinding binding) { + KeyBinding parent = ((NMUKKeyBinding) binding).nmuk_getParent(); + if (parent != null) { + ((KeyBindingAccessor) parent).setTimesPressed(((KeyBindingAccessor) parent).getTimesPressed() + 1); + callbackInfo.cancel(); + } + } +} diff --git a/src/main/resources/fabric.mod.json b/fabric/src/main/resources/fabric.mod.json similarity index 66% rename from src/main/resources/fabric.mod.json rename to fabric/src/main/resources/fabric.mod.json index 64baf24..9191e52 100644 --- a/src/main/resources/fabric.mod.json +++ b/fabric/src/main/resources/fabric.mod.json @@ -1,11 +1,11 @@ { "schemaVersion": 1, - "id": "nmuk", - "version": "${version}", - "name": "No More Useless Keys", - "description": "Add multiple key combinations per keybinding", + "id": "${mod_id}", + "version": "${mod_version}", + "name": "${mod_name}", + "description": "${mod_description}", "authors": [ - "Siphalor" + "${mod_authors}" ], "contributors": [], "contact": { @@ -14,7 +14,7 @@ "issues": "https://github.com/Siphalor/nmuk/issues" }, "license": "Apache-2.0", - "icon": "assets/nmuk/icon.png", + "icon": "icon.png", "environment": "client", "entrypoints": { "main": [], @@ -22,9 +22,9 @@ "server": [] }, "mixins": [ - "nmuk.mixins.json" + "nmuk.mixins.json", + "nmuk.mixins.fabric.json" ], - "accessWidener": "nmuk.accesswidener", "depends": { "fabricloader": ">=0.4.0", "minecraft": ">=1.19.4" diff --git a/fabric/src/main/resources/nmuk.mixins.fabric.json b/fabric/src/main/resources/nmuk.mixins.fabric.json new file mode 100644 index 0000000..10db687 --- /dev/null +++ b/fabric/src/main/resources/nmuk.mixins.fabric.json @@ -0,0 +1,15 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "de.siphalor.nmuk.impl.fabric.mixin", + "compatibilityLevel": "JAVA_8", + "mixins": [], + "client": [ + "MixinKeyBindingFabric", + "MixinGameOptionsFabric" + ], + "server": [], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/src/testmod/java/de/siphalor/nmuktestmod/NMUKTestMod.java b/fabric/src/testmod/java/de/siphalor/nmuktestmod/NMUKTestMod.java similarity index 100% rename from src/testmod/java/de/siphalor/nmuktestmod/NMUKTestMod.java rename to fabric/src/testmod/java/de/siphalor/nmuktestmod/NMUKTestMod.java diff --git a/src/testmod/resources/fabric.mod.json b/fabric/src/testmod/resources/fabric.mod.json similarity index 100% rename from src/testmod/resources/fabric.mod.json rename to fabric/src/testmod/resources/fabric.mod.json diff --git a/forge/build.gradle b/forge/build.gradle new file mode 100644 index 0000000..f6c6e7a --- /dev/null +++ b/forge/build.gradle @@ -0,0 +1,60 @@ +plugins { + id 'com.github.johnrengelman.shadow' +} + +loom { + forge { + mixinConfig "nmuk.mixins.json" + mixinConfig "nmuk.mixins.forge.json" + } +} + +architectury { + platformSetupLoomIde() + forge() +} + +configurations { + common { + canBeResolved = true + canBeConsumed = false + } + compileClasspath.extendsFrom common + runtimeClasspath.extendsFrom common + developmentForge.extendsFrom common + + // Files in this configuration will be bundled into your mod using the Shadow plugin. + // Don't use the `shadow` configuration from the plugin itself as it's meant for excluding files. + shadowBundle { + canBeResolved = true + canBeConsumed = false + } +} + +sourceSets { + testmod { + compileClasspath += main.compileClasspath + runtimeClasspath += main.runtimeClasspath + } +} + +dependencies { + forge "net.minecraftforge:forge:$rootProject.forge_version" + + // Architectury API. This is optional, and you can comment it out if you don't need it. + modImplementation "dev.architectury:architectury-forge:$rootProject.architectury_api_version" + + common(project(path: ':common', configuration: 'namedElements')) { transitive false } + shadowBundle project(path: ':common', configuration: 'transformProductionForge') + + testmodImplementation sourceSets.main.output +} + +shadowJar { + configurations = [project.configurations.shadowBundle] + archiveClassifier = 'dev-shadow' +} + +remapJar { + input.set shadowJar.archiveFile +} diff --git a/forge/gradle.properties b/forge/gradle.properties new file mode 100644 index 0000000..a58ba14 --- /dev/null +++ b/forge/gradle.properties @@ -0,0 +1 @@ +loom.platform = forge diff --git a/forge/src/main/java/de/siphalor/nmuk/forge/NMUKForge.java b/forge/src/main/java/de/siphalor/nmuk/forge/NMUKForge.java new file mode 100644 index 0000000..ef278ed --- /dev/null +++ b/forge/src/main/java/de/siphalor/nmuk/forge/NMUKForge.java @@ -0,0 +1,12 @@ +package de.siphalor.nmuk.forge; + +import de.siphalor.nmuk.NMUK; +import net.minecraftforge.fml.common.Mod; +import org.apache.logging.log4j.Level; + +@Mod("nmuk") +public class NMUKForge { + public NMUKForge() { + NMUK.log(Level.INFO, "NMUK Forge loaded"); + } +} diff --git a/forge/src/main/java/de/siphalor/nmuk/impl/forge/ModifierHandleImpl.java b/forge/src/main/java/de/siphalor/nmuk/impl/forge/ModifierHandleImpl.java new file mode 100644 index 0000000..53395b1 --- /dev/null +++ b/forge/src/main/java/de/siphalor/nmuk/impl/forge/ModifierHandleImpl.java @@ -0,0 +1,8 @@ +package de.siphalor.nmuk.impl.forge; + +import net.minecraft.client.option.KeyBinding; + +public class ModifierHandleImpl { + public static void resetKeyModifiers(KeyBinding keyBinding) { + } +} diff --git a/forge/src/main/java/de/siphalor/nmuk/impl/forge/mixin/MixinGameOptionsForge.java b/forge/src/main/java/de/siphalor/nmuk/impl/forge/mixin/MixinGameOptionsForge.java new file mode 100644 index 0000000..a062e82 --- /dev/null +++ b/forge/src/main/java/de/siphalor/nmuk/impl/forge/mixin/MixinGameOptionsForge.java @@ -0,0 +1,57 @@ +/* + * Copyright 2021 Siphalor + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. + * See the License for the specific language governing + * permissions and limitations under the License. + */ + +package de.siphalor.nmuk.impl.forge.mixin; + +import de.siphalor.nmuk.impl.NMUKKeyBinding; +import net.minecraft.client.option.GameOptions; +import net.minecraft.client.option.KeyBinding; +import org.spongepowered.asm.mixin.*; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.Arrays; + +@Mixin(value = GameOptions.class, priority = 800) +public class MixinGameOptionsForge { + @Unique + private KeyBinding[] tempKeysAll; + + @Mutable + @Shadow + @Final + public KeyBinding[] allKeys; + + // Prevent nmuk keybindings from getting saved to the Vanilla options file + @Inject( + method = "processOptionsForge", + at = @At(value = "FIELD", target = "Lnet/minecraft/client/option/GameOptions;allKeys:[Lnet/minecraft/client/option/KeyBinding;") + ) + public void removeNMUKBindings(CallbackInfo ci) { + tempKeysAll = allKeys; + allKeys = Arrays.stream(allKeys).filter(binding -> !((NMUKKeyBinding) binding).nmuk_isAlternative()).toArray(KeyBinding[]::new); + } + + @Inject( + method = "processOptionsForge", + at = @At(value = "INVOKE", target = "Lnet/minecraft/sound/SoundCategory;values()[Lnet/minecraft/sound/SoundCategory;") + ) + public void resetAllKeys(CallbackInfo ci) { + allKeys = tempKeysAll; + } +} diff --git a/forge/src/main/java/de/siphalor/nmuk/impl/forge/mixin/MixinKeyBindingForge.java b/forge/src/main/java/de/siphalor/nmuk/impl/forge/mixin/MixinKeyBindingForge.java new file mode 100644 index 0000000..22608cf --- /dev/null +++ b/forge/src/main/java/de/siphalor/nmuk/impl/forge/mixin/MixinKeyBindingForge.java @@ -0,0 +1,47 @@ +/* + * Copyright 2021 Siphalor + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. + * See the License for the specific language governing + * permissions and limitations under the License. + */ + +package de.siphalor.nmuk.impl.forge.mixin; + +import de.siphalor.nmuk.impl.NMUKKeyBinding; +import de.siphalor.nmuk.impl.mixin.KeyBindingAccessor; +import net.minecraft.client.option.KeyBinding; +import net.minecraft.client.util.InputUtil; +import org.spongepowered.asm.mixin.Mixin; +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.LocalCapture; + +import java.util.Iterator; + +@Mixin(value = KeyBinding.class, priority = 800) +public abstract class MixinKeyBindingForge implements NMUKKeyBinding { + @Inject( + method = "onKeyPressed", + at = @At(value = "FIELD", target = "Lnet/minecraft/client/option/KeyBinding;timesPressed:I"), + cancellable = true, + locals = LocalCapture.CAPTURE_FAILSOFT + ) + private static void onKeyPressed(InputUtil.Key key, CallbackInfo callbackInfo, Iterator var1, KeyBinding binding) { + KeyBinding parent = ((NMUKKeyBinding) binding).nmuk_getParent(); + if (parent != null) { + ((KeyBindingAccessor) parent).setTimesPressed(((KeyBindingAccessor) parent).getTimesPressed() + 1); + callbackInfo.cancel(); + } + } +} diff --git a/forge/src/main/resources/META-INF/mods.toml b/forge/src/main/resources/META-INF/mods.toml new file mode 100644 index 0000000..8f47a5f --- /dev/null +++ b/forge/src/main/resources/META-INF/mods.toml @@ -0,0 +1,27 @@ +modLoader="javafml" #mandatory +loaderVersion="${forge_version}" +license="Apache-2.0" + +[[mods]] #mandatory +modId="${mod_id}" #mandatory +version="${mod_version}" #mandatory +displayName="${mod_name}" #mandatory +authors="${mod_authors}" #optional +description='''${mod_description}''' +displayURL="https://github.com/Siphalor/nmuk" #optional +issueTrackerURL="https://github.com/Siphalor/nmuk/issues" #optional +logoFile="icon.png" #optional + +[[dependencies.${mod_id}]] #optional +modId="forge" #mandatory +mandatory=true #mandatory +versionRange="[${forge_version},)" #mandatory +ordering="NONE" +side="BOTH" + +[[dependencies.${mod_id}]] +modId="minecraft" +mandatory=true +versionRange="${minecraft_version_range}" +ordering="NONE" +side="BOTH" diff --git a/forge/src/main/resources/nmuk.mixins.forge.json b/forge/src/main/resources/nmuk.mixins.forge.json new file mode 100644 index 0000000..69b7aad --- /dev/null +++ b/forge/src/main/resources/nmuk.mixins.forge.json @@ -0,0 +1,15 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "de.siphalor.nmuk.impl.forge.mixin", + "compatibilityLevel": "JAVA_8", + "mixins": [], + "client": [ + "MixinKeyBindingForge", + "MixinGameOptionsForge" + ], + "server": [], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/forge/src/main/resources/pack.mcmeta b/forge/src/main/resources/pack.mcmeta new file mode 100644 index 0000000..ae03c9b --- /dev/null +++ b/forge/src/main/resources/pack.mcmeta @@ -0,0 +1,6 @@ +{ + "pack": { + "description": "${mod_name} resources", + "pack_format": 15 + } +} diff --git a/forge/src/testmod/java/de/siphalor/nmuktestmod/NMUKTestMod.java b/forge/src/testmod/java/de/siphalor/nmuktestmod/NMUKTestMod.java new file mode 100644 index 0000000..82465ea --- /dev/null +++ b/forge/src/testmod/java/de/siphalor/nmuktestmod/NMUKTestMod.java @@ -0,0 +1,51 @@ +/* + * Copyright 2021 Siphalor + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. + * See the License for the specific language governing + * permissions and limitations under the License. + */ + +package de.siphalor.nmuktestmod; + +import de.siphalor.nmuk.api.NMUKAlternatives; +import net.minecraft.client.option.KeyBinding; +import net.minecraft.client.util.InputUtil; +import net.minecraft.util.Identifier; +import net.minecraftforge.client.event.RegisterKeyMappingsEvent; +import net.minecraftforge.client.settings.KeyConflictContext; +import net.minecraftforge.client.settings.KeyModifier; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; + +@Mod("nmuk_testmod") +public class NMUKTestMod { + public static final String MOD_ID = "nmuk_testmod"; + + @SubscribeEvent + public void onRegisterKeyMappings(RegisterKeyMappingsEvent event) { + KeyBinding test = new KeyBinding(MOD_ID + ".test", InputUtil.Type.KEYSYM, 86, "key.categories.movement"); + event.register(test); + + NMUKAlternatives.create(test, 85); + + KeyBinding withModifier = new KeyBinding( + "key." + (new Identifier(MOD_ID, "").toTranslationKey()), + KeyConflictContext.UNIVERSAL, + KeyModifier.ALT, + InputUtil.Type.KEYSYM, + 86, + "" + ); + NMUKAlternatives.create(test, withModifier); + } +} diff --git a/forge/src/testmod/resources/META-INF/mods.toml b/forge/src/testmod/resources/META-INF/mods.toml new file mode 100644 index 0000000..e7951df --- /dev/null +++ b/forge/src/testmod/resources/META-INF/mods.toml @@ -0,0 +1,10 @@ +modLoader="javafml" #mandatory +loaderVersion="${forge_version}" +license="Apache-2.0" + +[[mods]] #mandatory +modId="${mod_id}_testmod" #mandatory +version="0.0.0" #mandatory +displayName="${mod_name}" #mandatory +authors="${mod_authors}" #optional +description='''Test Mod''' diff --git a/gradle.properties b/gradle.properties index 4164e21..f1f83fa 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,19 +1,23 @@ -org.gradle.jvmargs = -Xmx1G - +org.gradle.jvmargs=-Xmx1G #Fabric properties -minecraft_major_version = 1.20 -minecraft_version = 1.20.1 -yarn_mappings = 1.20.1+build.10 -loader_version = 0.14.21 +minecraft_major_version=1.20 +minecraft_version=1.20.1 +minecraft_version_range=[1.20.1, 1.20.2] +yarn_mappings=1.20.1+build.10 #Mod properties -mod_version = 1.1.1 -mod_release = release -mod_mc_versions = 1.20.1,1.20.2 -curseforge_mc_versions = 1.20.1,1.20.2 -mod_mc_version_specifier = 1.20.1+ -maven_group = de.siphalor -archives_base_name = nmuk +mod_id=nmuk +mod_version=1.1.1 +mod_name=No More Useless Keys +mod_description=Add multiple key combinations per keybinding +mod_release=release +mod_authors=Siphalor +maven_group=de.siphalor +archives_base_name=nmuk +enabled_platforms=fabric,forge #Dependencies -fabric_api_version = 0.86.0+1.20.1 +architectury_api_version=9.2.14 +fabric_loader_version=0.16.5 +forge_version=1.20.1-47.2.30 +fabric_api_version=0.92.2+1.20.1 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ac72c34..a80b22c 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew old mode 100644 new mode 100755 diff --git a/settings.gradle b/settings.gradle index f91a4fe..f7e184f 100644 --- a/settings.gradle +++ b/settings.gradle @@ -4,6 +4,15 @@ pluginManagement { name = 'Fabric' url = 'https://maven.fabricmc.net/' } + maven { url "https://maven.architectury.dev/" } + maven { url "https://files.minecraftforge.net/maven/" } gradlePluginPortal() } } + +rootProject.name = "NMUK" + +include 'common' +include 'fabric' +include 'forge' + diff --git a/src/main/java/de/siphalor/nmuk/impl/NMUKKeyBindingHelper.java b/src/main/java/de/siphalor/nmuk/impl/NMUKKeyBindingHelper.java deleted file mode 100644 index e30f588..0000000 --- a/src/main/java/de/siphalor/nmuk/impl/NMUKKeyBindingHelper.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright 2021 Siphalor - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, - * either express or implied. - * See the License for the specific language governing - * permissions and limitations under the License. - */ - -package de.siphalor.nmuk.impl; - -import com.google.common.collect.Multimap; -import com.google.common.collect.Multimaps; -import de.siphalor.nmuk.impl.mixin.EntryListWidgetAccessor; -import de.siphalor.nmuk.impl.mixin.GameOptionsAccessor; -import de.siphalor.nmuk.impl.mixin.KeybindsScreenAccessor; -import net.fabricmc.loader.api.FabricLoader; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.gui.screen.option.ControlsListWidget; -import net.minecraft.client.option.GameOptions; -import net.minecraft.client.option.KeyBinding; -import net.minecraft.client.util.InputUtil; -import net.minecraft.text.Text; -import org.apache.commons.lang3.ArrayUtils; -import org.jetbrains.annotations.ApiStatus; - -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; - -@ApiStatus.Internal -public class NMUKKeyBindingHelper { - public static final Multimap defaultAlternatives = Multimaps.newSetMultimap(new HashMap<>(), HashSet::new); - private static final boolean isAmecsLoaded = FabricLoader.getInstance().isModLoaded("amecsapi"); - - public static void removeKeyBinding(KeyBinding binding) { - GameOptionsAccessor options = (GameOptionsAccessor) MinecraftClient.getInstance().options; - KeyBinding[] keysAll = options.getAllKeys(); - int index = ArrayUtils.indexOf(keysAll, binding); - KeyBinding[] newKeysAll = new KeyBinding[keysAll.length - 1]; - System.arraycopy(keysAll, 0, newKeysAll, 0, index); - System.arraycopy(keysAll, index + 1, newKeysAll, index, keysAll.length - index - 1); - options.setAllKeys(newKeysAll); - KeyBinding.updateKeysByCode(); - } - - public static void registerKeyBinding(KeyBinding binding) { - GameOptionsAccessor options = (GameOptionsAccessor) MinecraftClient.getInstance().options; - if (options != null) { // Game is during initialization - this is handled by Fapi already - KeyBinding[] keysAll = options.getAllKeys(); - KeyBinding[] newKeysAll = new KeyBinding[keysAll.length + 1]; - System.arraycopy(keysAll, 0, newKeysAll, 0, keysAll.length); - newKeysAll[keysAll.length] = binding; - options.setAllKeys(newKeysAll); - } - KeyBinding.updateKeysByCode(); - } - - public static void registerKeyBindings(GameOptions gameOptions, Collection bindings) { - GameOptionsAccessor options = (GameOptionsAccessor) gameOptions; - KeyBinding[] keysAll = options.getAllKeys(); - KeyBinding[] newKeysAll = new KeyBinding[keysAll.length + bindings.size()]; - System.arraycopy(keysAll, 0, newKeysAll, 0, keysAll.length); - int i = keysAll.length; - for (KeyBinding binding : bindings) { - newKeysAll[i] = binding; - i++; - } - options.setAllKeys(newKeysAll); - KeyBinding.updateKeysByCode(); - } - - public static void resetSingleKeyBinding(KeyBinding keyBinding) { - keyBinding.setBoundKey(keyBinding.getDefaultKey()); - if (isAmecsLoaded) { - AmecsProxy.resetKeyModifiers(keyBinding); - } - } - - public static KeyBinding createAlternativeKeyBinding(KeyBinding base) { - return createAlternativeKeyBinding(base, -1); - } - - public static KeyBinding createAlternativeKeyBinding(KeyBinding base, int code) { - return createAlternativeKeyBinding(base, InputUtil.Type.KEYSYM, code); - } - - public static KeyBinding createAlternativeKeyBinding(KeyBinding base, InputUtil.Type type, int code) { - IKeyBinding parent = (IKeyBinding) base; - KeyBinding alt = new AlternativeKeyBinding(base, base.getTranslationKey() + "%" + parent.nmuk_getNextChildId(), type, code, base.getCategory()); - parent.nmuk_addAlternative(alt); - return alt; - } - - public static List getControlsListWidgetEntries() { - Screen screen = MinecraftClient.getInstance().currentScreen; - if (screen instanceof KeybindsScreenAccessor) { - //noinspection unchecked - return (List) (Object) - ((EntryListWidgetAccessor) ((KeybindsScreenAccessor) screen).getControlsList()).getChildren(); - } - return null; - } - - public static ControlsListWidget.KeyBindingEntry createKeyBindingEntry(ControlsListWidget listWidget, KeyBinding binding, Text text) { - try { - // noinspection JavaReflectionMemberAccess,JavaReflectionMemberAccess - Constructor constructor = ControlsListWidget.KeyBindingEntry.class.getDeclaredConstructor(ControlsListWidget.class, KeyBinding.class, Text.class); - constructor.setAccessible(true); - return constructor.newInstance(listWidget, binding, text); - } catch (IllegalAccessException | InstantiationException | InvocationTargetException | NoSuchMethodException e) { - e.printStackTrace(); - } - return null; - } -}