Skip to content

Commit

Permalink
Switch to local data management, add admin commands
Browse files Browse the repository at this point in the history
  • Loading branch information
Ale32bit committed Oct 16, 2024
1 parent 5176488 commit fcce433
Show file tree
Hide file tree
Showing 11 changed files with 343 additions and 72 deletions.
33 changes: 30 additions & 3 deletions src/main/java/cc/reconnected/chatbox/Chatbox.java
Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
package cc.reconnected.chatbox;

import cc.reconnected.chatbox.command.ChatboxCommand;
import cc.reconnected.chatbox.data.StateSaverAndLoader;
import cc.reconnected.chatbox.state.StateSaverAndLoader;
import com.google.gson.Gson;
import cc.reconnected.chatbox.license.LicenseManager;
import cc.reconnected.chatbox.ws.WsServer;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
import net.minecraft.util.WorldSavePath;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.nio.file.Path;

public class Chatbox implements ModInitializer {

public static final String MOD_ID = "rcc-chatbox";
public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID);
public static final cc.reconnected.chatbox.ChatboxConfig CONFIG = cc.reconnected.chatbox.ChatboxConfig.createAndLoad();
public static final Gson GSON = new Gson();
public static final LicenseManager LicenseManager = new LicenseManager();
private static LicenseManager licenseManager;

private static Chatbox INSTANCE;

Expand All @@ -31,6 +34,10 @@ public Chatbox() {

private WsServer wss;

public static LicenseManager licenseManager() {
return licenseManager;
}

public void wss(WsServer wss) {
this.wss = wss;
}
Expand All @@ -39,7 +46,14 @@ public WsServer wss() {
return wss;
}

private static Path dataDirectory;

public static Path dataDirectory() {
return dataDirectory;
}

private StateSaverAndLoader serverState;

public StateSaverAndLoader serverState() {
return serverState;
}
Expand All @@ -48,7 +62,20 @@ public StateSaverAndLoader serverState() {
public void onInitialize() {
CommandRegistrationCallback.EVENT.register(ChatboxCommand::register);

ServerLifecycleEvents.SERVER_STARTED.register(server -> serverState = StateSaverAndLoader.getServerState(server));
ServerLifecycleEvents.SERVER_STARTING.register(server -> {
dataDirectory = server.getSavePath(WorldSavePath.ROOT).resolve("data").resolve(MOD_ID);
licenseManager = new LicenseManager();
if (!dataDirectory.toFile().isDirectory()) {
if (!dataDirectory.toFile().mkdir()) {
LOGGER.error("Failed to create rcc-chatbox data directory");
}
}
});

ServerLifecycleEvents.SERVER_STARTED.register(server -> {
serverState = StateSaverAndLoader.getServerState(server);
});


ChatboxEvents.register();
}
Expand Down
5 changes: 1 addition & 4 deletions src/main/java/cc/reconnected/chatbox/ChatboxEvents.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import cc.reconnected.chatbox.api.events.ClientConnectionEvents;
import cc.reconnected.chatbox.api.events.PlayerCommandEvent;
import cc.reconnected.chatbox.data.StateSaverAndLoader;
import cc.reconnected.chatbox.state.StateSaverAndLoader;
import cc.reconnected.chatbox.license.Capability;
import cc.reconnected.chatbox.models.DiscordUser;
import cc.reconnected.chatbox.packets.serverPackets.HelloPacket;
Expand Down Expand Up @@ -69,9 +69,6 @@ public static void register() {
}
});

ClientConnectionEvents.DISCONNECT.register((conn, license, code, reason, remote) ->
Chatbox.LicenseManager.clearCache(license.uuid()));

ServerLifecycleEvents.SERVER_STARTING.register(server ->
mcServer = server);

Expand Down
214 changes: 214 additions & 0 deletions src/main/java/cc/reconnected/chatbox/command/AdminSubCommand.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
package cc.reconnected.chatbox.command;

import cc.reconnected.chatbox.Chatbox;
import cc.reconnected.chatbox.license.Capability;
import cc.reconnected.chatbox.license.License;
import cc.reconnected.chatbox.ws.CloseCodes;
import com.mojang.brigadier.Command;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.arguments.BoolArgumentType;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import me.lucko.fabric.api.permissions.v0.Permissions;
import net.kyori.adventure.text.Component;
import net.minecraft.command.CommandRegistryAccess;
import net.minecraft.command.CommandSource;
import net.minecraft.command.argument.GameProfileArgumentType;
import net.minecraft.server.PlayerManager;
import net.minecraft.server.command.CommandManager;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Style;
import net.minecraft.text.Text;
import net.minecraft.util.Formatting;
import org.jetbrains.annotations.Nullable;

import java.util.*;

import static cc.reconnected.chatbox.command.ChatboxCommand.prefix;
import static net.minecraft.server.command.CommandManager.*;

public class AdminSubCommand {
private static @Nullable License getLicenseFromArgument(String id, PlayerManager playerManager) {
UUID uuid;
try {
uuid = UUID.fromString(id);

} catch (IllegalArgumentException e) {
var player = playerManager.getPlayer(id);
if (player == null) {
return null;
}
uuid = player.getGameProfile().getId();
}

var license = Chatbox.licenseManager().getLicense(uuid);
if (license == null) {
license = Chatbox.licenseManager().getLicenseFromUser(uuid);
}

return license;
}

public static LiteralArgumentBuilder<ServerCommandSource> register(CommandDispatcher<ServerCommandSource> dispatcher, CommandRegistryAccess registryAccess, CommandManager.RegistrationEnvironment environment) {
return literal("admin")
.requires(Permissions.require("chatbox.admin", 3))
.executes(context -> {
var commands = new String[]{
"<user/license>",
"<user/license> revoke",
//"<user/license> disable",
//"<user/license> enable",
"<user/license> capabilities",
"<user/license> capabilities enable <capability>",
"<user/license> capabilities disable <capability>",
};

final var text =
Text.empty()
.append(prefix)
.append("Chatbox admin commands:")
.append(ChatboxCommand.buildHelpMessage("chatbox admin", commands));

context.getSource().sendFeedback(() -> text, false);
return 1;
})
.then(argument("user/license", StringArgumentType.string())
.suggests((context, builder) -> {
var playerManager = context.getSource().getServer().getPlayerManager();
var list = new ArrayList<String>();
list.addAll(playerManager.getPlayerList()
.stream()
.map(player -> player.getGameProfile().getName())
.toList());
list.addAll(Chatbox.licenseManager().getLicenseList());
return CommandSource.suggestMatching(
list,
builder
);
})
.executes(context -> {
var id = StringArgumentType.getString(context, "user/license");
var playerManager = context.getSource().getServer().getPlayerManager();

var license = getLicenseFromArgument(id, playerManager);
if (license == null) {
context.getSource().sendFeedback(() -> Text.empty().append(prefix).append(Text.literal("Player or license not found").setStyle(Style.EMPTY.withColor(Formatting.RED))), false);
return 1;
}

String playerName = license.userId().toString();

ServerPlayerEntity player = playerManager.getPlayer(license.userId());
if (player == null) {
player = playerManager.getPlayer(license.userId());
}
if (player != null) {
playerName = player.getGameProfile().getName();
}

var text = Text.empty()
.append(prefix)
.append(Text.literal("This license belongs to ")
.append(Text.literal(playerName)));

context.getSource().sendFeedback(() -> text, false);

return 1;
})
.then(literal("revoke")
.executes(context -> {
var id = StringArgumentType.getString(context, "user/license");
var playerManager = context.getSource().getServer().getPlayerManager();
var license = getLicenseFromArgument(id, playerManager);
if (license == null) {
context.getSource().sendFeedback(() -> Text.empty().append(prefix).append(Text.literal("Player or license not found").setStyle(Style.EMPTY.withColor(Formatting.RED))), false);
return 1;
}

String playerName = license.userId().toString();
ServerPlayerEntity player = playerManager.getPlayer(license.userId());
if (player == null) {
player = playerManager.getPlayer(license.userId());
}
if (player != null) {
playerName = player.getGameProfile().getName();
}

Chatbox.licenseManager().deleteLicense(license.uuid());
Chatbox.getInstance().wss().closeLicenseClients(license.uuid(), CloseCodes.CHANGED_LICENSE_KEY);

final var finalPlayerName = playerName;
context.getSource().sendFeedback(() -> Text.empty().append(prefix).append(Text.literal("Revoked " + finalPlayerName + " license!").setStyle(Style.EMPTY.withColor(Formatting.GREEN))), true);

return 1;
})
)
.then(literal("capabilities")
.executes(context -> {
var id = StringArgumentType.getString(context, "user/license");
var playerManager = context.getSource().getServer().getPlayerManager();
var license = getLicenseFromArgument(id, playerManager);
if (license == null) {
context.getSource().sendFeedback(() -> Text.empty().append(prefix).append(Text.literal("Player or license not found").setStyle(Style.EMPTY.withColor(Formatting.RED))), false);
return 1;
}

var text = Text.empty().append(prefix).append("License capabilities: ");
license.capabilities().forEach(c -> {
text.append(Text.of(c.name())).append(Text.of(";"));
});
context.getSource().sendFeedback(() -> text, false);
return 1;
})
.then(argument("capability", StringArgumentType.word())
.suggests((context, builder) ->
CommandSource.suggestMatching(Arrays.stream(Capability.values()).map(Enum::name), builder)
)
.then(argument("toggle", BoolArgumentType.bool())
.executes(context -> {
var capabilityName = StringArgumentType.getString(context, "capability");
var toggle = BoolArgumentType.getBool(context, "toggle");
var id = StringArgumentType.getString(context, "user/license");
var playerManager = context.getSource().getServer().getPlayerManager();
var license = getLicenseFromArgument(id, playerManager);
if (license == null) {
context.getSource().sendFeedback(() -> Text.empty().append(prefix).append(Text.literal("Player or license not found").setStyle(Style.EMPTY.withColor(Formatting.RED))), false);
return 1;
}

String playerName = license.userId().toString();
ServerPlayerEntity player = playerManager.getPlayer(license.userId());
if (player == null) {
player = playerManager.getPlayer(license.userId());
}
if (player != null) {
playerName = player.getGameProfile().getName();
}

var licenseManager = Chatbox.licenseManager();

var capability = Capability.valueOf(capabilityName);

Text text;
var capabilities = new HashSet<>(license.capabilities());
if (toggle) {
capabilities.add(capability);
text = Text.literal("Granted '" + capability + "' to " + playerName).setStyle(Style.EMPTY.withColor(Formatting.GREEN));
} else {
capabilities.remove(capability);
text = Text.literal("Revoked '" + capability + "' from " + playerName).setStyle(Style.EMPTY.withColor(Formatting.RED));
}
// save to file
licenseManager.updateLicense(license.uuid(), capabilities);

final var finalText = Text.empty().append(prefix).append(text);
context.getSource().sendFeedback(() -> finalText, true);

return 1;
})))
)

);
}
}
39 changes: 23 additions & 16 deletions src/main/java/cc/reconnected/chatbox/command/ChatboxCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,21 @@ public class ChatboxCommand {
.append(Text.literal("]").setStyle(Style.EMPTY.withColor(Formatting.GRAY)))
.append(" ");

public static MutableText buildHelpMessage(String base, String[] subs) {
var text = Text.empty();
for (var command : subs) {
text = text.append(Text.of("\n - "))
.append(Text.literal("/" + base + " " + command)
.setStyle(Style.EMPTY.withColor(Formatting.BLUE).withUnderline(true)
.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Text.of("Click to suggest command")))
.withClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, "/" + base + " " + command))
)
);
}

return text;
}

public static void register(CommandDispatcher<ServerCommandSource> dispatcher,
CommandRegistryAccess registryAccess,
CommandManager.RegistrationEnvironment environment) {
Expand All @@ -30,26 +45,18 @@ public static void register(CommandDispatcher<ServerCommandSource> dispatcher,
"spy"
};

var text = Text.empty()
final var text = Text.empty()
.append(prefix)
.append("Manage your Chatbox license:");

for (var command : commands) {
text = text.append(Text.of("\n - "))
.append(Text.literal("/chatbox " + command)
.setStyle(Style.EMPTY.withColor(Formatting.BLUE).withUnderline(true)
.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Text.of("Click to suggest command")))
.withClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, "/chatbox " + command))
)
);
}

final var finalText = text;
context.getSource().sendFeedback(() -> finalText, false);
.append("Manage your Chatbox license:")
.append(buildHelpMessage("chatbox", commands));


context.getSource().sendFeedback(() -> text, false);
return 1;
})
.then(LicenseSubCommand.register(dispatcher, registryAccess, environment))
.then(SpySubCommand.register(dispatcher, registryAccess, environment));
.then(SpySubCommand.register(dispatcher, registryAccess, environment))
.then(AdminSubCommand.register(dispatcher, registryAccess, environment));

dispatcher.register(rootCommand);
}
Expand Down
Loading

0 comments on commit fcce433

Please sign in to comment.