- [FEAT] New APIs for Maintenance Mode and rewrite commands system

- [FEAT] Improved config system to fix old loading bugs and support JSON
- [FEAT] LuckPerms support for commands
This commit is contained in:
2024-08-10 15:17:10 +02:00
parent e14ac2a136
commit 614fb0bc49
352 changed files with 6045 additions and 1798 deletions

View File

@@ -0,0 +1,77 @@
--- a/Common/src/main/java/com/hypherionmc/craterlib/api/commands/CraterCommand.java
+++ b/Common/src/main/java/com/hypherionmc/craterlib/api/commands/CraterCommand.java
@@ -14,6 +14,7 @@
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.Commands;
import net.minecraft.commands.arguments.GameProfileArgument;
+import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Player;
import org.jetbrains.annotations.ApiStatus;
@@ -53,7 +54,7 @@
public CraterCommand withGameProfilesArgument(String key, CommandExecutorWithArgs<List<BridgedGameProfile>> executor) {
this.mojangCommand.then(Commands.argument(key, GameProfileArgument.gameProfile())
.executes(context -> executor.run(
- BridgedPlayer.of(context.getSource().getPlayer()),
+ BridgedPlayer.of(context.getSource().getPlayerOrException()),
GameProfileArgument.getGameProfiles(context, key).stream().map(BridgedGameProfile::of).toList(),
BridgedCommandSourceStack.of(context.getSource()))
));
@@ -63,7 +64,7 @@
public CraterCommand withBoolArgument(String key, CommandExecutorWithArgs<Boolean> executor) {
this.mojangCommand.then(Commands.argument(key, BoolArgumentType.bool())
.executes(context -> executor.run(
- BridgedPlayer.of(context.getSource().getPlayer()),
+ BridgedPlayer.of(context.getSource().getPlayerOrException()),
BoolArgumentType.getBool(context, key),
BridgedCommandSourceStack.of(context.getSource())
)));
@@ -73,7 +74,7 @@
public CraterCommand withWordArgument(String key, CommandExecutorWithArgs<String> executor) {
this.mojangCommand.then(Commands.argument(key, StringArgumentType.word())
.executes(context -> executor.run(
- BridgedPlayer.of(context.getSource().getPlayer()),
+ BridgedPlayer.of(context.getSource().getPlayerOrException()),
StringArgumentType.getString(context, key),
BridgedCommandSourceStack.of(context.getSource())
)));
@@ -83,7 +84,7 @@
public CraterCommand withStringArgument(String key, CommandExecutorWithArgs<String> executor) {
this.mojangCommand.then(Commands.argument(key, StringArgumentType.string())
.executes(context -> executor.run(
- BridgedPlayer.of(context.getSource().getPlayer()),
+ BridgedPlayer.of(context.getSource().getPlayerOrException()),
StringArgumentType.getString(context, key),
BridgedCommandSourceStack.of(context.getSource())
)));
@@ -93,7 +94,7 @@
public CraterCommand withPhraseArgument(String key, CommandExecutorWithArgs<String> executor) {
this.mojangCommand.then(Commands.argument(key, StringArgumentType.greedyString())
.executes(context -> executor.run(
- BridgedPlayer.of(context.getSource().getPlayer()),
+ BridgedPlayer.of(context.getSource().getPlayerOrException()),
StringArgumentType.getString(context, key),
BridgedCommandSourceStack.of(context.getSource())
)));
@@ -103,7 +104,7 @@
public CraterCommand withIntegerArgument(String key, CommandExecutorWithArgs<Integer> executor) {
this.mojangCommand.then(Commands.argument(key, IntegerArgumentType.integer())
.executes(context -> executor.run(
- BridgedPlayer.of(context.getSource().getPlayer()),
+ BridgedPlayer.of(context.getSource().getPlayerOrException()),
IntegerArgumentType.getInteger(context, key),
BridgedCommandSourceStack.of(context.getSource())
)));
@@ -137,10 +138,10 @@
}
private boolean checkPermission(CommandSourceStack stack) {
- if (!ModloaderEnvironment.INSTANCE.isModLoaded("luckperms") || !stack.isPlayer() || luckPermNode.isEmpty())
+ if (!ModloaderEnvironment.INSTANCE.isModLoaded("luckperms") || !(stack.getEntity() instanceof Player) || luckPermNode.isEmpty())
return stack.hasPermission(this.permLevel);
- return LuckPermsCompat.INSTANCE.hasPermission(stack.getPlayer(), this.luckPermNode) || stack.hasPermission(this.permLevel);
+ return LuckPermsCompat.INSTANCE.hasPermission((ServerPlayer) stack.getEntity(), this.luckPermNode) || stack.hasPermission(this.permLevel);
}
@FunctionalInterface

View File

@@ -26,7 +26,7 @@
@@ -49,7 +50,7 @@
private boolean dragging;
public CraterConfigScreen(ModuleConfig config, Screen parent, Object subConfig) {
public CraterConfigScreen(AbstractConfig config, Screen parent, Object subConfig) {
- super(Component.translatable("cl." + config.getClass().getSimpleName().toLowerCase() + ".title"));
+ super(new TranslatableComponent("cl." + config.getClass().getSimpleName().toLowerCase() + ".title"));
this.parent = parent;

View File

@@ -3,7 +3,7 @@
@@ -2,12 +2,12 @@
import com.hypherionmc.craterlib.client.gui.config.CraterConfigScreen;
import com.hypherionmc.craterlib.core.config.ModuleConfig;
import com.hypherionmc.craterlib.core.config.AbstractConfig;
+import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Font;

View File

@@ -0,0 +1,20 @@
--- a/Common/src/main/java/com/hypherionmc/craterlib/mixin/events/ServerStatusMixin.java
+++ b/Common/src/main/java/com/hypherionmc/craterlib/mixin/events/ServerStatusMixin.java
@@ -14,13 +14,13 @@
@Mixin(ServerStatus.class)
public class ServerStatusMixin {
- @Inject(method = "favicon", at = @At("RETURN"), cancellable = true)
- private void injectIconEvent(CallbackInfoReturnable<Optional<ServerStatus.Favicon>> cir) {
- ServerStatusEvent.FaviconRequestEvent event = new ServerStatusEvent.FaviconRequestEvent(cir.getReturnValue().isEmpty() ? Optional.empty() : Optional.of(new WrappedServerStatus.WrappedFavicon(cir.getReturnValue().get())));
+ @Inject(method = "getFavicon", at = @At("RETURN"), cancellable = true)
+ private void injectIconEvent(CallbackInfoReturnable<String> cir) {
+ ServerStatusEvent.FaviconRequestEvent event = new ServerStatusEvent.FaviconRequestEvent(cir.getReturnValue().isEmpty() ? Optional.empty() : Optional.of(new WrappedServerStatus.WrappedFavicon(cir.getReturnValue())));
CraterEventBus.INSTANCE.postEvent(event);
if (event.getNewIcon().isPresent()) {
- cir.setReturnValue(Optional.of(event.getNewIcon().get().toMojang()));
+ cir.setReturnValue(event.getNewIcon().get().toMojang());
}
}

View File

@@ -0,0 +1,49 @@
--- /dev/null
+++ b/Common/src/main/java/com/hypherionmc/craterlib/mixin/events/ServerStatusPacketListenerMixin.java
@@ -1,0 +1,46 @@
+package com.hypherionmc.craterlib.mixin.events;
+
+import com.hypherionmc.craterlib.api.events.server.ServerStatusEvent;
+import com.hypherionmc.craterlib.core.event.CraterEventBus;
+import com.hypherionmc.craterlib.utils.ChatUtils;
+import net.minecraft.network.Connection;
+import net.minecraft.network.protocol.status.ClientboundStatusResponsePacket;
+import net.minecraft.network.protocol.status.ServerStatus;
+import net.minecraft.network.protocol.status.ServerboundStatusRequestPacket;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.server.network.ServerStatusPacketListenerImpl;
+import org.spongepowered.asm.mixin.Final;
+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(ServerStatusPacketListenerImpl.class)
+public class ServerStatusPacketListenerMixin {
+
+ @Shadow @Final private Connection connection;
+
+ @Shadow @Final private MinecraftServer server;
+
+ @Inject(method = "handleStatusRequest",
+ at = @At(
+ value = "INVOKE",
+ target = "Lnet/minecraft/network/Connection;send(Lnet/minecraft/network/protocol/Packet;)V",
+ shift = At.Shift.BEFORE),
+ cancellable = true
+ )
+ private void injectHandleStatusRequest(ServerboundStatusRequestPacket arg, CallbackInfo ci) {
+ ServerStatusEvent.StatusRequestEvent event = new ServerStatusEvent.StatusRequestEvent(ChatUtils.mojangToAdventure(server.getStatus().getDescription()));
+ CraterEventBus.INSTANCE.postEvent(event);
+
+ if (event.getNewStatus() != null) {
+ ci.cancel();
+ ServerStatus serverStatus = this.server.getStatus();
+ serverStatus.setDescription(ChatUtils.adventureToMojang(event.getNewStatus()));
+
+ this.connection.send(new ClientboundStatusResponsePacket(serverStatus));
+ }
+ }
+
+}

View File

@@ -8,4 +8,4 @@
+ internal.sendSuccess(ChatUtils.adventureToMojang(supplier.get()), bl);
}
public CommandSourceStack toMojang() {
public void sendFailure(Component text) {

View File

@@ -1,11 +0,0 @@
--- a/Common/src/main/java/com/hypherionmc/craterlib/nojang/commands/CommandsRegistry.java
+++ b/Common/src/main/java/com/hypherionmc/craterlib/nojang/commands/CommandsRegistry.java
@@ -70,7 +70,7 @@
profiles.forEach(p -> bridgedGameProfiles.add(BridgedGameProfile.of(p)));
((TriConsumer<BridgedPlayer, List<BridgedGameProfile>, BridgedCommandSourceStack>) pair.getRight())
- .accept(BridgedPlayer.of(context.getSource().getPlayer()), bridgedGameProfiles, BridgedCommandSourceStack.of(context.getSource()));
+ .accept(BridgedPlayer.of(context.getSource().getPlayerOrException()), bridgedGameProfiles, BridgedCommandSourceStack.of(context.getSource()));
return 1;
}

View File

@@ -0,0 +1,48 @@
--- a/Common/src/main/java/com/hypherionmc/craterlib/nojang/network/protocol/status/WrappedServerStatus.java
+++ b/Common/src/main/java/com/hypherionmc/craterlib/nojang/network/protocol/status/WrappedServerStatus.java
@@ -1,28 +1,39 @@
package com.hypherionmc.craterlib.nojang.network.protocol.status;
-import net.minecraft.network.protocol.status.ServerStatus;
import org.jetbrains.annotations.ApiStatus;
+import java.nio.charset.StandardCharsets;
+import java.util.Base64;
+
public final class WrappedServerStatus {
public static final class WrappedFavicon {
- private final ServerStatus.Favicon internal;
+ private final String internal;
+ private final byte[] iconBytes;
public WrappedFavicon(byte[] iconBytes) {
- internal = new ServerStatus.Favicon(iconBytes);
+ this.iconBytes = iconBytes;
+
+ if (iconBytes != null) {
+ byte[] encoded = Base64.getEncoder().encode(iconBytes);
+ internal = "data:image/png;base64," + new String(encoded, StandardCharsets.UTF_8);
+ } else {
+ internal = null;
+ }
}
@ApiStatus.Internal
- public WrappedFavicon(ServerStatus.Favicon internal) {
+ public WrappedFavicon(String internal) {
this.internal = internal;
+ this.iconBytes = new byte[0];
}
public byte[] iconBytes() {
- return internal.iconBytes();
+ return iconBytes;
}
- public ServerStatus.Favicon toMojang() {
+ public String toMojang() {
return internal;
}

View File

@@ -73,4 +73,4 @@
+ return mojangToAdventure(new TranslatableComponent(Util.makeDescriptionId("biome", identifier.toMojang())));
}
}
public static net.kyori.adventure.text.Component format(String value) {

View File

@@ -0,0 +1,12 @@
--- a/Common/src/main/resources/craterlib.mixins.json
+++ b/Common/src/main/resources/craterlib.mixins.json
@@ -17,7 +17,8 @@
"events.PlayerAdvancementsMixin",
"events.PlayerListMixin",
"events.ServerPlayerMixin",
- "events.ServerStatusMixin"
+ "events.ServerStatusMixin",
+ "events.ServerStatusPacketListenerMixin"
],
"injectors": {
"defaultRequire": 1