Skip to content

Commit df33d95

Browse files
committed
some event stuff for action controller
1 parent 63f3147 commit df33d95

File tree

6 files changed

+393
-2
lines changed

6 files changed

+393
-2
lines changed
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* This file is part of npc-lib, licensed under the MIT License (MIT).
3+
*
4+
* Copyright (c) 2022-2025 Julian M., Pasqual K. and contributors
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in
14+
* all copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
* THE SOFTWARE.
23+
*/
24+
25+
package com.github.juliarn.npclib.fabric.controller;
26+
27+
public class FabricActionController {
28+
29+
}
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
/*
2+
* This file is part of npc-lib, licensed under the MIT License (MIT).
3+
*
4+
* Copyright (c) 2022-2025 Julian M., Pasqual K. and contributors
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in
14+
* all copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
* THE SOFTWARE.
23+
*/
24+
25+
package com.github.juliarn.npclib.fabric.controller;
26+
27+
import net.fabricmc.fabric.api.event.Event;
28+
import net.fabricmc.fabric.api.event.EventFactory;
29+
import net.minecraft.server.level.ServerLevel;
30+
import net.minecraft.server.level.ServerPlayer;
31+
import net.minecraft.world.phys.Vec2;
32+
import net.minecraft.world.phys.Vec3;
33+
import org.jetbrains.annotations.ApiStatus;
34+
import org.jetbrains.annotations.NotNull;
35+
import org.jetbrains.annotations.Nullable;
36+
37+
/**
38+
* Internal event for notifying the action controller about player actions.
39+
*/
40+
@ApiStatus.Internal
41+
public interface FabricActionControllerEvents {
42+
43+
Event<ServerPlayerPreLevelChange> PRE_SERVER_PLAYER_LEVEL_CHANGE = EventFactory.createArrayBacked(
44+
ServerPlayerPreLevelChange.class,
45+
callbacks -> (player, oldLevel, newLevel) -> {
46+
for (var callback : callbacks) {
47+
callback.preLevelChange(player, oldLevel, newLevel);
48+
}
49+
}
50+
);
51+
52+
Event<ServerPlayerToggleSneak> SERVER_PLAYER_TOGGLE_SNEAK = EventFactory.createArrayBacked(
53+
ServerPlayerToggleSneak.class,
54+
callbacks -> (player, sneak) -> {
55+
for (var callback : callbacks) {
56+
callback.toggleSneak(player, sneak);
57+
}
58+
}
59+
);
60+
61+
Event<ServerPlayerHandSwing> SERVER_PLAYER_HAND_SWING = EventFactory.createArrayBacked(
62+
ServerPlayerHandSwing.class,
63+
callbacks -> player -> {
64+
for (var callback : callbacks) {
65+
callback.swingHand(player);
66+
}
67+
}
68+
);
69+
70+
Event<ServerPlayerDisconnect> SERVER_PLAYER_DISCONNECT = EventFactory.createArrayBacked(
71+
ServerPlayerDisconnect.class,
72+
callbacks -> player -> {
73+
for (var callback : callbacks) {
74+
callback.disconnect(player);
75+
}
76+
}
77+
);
78+
79+
Event<ServerPlayerMove> SERVER_PLAYER_MOVE = EventFactory.createArrayBacked(
80+
ServerPlayerMove.class,
81+
callbacks -> (player, posTo, rotTo) -> {
82+
for (var callback : callbacks) {
83+
callback.move(player, posTo, rotTo);
84+
}
85+
}
86+
);
87+
88+
/**
89+
* Called before a server player changes the level.
90+
*/
91+
@FunctionalInterface
92+
interface ServerPlayerPreLevelChange {
93+
94+
void preLevelChange(@NotNull ServerPlayer player, @Nullable ServerLevel oldLevel, @NotNull ServerLevel newLevel);
95+
}
96+
97+
/**
98+
* Called when a server player starts or stops sprinting.
99+
*/
100+
@FunctionalInterface
101+
interface ServerPlayerToggleSneak {
102+
103+
void toggleSneak(@NotNull ServerPlayer player, boolean sneaking);
104+
}
105+
106+
/**
107+
* Called when a server player swings his hand (left click).
108+
*/
109+
@FunctionalInterface
110+
interface ServerPlayerHandSwing {
111+
112+
void swingHand(@NotNull ServerPlayer player);
113+
}
114+
115+
/**
116+
* Called when a server player disconnects.
117+
*/
118+
@FunctionalInterface
119+
interface ServerPlayerDisconnect {
120+
121+
void disconnect(@NotNull ServerPlayer player);
122+
}
123+
124+
/**
125+
* Called when a server player moves. Note that the pos and rot is only given if it was changed by the client.
126+
*/
127+
@FunctionalInterface
128+
interface ServerPlayerMove {
129+
130+
void move(@NotNull ServerPlayer player, @Nullable Vec3 posTo, @Nullable Vec2 rotTo);
131+
}
132+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* This file is part of npc-lib, licensed under the MIT License (MIT).
3+
*
4+
* Copyright (c) 2022-2025 Julian M., Pasqual K. and contributors
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in
14+
* all copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
* THE SOFTWARE.
23+
*/
24+
25+
package com.github.juliarn.npclib.fabric.mixins;
26+
27+
import com.github.juliarn.npclib.fabric.controller.FabricActionControllerEvents;
28+
import net.minecraft.server.level.ServerPlayer;
29+
import net.minecraft.server.players.PlayerList;
30+
import org.spongepowered.asm.mixin.Mixin;
31+
import org.spongepowered.asm.mixin.injection.At;
32+
import org.spongepowered.asm.mixin.injection.Inject;
33+
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
34+
35+
@Mixin(PlayerList.class)
36+
public abstract class PlayerListMixin {
37+
38+
@Inject(method = "remove", at = @At("TAIL"))
39+
public void npc_lib$remove(ServerPlayer player, CallbackInfo ci) {
40+
var invoker = FabricActionControllerEvents.SERVER_PLAYER_DISCONNECT.invoker();
41+
invoker.disconnect(player);
42+
}
43+
}
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
/*
2+
* This file is part of npc-lib, licensed under the MIT License (MIT).
3+
*
4+
* Copyright (c) 2022-2025 Julian M., Pasqual K. and contributors
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in
14+
* all copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
* THE SOFTWARE.
23+
*/
24+
25+
package com.github.juliarn.npclib.fabric.mixins;
26+
27+
import com.github.juliarn.npclib.fabric.controller.FabricActionControllerEvents;
28+
import net.minecraft.network.protocol.game.ServerboundMovePlayerPacket;
29+
import net.minecraft.network.protocol.game.ServerboundMoveVehiclePacket;
30+
import net.minecraft.network.protocol.game.ServerboundPlayerCommandPacket;
31+
import net.minecraft.network.protocol.game.ServerboundSwingPacket;
32+
import net.minecraft.server.level.ServerPlayer;
33+
import net.minecraft.server.network.ServerGamePacketListenerImpl;
34+
import net.minecraft.world.phys.Vec2;
35+
import net.minecraft.world.phys.Vec3;
36+
import org.spongepowered.asm.mixin.Mixin;
37+
import org.spongepowered.asm.mixin.Shadow;
38+
import org.spongepowered.asm.mixin.injection.At;
39+
import org.spongepowered.asm.mixin.injection.Inject;
40+
import org.spongepowered.asm.mixin.injection.Slice;
41+
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
42+
43+
@Mixin(ServerGamePacketListenerImpl.class)
44+
public abstract class ServerGamePacketListenerImplMixin {
45+
46+
@Shadow
47+
public abstract ServerPlayer getPlayer();
48+
49+
@Inject(method = "handlePlayerCommand", at = @At("TAIL"))
50+
public void npc_lib$handlePlayerCommand(ServerboundPlayerCommandPacket packet, CallbackInfo ci) {
51+
var player = this.getPlayer();
52+
var command = packet.getAction();
53+
if (command == ServerboundPlayerCommandPacket.Action.PRESS_SHIFT_KEY
54+
|| command == ServerboundPlayerCommandPacket.Action.RELEASE_SHIFT_KEY) {
55+
var invoker = FabricActionControllerEvents.SERVER_PLAYER_TOGGLE_SNEAK.invoker();
56+
var sprintStarted = command == ServerboundPlayerCommandPacket.Action.PRESS_SHIFT_KEY;
57+
invoker.toggleSneak(player, sprintStarted);
58+
}
59+
}
60+
61+
@Inject(method = "handleAnimate", at = @At("TAIL"))
62+
public void npc_lib$handleAnimate(ServerboundSwingPacket packet, CallbackInfo ci) {
63+
var player = this.getPlayer();
64+
var invoker = FabricActionControllerEvents.SERVER_PLAYER_HAND_SWING.invoker();
65+
invoker.swingHand(player);
66+
}
67+
68+
@Inject(
69+
method = "handleMovePlayer",
70+
at = @At(
71+
value = "INVOKE",
72+
target = "Lnet/minecraft/network/protocol/game/ServerboundMovePlayerPacket;getYRot(F)F"
73+
),
74+
slice = @Slice(
75+
from = @At(value = "INVOKE", target = "Lnet/minecraft/server/network/ServerGamePacketListenerImpl;updateAwaitingTeleport()Z"),
76+
to = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerPlayer;isPassenger()Z")
77+
)
78+
)
79+
public void npc_lib$handleMovePlayer(ServerboundMovePlayerPacket packet, CallbackInfo ci) {
80+
// ensure that the packet contains at least position and rotation
81+
var hasPos = packet.hasPosition();
82+
var hasRot = packet.hasRotation();
83+
if (!hasPos && !hasRot) {
84+
return;
85+
}
86+
87+
// get the new target position, null in case it's not provided by the packet
88+
var player = this.getPlayer();
89+
var posToX = packet.getX(player.getX());
90+
var posToY = packet.getY(player.getY());
91+
var posToZ = packet.getZ(player.getZ());
92+
var posTo = hasPos ? new Vec3(posToX, posToY, posToZ) : null;
93+
94+
// get the new target rotation, null in case it's not provided by the packet
95+
var rotToX = packet.getXRot(player.getXRot());
96+
var rotToY = packet.getYRot(player.getYRot());
97+
var rotTo = hasRot ? new Vec2(rotToX, rotToY) : null;
98+
99+
// invoke the player move event
100+
var invoker = FabricActionControllerEvents.SERVER_PLAYER_MOVE.invoker();
101+
invoker.move(player, posTo, rotTo);
102+
}
103+
104+
@Inject(
105+
method = "handleMoveVehicle",
106+
at = @At(
107+
value = "INVOKE",
108+
target = "Lnet/minecraft/world/entity/Entity;getControllingPassenger()Lnet/minecraft/world/entity/LivingEntity;"
109+
)
110+
)
111+
public void npc_lib$handleMoveVehicle(ServerboundMoveVehiclePacket packet, CallbackInfo ci) {
112+
var player = this.getPlayer();
113+
var rootVehicle = player.getRootVehicle();
114+
115+
// get the target position, set to null in case it didn't change
116+
var posFrom = rootVehicle.position();
117+
var posTo = packet.position();
118+
if (posTo.equals(posFrom)) {
119+
posTo = null;
120+
}
121+
122+
// get the target rotation, set to null in case it didn't change
123+
var rotFrom = rootVehicle.getRotationVector();
124+
var rotTo = new Vec2(packet.xRot(), packet.yRot());
125+
if (rotTo.equals(rotFrom)) {
126+
rotTo = null;
127+
}
128+
129+
// fire player move event in case position or rotation changed
130+
if (posTo != null || rotTo != null) {
131+
var invoker = FabricActionControllerEvents.SERVER_PLAYER_MOVE.invoker();
132+
invoker.move(player, posTo, rotTo);
133+
}
134+
}
135+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* This file is part of npc-lib, licensed under the MIT License (MIT).
3+
*
4+
* Copyright (c) 2022-2025 Julian M., Pasqual K. and contributors
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in
14+
* all copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
* THE SOFTWARE.
23+
*/
24+
25+
package com.github.juliarn.npclib.fabric.mixins;
26+
27+
import com.github.juliarn.npclib.fabric.controller.FabricActionControllerEvents;
28+
import net.minecraft.server.level.ServerLevel;
29+
import net.minecraft.server.level.ServerPlayer;
30+
import org.spongepowered.asm.mixin.Mixin;
31+
import org.spongepowered.asm.mixin.Shadow;
32+
import org.spongepowered.asm.mixin.injection.At;
33+
import org.spongepowered.asm.mixin.injection.Inject;
34+
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
35+
36+
@Mixin(ServerPlayer.class)
37+
public abstract class ServerPlayerMixin {
38+
39+
@Shadow
40+
public abstract ServerLevel serverLevel();
41+
42+
@Inject(method = "setServerLevel", at = @At("HEAD"))
43+
public void npc_lib$setServerLevel(ServerLevel level, CallbackInfo ci) {
44+
var currentLevel = this.serverLevel();
45+
var player = (ServerPlayer) (Object) this;
46+
var eventInvoker = FabricActionControllerEvents.PRE_SERVER_PLAYER_LEVEL_CHANGE.invoker();
47+
eventInvoker.preLevelChange(player, currentLevel, level);
48+
}
49+
}

0 commit comments

Comments
 (0)