diff --git a/src/client/java/com/padbro/greeterbro/client/GreeterBroClient.java b/src/client/java/com/padbro/greeterbro/client/GreeterBroClient.java index 0d72c3a..8069fd5 100644 --- a/src/client/java/com/padbro/greeterbro/client/GreeterBroClient.java +++ b/src/client/java/com/padbro/greeterbro/client/GreeterBroClient.java @@ -5,48 +5,58 @@ import com.padbro.greeterbro.client.managers.AfkManager; import com.padbro.greeterbro.client.managers.MigrationManager; import com.padbro.greeterbro.client.managers.TickManager; +import com.padbro.greeterbro.config.GreeterBroServerConfig; +import com.padbro.greeterbro.records.ConfigS2CPayload; import me.shedaniel.autoconfig.AutoConfig; import me.shedaniel.autoconfig.ConfigHolder; import me.shedaniel.autoconfig.serializer.Toml4jConfigSerializer; import net.fabricmc.api.ClientModInitializer; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents; +import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; public class GreeterBroClient implements ClientModInitializer { - - private static ConfigHolder config; - private static JoinCache joinCache; - public static boolean isJoining = false; - public static final String MOD_ID = "GreeterBro"; - public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID); - - public static GreeterBroConfig getConfig() { - config.save(); - return config.get(); - } - - public static JoinCache getJoinCache() { - return joinCache; - } - - public static void saveConfig() { - config.save(); - } - - @Override - public void onInitializeClient() { - config = AutoConfig.register(GreeterBroConfig.class, Toml4jConfigSerializer::new); - MigrationManager.migrate(); - - joinCache = JoinCache.loadCache(); - - ClientTickEvents.END_CLIENT_TICK.register( - client -> { - TickManager.onTick(); - AfkManager.onTick(); + public static boolean isJoining = false; + public static GreeterBroServerConfig serverConfig; + private static ConfigHolder config; + private static JoinCache joinCache; + + public static GreeterBroConfig getConfig() { + config.save(); + return config.get(); + } + + public static JoinCache getJoinCache() { + return joinCache; + } + + public static void saveConfig() { + config.save(); + } + + @Override + public void onInitializeClient() { + config = AutoConfig.register(GreeterBroConfig.class, Toml4jConfigSerializer::new); + MigrationManager.migrate(); + + joinCache = JoinCache.loadCache(); + + ClientTickEvents.END_CLIENT_TICK.register( + client -> { + TickManager.onTick(); + AfkManager.onTick(); + }); + + ClientPlayConnectionEvents.DISCONNECT.register((handler, client) -> { + serverConfig = null; }); - CommandManager.register(); - } + CommandManager.register(); + + ClientPlayNetworking.registerGlobalReceiver( + ConfigS2CPayload.ID, + (payload, context) -> { + serverConfig = payload.config(); + }); + } } diff --git a/src/client/java/com/padbro/greeterbro/client/JoinCache.java b/src/client/java/com/padbro/greeterbro/client/JoinCache.java index 2d2756b..35265ca 100644 --- a/src/client/java/com/padbro/greeterbro/client/JoinCache.java +++ b/src/client/java/com/padbro/greeterbro/client/JoinCache.java @@ -4,8 +4,10 @@ import com.google.gson.GsonBuilder; import com.google.gson.JsonSyntaxException; import com.google.gson.reflect.TypeToken; +import com.padbro.greeterbro.GreeterBro; import com.padbro.greeterbro.client.config.CacheClearType; import com.padbro.greeterbro.client.config.ReturningPlayerConfig; + import java.io.File; import java.io.FileReader; import java.io.FileWriter; @@ -19,121 +21,122 @@ import java.util.Optional; public class JoinCache { - private static final Gson gson = new GsonBuilder().setPrettyPrinting().create(); - private ArrayList joins; - private String date; - private static final File file = new File("join_cache.json"); - - public static JoinCache loadCache() { - String currentDate = getCurrentDate(); - if (!file.exists()) { - return new JoinCache(currentDate, new ArrayList<>()); + private static final Gson gson = new GsonBuilder().setPrettyPrinting().create(); + private static final File file = new File("join_cache.json"); + private ArrayList joins; + private String date; + + public JoinCache(String date, ArrayList joins) { + this.joins = joins; + this.date = date; } - try (FileReader reader = new FileReader(file)) { - JoinCache joinCache = gson.fromJson(reader, new TypeToken<>() {}); - ReturningPlayerConfig config = GreeterBroClient.getConfig().returningPlayerConfig; - - // Don`t clear the cache if cacheClearType is Never - // Clear the cache if it`s a new day or if cacheClearType is OnNewSession - if (config.cacheClearType != CacheClearType.Never - && (!Objects.equals(joinCache.date, currentDate) - || config.cacheClearType == CacheClearType.OnNewSession)) { - joinCache.joins = new ArrayList<>(); - joinCache.date = currentDate; - writeToFile(joinCache); - } - return joinCache; - } catch (JsonSyntaxException exception) { - return new JoinCache("", new ArrayList<>()); - } catch (Exception exception) { - throw new RuntimeException( - "Cannot load player cache (%s)".formatted(file.getAbsolutePath()), exception); + + public static JoinCache loadCache() { + String currentDate = getCurrentDate(); + if (!file.exists()) { + return new JoinCache(currentDate, new ArrayList<>()); + } + try (FileReader reader = new FileReader(file)) { + JoinCache joinCache = gson.fromJson(reader, new TypeToken<>() { + }); + ReturningPlayerConfig config = GreeterBroClient.getConfig().returningPlayerConfig; + + // Don`t clear the cache if cacheClearType is Never + // Clear the cache if it`s a new day or if cacheClearType is OnNewSession + if (config.cacheClearType != CacheClearType.Never + && (!Objects.equals(joinCache.date, currentDate) + || config.cacheClearType == CacheClearType.OnNewSession)) { + joinCache.joins = new ArrayList<>(); + joinCache.date = currentDate; + writeToFile(joinCache); + } + return joinCache; + } catch (JsonSyntaxException exception) { + return new JoinCache("", new ArrayList<>()); + } catch (Exception exception) { + throw new RuntimeException( + "Cannot load player cache (%s)".formatted(file.getAbsolutePath()), exception); + } } - } - public JoinCache(String date, ArrayList joins) { - this.joins = joins; - this.date = date; - } + private static String getCurrentDate() { + return Instant.now() + .atZone(ZoneId.systemDefault()) + .toLocalDate() + .format(DateTimeFormatter.ISO_LOCAL_DATE); + } - public void add(String player) { - Optional playerCacheEntry = getPlayerCacheEntry(player); + private static void writeToFile(JoinCache joinCache) { + try (FileWriter writer = new FileWriter(file)) { + gson.toJson(joinCache, writer); + } catch (IOException e) { + GreeterBro.LOGGER.warn("Failed to save cache data to file"); + } + } - if (playerCacheEntry.isEmpty()) { - this.joins.add(new PlayerCacheEntry(player, Instant.now())); - } else { - playerCacheEntry.get().setJoinedAt(Instant.now()); + public void add(String player) { + Optional playerCacheEntry = getPlayerCacheEntry(player); + + if (playerCacheEntry.isEmpty()) { + this.joins.add(new PlayerCacheEntry(player, Instant.now())); + } else { + playerCacheEntry.get().setJoinedAt(Instant.now()); + } + writeToFile(this); } - writeToFile(this); - } - public boolean hasRecentlyJoined(String player) { - Optional playerCacheEntry = this.getPlayerCacheEntry(player); - if (playerCacheEntry.isEmpty()) { - return false; + public boolean hasRecentlyJoined(String player) { + Optional playerCacheEntry = this.getPlayerCacheEntry(player); + if (playerCacheEntry.isEmpty()) { + return false; + } + + Instant joinedAt = playerCacheEntry.get().getJoinedAt(); + + return joinedAt.isAfter( + Instant.now() + .minus( + GreeterBroClient.getConfig().returningPlayerConfig.ignoreForMin, + ChronoUnit.MINUTES)); } - Instant joinedAt = playerCacheEntry.get().getJoinedAt(); - - return joinedAt.isAfter( - Instant.now() - .minus( - GreeterBroClient.getConfig().returningPlayerConfig.ignoreForMin, - ChronoUnit.MINUTES)); - } - - public boolean hasJoined(String player) { - return this.getPlayerCacheEntry(player).isPresent(); - } - - public void clear() { - joins = new ArrayList<>(); - writeToFile(this); - } - - private static String getCurrentDate() { - return Instant.now() - .atZone(ZoneId.systemDefault()) - .toLocalDate() - .format(DateTimeFormatter.ISO_LOCAL_DATE); - } - - private Optional getPlayerCacheEntry(String player) { - return this.joins.stream() - .filter(playerCacheEntry -> player.equals(playerCacheEntry.name)) - .findFirst(); - } - - private static void writeToFile(JoinCache joinCache) { - try (FileWriter writer = new FileWriter(file)) { - gson.toJson(joinCache, writer); - } catch (IOException e) { - GreeterBroClient.LOGGER.warn("Failed to save cache data to file"); + public boolean hasJoined(String player) { + return this.getPlayerCacheEntry(player).isPresent(); } - } - - public boolean shouldClearOnJoin() { - ReturningPlayerConfig config = GreeterBroClient.getConfig().returningPlayerConfig; - return config.cacheClearType == CacheClearType.OnJoin || - (config.cacheClearType == CacheClearType.OnNewDay && - !Objects.equals(this.date, getCurrentDate())); - } - - public static class PlayerCacheEntry { - private final String name; - private long joinedAt; - - public PlayerCacheEntry(String name, Instant joinedAt) { - this.name = name; - this.joinedAt = joinedAt.toEpochMilli(); + + public void clear() { + joins = new ArrayList<>(); + writeToFile(this); + } + + private Optional getPlayerCacheEntry(String player) { + return this.joins.stream() + .filter(playerCacheEntry -> player.equals(playerCacheEntry.name)) + .findFirst(); } - public Instant getJoinedAt() { - return Instant.ofEpochMilli(joinedAt); + public boolean shouldClearOnJoin() { + ReturningPlayerConfig config = GreeterBroClient.getConfig().returningPlayerConfig; + return config.cacheClearType == CacheClearType.OnJoin || + (config.cacheClearType == CacheClearType.OnNewDay && + !Objects.equals(this.date, getCurrentDate())); } - public void setJoinedAt(Instant instant) { - this.joinedAt = instant.toEpochMilli(); + public static class PlayerCacheEntry { + private final String name; + private long joinedAt; + + public PlayerCacheEntry(String name, Instant joinedAt) { + this.name = name; + this.joinedAt = joinedAt.toEpochMilli(); + } + + public Instant getJoinedAt() { + return Instant.ofEpochMilli(joinedAt); + } + + public void setJoinedAt(Instant instant) { + this.joinedAt = instant.toEpochMilli(); + } } - } } diff --git a/src/client/java/com/padbro/greeterbro/client/commands/BlacklistCommand.java b/src/client/java/com/padbro/greeterbro/client/commands/BlacklistCommand.java index d9523e7..167bb98 100644 --- a/src/client/java/com/padbro/greeterbro/client/commands/BlacklistCommand.java +++ b/src/client/java/com/padbro/greeterbro/client/commands/BlacklistCommand.java @@ -1,10 +1,5 @@ package com.padbro.greeterbro.client.commands; -import static com.mojang.brigadier.arguments.StringArgumentType.getString; -import static com.mojang.brigadier.arguments.StringArgumentType.string; -import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.argument; -import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.literal; - import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.context.CommandContext; import com.padbro.greeterbro.client.GreeterBroClient; @@ -15,73 +10,78 @@ import net.minecraft.text.Text; import net.minecraft.util.Formatting; +import static com.mojang.brigadier.arguments.StringArgumentType.getString; +import static com.mojang.brigadier.arguments.StringArgumentType.string; +import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.argument; +import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.literal; + public class BlacklistCommand { - public static void register(LiteralArgumentBuilder root) { - root.then( - literal("blacklist") - .executes(BlacklistCommand::list) - .then( - literal("add") - .then( - argument("player", string()) - .suggests(new PlayerSuggestionProvider()) - .executes(BlacklistCommand::add))) - .then( - literal("remove") - .then( - argument("player", string()) - .suggests(new BlacklistSuggestionProvider()) - .executes(BlacklistCommand::remove)))); - } + public static void register(LiteralArgumentBuilder root) { + root.then( + literal("blacklist") + .executes(BlacklistCommand::list) + .then( + literal("add") + .then( + argument("player", string()) + .suggests(new PlayerSuggestionProvider()) + .executes(BlacklistCommand::add))) + .then( + literal("remove") + .then( + argument("player", string()) + .suggests(new BlacklistSuggestionProvider()) + .executes(BlacklistCommand::remove)))); + } - public static int list(CommandContext context) { - GreeterBroConfig config = GreeterBroClient.getConfig(); - FabricClientCommandSource source = context.getSource(); - String players = String.join(", ", config.blacklistConfig.players); + public static int list(CommandContext context) { + GreeterBroConfig config = GreeterBroClient.getConfig(); + FabricClientCommandSource source = context.getSource(); + String players = String.join(", ", config.blacklistConfig.getPlayers()); - source.sendFeedback( - Text.translatable( - "text.command.GreeterBro.blacklist.get.success", - config.blacklistConfig.players.size(), - players) - .formatted(Formatting.GRAY)); - return 0; - } + source.sendFeedback( + Text.translatable( + "text.command.GreeterBro.blacklist.get.success", + config.blacklistConfig.getPlayers().size(), + players) + .formatted(Formatting.GRAY)); + return 0; + } + + public static int add(CommandContext context) { + GreeterBroConfig config = GreeterBroClient.getConfig(); + FabricClientCommandSource source = context.getSource(); + String player = getString(context, "player"); + if (config.blacklistConfig.getPlayers().contains(player)) { - public static int add(CommandContext context) { - GreeterBroConfig config = GreeterBroClient.getConfig(); - FabricClientCommandSource source = context.getSource(); - String player = getString(context, "player"); - if (config.blacklistConfig.players.contains(player)) { + source.sendError(Text.translatable("text.command.GreeterBro.blacklist.add.error.exists")); + return 0; + } - source.sendError(Text.translatable("text.command.GreeterBro.blacklist.add.error.exists")); - return 0; + config.blacklistConfig.addPlayer(player); + GreeterBroClient.saveConfig(); + source.sendFeedback( + Text.translatable("text.command.GreeterBro.blacklist.add.success", player) + .formatted(Formatting.GRAY)); + return 0; } - config.blacklistConfig.players.add(player); - GreeterBroClient.saveConfig(); - source.sendFeedback( - Text.translatable("text.command.GreeterBro.blacklist.add.success", player) - .formatted(Formatting.GRAY)); - return 0; - } + public static int remove(CommandContext context) { + GreeterBroConfig config = GreeterBroClient.getConfig(); + FabricClientCommandSource source = context.getSource(); + String player = getString(context, "player"); - public static int remove(CommandContext context) { - GreeterBroConfig config = GreeterBroClient.getConfig(); - FabricClientCommandSource source = context.getSource(); - String player = getString(context, "player"); + if (!config.blacklistConfig.getPlayers().contains(player)) { + source.sendError(Text.translatable("text.command.GreeterBro.blacklist.remove.error.exists")); + return 0; + } - if (!config.blacklistConfig.players.contains(player)) { - source.sendError(Text.translatable("text.command.GreeterBro.blacklist.remove.error.exists")); - return 0; + config.blacklistConfig.removePlayer(player); + GreeterBroClient.saveConfig(); + source.sendFeedback( + Text.translatable("text.command.GreeterBro.blacklist.remove.success", player) + .formatted(Formatting.GRAY)); + return 0; } - - config.blacklistConfig.players.remove(player); - GreeterBroClient.saveConfig(); - source.sendFeedback( - Text.translatable("text.command.GreeterBro.blacklist.remove.success", player) - .formatted(Formatting.GRAY)); - return 0; - } } diff --git a/src/client/java/com/padbro/greeterbro/client/commands/CommandManager.java b/src/client/java/com/padbro/greeterbro/client/commands/CommandManager.java index 33bbdaf..a8c294d 100644 --- a/src/client/java/com/padbro/greeterbro/client/commands/CommandManager.java +++ b/src/client/java/com/padbro/greeterbro/client/commands/CommandManager.java @@ -1,30 +1,30 @@ package com.padbro.greeterbro.client.commands; -import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.literal; - import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.builder.LiteralArgumentBuilder; import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; import net.minecraft.command.CommandRegistryAccess; +import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.literal; + public class CommandManager { - private static final LiteralArgumentBuilder commandRoot = - literal("greeterBro"); + private static final LiteralArgumentBuilder commandRoot = + literal("greeterBro"); - public static void register() { - ClientCommandRegistrationCallback.EVENT.register(CommandManager::registerGreeterBro); - } + public static void register() { + ClientCommandRegistrationCallback.EVENT.register(CommandManager::registerGreeterBro); + } - private static void registerGreeterBro( - CommandDispatcher dispatcher, - CommandRegistryAccess registryAccess) { + private static void registerGreeterBro( + CommandDispatcher dispatcher, + CommandRegistryAccess registryAccess) { - BlacklistCommand.register(commandRoot); - EnableCommand.register(commandRoot); - DisableCommand.register(commandRoot); - AfkCommand.register(commandRoot); + BlacklistCommand.register(commandRoot); + EnableCommand.register(commandRoot); + DisableCommand.register(commandRoot); + AfkCommand.register(commandRoot); - dispatcher.register(commandRoot); - } + dispatcher.register(commandRoot); + } } diff --git a/src/client/java/com/padbro/greeterbro/client/commands/DisableCommand.java b/src/client/java/com/padbro/greeterbro/client/commands/DisableCommand.java index 7fd8cd7..aa3a72e 100644 --- a/src/client/java/com/padbro/greeterbro/client/commands/DisableCommand.java +++ b/src/client/java/com/padbro/greeterbro/client/commands/DisableCommand.java @@ -1,7 +1,5 @@ package com.padbro.greeterbro.client.commands; -import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.literal; - import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.context.CommandContext; import com.padbro.greeterbro.client.GreeterBroClient; @@ -10,25 +8,32 @@ import net.minecraft.text.Text; import net.minecraft.util.Formatting; +import static net.fabricmc.fabric.api.client.command.v2.ClientCommandManager.literal; + public class DisableCommand { - public static void register(LiteralArgumentBuilder root) { - root.then(literal("disable").executes(DisableCommand::disable)); - } + public static void register(LiteralArgumentBuilder root) { + root.then(literal("disable").executes(DisableCommand::disable)); + } - public static int disable(CommandContext context) { - GreeterBroConfig config = GreeterBroClient.getConfig(); - FabricClientCommandSource source = context.getSource(); + public static int disable(CommandContext context) { + GreeterBroConfig config = GreeterBroClient.getConfig(); + FabricClientCommandSource source = context.getSource(); - if (!config.generalConfig.enable) { - source.sendError(Text.translatable("text.command.GreeterBro.disable.error.disabled")); - return 0; - } + if (GreeterBroClient.serverConfig != null && GreeterBroClient.serverConfig.generalConfig.enabled == false) { + source.sendError(Text.translatable("text.command.GreeterBro.disable.error.server.disabled")); + return 0; + } - config.generalConfig.enable = false; - GreeterBroClient.saveConfig(); - source.sendFeedback( - Text.translatable("text.command.GreeterBro.disable.success").formatted(Formatting.GRAY)); + if (!config.generalConfig.getEnabled()) { + source.sendError(Text.translatable("text.command.GreeterBro.disable.error.disabled")); + return 0; + } - return 0; - } + config.generalConfig.setEnabled(false); + GreeterBroClient.saveConfig(); + source.sendFeedback( + Text.translatable("text.command.GreeterBro.disable.success").formatted(Formatting.GRAY)); + + return 0; + } } diff --git a/src/client/java/com/padbro/greeterbro/client/commands/EnableCommand.java b/src/client/java/com/padbro/greeterbro/client/commands/EnableCommand.java index d3b75de..5890c04 100644 --- a/src/client/java/com/padbro/greeterbro/client/commands/EnableCommand.java +++ b/src/client/java/com/padbro/greeterbro/client/commands/EnableCommand.java @@ -19,12 +19,17 @@ public static int enable(CommandContext context) { GreeterBroConfig config = GreeterBroClient.getConfig(); FabricClientCommandSource source = context.getSource(); - if (config.generalConfig.enable) { + if (GreeterBroClient.serverConfig != null && GreeterBroClient.serverConfig.generalConfig.enabled == false) { + source.sendError(Text.translatable("text.command.GreeterBro.enable.error.server.disabled")); + return 0; + } + + if (config.generalConfig.getEnabled()) { source.sendError(Text.translatable("text.command.GreeterBro.enable.error.enabled")); return 0; } - config.generalConfig.enable = true; + config.generalConfig.setEnabled(true); GreeterBroClient.saveConfig(); source.sendFeedback( Text.translatable("text.command.GreeterBro.enable.success").formatted(Formatting.GRAY)); diff --git a/src/client/java/com/padbro/greeterbro/client/commands/provider/BlacklistSuggestionProvider.java b/src/client/java/com/padbro/greeterbro/client/commands/provider/BlacklistSuggestionProvider.java index a7f7a97..1d000d4 100644 --- a/src/client/java/com/padbro/greeterbro/client/commands/provider/BlacklistSuggestionProvider.java +++ b/src/client/java/com/padbro/greeterbro/client/commands/provider/BlacklistSuggestionProvider.java @@ -15,7 +15,7 @@ public CompletableFuture getSuggestions( CommandContext context, SuggestionsBuilder builder) { String partialQuery = builder.getRemainingLowerCase(); - for (String player : GreeterBroClient.getConfig().blacklistConfig.players) { + for (String player : GreeterBroClient.getConfig().blacklistConfig.getPlayers()) { if (player.toLowerCase().startsWith(partialQuery)) { builder.suggest(player); } diff --git a/src/client/java/com/padbro/greeterbro/client/config/AfkConfig.java b/src/client/java/com/padbro/greeterbro/client/config/AfkConfig.java index f8a53fc..4fcbad9 100644 --- a/src/client/java/com/padbro/greeterbro/client/config/AfkConfig.java +++ b/src/client/java/com/padbro/greeterbro/client/config/AfkConfig.java @@ -1,19 +1,34 @@ package com.padbro.greeterbro.client.config; +import com.padbro.greeterbro.client.GreeterBroClient; import me.shedaniel.autoconfig.ConfigData; import me.shedaniel.autoconfig.annotation.Config; import me.shedaniel.autoconfig.annotation.ConfigEntry; @Config(name = "afk") public class AfkConfig implements ConfigData { - @ConfigEntry.Gui.Tooltip public boolean enable = true; + @ConfigEntry.Gui.Tooltip private boolean enable = true; - @ConfigEntry.Gui.Tooltip public int afkTime = 5; + @ConfigEntry.Gui.Tooltip private int afkTime = 5; @ConfigEntry.Gui.Tooltip @ConfigEntry.Gui.EnumHandler(option = ConfigEntry.Gui.EnumHandler.EnumDisplayOption.BUTTON) public AfkNotifyType notifyType = AfkNotifyType.Chat; + public boolean getEnabled() { + boolean enforceAfkMode = GreeterBroClient.serverConfig != null + ? GreeterBroClient.serverConfig.afkConfig.enforceAfkMode + : false; + return enforceAfkMode || this.enable; + } + + public int getAfkTime() { + if (GreeterBroClient.serverConfig != null && GreeterBroClient.serverConfig.afkConfig.afkTime != -1) { + return GreeterBroClient.serverConfig.afkConfig.afkTime; + } + return this.afkTime; + } + @Override public void validatePostLoad() { if (this.afkTime < 0) { diff --git a/src/client/java/com/padbro/greeterbro/client/config/BlacklistConfig.java b/src/client/java/com/padbro/greeterbro/client/config/BlacklistConfig.java index 15f977b..b1b8c6e 100644 --- a/src/client/java/com/padbro/greeterbro/client/config/BlacklistConfig.java +++ b/src/client/java/com/padbro/greeterbro/client/config/BlacklistConfig.java @@ -1,17 +1,48 @@ package com.padbro.greeterbro.client.config; +import com.padbro.greeterbro.client.GreeterBroClient; +import me.shedaniel.autoconfig.ConfigData; +import me.shedaniel.autoconfig.annotation.Config; + import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; -import me.shedaniel.autoconfig.ConfigData; -import me.shedaniel.autoconfig.annotation.Config; +import java.util.stream.Stream; @Config(name = "blacklist") public class BlacklistConfig implements ConfigData { - public List players = new ArrayList<>(); + private List players = new ArrayList<>(); + + public List getAllPlayers() { + return Stream.concat(getPlayers().stream(), getServerPlayers().stream()).toList(); + } + + public List getPlayers() { + return players; + } + + public void setPlayers(List players) { + this.players = players; + } + + public void removePlayer(String name) { + this.players.remove(name); + } + + public void addPlayer(String name) { + this.players.add(name); + } + + public List getServerPlayers() { + if (GreeterBroClient.serverConfig != null) { + return GreeterBroClient.serverConfig.blacklistConfig.players; + } + + return List.of(); + } - @Override - public void validatePostLoad() { - this.players = players.stream().filter(s -> !s.trim().isEmpty()).collect(Collectors.toList()); - } + @Override + public void validatePostLoad() { + this.players = players.stream().filter(s -> !s.trim().isEmpty()).collect(Collectors.toList()); + } } diff --git a/src/client/java/com/padbro/greeterbro/client/config/FirstJoinConfig.java b/src/client/java/com/padbro/greeterbro/client/config/FirstJoinConfig.java index c3d755e..d86ab72 100644 --- a/src/client/java/com/padbro/greeterbro/client/config/FirstJoinConfig.java +++ b/src/client/java/com/padbro/greeterbro/client/config/FirstJoinConfig.java @@ -1,26 +1,35 @@ package com.padbro.greeterbro.client.config; -import java.util.List; -import java.util.stream.Collectors; - +import com.padbro.greeterbro.client.GreeterBroClient; import me.shedaniel.autoconfig.ConfigData; import me.shedaniel.autoconfig.annotation.Config; import me.shedaniel.autoconfig.annotation.ConfigEntry; +import java.util.List; +import java.util.stream.Collectors; + @Config(name = "firstJoin") public class FirstJoinConfig implements ConfigData { - public boolean enable = true; - - @ConfigEntry.Gui.Tooltip public String customMessage = ""; + public boolean enable = true; - @ConfigEntry.BoundedDiscrete(max = 100) - @ConfigEntry.Gui.Tooltip public int greetingChance = 100; + @ConfigEntry.Gui.Tooltip + public String customMessage = ""; + @ConfigEntry.Gui.Tooltip + public List greetings = List.of("Welcome"); + @ConfigEntry.BoundedDiscrete(max = 100) + @ConfigEntry.Gui.Tooltip + private int greetingChance = 100; - @ConfigEntry.Gui.Tooltip public List greetings = List.of("Welcome"); + @Override + public void validatePostLoad() { + this.greetings = + greetings.stream().filter(s -> !s.trim().isEmpty()).collect(Collectors.toList()); + } - @Override - public void validatePostLoad() { - this.greetings = - greetings.stream().filter(s -> !s.trim().isEmpty()).collect(Collectors.toList()); - } + public int getGreetingChance() { + if (GreeterBroClient.serverConfig != null && GreeterBroClient.serverConfig.generalConfig.greetingChance != -1) { + return GreeterBroClient.serverConfig.generalConfig.greetingChance; + } + return this.greetingChance; + } } diff --git a/src/client/java/com/padbro/greeterbro/client/config/GeneralConfig.java b/src/client/java/com/padbro/greeterbro/client/config/GeneralConfig.java index f011da8..08c7176 100644 --- a/src/client/java/com/padbro/greeterbro/client/config/GeneralConfig.java +++ b/src/client/java/com/padbro/greeterbro/client/config/GeneralConfig.java @@ -1,64 +1,116 @@ package com.padbro.greeterbro.client.config; -import java.util.List; -import java.util.stream.Collectors; +import com.padbro.greeterbro.client.GreeterBroClient; import me.shedaniel.autoconfig.ConfigData; import me.shedaniel.autoconfig.annotation.Config; import me.shedaniel.autoconfig.annotation.ConfigEntry; +import java.util.List; +import java.util.stream.Collectors; + @Config(name = "general") public class GeneralConfig implements ConfigData { - @ConfigEntry.Gui.Excluded public int configVersion = 0; + @ConfigEntry.Gui.Excluded + public int configVersion = 0; + @ConfigEntry.Gui.Tooltip + public boolean enableOwnJoin = true; + @ConfigEntry.Gui.Tooltip + public String customMessage = ""; + public boolean cancelOnLeave = true; + @ConfigEntry.Gui.Tooltip + public String customLeaveMessage = ""; + @ConfigEntry.Gui.Tooltip + public List greetings = List.of("Hello", "o/"); + @ConfigEntry.Gui.CollapsibleObject(startExpanded = true) + public DelayRange delayRange = new DelayRange(3, 5); + @ConfigEntry.Gui.Tooltip + private boolean enable = true; + @ConfigEntry.BoundedDiscrete(max = 100) + @ConfigEntry.Gui.Tooltip + private int greetingChance = 100; + + public boolean getEnabled() { + if (GreeterBroClient.serverConfig != null && GreeterBroClient.serverConfig.generalConfig.enabled == false) { + return false; + } + return this.enable; + } - @ConfigEntry.Gui.Tooltip public boolean enable = true; + public void setEnabled(boolean enabled) { + this.enable = enabled; + } - @ConfigEntry.Gui.Tooltip public boolean enableOwnJoin = true; + public int getGreetingChance() { + if (GreeterBroClient.serverConfig != null && GreeterBroClient.serverConfig.generalConfig.greetingChance != -1) { + return GreeterBroClient.serverConfig.generalConfig.greetingChance; + } + return this.greetingChance; + } - @ConfigEntry.Gui.Tooltip public String customMessage = ""; + @Override + public void validatePostLoad() { - @ConfigEntry.BoundedDiscrete(max = 100) - @ConfigEntry.Gui.Tooltip - public int greetingChance = 100; + float actualMin = Math.min(this.delayRange.min, this.delayRange.max); + float actualMax = Math.max(this.delayRange.min, this.delayRange.max); + this.delayRange.min = Math.max(actualMin, 0); + this.delayRange.max = Math.max(actualMax, 0); - public boolean cancelOnLeave = true; - @ConfigEntry.Gui.Tooltip public String customLeaveMessage = ""; + this.greetings = + greetings.stream().filter(s -> !s.trim().isEmpty()).collect(Collectors.toList()); + } - @ConfigEntry.Gui.Tooltip public List greetings = List.of("Hello", "o/"); + public static class DelayRange { + @ConfigEntry.BoundedDiscrete(max = 10, min = 0) + private float min; + @ConfigEntry.BoundedDiscrete(max = 10, min = 0) + private float max; - @ConfigEntry.Gui.CollapsibleObject(startExpanded = true) - public DelayRange delayRange = new DelayRange(3, 5); + DelayRange(float min, float max) { + this.min = min; + this.max = max; + } - @Override - public void validatePostLoad() { + public float getMax() { + return max; + } - float actualMin = Math.min(this.delayRange.min, this.delayRange.max); - float actualMax = Math.max(this.delayRange.min, this.delayRange.max); - this.delayRange.min = Math.max(actualMin, 0); - this.delayRange.max = Math.max(actualMax, 0); + public void setMax(float max) { + this.max = max; + } - this.greetings = - greetings.stream().filter(s -> !s.trim().isEmpty()).collect(Collectors.toList()); - } + public float getMin() { + return min; + } - public static class DelayRange { - @ConfigEntry.BoundedDiscrete(max = 10, min = 0) - public float min; + public void setMin(float min) { + this.min = min; + } - @ConfigEntry.BoundedDiscrete(max = 10, min = 0) - public float max; + public int getRandomDelayInTicks() { + com.padbro.greeterbro.config.GeneralConfig generalServerConfig = GreeterBroClient.serverConfig != null + ? GreeterBroClient.serverConfig.generalConfig + : null; - DelayRange(float min, float max) { - this.min = min; - this.max = max; - } + float clientMin = Math.min(this.min, this.max); + float clientMax = Math.max(this.min, this.max); + + float actualMin = clientMin; + float actualMax = clientMax; + + if (generalServerConfig != null && generalServerConfig.minDelay != -1) { + actualMin = Math.max(generalServerConfig.minDelay, clientMin); + } + + if (generalServerConfig != null && generalServerConfig.maxDelay != -1) { + actualMax = Math.max(generalServerConfig.maxDelay, clientMax); + } + + float min = Math.max(actualMin, 0); + float max = Math.max(actualMax, 0); + + float randomDelay = (float) (Math.random() * (max - min + 1)) + min; - public int getRandomDelayInTicks() { - float actualMin = Math.min(this.min, this.max); - float actualMax = Math.max(this.min, this.max); - float min = Math.max(actualMin, 0); - float max = Math.max(actualMax, 0); - float randomDelay = (float) (Math.random() * (max - min + 1)) + min; - return Math.round(randomDelay * 20); + return Math.round(randomDelay * 20); + } } - } } diff --git a/src/client/java/com/padbro/greeterbro/client/config/NameChangeConfig.java b/src/client/java/com/padbro/greeterbro/client/config/NameChangeConfig.java index 7c4a3d1..33c2af8 100644 --- a/src/client/java/com/padbro/greeterbro/client/config/NameChangeConfig.java +++ b/src/client/java/com/padbro/greeterbro/client/config/NameChangeConfig.java @@ -1,25 +1,35 @@ package com.padbro.greeterbro.client.config; -import java.util.List; -import java.util.stream.Collectors; +import com.padbro.greeterbro.client.GreeterBroClient; import me.shedaniel.autoconfig.ConfigData; import me.shedaniel.autoconfig.annotation.Config; import me.shedaniel.autoconfig.annotation.ConfigEntry; +import java.util.List; +import java.util.stream.Collectors; + @Config(name = "nameChange") public class NameChangeConfig implements ConfigData { - public boolean enable = true; - - @ConfigEntry.Gui.Tooltip public String customMessage = ""; + public boolean enable = true; - @ConfigEntry.BoundedDiscrete(max = 100) - @ConfigEntry.Gui.Tooltip public int greetingChance = 100; + @ConfigEntry.Gui.Tooltip + public String customMessage = ""; + @ConfigEntry.Gui.Tooltip + public List greetings = List.of(); + @ConfigEntry.BoundedDiscrete(max = 100) + @ConfigEntry.Gui.Tooltip + private int greetingChance = 100; - @ConfigEntry.Gui.Tooltip public List greetings = List.of(); + @Override + public void validatePostLoad() { + this.greetings = + greetings.stream().filter(s -> !s.trim().isEmpty()).collect(Collectors.toList()); + } - @Override - public void validatePostLoad() { - this.greetings = - greetings.stream().filter(s -> !s.trim().isEmpty()).collect(Collectors.toList()); - } + public int getGreetingChance() { + if (GreeterBroClient.serverConfig != null && GreeterBroClient.serverConfig.generalConfig.greetingChance != -1) { + return GreeterBroClient.serverConfig.generalConfig.greetingChance; + } + return this.greetingChance; + } } diff --git a/src/client/java/com/padbro/greeterbro/client/config/ReturningPlayerConfig.java b/src/client/java/com/padbro/greeterbro/client/config/ReturningPlayerConfig.java index add3c44..a362fac 100644 --- a/src/client/java/com/padbro/greeterbro/client/config/ReturningPlayerConfig.java +++ b/src/client/java/com/padbro/greeterbro/client/config/ReturningPlayerConfig.java @@ -1,33 +1,43 @@ package com.padbro.greeterbro.client.config; -import java.util.List; -import java.util.stream.Collectors; +import com.padbro.greeterbro.client.GreeterBroClient; import me.shedaniel.autoconfig.ConfigData; import me.shedaniel.autoconfig.annotation.Config; import me.shedaniel.autoconfig.annotation.ConfigEntry; import me.shedaniel.autoconfig.annotation.ConfigEntry.Gui.EnumHandler.EnumDisplayOption; +import java.util.List; +import java.util.stream.Collectors; + @Config(name = "returningPlayer") public class ReturningPlayerConfig implements ConfigData { - public boolean enable = true; - - @ConfigEntry.Gui.Tooltip public boolean cacheOnJoin = true; - - @ConfigEntry.BoundedDiscrete(max = 10) - public int ignoreForMin = 5; - - @ConfigEntry.Gui.Tooltip - @ConfigEntry.Gui.EnumHandler(option = EnumDisplayOption.BUTTON) - public CacheClearType cacheClearType = CacheClearType.OnJoin; - - @ConfigEntry.BoundedDiscrete(max = 100) - @ConfigEntry.Gui.Tooltip public int greetingChance = 100; - - @ConfigEntry.Gui.Tooltip public List greetings = List.of("Welcome back", "wb", "o/"); - - @Override - public void validatePostLoad() { - this.greetings = - greetings.stream().filter(s -> !s.trim().isEmpty()).collect(Collectors.toList()); - } + public boolean enable = true; + + @ConfigEntry.Gui.Tooltip + public boolean cacheOnJoin = true; + + @ConfigEntry.BoundedDiscrete(max = 10) + public int ignoreForMin = 5; + + @ConfigEntry.Gui.Tooltip + @ConfigEntry.Gui.EnumHandler(option = EnumDisplayOption.BUTTON) + public CacheClearType cacheClearType = CacheClearType.OnJoin; + @ConfigEntry.Gui.Tooltip + public List greetings = List.of("Welcome back", "wb", "o/"); + @ConfigEntry.BoundedDiscrete(max = 100) + @ConfigEntry.Gui.Tooltip + private int greetingChance = 100; + + @Override + public void validatePostLoad() { + this.greetings = + greetings.stream().filter(s -> !s.trim().isEmpty()).collect(Collectors.toList()); + } + + public int getGreetingChance() { + if (GreeterBroClient.serverConfig != null && GreeterBroClient.serverConfig.generalConfig.greetingChance != -1) { + return GreeterBroClient.serverConfig.generalConfig.greetingChance; + } + return this.greetingChance; + } } diff --git a/src/client/java/com/padbro/greeterbro/client/managers/AfkManager.java b/src/client/java/com/padbro/greeterbro/client/managers/AfkManager.java index f1a13bf..72eb5b3 100644 --- a/src/client/java/com/padbro/greeterbro/client/managers/AfkManager.java +++ b/src/client/java/com/padbro/greeterbro/client/managers/AfkManager.java @@ -23,7 +23,7 @@ public class AfkManager { private static Instant lastActiveAt = Instant.now(); public static void onTick() { - if (!config.enable || !afkConfig.enable) { + if (!config.getEnabled() || !afkConfig.getEnabled()) { return; } @@ -37,7 +37,7 @@ public static void onTick() { } boolean isBefore = - lastActiveAt.isBefore(Instant.now().minus(afkConfig.afkTime, ChronoUnit.MINUTES)); + lastActiveAt.isBefore(Instant.now().minus(afkConfig.getAfkTime(), ChronoUnit.MINUTES)); if (isBefore) { goAfk(); diff --git a/src/client/java/com/padbro/greeterbro/client/managers/JoinMessageManager.java b/src/client/java/com/padbro/greeterbro/client/managers/JoinMessageManager.java new file mode 100644 index 0000000..84c1ffc --- /dev/null +++ b/src/client/java/com/padbro/greeterbro/client/managers/JoinMessageManager.java @@ -0,0 +1,54 @@ +package com.padbro.greeterbro.client.managers; + +import com.padbro.greeterbro.client.GreeterBroClient; +import com.padbro.greeterbro.client.JoinCache; +import com.padbro.greeterbro.client.config.GreeterBroConfig; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.network.ClientPlayerEntity; + +import java.util.List; +import java.util.Random; + +public class JoinMessageManager { + public static void execute() { + GreeterBroConfig config = GreeterBroClient.getConfig(); + JoinCache joinCache = GreeterBroClient.getJoinCache(); + if (!config.generalConfig.getEnabled()) { + return; + } + + if (config.afkConfig.getEnabled()) { + AfkManager.isAfk = false; + AfkManager.setLastActiveNow(false); + } + + if (joinCache.shouldClearOnJoin()) { + GreeterBroClient.getJoinCache().clear(); + } + + if (config.generalConfig.enableOwnJoin) { + List greetingList = config.generalConfig.greetings; + + ClientPlayerEntity player = MinecraftClient.getInstance().player; + if (player == null) { + return; + } + TickManager.scheduleTask( + new TickManager.ScheduledTask( + config.generalConfig.delayRange.getRandomDelayInTicks(), + () -> { + ClientPlayerEntity currentPlayer = MinecraftClient.getInstance().player; + if (currentPlayer == null) { + return; + } + Random rand = new Random(); + String greetingTemplate = greetingList.get(rand.nextInt(greetingList.size())); + String greeting = greetingTemplate.replaceAll("\\s*%player%", ""); + if (!greeting.isEmpty()) { + currentPlayer.networkHandler.sendChatMessage(greeting); + } + }, + player.getName().getString())); + } + } +} diff --git a/src/client/java/com/padbro/greeterbro/client/managers/MigrationManager.java b/src/client/java/com/padbro/greeterbro/client/managers/MigrationManager.java index a83a69d..7f126bf 100644 --- a/src/client/java/com/padbro/greeterbro/client/managers/MigrationManager.java +++ b/src/client/java/com/padbro/greeterbro/client/managers/MigrationManager.java @@ -4,24 +4,27 @@ import com.padbro.greeterbro.client.config.GreeterBroConfig; public class MigrationManager { - public static void migrate() { - boolean migrated = false; - GreeterBroConfig config = GreeterBroClient.getConfig(); - int configVersion = config.generalConfig.configVersion; + public static void migrate() { + boolean migrated = false; + GreeterBroConfig config = GreeterBroClient.getConfig(); + int configVersion = config.generalConfig.configVersion; - if (configVersion < 1) { - if (config.generalConfig.delayRange.min != 3.0 - && config.generalConfig.delayRange.max != 5.0) { - config.generalConfig.delayRange.max /= 20; - config.generalConfig.delayRange.min /= 20; - } + if (configVersion < 1) { + float min = config.generalConfig.delayRange.getMin(); + float max = config.generalConfig.delayRange.getMax(); + if (min != 3.0 + && max != 5.0) { - config.generalConfig.configVersion = 1; - migrated = true; - } + config.generalConfig.delayRange.setMax(max / 20); + config.generalConfig.delayRange.setMin(min / 20); + } + + config.generalConfig.configVersion = 1; + migrated = true; + } - if (migrated) { - GreeterBroClient.saveConfig(); + if (migrated) { + GreeterBroClient.saveConfig(); + } } - } } diff --git a/src/client/java/com/padbro/greeterbro/client/mixin/ChatMixin.java b/src/client/java/com/padbro/greeterbro/client/mixin/ChatMixin.java index e623996..b4e7077 100644 --- a/src/client/java/com/padbro/greeterbro/client/mixin/ChatMixin.java +++ b/src/client/java/com/padbro/greeterbro/client/mixin/ChatMixin.java @@ -30,9 +30,9 @@ public class ChatMixin { @Inject(method = "onGameMessage", at = @At("HEAD")) public void onMessage(Text message, boolean overlay, CallbackInfo ci) { GreeterBroConfig config = GreeterBroClient.getConfig(); - if (!config.generalConfig.enable + if (!config.generalConfig.getEnabled() || MinecraftClient.getInstance().player == null - || (config.afkConfig.enable && AfkManager.isAfk)) { + || (config.afkConfig.getEnabled() && AfkManager.isAfk)) { return; } @@ -45,15 +45,15 @@ public void onMessage(Text message, boolean overlay, CallbackInfo ci) { if (this.isFirstJoin(message)) { greetingList = config.firstJoinConfig.greetings; player = getPlayerName(message, config.firstJoinConfig.customMessage); - chance = config.firstJoinConfig.greetingChance; + chance = config.firstJoinConfig.getGreetingChance(); } else if (this.isNameChange(message)) { greetingList = config.nameChangeConfig.greetings; player = getPlayerName(message, config.nameChangeConfig.customMessage); - chance = config.nameChangeConfig.greetingChance; + chance = config.nameChangeConfig.getGreetingChance(); } else if (this.isJoinMessage(message)) { greetingList = config.generalConfig.greetings; player = getPlayerName(message, config.generalConfig.customMessage); - chance = config.generalConfig.greetingChance; + chance = config.generalConfig.getGreetingChance(); } else if (this.isLeaveMessage(message) && config.generalConfig.cancelOnLeave) { player = getPlayerName(message, config.generalConfig.customLeaveMessage); TickManager.cancelTaskByPlayerName(player); @@ -63,7 +63,7 @@ public void onMessage(Text message, boolean overlay, CallbackInfo ci) { } if (player != null) { - if (config.blacklistConfig.players.contains(player)) { + if (config.blacklistConfig.getAllPlayers().contains(player)) { return; } @@ -89,7 +89,7 @@ public void onMessage(Text message, boolean overlay, CallbackInfo ci) { chance = specialGreeting.get().greetingChance; } else { greetingList = config.returningPlayerConfig.greetings; - chance = config.returningPlayerConfig.greetingChance; + chance = config.returningPlayerConfig.getGreetingChance(); } } } diff --git a/src/client/java/com/padbro/greeterbro/client/mixin/OnChatSendMixin.java b/src/client/java/com/padbro/greeterbro/client/mixin/OnChatSendMixin.java index ac4e50e..76f50b5 100644 --- a/src/client/java/com/padbro/greeterbro/client/mixin/OnChatSendMixin.java +++ b/src/client/java/com/padbro/greeterbro/client/mixin/OnChatSendMixin.java @@ -23,7 +23,7 @@ private void onSendCommandMessage(String content, CallbackInfo ci) { @Unique private void onMessageSend(String content, CallbackInfo ci) { - if (GreeterBroClient.getConfig().afkConfig.enable) { + if (GreeterBroClient.getConfig().afkConfig.getEnabled()) { AfkManager.setLastActiveNow(true); } } diff --git a/src/client/java/com/padbro/greeterbro/client/mixin/OnGameJoinMixin.java b/src/client/java/com/padbro/greeterbro/client/mixin/OnGameJoinMixin.java index fd67d8b..1a864a5 100644 --- a/src/client/java/com/padbro/greeterbro/client/mixin/OnGameJoinMixin.java +++ b/src/client/java/com/padbro/greeterbro/client/mixin/OnGameJoinMixin.java @@ -1,64 +1,28 @@ package com.padbro.greeterbro.client.mixin; -import com.padbro.greeterbro.client.managers.AfkManager; import com.padbro.greeterbro.client.GreeterBroClient; import com.padbro.greeterbro.client.JoinCache; -import com.padbro.greeterbro.client.managers.TickManager; import com.padbro.greeterbro.client.config.GreeterBroConfig; -import java.util.List; -import java.util.Random; +import com.padbro.greeterbro.client.managers.AfkManager; +import com.padbro.greeterbro.client.managers.TickManager; +import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; import net.minecraft.client.MinecraftClient; import net.minecraft.client.network.ClientPlayNetworkHandler; import net.minecraft.client.network.ClientPlayerEntity; import net.minecraft.network.packet.s2c.play.GameJoinS2CPacket; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import java.util.List; +import java.util.Random; + @Mixin(ClientPlayNetworkHandler.class) public class OnGameJoinMixin { - @Inject(at = @At("RETURN"), method = "onGameJoin") - public void onReady(GameJoinS2CPacket packet, CallbackInfo ci) { - GreeterBroClient.isJoining = true; - GreeterBroConfig config = GreeterBroClient.getConfig(); - JoinCache joinCache = GreeterBroClient.getJoinCache(); - if (!config.generalConfig.enable) { - return; - } - - if (config.afkConfig.enable) { - AfkManager.isAfk = false; - AfkManager.setLastActiveNow(false); - } - - if (joinCache.shouldClearOnJoin()) { - GreeterBroClient.getJoinCache().clear(); - } - - if (config.generalConfig.enableOwnJoin) { - List greetingList = config.generalConfig.greetings; - - ClientPlayerEntity player = MinecraftClient.getInstance().player; - if (player == null) { - return; - } - TickManager.scheduleTask( - new TickManager.ScheduledTask( - config.generalConfig.delayRange.getRandomDelayInTicks(), - () -> { - ClientPlayerEntity currentPlayer = MinecraftClient.getInstance().player; - if (currentPlayer == null) { - return; - } - Random rand = new Random(); - String greetingTemplate = greetingList.get(rand.nextInt(greetingList.size())); - String greeting = greetingTemplate.replaceAll("\\s*%player%", ""); - if (!greeting.isEmpty()) { - currentPlayer.networkHandler.sendChatMessage(greeting); - } - }, - player.getName().getString())); + @Inject(at = @At("RETURN"), method = "onGameJoin") + public void onReady(GameJoinS2CPacket packet, CallbackInfo ci) { + GreeterBroClient.isJoining = true; } - } } diff --git a/src/client/java/com/padbro/greeterbro/client/mixin/OnPlayerListMixin.java b/src/client/java/com/padbro/greeterbro/client/mixin/OnPlayerListMixin.java index 56f55dd..04b21fd 100644 --- a/src/client/java/com/padbro/greeterbro/client/mixin/OnPlayerListMixin.java +++ b/src/client/java/com/padbro/greeterbro/client/mixin/OnPlayerListMixin.java @@ -3,7 +3,7 @@ import com.padbro.greeterbro.client.GreeterBroClient; import com.padbro.greeterbro.client.JoinCache; import com.padbro.greeterbro.client.config.GreeterBroConfig; -import java.util.List; +import com.padbro.greeterbro.client.managers.JoinMessageManager; import net.minecraft.client.network.ClientPlayNetworkHandler; import net.minecraft.network.packet.s2c.play.PlayerListS2CPacket; import org.spongepowered.asm.mixin.Mixin; @@ -11,26 +11,29 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import java.util.List; + @Mixin(ClientPlayNetworkHandler.class) public class OnPlayerListMixin { - @Inject(method = "onPlayerList", at = @At("TAIL")) - private void onPlayerList(PlayerListS2CPacket packet, CallbackInfo ci) { - if (!GreeterBroClient.isJoining) { - return; - } + @Inject(method = "onPlayerList", at = @At("TAIL")) + private void onPlayerList(PlayerListS2CPacket packet, CallbackInfo ci) { + if (!GreeterBroClient.isJoining) { + return; + } - GreeterBroConfig config = GreeterBroClient.getConfig(); - if (!config.returningPlayerConfig.cacheOnJoin) { - return; - } + GreeterBroConfig config = GreeterBroClient.getConfig(); + if (!config.returningPlayerConfig.cacheOnJoin) { + return; + } - List players = packet.getPlayerAdditionEntries(); - JoinCache joinCache = GreeterBroClient.getJoinCache(); - for (PlayerListS2CPacket.Entry entry : players) { - if (entry.profile() != null) { - joinCache.add(entry.profile().name()); - } + List players = packet.getPlayerAdditionEntries(); + JoinCache joinCache = GreeterBroClient.getJoinCache(); + for (PlayerListS2CPacket.Entry entry : players) { + if (entry.profile() != null) { + joinCache.add(entry.profile().name()); + } + } + GreeterBroClient.isJoining = false; + JoinMessageManager.execute(); } - GreeterBroClient.isJoining = false; - } } diff --git a/src/client/resources/assets/greeterbro/lang/en_us.json b/src/client/resources/assets/greeterbro/lang/en_us.json index 9f9819f..03a3508 100644 --- a/src/client/resources/assets/greeterbro/lang/en_us.json +++ b/src/client/resources/assets/greeterbro/lang/en_us.json @@ -83,8 +83,10 @@ "text.command.GreeterBro.blacklist.remove.error.exists": "The player is not in the blacklist.", "text.command.GreeterBro.blacklist.remove.success": "The player \"%1$s\" has been removed from the blacklist.", "text.command.GreeterBro.enable.error.enabled": "GreeterBro is already enabled.", + "text.command.GreeterBro.enable.error.server.disabled": "This server has GreeterBro disabled.", "text.command.GreeterBro.enable.success": "GreeterBro enabled.", "text.command.GreeterBro.disable.error.disabled": "GreeterBro is already disabled.", + "text.command.GreeterBro.disable.error.server.disabled": "This server has GreeterBro disabled.", "text.command.GreeterBro.disable.success": "GreeterBro disabled.", "text.command.GreeterBro.afk.error.isAfk": "You are already AFK.", "text.message.GreeterBro.afk.enter_afk": "Entering AFK mode. Greetings disabled.", diff --git a/src/main/java/com/padbro/greeterbro/GreeterBro.java b/src/main/java/com/padbro/greeterbro/GreeterBro.java index 05cfa57..1270d88 100644 --- a/src/main/java/com/padbro/greeterbro/GreeterBro.java +++ b/src/main/java/com/padbro/greeterbro/GreeterBro.java @@ -1,9 +1,47 @@ package com.padbro.greeterbro; +import com.padbro.greeterbro.commands.CommandManager; +import com.padbro.greeterbro.config.GreeterBroServerConfig; +import com.padbro.greeterbro.records.ConfigS2CPayload; +import me.shedaniel.autoconfig.AutoConfig; +import me.shedaniel.autoconfig.ConfigHolder; +import me.shedaniel.autoconfig.serializer.JanksonConfigSerializer; +import net.fabricmc.api.EnvType; import net.fabricmc.api.ModInitializer; +import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; +import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; +import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; +import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.server.network.ServerPlayerEntity; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class GreeterBro implements ModInitializer { + public static final String MOD_ID = "GreeterBro"; + public static final Logger LOGGER = LoggerFactory.getLogger(GreeterBro.MOD_ID); + public static ConfigHolder config; - @Override - public void onInitialize() {} + @Override + public void onInitialize() { + PayloadTypeRegistry.playS2C().register(ConfigS2CPayload.ID, ConfigS2CPayload.CODEC); + + if (FabricLoader.getInstance().getEnvironmentType() != EnvType.SERVER) { + return; + } + + CommandManager.register(); + config = AutoConfig.register(GreeterBroServerConfig.class, JanksonConfigSerializer::new); + + ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> { + sendConfigToClient(handler.getPlayer()); + }); + } + + public static void loadConfig() { + config.load(); + } + + public static void sendConfigToClient(ServerPlayerEntity player) { + ServerPlayNetworking.send(player, new ConfigS2CPayload(config.getConfig())); + } } diff --git a/src/main/java/com/padbro/greeterbro/commands/CommandManager.java b/src/main/java/com/padbro/greeterbro/commands/CommandManager.java new file mode 100644 index 0000000..d6dc993 --- /dev/null +++ b/src/main/java/com/padbro/greeterbro/commands/CommandManager.java @@ -0,0 +1,28 @@ +package com.padbro.greeterbro.commands; + +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; +import net.minecraft.command.CommandRegistryAccess; +import net.minecraft.server.command.CommandManager.RegistrationEnvironment; +import net.minecraft.server.command.ServerCommandSource; + +import static com.mojang.brigadier.builder.LiteralArgumentBuilder.literal; + +public class CommandManager { + private static final LiteralArgumentBuilder commandRoot = + literal("greeterBroServer"); + + public static void register() { + CommandRegistrationCallback.EVENT.register(CommandManager::registerGreeterBro); + } + + private static void registerGreeterBro( + CommandDispatcher dispatcher, + CommandRegistryAccess commandRegistryAccess, + RegistrationEnvironment registrationEnvironment + ) { + ReloadCommand.register(commandRoot); + dispatcher.register(commandRoot); + } +} diff --git a/src/main/java/com/padbro/greeterbro/commands/ReloadCommand.java b/src/main/java/com/padbro/greeterbro/commands/ReloadCommand.java new file mode 100644 index 0000000..404156c --- /dev/null +++ b/src/main/java/com/padbro/greeterbro/commands/ReloadCommand.java @@ -0,0 +1,27 @@ +package com.padbro.greeterbro.commands; + +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import com.padbro.greeterbro.GreeterBro; +import net.fabricmc.fabric.api.networking.v1.PlayerLookup; +import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.text.Text; + +public class ReloadCommand { + public static void register(LiteralArgumentBuilder root) { + root.then(LiteralArgumentBuilder.literal("reload") + .executes(ReloadCommand::reload)); + } + + private static int reload(CommandContext context) { + ServerCommandSource source = context.getSource(); + GreeterBro.loadConfig(); + for (ServerPlayerEntity player : PlayerLookup.world(source.getWorld())) { + GreeterBro.sendConfigToClient(player); + } + source.sendFeedback(() -> Text.literal("GreeterBro config reloaded"), false); + return 1; + } +} \ No newline at end of file diff --git a/src/main/java/com/padbro/greeterbro/config/AfkConfig.java b/src/main/java/com/padbro/greeterbro/config/AfkConfig.java new file mode 100644 index 0000000..44e3ea7 --- /dev/null +++ b/src/main/java/com/padbro/greeterbro/config/AfkConfig.java @@ -0,0 +1,29 @@ +package com.padbro.greeterbro.config; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import me.shedaniel.cloth.clothconfig.shadowed.blue.endless.jankson.Comment; + +public class AfkConfig { + public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( + Codec.BOOL.fieldOf("enforceAfkMode").forGetter((AfkConfig sc) -> sc.enforceAfkMode), + Codec.INT.fieldOf("afkTime").forGetter((AfkConfig sc) -> sc.afkTime) + ).apply(instance, AfkConfig::new)); + + @Comment("If afk mode should be enforced") + public Boolean enforceAfkMode; + @Comment("The time till a player counts as afk. (-1 will not enforce the time)") + public int afkTime; + + public AfkConfig( + Boolean enforceAfkMode, + int afkTime + ) { + this.enforceAfkMode = enforceAfkMode; + this.afkTime = afkTime; + } + + public AfkConfig() { + this(false, -1); + } +} diff --git a/src/main/java/com/padbro/greeterbro/config/BlacklistConfig.java b/src/main/java/com/padbro/greeterbro/config/BlacklistConfig.java new file mode 100644 index 0000000..b15516e --- /dev/null +++ b/src/main/java/com/padbro/greeterbro/config/BlacklistConfig.java @@ -0,0 +1,34 @@ +package com.padbro.greeterbro.config; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import me.shedaniel.autoconfig.ConfigData; +import me.shedaniel.cloth.clothconfig.shadowed.blue.endless.jankson.Comment; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public class BlacklistConfig implements ConfigData { + public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( + Codec.STRING.listOf().fieldOf("players").forGetter((BlacklistConfig sc) -> sc.players) + ).apply(instance, BlacklistConfig::new)); + + @Comment("Players that should never be greeted.") + public List players; + + public BlacklistConfig( + List players + ) { + this.players = players; + } + + public BlacklistConfig() { + this(new ArrayList<>()); + } + + @Override + public void validatePostLoad() { + this.players = players.stream().filter(s -> !s.trim().isEmpty()).collect(Collectors.toList()); + } +} diff --git a/src/main/java/com/padbro/greeterbro/config/FirstJoinConfig.java b/src/main/java/com/padbro/greeterbro/config/FirstJoinConfig.java new file mode 100644 index 0000000..a3d0b18 --- /dev/null +++ b/src/main/java/com/padbro/greeterbro/config/FirstJoinConfig.java @@ -0,0 +1,24 @@ +package com.padbro.greeterbro.config; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import me.shedaniel.cloth.clothconfig.shadowed.blue.endless.jankson.Comment; + +public class FirstJoinConfig { + public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( + Codec.INT.fieldOf("greetingChance").forGetter((FirstJoinConfig sc) -> sc.greetingChance) + ).apply(instance, FirstJoinConfig::new)); + + @Comment("Forces a specific greeting chance from 0-100. (-1 will not enforce the chance)") + public int greetingChance; + + public FirstJoinConfig( + int greetingChance + ) { + this.greetingChance = greetingChance; + } + + public FirstJoinConfig() { + this(-1); + } +} diff --git a/src/main/java/com/padbro/greeterbro/config/GeneralConfig.java b/src/main/java/com/padbro/greeterbro/config/GeneralConfig.java new file mode 100644 index 0000000..4ca8cc6 --- /dev/null +++ b/src/main/java/com/padbro/greeterbro/config/GeneralConfig.java @@ -0,0 +1,57 @@ +package com.padbro.greeterbro.config; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import me.shedaniel.autoconfig.ConfigData; +import me.shedaniel.cloth.clothconfig.shadowed.blue.endless.jankson.Comment; + +import java.util.stream.Collectors; + +public class GeneralConfig implements ConfigData { + public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( + Codec.INT.fieldOf("configVersion").forGetter((GeneralConfig sc) -> sc.configVersion), + Codec.BOOL.fieldOf("enabled").forGetter((GeneralConfig sc) -> sc.enabled), + Codec.INT.fieldOf("greetingChance").forGetter((GeneralConfig sc) -> sc.greetingChance), + Codec.FLOAT.fieldOf("minDelay").forGetter((GeneralConfig sc) -> sc.minDelay), + Codec.FLOAT.fieldOf("maxDelay").forGetter((GeneralConfig sc) -> sc.maxDelay) + ).apply(instance, GeneralConfig::new)); + + @Comment("Do not edit the version manually.") + public int configVersion; + + @Comment("Enables/Disables GreeterBro completely on the server.") + public Boolean enabled; + @Comment("Forces a specific greeting chance from 0-100. (-1 will not enforce the chance)") + public int greetingChance; + + @Comment("The min delay before sending a greeting in seconds. (-1 will not enforce the min delay)") + public float minDelay; + @Comment("The max delay before sending a greeting in seconds. (-1 will not enforce the max delay)") + public float maxDelay; + + public GeneralConfig( + int configVersion, + Boolean enabled, + int greetingChance, + float minDelay, + float maxDelay + ) { + this.configVersion = configVersion; + this.enabled = enabled; + this.greetingChance = greetingChance; + this.minDelay = minDelay; + this.maxDelay = maxDelay; + } + + public GeneralConfig() { + this(1, true, -1, 3, 5); + } + + @Override + public void validatePostLoad() { + float actualMin = Math.min(this.minDelay, this.maxDelay); + float actualMax = Math.max(this.minDelay, this.maxDelay); + this.minDelay = Math.max(actualMin, 0); + this.maxDelay = Math.max(actualMax, 0); + } +} diff --git a/src/main/java/com/padbro/greeterbro/config/GreeterBroServerConfig.java b/src/main/java/com/padbro/greeterbro/config/GreeterBroServerConfig.java new file mode 100644 index 0000000..e2abf56 --- /dev/null +++ b/src/main/java/com/padbro/greeterbro/config/GreeterBroServerConfig.java @@ -0,0 +1,50 @@ +package com.padbro.greeterbro.config; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import me.shedaniel.autoconfig.ConfigData; +import me.shedaniel.autoconfig.annotation.Config; +import me.shedaniel.autoconfig.annotation.ConfigEntry; + +@Config(name = "GreeterBro") +public class GreeterBroServerConfig implements ConfigData { + public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( + GeneralConfig.CODEC.fieldOf("generalConfig").forGetter((GreeterBroServerConfig gbsc) -> gbsc.generalConfig), + AfkConfig.CODEC.fieldOf("afkConfig").forGetter((GreeterBroServerConfig gbsc) -> gbsc.afkConfig), + ReturningPlayerConfig.CODEC.fieldOf("returningPlayerConfig").forGetter((GreeterBroServerConfig gbsc) -> gbsc.returningPlayerConfig), + FirstJoinConfig.CODEC.fieldOf("firstJoinConfig").forGetter((GreeterBroServerConfig gbsc) -> gbsc.firstJoinConfig), + NameChangeConfig.CODEC.fieldOf("nameChangeConfig").forGetter((GreeterBroServerConfig gbsc) -> gbsc.nameChangeConfig), + BlacklistConfig.CODEC.fieldOf("blacklistConfig").forGetter((GreeterBroServerConfig gbsc) -> gbsc.blacklistConfig) + ).apply(instance, GreeterBroServerConfig::new)); + + @ConfigEntry.Category("general") + public GeneralConfig generalConfig; + @ConfigEntry.Category("afk") + public AfkConfig afkConfig; + @ConfigEntry.Category("returningPlayer") + public ReturningPlayerConfig returningPlayerConfig; + @ConfigEntry.Category("firstJoin") + public FirstJoinConfig firstJoinConfig; + @ConfigEntry.Category("nameChange") + public NameChangeConfig nameChangeConfig; + @ConfigEntry.Category("blacklist") + public BlacklistConfig blacklistConfig; + + public GreeterBroServerConfig(GeneralConfig generalConfig, AfkConfig afkConfig, ReturningPlayerConfig returningPlayerConfig, FirstJoinConfig firstJoinConfig, NameChangeConfig nameChangeConfig, BlacklistConfig blacklistConfig) { + this.generalConfig = generalConfig; + this.afkConfig = afkConfig; + this.returningPlayerConfig = returningPlayerConfig; + this.firstJoinConfig = firstJoinConfig; + this.nameChangeConfig = nameChangeConfig; + this.blacklistConfig = blacklistConfig; + } + + public GreeterBroServerConfig() { + this.generalConfig = new GeneralConfig(); + this.afkConfig = new AfkConfig(); + this.returningPlayerConfig = new ReturningPlayerConfig(); + this.firstJoinConfig = new FirstJoinConfig(); + this.nameChangeConfig = new NameChangeConfig(); + this.blacklistConfig = new BlacklistConfig(); + } +} \ No newline at end of file diff --git a/src/main/java/com/padbro/greeterbro/config/NameChangeConfig.java b/src/main/java/com/padbro/greeterbro/config/NameChangeConfig.java new file mode 100644 index 0000000..2fdaa24 --- /dev/null +++ b/src/main/java/com/padbro/greeterbro/config/NameChangeConfig.java @@ -0,0 +1,24 @@ +package com.padbro.greeterbro.config; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import me.shedaniel.cloth.clothconfig.shadowed.blue.endless.jankson.Comment; + +public class NameChangeConfig { + public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( + Codec.INT.fieldOf("greetingChance").forGetter((NameChangeConfig sc) -> sc.greetingChance) + ).apply(instance, NameChangeConfig::new)); + + @Comment("Forces a specific greeting chance from 0-100. (-1 will not enforce the chance)") + public Integer greetingChance; + + public NameChangeConfig( + int greetingChance + ) { + this.greetingChance = greetingChance; + } + + public NameChangeConfig() { + this(-1); + } +} diff --git a/src/main/java/com/padbro/greeterbro/config/ReturningPlayerConfig.java b/src/main/java/com/padbro/greeterbro/config/ReturningPlayerConfig.java new file mode 100644 index 0000000..f984361 --- /dev/null +++ b/src/main/java/com/padbro/greeterbro/config/ReturningPlayerConfig.java @@ -0,0 +1,24 @@ +package com.padbro.greeterbro.config; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import me.shedaniel.cloth.clothconfig.shadowed.blue.endless.jankson.Comment; + +public class ReturningPlayerConfig { + public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( + Codec.INT.fieldOf("greetingChance").forGetter((ReturningPlayerConfig sc) -> sc.greetingChance) + ).apply(instance, ReturningPlayerConfig::new)); + + @Comment("Forces a specific greeting chance from 0-100. (-1 will not enforce the chance)") + public int greetingChance = -1; + + public ReturningPlayerConfig( + int greetingChance + ) { + this.greetingChance = greetingChance; + } + + public ReturningPlayerConfig() { + this(-1); + } +} diff --git a/src/main/java/com/padbro/greeterbro/records/ConfigS2CPayload.java b/src/main/java/com/padbro/greeterbro/records/ConfigS2CPayload.java new file mode 100644 index 0000000..b6818e5 --- /dev/null +++ b/src/main/java/com/padbro/greeterbro/records/ConfigS2CPayload.java @@ -0,0 +1,24 @@ +package com.padbro.greeterbro.records; + +import com.padbro.greeterbro.GreeterBro; +import com.padbro.greeterbro.config.GreeterBroServerConfig; +import io.netty.buffer.ByteBuf; +import net.minecraft.network.codec.PacketCodec; +import net.minecraft.network.codec.PacketCodecs; +import net.minecraft.network.packet.CustomPayload; +import net.minecraft.util.Identifier; + +public record ConfigS2CPayload(GreeterBroServerConfig config) implements CustomPayload { + + public static final CustomPayload.Id ID = + new CustomPayload.Id<>(Identifier.of(GreeterBro.MOD_ID.toLowerCase(), "config")); + + public static final PacketCodec CODEC = + PacketCodecs.codec(GreeterBroServerConfig.CODEC) + .xmap(ConfigS2CPayload::new, ConfigS2CPayload::config); + + @Override + public Id getId() { + return ID; + } +} diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 94e2bdd..8330478 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -10,7 +10,7 @@ "contact": {}, "license": "All-Rights-Reserved", "icon": "assets/greeterbro/icon.png", - "environment": "client", + "environment": "*", "entrypoints": { "client": [ "com.padbro.greeterbro.client.GreeterBroClient"