Freeze action in required linking module

This commit is contained in:
IxPrumxI 2025-01-15 14:18:46 +03:00
parent dd10abf0e4
commit 5e6499d849
7 changed files with 250 additions and 148 deletions

View File

@ -46,6 +46,7 @@ artifacts {
loom {
serverOnlyMinecraftJar()
accessWidenerPath = file('src/main/resources/discordsrv.accesswidener')
}
repositories {

View File

@ -0,0 +1,37 @@
/*
* This file is part of DiscordSRV, licensed under the GPLv3 License
* Copyright (c) 2016-2025 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.discordsrv.fabric.mixin.requiredlinking;
import com.discordsrv.fabric.requiredlinking.FabricRequiredLinkingModule;
import com.mojang.brigadier.ParseResults;
import net.minecraft.server.command.CommandManager;
import net.minecraft.server.command.ServerCommandSource;
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;
@Mixin(CommandManager.class)
public class CommandManagerMixin {
@Inject(method = "execute", at = @At("HEAD"), cancellable = true)
private void execute(ParseResults<ServerCommandSource> parseResults, String command, CallbackInfo ci) {
FabricRequiredLinkingModule.onCommandExecute(parseResults, command, ci);
}
}

View File

@ -0,0 +1,41 @@
/*
* This file is part of DiscordSRV, licensed under the GPLv3 License
* Copyright (c) 2016-2025 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.discordsrv.fabric.mixin.requiredlinking;
import com.discordsrv.fabric.requiredlinking.FabricRequiredLinkingModule;
import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket;
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;
@Mixin(ServerPlayNetworkHandler.class)
public class ServerPlayNetworkHandlerMixin {
@Shadow
public ServerPlayerEntity player;
@Inject(method = "onPlayerMove", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/network/ServerPlayerEntity;getServerWorld()Lnet/minecraft/server/world/ServerWorld;", ordinal = 1), cancellable = true)
private void onPlayerMove(PlayerMoveC2SPacket packet, CallbackInfo ci) {
FabricRequiredLinkingModule.onPlayerMove(player, packet, ci);
}
}

View File

@ -24,13 +24,25 @@ import com.discordsrv.common.abstraction.player.IPlayer;
import com.discordsrv.common.config.main.linking.ServerRequiredLinkingConfig;
import com.discordsrv.common.feature.linking.LinkStore;
import com.discordsrv.common.feature.linking.requirelinking.ServerRequireLinkingModule;
import com.discordsrv.fabric.player.FabricPlayer;
import com.github.benmanes.caffeine.cache.Cache;
import com.mojang.authlib.GameProfile;
import com.mojang.brigadier.ParseResults;
import net.fabricmc.fabric.api.message.v1.ServerMessageEvents;
import net.fabricmc.fabric.api.networking.v1.PacketSender;
import net.fabricmc.fabric.api.networking.v1.ServerConfigurationConnectionEvents;
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
import net.kyori.adventure.platform.modcommon.MinecraftServerAudiences;
import net.kyori.adventure.text.Component;
import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.server.network.ServerConfigurationNetworkHandler;
import net.minecraft.server.network.ServerPlayNetworkHandler;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.List;
import java.util.Map;
@ -51,6 +63,8 @@ public class FabricRequiredLinkingModule extends ServerRequireLinkingModule<Fabr
.expireAfterWrite(LinkStore.LINKING_CODE_RATE_LIMIT)
.build();
register();
instance = this;
}
@ -66,6 +80,20 @@ public class FabricRequiredLinkingModule extends ServerRequireLinkingModule<Fabr
this.enabled = true;
}
public void register() {
ServerMessageEvents.ALLOW_CHAT_MESSAGE.register((text, player, parameters) -> {
// True if the message should be sent
if (isFrozen(player)) {
player.sendMessage(frozen.get(player.getUuid()));
return false;
}
return true;
});
ServerConfigurationConnectionEvents.CONFIGURE.register(this::onPlayerPreLogin);
ServerPlayConnectionEvents.JOIN.register(this::onPlayerJoin);
ServerPlayConnectionEvents.DISCONNECT.register(this::onPlayerQuit);
}
@Override
public void disable() {
@ -74,30 +102,6 @@ public class FabricRequiredLinkingModule extends ServerRequireLinkingModule<Fabr
this.enabled = false;
}
@Nullable
public static Text checkCanJoin(GameProfile profile) {
if (instance == null || (instance.discordSRV != null && instance.discordSRV.status() != DiscordSRV.Status.CONNECTED)) {
return Text.of("Currently unavailable to check link status because the server is still connecting to Discord.\n\nTry again in a minute.");
}
if (!instance.enabled) return null;
FabricDiscordSRV discordSRV = instance.discordSRV;
ServerRequiredLinkingConfig config = instance.config();
if (!config.enabled || config.action != ServerRequiredLinkingConfig.Action.KICK) {
return null;
}
UUID playerUUID = profile.getId();
String playerName = profile.getName();
Component kickReason = instance.getBlockReason(playerUUID, playerName, true).join();
if (kickReason != null) {
return MinecraftServerAudiences.of(discordSRV.getServer()).asNative(kickReason);
}
return null;
}
@Override
public void recheck(IPlayer player) {
getBlockReason(player.uniqueId(), player.username(), false).whenComplete((component, throwable) -> {
@ -121,7 +125,35 @@ public class FabricRequiredLinkingModule extends ServerRequireLinkingModule<Fabr
}
//
// Freeze - TODO: Not implemented yet
// Kick
//
@Nullable
public static Text checkCanJoin(GameProfile profile) {
if (instance == null || (instance.discordSRV != null && instance.discordSRV.status() != DiscordSRV.Status.CONNECTED)) {
return Text.of("Currently unavailable to check link status because the server is still connecting to Discord.\n\nTry again in a minute.");
}
if (!instance.enabled) return null;
FabricDiscordSRV discordSRV = instance.discordSRV;
ServerRequiredLinkingConfig config = instance.config();
if (!config.enabled || config.action != ServerRequiredLinkingConfig.Action.KICK) {
return null;
}
UUID playerUUID = profile.getId();
String playerName = profile.getName();
Component kickReason = instance.getBlockReason(playerUUID, playerName, true).join();
if (kickReason != null) {
return MinecraftServerAudiences.of(discordSRV.getServer()).asNative(kickReason);
}
return null;
}
//
// Freeze
//
private final Map<UUID, Component> frozen = new ConcurrentHashMap<>();
@ -136,49 +168,41 @@ public class FabricRequiredLinkingModule extends ServerRequireLinkingModule<Fabr
player.sendMessage(blockReason);
}
// @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
// public void onAsyncPlayerPreLogin(AsyncPlayerPreLoginEvent event) {
// if (event.getLoginResult() != AsyncPlayerPreLoginEvent.Result.ALLOWED) {
// return;
// }
//
// UUID playerUUID = event.getUniqueId();
// loginsHandled.add(playerUUID);
// handleLogin(playerUUID, event.getName());
// }
//
// @EventHandler(priority = EventPriority.MONITOR)
// public void onPlayerLogin(PlayerLoginEvent event) {
// if (event.getResult() != PlayerLoginEvent.Result.ALLOWED) {
// frozen.remove(event.getPlayer().getUniqueId());
// }
// }
//
// @EventHandler(priority = EventPriority.LOWEST)
// public void onPlayerJoinLowest(PlayerJoinEvent event) {
// Player player = event.getPlayer();
// UUID playerUUID = player.getUniqueId();
// if (!loginsHandled.remove(playerUUID)) {
// handleLogin(playerUUID, player.getName());
// }
// }
//
// @EventHandler(priority = EventPriority.MONITOR)
// public void onPlayerJoinMonitor(PlayerJoinEvent event) {
// UUID playerUUID = event.getPlayer().getUniqueId();
//
// Component blockReason = frozen.get(playerUUID);
// if (blockReason == null) {
// return;
// }
//
// IPlayer srvPlayer = discordSRV.playerProvider().player(playerUUID);
// if (srvPlayer == null) {
// throw new IllegalStateException("Player not available: " + playerUUID);
// }
//
// srvPlayer.sendMessage(blockReason);
// }
private void onPlayerPreLogin(ServerConfigurationNetworkHandler handler, MinecraftServer minecraftServer) {
if(!enabled) return;
UUID playerUUID = handler.getDebugProfile().getId();
loginsHandled.add(playerUUID);
handleLogin(playerUUID, handler.getDebugProfile().getName());
}
private void onPlayerJoin(ServerPlayNetworkHandler serverPlayNetworkHandler, PacketSender packetSender, MinecraftServer minecraftServer) {
if(!enabled) return;
UUID playerUUID = serverPlayNetworkHandler.player.getUuid();
if(!loginsHandled.contains(playerUUID)) {
handleLogin(playerUUID, serverPlayNetworkHandler.player.getName().getString());
}
Component blockReason = frozen.get(playerUUID);
if (blockReason == null) {
return;
}
IPlayer srvPlayer = discordSRV.playerProvider().player(playerUUID);
if (srvPlayer == null) {
throw new IllegalStateException("Player not available: " + playerUUID);
}
srvPlayer.sendMessage(blockReason);
}
private void onPlayerQuit(ServerPlayNetworkHandler serverPlayNetworkHandler, MinecraftServer minecraftServer) {
if(!enabled) return;
UUID playerUUID = serverPlayNetworkHandler.player.getUuid();
loginsHandled.remove(playerUUID);
frozen.remove(playerUUID);
}
private void handleLogin(UUID playerUUID, String username) {
if (discordSRV.isShutdown()) {
@ -202,83 +226,72 @@ public class FabricRequiredLinkingModule extends ServerRequireLinkingModule<Fabr
}
}
// @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
// public void onPlayerMove(PlayerMoveEvent event) {
// Component freezeReason = frozen.get(event.getPlayer().getUniqueId());
// if (freezeReason == null) {
// return;
// }
//
// Location from = event.getFrom(), to = event.getTo();
// if (from.getWorld().getName().equals(to.getWorld().getName())
// && from.getBlockX() == to.getBlockX()
// && from.getBlockZ() == to.getBlockZ()
// && from.getBlockY() >= to.getBlockY()) {
// return;
// }
//
// event.setTo(
// new Location(
// from.getWorld(),
// from.getBlockX() + 0.5,
// from.getBlockY(),
// from.getBlockZ() + 0.5,
// from.getYaw(),
// from.getPitch()
// )
// );
//
// IPlayer player = discordSRV.playerProvider().player(event.getPlayer());
// player.sendMessage(freezeReason);
// }
//
// @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
// public void onAsyncPlayerChat(AsyncPlayerChatEvent event) {
// Component freezeReason = frozen.get(event.getPlayer().getUniqueId());
// if (freezeReason == null) {
// event.getRecipients().removeIf(this::isFrozen);
// return;
// }
//
// event.setCancelled(true);
//
// IPlayer player = discordSRV.playerProvider().player(event.getPlayer());
// player.sendMessage(freezeReason);
// }
//
// @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
// public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) {
// if (!isFrozen(event.getPlayer())) {
// return;
// }
//
// event.setCancelled(true);
//
// String message = event.getMessage();
// if (message.startsWith("/")) message = message.substring(1);
// if (message.equals("discord link") || message.equals("link")) {
// IPlayer player = discordSRV.playerProvider().player(event.getPlayer());
//
// if (linkCheckRateLimit.getIfPresent(player.uniqueId()) != null) {
// player.sendMessage(discordSRV.messagesConfig(player).pleaseWaitBeforeRunningThatCommandAgain.asComponent());
// return;
// }
// linkCheckRateLimit.put(player.uniqueId(), true);
//
// player.sendMessage(Component.text("Checking..."));
//
// UUID uuid = player.uniqueId();
// getBlockReason(uuid, player.username(), false).whenComplete((reason, t) -> {
// if (t != null) {
// return;
// }
//
// if (reason == null) {
// frozen.remove(uuid);
// } else {
// freeze(player, reason);
// }
// });
// }
// }
public static void onPlayerMove(ServerPlayerEntity player, PlayerMoveC2SPacket packet, CallbackInfo ci) {
if(instance == null || !instance.enabled) return;
Component freezeReason = instance.frozen.get(player.getUuid());
if (freezeReason == null) {
return;
}
double d = ServerPlayNetworkHandler.clampHorizontal(packet.getX(player.getX()));
double e = ServerPlayNetworkHandler.clampVertical(packet.getY(player.getY()));
double f = ServerPlayNetworkHandler.clampHorizontal(packet.getZ(player.getZ()));
double i = player.getX();
double j = player.getY();
double k = player.getZ();
double l = d - player.networkHandler.lastTickX;
double m = e - player.networkHandler.lastTickY;
double n = f - player.networkHandler.lastTickZ;
// If the player last position is the same. Don't move the player
if (l * l + m * m + n * n > 0.0001) {
player.networkHandler.requestTeleport(i, j, k, player.getYaw(), player.getPitch());
IPlayer iPlayer = instance.discordSRV.playerProvider().player(player);
iPlayer.sendMessage(freezeReason);
}
ci.cancel();
}
public static void onCommandExecute(ParseResults<ServerCommandSource> parseResults, String command, CallbackInfo ci) {
if(instance == null || !instance.enabled) return;
FabricDiscordSRV discordSRV = instance.discordSRV;
ServerPlayerEntity playerEntity = parseResults.getContext().getSource().getPlayer();
if(playerEntity == null) return;
if (!instance.isFrozen(playerEntity)) {
return;
}
if(command.startsWith("/")) command = command.substring(1);
if(command.equals("discord link") || command.equals("link")) {
FabricPlayer player = discordSRV.playerProvider().player(playerEntity);
UUID uuid = player.uniqueId();
if (instance.linkCheckRateLimit.getIfPresent(uuid) != null) {
player.sendMessage(discordSRV.messagesConfig(player).pleaseWaitBeforeRunningThatCommandAgain.asComponent());
return;
}
instance.linkCheckRateLimit.put(uuid, true);
player.sendMessage(discordSRV.messagesConfig(player).checkingLinkStatus.asComponent());
instance.getBlockReason(uuid, player.username(), false).whenComplete((reason, t) -> {
if (t != null) {
return;
}
if (reason == null) {
instance.frozen.remove(uuid);
player.sendMessage(discordSRV.messagesConfig(player).nowLinked1st.asComponent());
} else {
instance.freeze(player, reason);
}
});
}
ci.cancel();
}
}

View File

@ -0,0 +1,7 @@
accessWidener v1 named
accessible method net/minecraft/server/network/ServerPlayNetworkHandler clampHorizontal (D)D
accessible method net/minecraft/server/network/ServerPlayNetworkHandler clampVertical (D)D
accessible field net/minecraft/server/network/ServerPlayNetworkHandler lastTickX D
accessible field net/minecraft/server/network/ServerPlayNetworkHandler lastTickY D
accessible field net/minecraft/server/network/ServerPlayNetworkHandler lastTickZ D

View File

@ -5,7 +5,9 @@
"mixins": [
"PlayerAdvancementTrackerMixin",
"ban.BanCommandMixin",
"requiredlinking.PlayerManagerMixin"
"requiredlinking.CommandManagerMixin",
"requiredlinking.PlayerManagerMixin",
"requiredlinking.ServerPlayNetworkHandlerMixin"
],
"injectors": {
"defaultRequire": 1

View File

@ -21,6 +21,7 @@
"file": "META-INF/jars/adventure-platform-mod-shared-fabric-repack-6.1.0.jar"
}
],
"accessWidener": "discordsrv.accesswidener",
"depends": {
"fabricloader": ">=${LOADER_VERSION}",
"fabric": "*",