Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
a3cd3b7
implement a basic event system
TheDeathlyCow Jul 7, 2025
f877689
add sign block entity mixin to config and hopefully fix that weirdly …
TheDeathlyCow Jul 7, 2025
70d352e
consistent registry name
TheDeathlyCow Jul 7, 2025
7159fa7
refactor to use context objects and separate config/play events
TheDeathlyCow Jul 8, 2025
3db85ce
add a dialog test
TheDeathlyCow Jul 8, 2025
5e6b483
apply spotless checks
TheDeathlyCow Jul 8, 2025
745831a
fix blank line checkstyle violation
TheDeathlyCow Jul 8, 2025
517bf0c
add javadoc to api methods
TheDeathlyCow Jul 8, 2025
68fac72
add configuration phase tests
TheDeathlyCow Jul 8, 2025
65c8eba
add missing full stops to javadoc
TheDeathlyCow Jul 8, 2025
6819567
Merge branch '1.21.7' into custom-click-action-registry
TheDeathlyCow Jul 8, 2025
519d68e
use a mock dialog packet system for testing
TheDeathlyCow Jul 8, 2025
9d4734b
remove join event forcing dialog
TheDeathlyCow Jul 8, 2025
52caa7d
Merge branch 'custom-click-action-registry' of https://github.com/The…
TheDeathlyCow Jul 8, 2025
4049294
run spotlessapply
TheDeathlyCow Jul 8, 2025
25cf3a7
move tests into own class and use a command to enable configuration test
TheDeathlyCow Jul 14, 2025
66a1dc4
fix checkstyle
TheDeathlyCow Jul 14, 2025
d2ca80f
convert to a single event for the registry
TheDeathlyCow Jul 14, 2025
2503992
add an event to handle "any" custom click action being received
TheDeathlyCow Jul 14, 2025
4fc69f7
add override annotations to context
TheDeathlyCow Jul 14, 2025
05cc21b
remove player from event context
TheDeathlyCow Jul 27, 2025
3f593f0
move test play handling into same listener as config
TheDeathlyCow Jul 27, 2025
3f9130e
move context impls to respective addons
TheDeathlyCow Jul 27, 2025
2ac4575
remove any event and move create event to own method
TheDeathlyCow Jul 27, 2025
2c4a29f
clear up some javadoc
TheDeathlyCow Jul 27, 2025
991c6bd
move payload into event parameter
TheDeathlyCow Jul 27, 2025
e25b3f6
add player convenience method to the play context
TheDeathlyCow Jul 27, 2025
150a4d0
import style fixes
TheDeathlyCow Jul 27, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package net.fabricmc.fabric.api.networking.v1;

import net.minecraft.nbt.NbtElement;
import net.minecraft.server.network.ServerPlayerEntity;

import org.jetbrains.annotations.Nullable;

@FunctionalInterface
public interface CustomClickActionListener {
void handleCustomClickAction(ServerPlayerEntity player, @Nullable NbtElement payload);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package net.fabricmc.fabric.api.networking.v1;

import java.util.Objects;

import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.impl.networking.CustomClickEventHandlerRegistry;

import net.minecraft.util.Identifier;

public final class CustomClickActions {
public static Event<CustomClickActionListener> getListenerEvent(Identifier id) {
Objects.requireNonNull(id, "ID cannot be null");
return CustomClickEventHandlerRegistry.getOrCreateListenerEvent(id);
}

private CustomClickActions() {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package net.fabricmc.fabric.impl.networking;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

import net.minecraft.nbt.NbtElement;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.util.Identifier;

import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.fabricmc.fabric.api.networking.v1.CustomClickActionListener;

public class CustomClickEventHandlerRegistry {
private static final Map<Identifier, Event<CustomClickActionListener>> REGISTRY = new HashMap<>();

public static Event<CustomClickActionListener> getOrCreateListenerEvent(Identifier id) {
return REGISTRY.computeIfAbsent(
id,
idx -> {
return EventFactory.createArrayBacked(
CustomClickActionListener.class,
listeners -> (player, payload) -> {
for (CustomClickActionListener listener : listeners) {
listener.handleCustomClickAction(player, payload);
}
}
);
}
);
}

public static void invokeListenerEvent(Identifier id, ServerPlayerEntity player, Optional<NbtElement> payload) {
Event<CustomClickActionListener> event = REGISTRY.get(id);
if (event != null) {
event.invoker().handleCustomClickAction(player, payload.orElse(null));
}
}

private CustomClickEventHandlerRegistry() {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,21 @@

package net.fabricmc.fabric.mixin.networking;

import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;

import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.networking.v1.CustomClickActionListener;
import net.fabricmc.fabric.impl.networking.CustomClickEventHandlerRegistry;

import net.minecraft.network.packet.c2s.common.CustomClickActionC2SPacket;

import net.minecraft.server.network.ServerPlayNetworkHandler;

import net.minecraft.server.network.ServerPlayerEntity;

import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
Expand Down Expand Up @@ -55,4 +69,21 @@ private void onPlayPong(CommonPongC2SPacket packet, CallbackInfo ci) {
addon.onPong(packet.getParameter());
}
}

@WrapMethod(method = "onCustomClickAction")
protected void overrideCustomClickAction(CustomClickActionC2SPacket packet, Operation<Void> original) {
original.call(packet);
}

@Mixin(ServerPlayNetworkHandler.class)
private abstract static class ServerPlayNetworkHandlerMixin extends ServerCommonNetworkHandlerMixin {
@Shadow
public ServerPlayerEntity player;

@Override
protected void overrideCustomClickAction(CustomClickActionC2SPacket packet, Operation<Void> original) {
super.overrideCustomClickAction(packet, original);
CustomClickEventHandlerRegistry.invokeListenerEvent(packet.id(), this.player, packet.payload());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package net.fabricmc.fabric.mixin.networking;

import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;

import com.llamalad7.mixinextras.sugar.Local;

import net.fabricmc.fabric.impl.networking.CustomClickEventHandlerRegistry;

import net.minecraft.block.entity.SignBlockEntity;

import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.nbt.NbtElement;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.util.Identifier;

import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;

import java.util.Optional;

@Mixin(SignBlockEntity.class)
public class SignBlockEntityMixin {
@WrapOperation(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why a wrap operation and not just an inject?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

an Inject would require capturing more locals

method = "runCommandClickEvent",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/server/MinecraftServer;handleCustomClickAction(Lnet/minecraft/util/Identifier;Ljava/util/Optional;)V"
)
)
private void hookCustomClickActionListener(MinecraftServer instance, Identifier id, Optional<NbtElement> payload, Operation<Void> original, @Local(argsOnly = true) PlayerEntity player) {
original.call(instance, id, payload);

// base method has a serverworld parameter, so the player should be a server player
CustomClickEventHandlerRegistry.invokeListenerEvent(id, (ServerPlayerEntity) player, payload);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@
"PlayerManagerMixin",
"RegistryByteBufMixin",
"ServerCommonNetworkHandlerMixin",
"ServerCommonNetworkHandlerMixin$ServerPlayNetworkHandlerMixin",
"ServerConfigurationNetworkHandlerMixin",
"ServerLoginNetworkHandlerMixin",
"ServerPlayNetworkHandlerMixin",
"SignBlockEntityMixin",
"accessor.EntityTrackerAccessor",
"accessor.ServerCommonNetworkHandlerAccessor",
"accessor.ServerLoginNetworkHandlerAccessor",
Expand Down
Loading