Fabric API

Fabric API

106M Downloads

Keybindings crashes servers

Bob74 opened this issue ยท 3 comments

commented

Versions:

  • Minecraft version : 1.16.1
  • Fabric API : 0.18.0+build.387
  • Fabric loader : 0.9.3+build.207
  • No other mod than fabric-api + my keybinding test mod

Hi, I'm trying to add keybindings to a mod.

It does work on a debug minecraft client run but when I try on a dedicated server, the server crashes on start.

To narrow the problem down, I built the fabric mod example 1.16.1: https://github.com/FabricMC/fabric-example-mod/tree/6efb5c4830dd5afcdeceb34e459da47c0ec350a9
It works well on local and server.

I then added the keybinding part to the example mod: https://github.com/FabricMC/fabric/tree/1.16/fabric-key-binding-api-v1/src/testmod
It still works well on local but crashes the server:

[12:38:02] [main/INFO]: Loading for game Minecraft 1.16.1
[12:38:02] [main/INFO]: [FabricLoader] Loading 42 mods: [email protected]+eae12eb802, [email protected]+97324d1102, [email protected], [email protected]+b50ffc7b02, [email protected]+3fa9f7c502, [email protected]+5ce5339802, [email protected]+build.207, [email protected]+91fca5cd02, [email protected]+34d6c87102, [email protected]+045df74f02, [email protected]+2242e77202, [email protected]+a71b305302, [email protected]+059ea86602, [email protected]+16acbe5b02, [email protected]+b7f9825d02, [email protected]+e540c58402, [email protected]+fe81e12502, [email protected]+12a8474c02, [email protected]+5341049002, [email protected]+346247d702, [email protected]+f404f3be02, [email protected]+b7f9825d02, [email protected]+f41e209802, [email protected]+eae12eb802, [email protected]+059ea86602, [email protected]+a4c57d8e02, [email protected]+b7084faa02, [email protected]+7dba2d6c02, [email protected]+52d3083602, [email protected], [email protected]+c6a8ea8902, [email protected]+e83e061c02, [email protected]+b764ce9902, [email protected]+be551d3c02, [email protected]+386eb69e02, [email protected]+16acbe5b02, [email protected]+build.387-1.16.1, [email protected]+0a6f2a7002, [email protected]+dfdb52d602, [email protected]+438f963602, [email protected]+a2d21ddd02, [email protected]+e00ecb5f02
[12:38:02] [main/INFO]: SpongePowered MIXIN Subsystem Version=0.8.1 Source=file:/C:/Test%20server/fabric-server-launch.jar Service=Knot/Fabric Env=SERVER
[12:38:10] [main/INFO]: [STDOUT]: Hello Fabric world!
[12:38:10] [main/FATAL]: Failed to start the minecraft server
java.lang.RuntimeException: Could not execute entrypoint stage 'main' due to errors, provided by 'modid'!
	at net.fabricmc.loader.entrypoint.minecraft.hooks.EntrypointUtils.invoke0(EntrypointUtils.java:53) ~[fabric-server-launch.jar:?]
	at net.fabricmc.loader.entrypoint.minecraft.hooks.EntrypointUtils.invoke(EntrypointUtils.java:36) ~[fabric-server-launch.jar:?]
	at net.fabricmc.loader.entrypoint.minecraft.hooks.EntrypointServer.start(EntrypointServer.java:32) ~[fabric-server-launch.jar:?]
	at net.minecraft.server.Main.main(Main.java:92) [intermediary-server.jar:?]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_265]
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_265]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_265]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_265]
	at net.fabricmc.loader.game.MinecraftGameProvider.launch(MinecraftGameProvider.java:192) [fabric-server-launch.jar:?]
	at net.fabricmc.loader.launch.knot.Knot.init(Knot.java:140) [fabric-server-launch.jar:?]
	at net.fabricmc.loader.launch.knot.KnotServer.main(KnotServer.java:26) [fabric-server-launch.jar:?]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_265]
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_265]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_265]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_265]
	at net.fabricmc.loader.launch.server.FabricServerLauncher.launch(FabricServerLauncher.java:61) [fabric-server-launch.jar:?]
	at net.fabricmc.loader.launch.server.FabricServerLauncher.setup(FabricServerLauncher.java:105) [fabric-server-launch.jar:?]
	at net.fabricmc.loader.launch.server.FabricServerLauncher.main(FabricServerLauncher.java:49) [fabric-server-launch.jar:?]
Caused by: java.lang.NoClassDefFoundError: net/minecraft/class_304
	at net.fabricmc.example.ExampleMod.onInitialize(ExampleMod.java:23) ~[fabric-example-mod-1.0.0.jar:?]
	at net.fabricmc.loader.entrypoint.minecraft.hooks.EntrypointUtils.invoke0(EntrypointUtils.java:50) ~[fabric-server-launch.jar:?]
	... 17 more
Caused by: java.lang.ClassNotFoundException: net.minecraft.class_304
	at java.net.URLClassLoader.findClass(URLClassLoader.java:382) ~[?:1.8.0_265]
	at java.lang.ClassLoader.loadClass(ClassLoader.java:418) ~[?:1.8.0_265]
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:352) ~[?:1.8.0_265]
	at java.lang.ClassLoader.loadClass(ClassLoader.java:351) ~[?:1.8.0_265]
	at net.fabricmc.loader.launch.server.InjectingURLClassLoader.loadClass(InjectingURLClassLoader.java:56) ~[fabric-server-launch.jar:?]
	at java.lang.ClassLoader.loadClass(ClassLoader.java:351) ~[?:1.8.0_265]
	at net.fabricmc.loader.launch.knot.KnotClassLoader.loadClass(KnotClassLoader.java:166) ~[fabric-server-launch.jar:?]
	at java.lang.ClassLoader.loadClass(ClassLoader.java:351) ~[?:1.8.0_265]
	at net.fabricmc.example.ExampleMod.onInitialize(ExampleMod.java:23) ~[fabric-example-mod-1.0.0.jar:?]
	at net.fabricmc.loader.entrypoint.minecraft.hooks.EntrypointUtils.invoke0(EntrypointUtils.java:50) ~[fabric-server-launch.jar:?]
	... 17 more

The source code of the edited mod example that crashes the server is available here:
https://github.com/Bob74/fabric-example-mod-keybinding

Did I miss something to make it work on a server?

commented

Oh... of course it makes a lot more sense now!
I've just edited to add the client class and added the entrypoint to fabric.mod.json and it seems to work very well.

I'm trying to change the way an item is used when the client is pressing a key.

I guess I'll have to send a packet from the server to get the key state of the client? (directly getting the state of the keybind from the client class doesn't work but it seems normal)

commented

Keybinds should only be registered on the client initializer, since they are client only. If the server needs to know if someone has pressed your keybind, you should register a packet for that.

commented

I solved the issue using packets as you said, thank you for the tips :)

I'm editing SorceryCraft and I'm not the author, all credits goes to TheBrokenRail (https://gitea.thebrokenrail.com/TheBrokenRail/SorceryCraft.git).

(Client) onInitializeClient()

selfcast_keybind = KeyBindingHelper.registerKeyBinding(new KeyBinding("key.sorcerycraft.spellonself", InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_LEFT_ALT, "category.sorcerycraft.keys"));

ClientTickCallback.EVENT.register(client -> {
	// We send a packet only when the key state changes
	if (selfcast_keybinding_state && !selfcast_keybind.isPressed()) {
		selfcast_keybinding_state = false;
		PacketByteBuf passedData = new PacketByteBuf(Unpooled.buffer());
		passedData.writeBoolean(selfcast_keybinding_state);
		ClientSidePacketRegistry.INSTANCE.sendToServer(SorceryCraft.SET_SELFCAST_KEYBINDING_STATE, passedData);
	}
	if (!selfcast_keybinding_state && selfcast_keybind.isPressed()) {
		selfcast_keybinding_state = true;
		PacketByteBuf passedData = new PacketByteBuf(Unpooled.buffer());
		passedData.writeBoolean(selfcast_keybinding_state);
		ClientSidePacketRegistry.INSTANCE.sendToServer(SorceryCraft.SET_SELFCAST_KEYBINDING_STATE, passedData);
	}
});

(Common) onInitialize()

ServerSidePacketRegistry.INSTANCE.register(SET_SELFCAST_KEYBINDING_STATE, (packetContext, attachedData) -> {
	// Get the BlockPos we put earlier in the IO thread
	boolean keybinding_state = attachedData.readBoolean();
	PlayerEntity player = packetContext.getPlayer();
	packetContext.getTaskQueue().execute(() -> {
		// Execute on the main thread

		// Set the keybinding state for the player
		selfcast_keybinding_state.put(player, keybinding_state);
	});
});

Using public static Map<PlayerEntity, Boolean> selfcast_keybinding_state = new HashMap<>(); to store the keypress statuses for every players.