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 { loom {
serverOnlyMinecraftJar() serverOnlyMinecraftJar()
accessWidenerPath = file('src/main/resources/discordsrv.accesswidener')
} }
repositories { 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.config.main.linking.ServerRequiredLinkingConfig;
import com.discordsrv.common.feature.linking.LinkStore; import com.discordsrv.common.feature.linking.LinkStore;
import com.discordsrv.common.feature.linking.requirelinking.ServerRequireLinkingModule; import com.discordsrv.common.feature.linking.requirelinking.ServerRequireLinkingModule;
import com.discordsrv.fabric.player.FabricPlayer;
import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Cache;
import com.mojang.authlib.GameProfile; 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.platform.modcommon.MinecraftServerAudiences;
import net.kyori.adventure.text.Component; 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.server.network.ServerPlayerEntity;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -51,6 +63,8 @@ public class FabricRequiredLinkingModule extends ServerRequireLinkingModule<Fabr
.expireAfterWrite(LinkStore.LINKING_CODE_RATE_LIMIT) .expireAfterWrite(LinkStore.LINKING_CODE_RATE_LIMIT)
.build(); .build();
register();
instance = this; instance = this;
} }
@ -66,6 +80,20 @@ public class FabricRequiredLinkingModule extends ServerRequireLinkingModule<Fabr
this.enabled = true; 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 @Override
public void disable() { public void disable() {
@ -74,30 +102,6 @@ public class FabricRequiredLinkingModule extends ServerRequireLinkingModule<Fabr
this.enabled = false; 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 @Override
public void recheck(IPlayer player) { public void recheck(IPlayer player) {
getBlockReason(player.uniqueId(), player.username(), false).whenComplete((component, throwable) -> { 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<>(); private final Map<UUID, Component> frozen = new ConcurrentHashMap<>();
@ -136,49 +168,41 @@ public class FabricRequiredLinkingModule extends ServerRequireLinkingModule<Fabr
player.sendMessage(blockReason); player.sendMessage(blockReason);
} }
// @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) private void onPlayerPreLogin(ServerConfigurationNetworkHandler handler, MinecraftServer minecraftServer) {
// public void onAsyncPlayerPreLogin(AsyncPlayerPreLoginEvent event) { if(!enabled) return;
// if (event.getLoginResult() != AsyncPlayerPreLoginEvent.Result.ALLOWED) { UUID playerUUID = handler.getDebugProfile().getId();
// return; loginsHandled.add(playerUUID);
// } handleLogin(playerUUID, handler.getDebugProfile().getName());
// }
// UUID playerUUID = event.getUniqueId();
// loginsHandled.add(playerUUID);
// handleLogin(playerUUID, event.getName()); private void onPlayerJoin(ServerPlayNetworkHandler serverPlayNetworkHandler, PacketSender packetSender, MinecraftServer minecraftServer) {
// } if(!enabled) return;
// UUID playerUUID = serverPlayNetworkHandler.player.getUuid();
// @EventHandler(priority = EventPriority.MONITOR)
// public void onPlayerLogin(PlayerLoginEvent event) { if(!loginsHandled.contains(playerUUID)) {
// if (event.getResult() != PlayerLoginEvent.Result.ALLOWED) { handleLogin(playerUUID, serverPlayNetworkHandler.player.getName().getString());
// frozen.remove(event.getPlayer().getUniqueId()); }
// }
// } Component blockReason = frozen.get(playerUUID);
// if (blockReason == null) {
// @EventHandler(priority = EventPriority.LOWEST) return;
// public void onPlayerJoinLowest(PlayerJoinEvent event) { }
// Player player = event.getPlayer();
// UUID playerUUID = player.getUniqueId(); IPlayer srvPlayer = discordSRV.playerProvider().player(playerUUID);
// if (!loginsHandled.remove(playerUUID)) { if (srvPlayer == null) {
// handleLogin(playerUUID, player.getName()); throw new IllegalStateException("Player not available: " + playerUUID);
// } }
// }
// srvPlayer.sendMessage(blockReason);
// @EventHandler(priority = EventPriority.MONITOR) }
// public void onPlayerJoinMonitor(PlayerJoinEvent event) {
// UUID playerUUID = event.getPlayer().getUniqueId(); private void onPlayerQuit(ServerPlayNetworkHandler serverPlayNetworkHandler, MinecraftServer minecraftServer) {
// if(!enabled) return;
// Component blockReason = frozen.get(playerUUID); UUID playerUUID = serverPlayNetworkHandler.player.getUuid();
// if (blockReason == null) { loginsHandled.remove(playerUUID);
// return; frozen.remove(playerUUID);
// } }
//
// IPlayer srvPlayer = discordSRV.playerProvider().player(playerUUID);
// if (srvPlayer == null) {
// throw new IllegalStateException("Player not available: " + playerUUID);
// }
//
// srvPlayer.sendMessage(blockReason);
// }
private void handleLogin(UUID playerUUID, String username) { private void handleLogin(UUID playerUUID, String username) {
if (discordSRV.isShutdown()) { if (discordSRV.isShutdown()) {
@ -202,83 +226,72 @@ public class FabricRequiredLinkingModule extends ServerRequireLinkingModule<Fabr
} }
} }
// @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) public static void onPlayerMove(ServerPlayerEntity player, PlayerMoveC2SPacket packet, CallbackInfo ci) {
// public void onPlayerMove(PlayerMoveEvent event) { if(instance == null || !instance.enabled) return;
// Component freezeReason = frozen.get(event.getPlayer().getUniqueId()); Component freezeReason = instance.frozen.get(player.getUuid());
// if (freezeReason == null) { if (freezeReason == null) {
// return; return;
// } }
//
// Location from = event.getFrom(), to = event.getTo(); double d = ServerPlayNetworkHandler.clampHorizontal(packet.getX(player.getX()));
// if (from.getWorld().getName().equals(to.getWorld().getName()) double e = ServerPlayNetworkHandler.clampVertical(packet.getY(player.getY()));
// && from.getBlockX() == to.getBlockX() double f = ServerPlayNetworkHandler.clampHorizontal(packet.getZ(player.getZ()));
// && from.getBlockZ() == to.getBlockZ() double i = player.getX();
// && from.getBlockY() >= to.getBlockY()) { double j = player.getY();
// return; double k = player.getZ();
// } double l = d - player.networkHandler.lastTickX;
// double m = e - player.networkHandler.lastTickY;
// event.setTo( double n = f - player.networkHandler.lastTickZ;
// new Location( // If the player last position is the same. Don't move the player
// from.getWorld(), if (l * l + m * m + n * n > 0.0001) {
// from.getBlockX() + 0.5, player.networkHandler.requestTeleport(i, j, k, player.getYaw(), player.getPitch());
// from.getBlockY(), IPlayer iPlayer = instance.discordSRV.playerProvider().player(player);
// from.getBlockZ() + 0.5, iPlayer.sendMessage(freezeReason);
// from.getYaw(),
// from.getPitch() }
// )
// ); ci.cancel();
// }
// IPlayer player = discordSRV.playerProvider().player(event.getPlayer());
// player.sendMessage(freezeReason); public static void onCommandExecute(ParseResults<ServerCommandSource> parseResults, String command, CallbackInfo ci) {
// } if(instance == null || !instance.enabled) return;
// FabricDiscordSRV discordSRV = instance.discordSRV;
// @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) ServerPlayerEntity playerEntity = parseResults.getContext().getSource().getPlayer();
// public void onAsyncPlayerChat(AsyncPlayerChatEvent event) { if(playerEntity == null) return;
// Component freezeReason = frozen.get(event.getPlayer().getUniqueId());
// if (freezeReason == null) { if (!instance.isFrozen(playerEntity)) {
// event.getRecipients().removeIf(this::isFrozen); return;
// return; }
// }
// if(command.startsWith("/")) command = command.substring(1);
// event.setCancelled(true); if(command.equals("discord link") || command.equals("link")) {
//
// IPlayer player = discordSRV.playerProvider().player(event.getPlayer()); FabricPlayer player = discordSRV.playerProvider().player(playerEntity);
// player.sendMessage(freezeReason);
// } UUID uuid = player.uniqueId();
//
// @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) if (instance.linkCheckRateLimit.getIfPresent(uuid) != null) {
// public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) { player.sendMessage(discordSRV.messagesConfig(player).pleaseWaitBeforeRunningThatCommandAgain.asComponent());
// if (!isFrozen(event.getPlayer())) { return;
// return; }
// } instance.linkCheckRateLimit.put(uuid, true);
//
// event.setCancelled(true); player.sendMessage(discordSRV.messagesConfig(player).checkingLinkStatus.asComponent());
//
// String message = event.getMessage(); instance.getBlockReason(uuid, player.username(), false).whenComplete((reason, t) -> {
// if (message.startsWith("/")) message = message.substring(1); if (t != null) {
// if (message.equals("discord link") || message.equals("link")) { return;
// IPlayer player = discordSRV.playerProvider().player(event.getPlayer()); }
//
// if (linkCheckRateLimit.getIfPresent(player.uniqueId()) != null) { if (reason == null) {
// player.sendMessage(discordSRV.messagesConfig(player).pleaseWaitBeforeRunningThatCommandAgain.asComponent()); instance.frozen.remove(uuid);
// return; player.sendMessage(discordSRV.messagesConfig(player).nowLinked1st.asComponent());
// } } else {
// linkCheckRateLimit.put(player.uniqueId(), true); instance.freeze(player, reason);
// }
// player.sendMessage(Component.text("Checking...")); });
// }
// UUID uuid = player.uniqueId();
// getBlockReason(uuid, player.username(), false).whenComplete((reason, t) -> { ci.cancel();
// if (t != null) { }
// return;
// }
//
// if (reason == null) {
// frozen.remove(uuid);
// } else {
// freeze(player, reason);
// }
// });
// }
// }
} }

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": [ "mixins": [
"PlayerAdvancementTrackerMixin", "PlayerAdvancementTrackerMixin",
"ban.BanCommandMixin", "ban.BanCommandMixin",
"requiredlinking.PlayerManagerMixin" "requiredlinking.CommandManagerMixin",
"requiredlinking.PlayerManagerMixin",
"requiredlinking.ServerPlayNetworkHandlerMixin"
], ],
"injectors": { "injectors": {
"defaultRequire": 1 "defaultRequire": 1

View File

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