migrate to fabric-keybindings-v1 and remove builder (#615)

* Edited Clone of #244
- Fixed checkstyle issues
- Migrated to fabric-keybindings-v1
- Removed sticky keybindings from #244 as it sounds useless and you can just around it by simply adding that functionality yourself, I might add it back if someone can tell me the advantages of sticky keys except bloat
- Added a test mod
- Added FabricKeyBinding#getBoundKeyOf for getting vanilla bound keys with ease
- Renamed `registered` to `automaticallyRegister` as that is more of a better name
- Added a couple Objects.requireNonNull validations

* Add back StickyFabricKeyBinding as it is in vanilla, did not notice.

* Remove extra "key."

* Bump to 1.0.0

* build().register()

* Remove `register()`

Signed-off-by: shedaniel <daniel@shedaniel.me>

* Fix test

Signed-off-by: shedaniel <daniel@shedaniel.me>

* Rename module

Signed-off-by: shedaniel <daniel@shedaniel.me>

* Fix checkstyle violation

Signed-off-by: shedaniel <daniel@shedaniel.me>

* major refactor

Signed-off-by: shedaniel <daniel@shedaniel.me>

* revert some stuff

Signed-off-by: shedaniel <daniel@shedaniel.me>

* fix build

Signed-off-by: shedaniel <daniel@shedaniel.me>

* major stuff

Signed-off-by: shedaniel <daniel@shedaniel.me>

* fix license, of course

Signed-off-by: shedaniel <daniel@shedaniel.me>

* Add resource loader v0

Signed-off-by: shedaniel <daniel@shedaniel.me>

* Let's not break the api.

Signed-off-by: shedaniel <daniel@shedaniel.me>

* Rename to buildAndRegister

Signed-off-by: shedaniel <daniel@shedaniel.me>

* resolve reviews

Signed-off-by: shedaniel <daniel@shedaniel.me>

* Use GLFW

Signed-off-by: shedaniel <daniel@shedaniel.me>

* Dump the builder entirely

Signed-off-by: shedaniel <daniel@shedaniel.me>

* Rename to Key Binding

Signed-off-by: shedaniel <daniel@shedaniel.me>
This commit is contained in:
shedaniel 2020-06-12 18:18:17 +08:00 committed by GitHub
parent 0121bd9039
commit 2af3af9102
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 295 additions and 137 deletions

View file

@ -0,0 +1,8 @@
archivesBaseName = "fabric-key-binding-api-v1"
version = getSubprojectVersion(project, "1.0.0")
dependencies {
testmodCompile project(path: ':fabric-api-base', configuration: 'dev')
testmodCompile project(path: ':fabric-events-lifecycle-v0', configuration: 'dev')
testmodCompile project(path: ':fabric-resource-loader-v0', configuration: 'dev')
}

View file

@ -0,0 +1,58 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* 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 net.fabricmc.fabric.api.client.keybinding.v1;
import net.minecraft.client.options.KeyBinding;
import net.minecraft.client.util.InputUtil;
import net.fabricmc.fabric.impl.client.keybinding.KeyBindingRegistryImpl;
import net.fabricmc.fabric.mixin.client.keybinding.KeyCodeAccessor;
/**
* Helper for registering key bindings.
*
* <p>Helper class for {@link KeyBinding} for use by Fabric mods.</p>
*
* <pre><code>
* KeyBinding left = KeyBindingHelper.registerKeyBinding(new KeyBinding("key.example.left", InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_P, "key.category.example"));
* KeyBinding right = KeyBindingHelper.registerKeyBinding(new KeyBinding("key.example.right", InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_U, "key.category.example"));
* </code></pre>
*/
public final class KeyBindingHelper {
private KeyBindingHelper() {
}
/**
* Registers the keybinding and add the keybinding category if required.
*
* @param keyBinding the keybinding
* @return the keybinding itself
*/
public static KeyBinding registerKeyBinding(KeyBinding keyBinding) {
return KeyBindingRegistryImpl.registerKeyBinding(keyBinding);
}
/**
* Returns the configured KeyCode bound to the KeyBinding from the player's settings.
*
* @param keyBinding the keybinding
* @return configured KeyCode
*/
public static InputUtil.KeyCode getBoundKeyOf(KeyBinding keyBinding) {
return ((KeyCodeAccessor) keyBinding).getKeyCode();
}
}

View file

@ -0,0 +1,86 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* 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 net.fabricmc.fabric.impl.client.keybinding;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import com.google.common.collect.Lists;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import net.minecraft.client.options.KeyBinding;
import net.fabricmc.fabric.mixin.client.keybinding.KeyBindingAccessor;
public final class KeyBindingRegistryImpl {
private static final Logger LOGGER = LogManager.getLogger();
private static final List<KeyBinding> moddedKeyBindings = Lists.newArrayList();
private KeyBindingRegistryImpl() {
}
private static Map<String, Integer> getCategoryMap() {
return KeyBindingAccessor.fabric_getCategoryMap();
}
private static boolean hasCategory(String categoryTranslationKey) {
return getCategoryMap().containsKey(categoryTranslationKey);
}
public static boolean addCategory(String categoryTranslationKey) {
Map<String, Integer> map = getCategoryMap();
if (map.containsKey(categoryTranslationKey)) {
return false;
}
Optional<Integer> largest = map.values().stream().max(Integer::compareTo);
int largestInt = largest.orElse(0);
map.put(categoryTranslationKey, largestInt + 1);
return true;
}
public static KeyBinding registerKeyBinding(KeyBinding binding) {
for (KeyBinding existingKeyBindings : moddedKeyBindings) {
if (existingKeyBindings == binding) {
throw null;
} else if (existingKeyBindings.getId().equals(binding.getId())) {
throw new RuntimeException("Attempted to register two key bindings with equal ID: " + binding.getId() + "!");
}
}
if (!hasCategory(binding.getCategory())) {
addCategory(binding.getCategory());
}
return moddedKeyBindings.add(binding) ? binding : null;
}
/**
* Processes the keybindings array for our modded ones by first removing existing modded keybindings and readding them,
* we can make sure that there are no duplicates this way.
*/
public static KeyBinding[] process(KeyBinding[] keysAll) {
List<KeyBinding> newKeysAll = Lists.newArrayList(keysAll);
newKeysAll.removeAll(moddedKeyBindings);
newKeysAll.addAll(moddedKeyBindings);
return newKeysAll.toArray(new KeyBinding[0]);
}
}

View file

@ -19,16 +19,14 @@ package net.fabricmc.fabric.mixin.client.keybinding;
import java.util.Map;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.gen.Accessor;
import net.minecraft.client.options.KeyBinding;
@Mixin(KeyBinding.class)
public class MixinKeyBinding {
@Shadow
private static Map<String, Integer> categoryOrderMap;
private static Map<String, Integer> fabric_getCategoryMap() {
return categoryOrderMap;
public interface KeyBindingAccessor {
@Accessor("categoryOrderMap")
static Map<String, Integer> fabric_getCategoryMap() {
throw new AssertionError();
}
}

View file

@ -16,7 +16,9 @@
package net.fabricmc.fabric.mixin.client.keybinding;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Mutable;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
@ -29,11 +31,13 @@ import net.fabricmc.fabric.impl.client.keybinding.KeyBindingRegistryImpl;
@Mixin(GameOptions.class)
public class MixinGameOptions {
@Mutable
@Final
@Shadow
public KeyBinding[] keysAll;
@Inject(at = @At("HEAD"), method = "load()V")
public void loadHook(CallbackInfo info) {
keysAll = KeyBindingRegistryImpl.INSTANCE.process(keysAll);
keysAll = KeyBindingRegistryImpl.process(keysAll);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View file

@ -3,9 +3,9 @@
"package": "net.fabricmc.fabric.mixin.client.keybinding",
"compatibilityLevel": "JAVA_8",
"client": [
"MixinGameOptions",
"MixinKeyBinding",
"KeyCodeAccessor"
"KeyBindingAccessor",
"KeyCodeAccessor",
"MixinGameOptions"
],
"injectors": {
"defaultRequire": 1

View file

@ -0,0 +1,25 @@
{
"schemaVersion": 1,
"id": "fabric-key-binding-api-v1",
"name": "Fabric Key Binding API (v1)",
"version": "${version}",
"environment": "client",
"license": "Apache-2.0",
"icon": "assets/fabric-key-binding-api-v1/icon.png",
"contact": {
"homepage": "https://fabricmc.net",
"irc": "irc://irc.esper.net:6667/fabric",
"issues": "https://github.com/FabricMC/fabric/issues",
"sources": "https://github.com/FabricMC/fabric"
},
"authors": [
"FabricMC"
],
"depends": {
"fabricloader": ">=0.4.0"
},
"description": "Key Binding registry API.",
"mixins": [
"fabric-key-binding-api-v1.mixins.json"
]
}

View file

@ -0,0 +1,51 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* 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 net.fabricmc.fabric.test.client.keybinding;
import org.lwjgl.glfw.GLFW;
import net.minecraft.client.options.KeyBinding;
import net.minecraft.client.options.StickyKeyBinding;
import net.minecraft.client.util.InputUtil;
import net.minecraft.text.LiteralText;
import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
import net.fabricmc.fabric.api.event.client.ClientTickCallback;
public class KeyBindingsTest implements ClientModInitializer {
@Override
public void onInitializeClient() {
KeyBinding binding1 = KeyBindingHelper.registerKeyBinding(new KeyBinding("key.fabric-key-binding-api-v1-testmod.test_keybinding_1", InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_P, "key.category.first.test"));
KeyBinding binding2 = KeyBindingHelper.registerKeyBinding(new KeyBinding("key.fabric-key-binding-api-v1-testmod.test_keybinding_2", InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_U, "key.category.second.test"));
KeyBinding stickyBinding = KeyBindingHelper.registerKeyBinding(new StickyKeyBinding("key.fabric-key-binding-api-v1-testmod.test_keybinding_sticky", GLFW.GLFW_KEY_R, "key.category.first.test", () -> true));
ClientTickCallback.EVENT.register(client -> {
while (binding1.wasPressed()) {
client.player.sendMessage(new LiteralText("Key 1 was pressed!"));
}
while (binding2.wasPressed()) {
client.player.sendMessage(new LiteralText("Key 2 was pressed!"));
}
if (stickyBinding.isPressed()) {
client.player.sendMessage(new LiteralText("Sticky Key was pressed!"));
}
});
}
}

View file

@ -0,0 +1,7 @@
{
"key.category.first.test": "First Test Category",
"key.category.second.test": "Second Test Category",
"key.fabric-key-binding-api-v1-testmod.test_keybinding_1": "Test 1",
"key.fabric-key-binding-api-v1-testmod.test_keybinding_2": "Test 2",
"key.fabric-key-binding-api-v1-testmod.test_keybinding_sticky": "Sticky Test"
}

View file

@ -0,0 +1,18 @@
{
"schemaVersion": 1,
"id": "fabric-key-binding-api-v1-testmod",
"name": "Fabric Key Binding API (v1) Test Mod",
"version": "1.0.0",
"environment": "*",
"license": "Apache-2.0",
"depends": {
"fabric-api-base": "*",
"fabric-events-lifecycle-v0": "*",
"fabric-key-binding-api-v1": "*"
},
"entrypoints": {
"client": [
"net.fabricmc.fabric.test.client.keybinding.KeyBindingsTest"
]
}
}

View file

@ -1,6 +1,6 @@
archivesBaseName = "fabric-keybindings-v0"
version = getSubprojectVersion(project, "0.1.1")
version = getSubprojectVersion(project, "0.2.0")
dependencies {
compile project(path: ':fabric-api-base', configuration: 'dev')
compile project(path: ':fabric-key-binding-api-v1', configuration: 'dev')
}

View file

@ -20,27 +20,33 @@ import net.minecraft.client.options.KeyBinding;
import net.minecraft.client.util.InputUtil;
import net.minecraft.util.Identifier;
import net.fabricmc.fabric.mixin.client.keybinding.KeyCodeAccessor;
import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
/**
* Expanded version of {@link KeyBinding} for use by Fabric mods.
*
* <p>*ALL* instantiated FabricKeyBindings should be registered in
* {@link KeyBindingRegistry#register(FabricKeyBinding)}!
* {@link KeyBindingRegistry#register(FabricKeyBinding)}!</p>
*
* @deprecated Please migrate to v1. Please use {@link KeyBindingHelper#registerKeyBinding(KeyBinding)} instead.
*/
@Deprecated
public class FabricKeyBinding extends KeyBinding {
protected FabricKeyBinding(Identifier id, InputUtil.Type type, int code, String category) {
super("key." + id.toString().replace(':', '.'), type, code, category);
super(String.format("key.%s.%s", id.getNamespace(), id.getPath()), type, code, category);
}
/**
* Returns the configured KeyCode assigned to the KeyBinding from the player's settings.
*
* @return configured KeyCode
*/
@Deprecated
public InputUtil.KeyCode getBoundKey() {
return ((KeyCodeAccessor) this).getKeyCode();
return KeyBindingHelper.getBoundKeyOf(this);
}
@Deprecated
public static class Builder {
protected final FabricKeyBinding binding;

View file

@ -18,15 +18,28 @@ package net.fabricmc.fabric.api.client.keybinding;
import net.minecraft.client.options.KeyBinding;
import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
import net.fabricmc.fabric.impl.client.keybinding.KeyBindingRegistryImpl;
/**
* Interface for registering key bindings.
*
* @see KeyBinding
* @deprecated Please migrate to v1. Please use {@link KeyBindingHelper} instead.
*/
@Deprecated
public interface KeyBindingRegistry {
KeyBindingRegistry INSTANCE = KeyBindingRegistryImpl.INSTANCE;
KeyBindingRegistry INSTANCE = new KeyBindingRegistry() {
@Override
public boolean addCategory(String categoryName) {
return KeyBindingRegistryImpl.addCategory(categoryName);
}
@Override
public boolean register(FabricKeyBinding binding) {
return KeyBindingRegistryImpl.registerKeyBinding(binding) != null;
}
};
/**
* Add a new key binding category.

View file

@ -1,114 +0,0 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* 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 net.fabricmc.fabric.impl.client.keybinding;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import net.minecraft.client.options.KeyBinding;
import net.fabricmc.fabric.api.client.keybinding.FabricKeyBinding;
import net.fabricmc.fabric.api.client.keybinding.KeyBindingRegistry;
public class KeyBindingRegistryImpl implements KeyBindingRegistry {
public static final KeyBindingRegistryImpl INSTANCE = new KeyBindingRegistryImpl();
private static final Logger LOGGER = LogManager.getLogger();
private Map<String, Integer> cachedCategoryMap;
private List<FabricKeyBinding> fabricKeyBindingList;
private KeyBindingRegistryImpl() {
fabricKeyBindingList = new ArrayList<>();
}
private Map<String, Integer> getCategoryMap() {
if (cachedCategoryMap == null) {
try {
//noinspection JavaReflectionMemberAccess
Method m = KeyBinding.class.getDeclaredMethod("fabric_getCategoryMap");
m.setAccessible(true);
//noinspection unchecked
cachedCategoryMap = (Map<String, Integer>) m.invoke(null);
} catch (Exception e) {
throw new RuntimeException(e);
}
if (cachedCategoryMap == null) {
throw new RuntimeException("Cached key binding category map missing!");
}
}
return cachedCategoryMap;
}
private boolean hasCategory(String categoryName) {
return getCategoryMap().containsKey(categoryName);
}
@Override
public boolean addCategory(String categoryName) {
Map<String, Integer> map = getCategoryMap();
if (map.containsKey(categoryName)) {
return false;
}
Optional<Integer> largest = map.values().stream().max(Integer::compareTo);
int largestInt = largest.orElse(0);
map.put(categoryName, largestInt + 1);
return true;
}
@Override
public boolean register(FabricKeyBinding binding) {
for (KeyBinding exBinding : fabricKeyBindingList) {
if (exBinding == binding) {
return false;
} else if (exBinding.getId().equals(binding.getId())) {
throw new RuntimeException("Attempted to register two key bindings with equal ID: " + binding.getId() + "!");
}
}
if (!hasCategory(binding.getCategory())) {
LOGGER.warn("Tried to register key binding with unregistered category '" + binding.getCategory() + "' - please use addCategory to ensure intended category ordering!");
addCategory(binding.getCategory());
}
fabricKeyBindingList.add(binding);
return true;
}
public KeyBinding[] process(KeyBinding[] keysAll) {
List<KeyBinding> newKeysAll = new ArrayList<>();
for (KeyBinding binding : keysAll) {
if (!(binding instanceof FabricKeyBinding)) {
newKeysAll.add(binding);
}
}
newKeysAll.addAll(fabricKeyBindingList);
return newKeysAll.toArray(new KeyBinding[0]);
}
}

View file

@ -17,10 +17,7 @@
],
"depends": {
"fabricloader": ">=0.4.0",
"fabric-api-base": "*"
"fabric-key-binding-api-v1": "*"
},
"description": "Keybinding registry API.",
"mixins": [
"fabric-keybindings-v0.mixins.json"
]
"description": "Keybinding registry API."
}

View file

@ -26,6 +26,7 @@ include 'fabric-events-interaction-v0'
include 'fabric-events-lifecycle-v0'
include 'fabric-item-groups-v0'
include 'fabric-keybindings-v0'
include 'fabric-key-binding-api-v1'
include 'fabric-loot-tables-v1'
include 'fabric-mining-levels-v0'
include 'fabric-models-v0'