diff --git a/core/src/main/java/github/nighter/smartspawner/logging/LoggingMessageService.java b/core/src/main/java/github/nighter/smartspawner/logging/LoggingMessageService.java new file mode 100644 index 00000000..ca3ff803 --- /dev/null +++ b/core/src/main/java/github/nighter/smartspawner/logging/LoggingMessageService.java @@ -0,0 +1,178 @@ +package github.nighter.smartspawner.logging; + +import github.nighter.smartspawner.SmartSpawner; +import github.nighter.smartspawner.language.LanguageManager; +import org.bukkit.configuration.ConfigurationSection; + +import java.util.HashMap; +import java.util.Map; + +/** + * Service for managing logging messages and Discord embed configurations from language files. + */ +public class LoggingMessageService { + private final SmartSpawner plugin; + private final LanguageManager languageManager; + + public LoggingMessageService(SmartSpawner plugin) { + this.plugin = plugin; + this.languageManager = plugin.getLanguageManager(); + } + + /** + * Get localized description for an event type. + * Falls back to hardcoded description if not found in language files. + */ + public String getEventDescription(SpawnerEventType eventType) { + String key = "logging.events." + eventType.name(); + + try { + // Check if language manager is available + if (languageManager == null || languageManager.getCachedDefaultLocaleData() == null) { + return eventType.getDescription(); + } + + // Try to get from language manager's default locale + ConfigurationSection messages = languageManager.getCachedDefaultLocaleData().messages(); + if (messages == null) { + return eventType.getDescription(); + } + + String description = messages.getString(key); + + if (description != null && !description.isEmpty()) { + return description; + } + } catch (Exception e) { + plugin.getLogger().warning("Failed to load logging description for " + eventType.name() + ": " + e.getMessage()); + } + + // Fallback to hardcoded description + return eventType.getDescription(); + } + + /** + * Get Discord embed configuration for an event type from language files. + */ + public DiscordEmbedConfig getDiscordEmbedConfig(SpawnerEventType eventType) { + String key = "logging.discord_embeds." + eventType.name(); + + try { + // Check if language manager is available + if (languageManager == null || languageManager.getCachedDefaultLocaleData() == null) { + return getDefaultEmbedConfig(); + } + + ConfigurationSection messages = languageManager.getCachedDefaultLocaleData().messages(); + if (messages == null) { + return getDefaultEmbedConfig(); + } + + ConfigurationSection embedSection = messages.getConfigurationSection(key); + + if (embedSection != null) { + String title = embedSection.getString("title", "{description}"); + String description = embedSection.getString("description", "{description}"); + String colorHex = embedSection.getString("color", "5865F2"); + + // Parse fields if they exist + Map fields = new HashMap<>(); + ConfigurationSection fieldsSection = embedSection.getConfigurationSection("fields"); + if (fieldsSection != null) { + for (String fieldKey : fieldsSection.getKeys(false)) { + ConfigurationSection fieldSection = fieldsSection.getConfigurationSection(fieldKey); + if (fieldSection != null) { + String fieldName = fieldSection.getString("name", ""); + String fieldValue = fieldSection.getString("value", ""); + boolean inline = fieldSection.getBoolean("inline", false); + fields.put(fieldKey, new DiscordEmbedField(fieldName, fieldValue, inline)); + } + } + } + + return new DiscordEmbedConfig(title, description, parseColor(colorHex), fields); + } + } catch (Exception e) { + plugin.getLogger().warning("Failed to load Discord embed config for " + eventType.name() + ": " + e.getMessage()); + } + + // Return default config + return getDefaultEmbedConfig(); + } + + private DiscordEmbedConfig getDefaultEmbedConfig() { + return new DiscordEmbedConfig("{description}", "{description}", 0x5865F2, new HashMap<>()); + } + + private int parseColor(String colorHex) { + try { + // Remove # if present + if (colorHex.startsWith("#")) { + colorHex = colorHex.substring(1); + } + return Integer.parseInt(colorHex, 16); + } catch (NumberFormatException e) { + return 0x5865F2; // Default Discord blurple + } + } + + /** + * Container for Discord embed configuration from language files. + */ + public static class DiscordEmbedConfig { + private final String title; + private final String description; + private final int color; + private final Map fields; + + public DiscordEmbedConfig(String title, String description, int color, Map fields) { + this.title = title; + this.description = description; + this.color = color; + this.fields = fields; + } + + public String getTitle() { + return title; + } + + public String getDescription() { + return description; + } + + public int getColor() { + return color; + } + + public Map getFields() { + return fields; + } + } + + /** + * Container for Discord embed field configuration. + */ + public static class DiscordEmbedField { + private final String name; + private final String value; + private final boolean inline; + + public DiscordEmbedField(String name, String value, boolean inline) { + this.name = name; + this.value = value; + this.inline = inline; + } + + public String getName() { + return name; + } + + public String getValue() { + return value; + } + + public boolean isInline() { + return inline; + } + } +} diff --git a/core/src/main/java/github/nighter/smartspawner/logging/SpawnerActionLogger.java b/core/src/main/java/github/nighter/smartspawner/logging/SpawnerActionLogger.java index c20c952c..d3b9efd4 100644 --- a/core/src/main/java/github/nighter/smartspawner/logging/SpawnerActionLogger.java +++ b/core/src/main/java/github/nighter/smartspawner/logging/SpawnerActionLogger.java @@ -30,6 +30,7 @@ public class SpawnerActionLogger { private final AtomicBoolean isShuttingDown; private Scheduler.Task logTask; private DiscordWebhookLogger discordLogger; + private LoggingMessageService loggingMessageService; private File currentLogFile; private static final ThreadLocal dateFormat = @@ -40,6 +41,7 @@ public SpawnerActionLogger(SmartSpawner plugin, LoggingConfig config) { this.config = config; this.logQueue = new ConcurrentLinkedQueue<>(); this.isShuttingDown = new AtomicBoolean(false); + this.loggingMessageService = new LoggingMessageService(plugin); if (plugin.getConfig().getBoolean("enabled", true)) { setupLogDirectory(); @@ -49,7 +51,7 @@ public SpawnerActionLogger(SmartSpawner plugin, LoggingConfig config) { // Initialize Discord webhook logger DiscordWebhookConfig discordConfig = new DiscordWebhookConfig(plugin); if (discordConfig.isEnabled()) { - this.discordLogger = new DiscordWebhookLogger(plugin, discordConfig); + this.discordLogger = new DiscordWebhookLogger(plugin, discordConfig, loggingMessageService); } } @@ -61,8 +63,11 @@ public void log(SpawnerLogEntry entry) { return; } + // Get localized description + String description = loggingMessageService.getEventDescription(entry.getEventType()); + if (config.isConsoleOutput()) { - plugin.getLogger().info("[SpawnerLog] " + entry.toReadableString()); + plugin.getLogger().info("[SpawnerLog] " + entry.toReadableString(description)); } // Always use async logging @@ -145,7 +150,9 @@ private void writeLogEntries(List entries) { try (BufferedWriter writer = new BufferedWriter(new FileWriter(currentLogFile, true))) { for (SpawnerLogEntry entry : entries) { - String logLine = config.isJsonFormat() ? entry.toJson() : entry.toReadableString(); + // Get localized description + String description = loggingMessageService.getEventDescription(entry.getEventType()); + String logLine = config.isJsonFormat() ? entry.toJson(description) : entry.toReadableString(description); writer.write(logLine); writer.newLine(); } diff --git a/core/src/main/java/github/nighter/smartspawner/logging/SpawnerLogEntry.java b/core/src/main/java/github/nighter/smartspawner/logging/SpawnerLogEntry.java index aa1ed116..e336c34b 100644 --- a/core/src/main/java/github/nighter/smartspawner/logging/SpawnerLogEntry.java +++ b/core/src/main/java/github/nighter/smartspawner/logging/SpawnerLogEntry.java @@ -67,11 +67,19 @@ public Map getMetadata() { * Converts the log entry to a JSON string for structured logging. */ public String toJson() { + return toJson(null); + } + + /** + * Converts the log entry to a JSON string with custom description. + */ + public String toJson(String customDescription) { StringBuilder json = new StringBuilder("{"); json.append("\"timestamp\":\"").append(FORMATTER.format(Instant.ofEpochMilli(timestamp))).append("\","); json.append("\"timestamp_ms\":").append(timestamp).append(","); json.append("\"event_type\":\"").append(eventType.name()).append("\","); - json.append("\"description\":\"").append(eventType.getDescription()).append("\""); + String description = customDescription != null ? customDescription : eventType.getDescription(); + json.append("\"description\":\"").append(description).append("\""); if (playerName != null) { json.append(",\"player\":\"").append(escapeJson(playerName)).append("\""); @@ -116,9 +124,17 @@ public String toJson() { * Converts the log entry to a human-readable string. */ public String toReadableString() { + return toReadableString(null); + } + + /** + * Converts the log entry to a human-readable string with custom description. + */ + public String toReadableString(String customDescription) { StringBuilder sb = new StringBuilder(); sb.append("[").append(FORMATTER.format(Instant.ofEpochMilli(timestamp))).append("] "); - sb.append(eventType.getDescription()); + String description = customDescription != null ? customDescription : eventType.getDescription(); + sb.append(description); if (playerName != null) { sb.append(" | Player: ").append(playerName); diff --git a/core/src/main/java/github/nighter/smartspawner/logging/discord/DiscordEmbedBuilder.java b/core/src/main/java/github/nighter/smartspawner/logging/discord/DiscordEmbedBuilder.java index b7e47984..a3b898bb 100644 --- a/core/src/main/java/github/nighter/smartspawner/logging/discord/DiscordEmbedBuilder.java +++ b/core/src/main/java/github/nighter/smartspawner/logging/discord/DiscordEmbedBuilder.java @@ -1,6 +1,7 @@ package github.nighter.smartspawner.logging.discord; import github.nighter.smartspawner.SmartSpawner; +import github.nighter.smartspawner.logging.LoggingMessageService; import github.nighter.smartspawner.logging.SpawnerLogEntry; import org.bukkit.Location; @@ -17,22 +18,33 @@ public class DiscordEmbedBuilder { private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("HH:mm:ss") .withZone(ZoneId.systemDefault()); - public static DiscordEmbed buildEmbed(SpawnerLogEntry entry, DiscordWebhookConfig config, SmartSpawner plugin) { + public static DiscordEmbed buildEmbed(SpawnerLogEntry entry, DiscordWebhookConfig config, SmartSpawner plugin, LoggingMessageService loggingMessageService) { DiscordEmbed embed = new DiscordEmbed(); - - // Set color based on specific event type - embed.setColor(config.getColorForEvent(entry.getEventType())); + + // Get logging message service for localized descriptions (use provided or create new) + LoggingMessageService msgService = loggingMessageService != null ? loggingMessageService : new LoggingMessageService(plugin); + String localizedDescription = msgService.getEventDescription(entry.getEventType()); + + // Get embed configuration from language files + LoggingMessageService.DiscordEmbedConfig embedConfig = msgService.getDiscordEmbedConfig(entry.getEventType()); + + // Set color from language file or fallback to config + int color = embedConfig.getColor(); + if (color == 0x5865F2) { // If it's the default, try config + color = config.getColorForEvent(entry.getEventType()); + } + embed.setColor(color); // Build placeholders - Map placeholders = buildPlaceholders(entry); + Map placeholders = buildPlaceholders(entry, localizedDescription); - // Set compact title with icon + // Set compact title with icon - use language file config or fallback to config String eventIcon = getEventIcon(entry.getEventType()); - String title = eventIcon + " " + replacePlaceholders(config.getEmbedTitle(), placeholders); + String title = eventIcon + " " + replacePlaceholders(embedConfig.getTitle(), placeholders); embed.setTitle(title); - // Set compact description - String description = buildCompactDescription(entry, placeholders, config); + // Set compact description - use language file config + String description = buildCompactDescription(entry, placeholders, embedConfig.getDescription()); embed.setDescription(description); // Set footer @@ -49,6 +61,14 @@ public static DiscordEmbed buildEmbed(SpawnerLogEntry entry, DiscordWebhookConfi // Add only important metadata as inline fields addCompactFields(embed, entry); + + // Add custom fields from language file if any + for (Map.Entry fieldEntry : embedConfig.getFields().entrySet()) { + LoggingMessageService.DiscordEmbedField field = fieldEntry.getValue(); + String fieldName = replacePlaceholders(field.getName(), placeholders); + String fieldValue = replacePlaceholders(field.getValue(), placeholders); + embed.addField(fieldName, fieldValue, field.isInline()); + } // Add custom fields from config (if any) for (DiscordWebhookConfig.EmbedField customField : config.getCustomFields()) { @@ -60,22 +80,23 @@ public static DiscordEmbed buildEmbed(SpawnerLogEntry entry, DiscordWebhookConfi return embed; } - private static String buildCompactDescription(SpawnerLogEntry entry, Map placeholders, DiscordWebhookConfig config) { + private static String buildCompactDescription(SpawnerLogEntry entry, Map placeholders, String descriptionTemplate) { StringBuilder desc = new StringBuilder(); - // Main description - String mainDesc = replacePlaceholders(config.getEmbedDescription(), placeholders); + // Main description from template + String mainDesc = replacePlaceholders(descriptionTemplate, placeholders); desc.append(mainDesc); // Player info (if exists) if (entry.getPlayerName() != null) { - desc.append("👤 `").append(entry.getPlayerName()).append("`"); + desc.append("\n👤 `").append(entry.getPlayerName()).append("`"); } // Location info (compact format) if (entry.getLocation() != null) { Location loc = entry.getLocation(); if (entry.getPlayerName() != null) desc.append(" • "); + else desc.append("\n"); desc.append("📍 `").append(loc.getWorld().getName()) .append(" (").append(loc.getBlockX()) .append(", ").append(loc.getBlockY()) @@ -132,10 +153,10 @@ private static String formatCompactValue(Object value) { return "`" + str + "`"; } - private static Map buildPlaceholders(SpawnerLogEntry entry) { + private static Map buildPlaceholders(SpawnerLogEntry entry, String localizedDescription) { Map placeholders = new HashMap<>(); - placeholders.put("description", entry.getEventType().getDescription()); + placeholders.put("description", localizedDescription); placeholders.put("event_type", entry.getEventType().name()); placeholders.put("time", FORMATTER.format(Instant.ofEpochMilli(System.currentTimeMillis()))); @@ -176,6 +197,10 @@ private static String replacePlaceholders(String text, Map place for (Map.Entry entry : placeholders.entrySet()) { result = result.replace("{" + entry.getKey() + "}", entry.getValue()); } + + // Replace {newline} with actual newline + result = result.replace("{newline}", "\n"); + return result; } diff --git a/core/src/main/java/github/nighter/smartspawner/logging/discord/DiscordWebhookLogger.java b/core/src/main/java/github/nighter/smartspawner/logging/discord/DiscordWebhookLogger.java index 04c32d56..aa8729e3 100644 --- a/core/src/main/java/github/nighter/smartspawner/logging/discord/DiscordWebhookLogger.java +++ b/core/src/main/java/github/nighter/smartspawner/logging/discord/DiscordWebhookLogger.java @@ -2,6 +2,7 @@ import github.nighter.smartspawner.Scheduler; import github.nighter.smartspawner.SmartSpawner; +import github.nighter.smartspawner.logging.LoggingMessageService; import github.nighter.smartspawner.logging.SpawnerLogEntry; import java.io.IOException; @@ -26,18 +27,20 @@ public class DiscordWebhookLogger { private final AtomicLong lastWebhookTime; private final AtomicLong webhooksSentThisMinute; private Scheduler.Task webhookTask; + private final LoggingMessageService loggingMessageService; // Discord rate limits: 30 requests per minute per webhook private static final int MAX_REQUESTS_PER_MINUTE = 25; // Leave some buffer private static final long MINUTE_IN_MILLIS = 60000; - public DiscordWebhookLogger(SmartSpawner plugin, DiscordWebhookConfig config) { + public DiscordWebhookLogger(SmartSpawner plugin, DiscordWebhookConfig config, LoggingMessageService loggingMessageService) { this.plugin = plugin; this.config = config; this.webhookQueue = new ConcurrentLinkedQueue<>(); this.isShuttingDown = new AtomicBoolean(false); this.lastWebhookTime = new AtomicLong(System.currentTimeMillis()); this.webhooksSentThisMinute = new AtomicLong(0); + this.loggingMessageService = loggingMessageService; if (config.isEnabled()) { startWebhookTask(); @@ -103,7 +106,7 @@ private void sendWebhook(SpawnerLogEntry entry) { try { // Build the embed - DiscordEmbed embed = DiscordEmbedBuilder.buildEmbed(entry, config, plugin); + DiscordEmbed embed = DiscordEmbedBuilder.buildEmbed(entry, config, plugin, loggingMessageService); String jsonPayload = embed.toJson(); // Send async HTTP request diff --git a/core/src/main/resources/config.yml b/core/src/main/resources/config.yml index 59ad80d8..bdb022bd 100644 --- a/core/src/main/resources/config.yml +++ b/core/src/main/resources/config.yml @@ -236,6 +236,15 @@ ghost_spawners: #--------------------------------------------------- # Comprehensive logging system for tracking spawner interactions and events # Provides audit trail and debugging capabilities with minimal performance impact +# +# MULTI-LANGUAGE SUPPORT: +# - Event descriptions can be customized in language files (language/{locale}/messages.yml) +# - Look for the "logging.events" section in messages.yml to customize event descriptions +# - Discord embed configurations (title, description, color, fields) can also be customized +# in language files under "logging.discord_embeds" section +# - Use {newline} placeholder for line breaks in messages +# - Available placeholders: {player}, {location}, {world}, {x}, {y}, {z}, {entity}, {time}, +# {description}, {event_type}, and event-specific metadata fields logging: # Enable/disable the logging system enabled: true @@ -326,6 +335,9 @@ logging: - COMMAND_EXECUTE_RCON # Discord Embed Configuration + # NOTE: For multi-language support, embed configurations (title, description, color, fields) + # can now be customized in language files under logging.discord_embeds section. + # Settings here will be used as fallback if not found in language files. embed: # Embed title (supports placeholders) title: "{description}" diff --git a/core/src/main/resources/language/DonutSMP/messages.yml b/core/src/main/resources/language/DonutSMP/messages.yml index fddd0c4f..1c3731b1 100644 --- a/core/src/main/resources/language/DonutSMP/messages.yml +++ b/core/src/main/resources/language/DonutSMP/messages.yml @@ -273,4 +273,156 @@ no_priceable_items: spawner_management: removed: message: "&#e6e6faꜱᴘᴀᴡɴᴇʀ &#ff5252ʀᴇᴍᴏᴠᴇᴅ &#e6e6faꜱᴜᴄᴄᴇꜱꜱꜰᴜʟʟʏ!" - sound: entity.item.break \ No newline at end of file + sound: entity.item.break + +# ------------------------------------------------------ +# Spawner Logging Messages +# ------------------------------------------------------ +# These messages are used for logging spawner events +# Placeholders: {player}, {location}, {world}, {x}, {y}, {z}, {entity}, {time}, and metadata fields +# Use {newline} for line breaks in messages +logging: + events: + SPAWNER_PLACE: "Spawner placed" + SPAWNER_BREAK: "Spawner broken" + SPAWNER_EXPLODE: "Spawner destroyed by explosion" + SPAWNER_STACK_HAND: "Spawner stacked by hand" + SPAWNER_STACK_GUI: "Spawner stacked via GUI" + SPAWNER_DESTACK_GUI: "Spawner destacked via GUI" + SPAWNER_GUI_OPEN: "Spawner GUI opened" + SPAWNER_STORAGE_OPEN: "Storage GUI opened" + SPAWNER_STACKER_OPEN: "Stacker GUI opened" + SPAWNER_EXP_CLAIM: "Experience claimed" + SPAWNER_SELL_ALL: "Items sold" + SPAWNER_ITEM_TAKE_ALL: "All items taken from storage" + SPAWNER_ITEM_DROP: "Item dropped from storage" + SPAWNER_ITEMS_SORT: "Items sorted in storage" + SPAWNER_ITEM_FILTER: "Item filter toggled" + SPAWNER_DROP_PAGE_ITEMS: "Page items dropped" + COMMAND_EXECUTE_PLAYER: "Command executed by player" + COMMAND_EXECUTE_CONSOLE: "Command executed by console" + COMMAND_EXECUTE_RCON: "Command executed by RCON" + SPAWNER_EGG_CHANGE: "Spawner entity type changed" + + # Discord embed configurations for each event type + # Supports all placeholders from logging events + discord_embeds: + SPAWNER_PLACE: + title: "{description}" + description: "{description}" + color: "57F287" + fields: [] + + SPAWNER_BREAK: + title: "{description}" + description: "{description}" + color: "ED4245" + fields: [] + + SPAWNER_EXPLODE: + title: "{description}" + description: "{description}" + color: "FF6B6B" + fields: [] + + SPAWNER_STACK_HAND: + title: "{description}" + description: "{description}" + color: "FEE75C" + fields: [] + + SPAWNER_STACK_GUI: + title: "{description}" + description: "{description}" + color: "F1C40F" + fields: [] + + SPAWNER_DESTACK_GUI: + title: "{description}" + description: "{description}" + color: "E67E22" + fields: [] + + SPAWNER_GUI_OPEN: + title: "{description}" + description: "{description}" + color: "9B59B6" + fields: [] + + SPAWNER_STORAGE_OPEN: + title: "{description}" + description: "{description}" + color: "8E44AD" + fields: [] + + SPAWNER_STACKER_OPEN: + title: "{description}" + description: "{description}" + color: "BB8FCE" + fields: [] + + SPAWNER_EXP_CLAIM: + title: "{description}" + description: "{description}" + color: "2ECC71" + fields: [] + + SPAWNER_SELL_ALL: + title: "{description}" + description: "{description}" + color: "27AE60" + fields: [] + + SPAWNER_ITEM_TAKE_ALL: + title: "{description}" + description: "{description}" + color: "1ABC9C" + fields: [] + + SPAWNER_ITEM_DROP: + title: "{description}" + description: "{description}" + color: "16A085" + fields: [] + + SPAWNER_ITEMS_SORT: + title: "{description}" + description: "{description}" + color: "48C9B0" + fields: [] + + SPAWNER_ITEM_FILTER: + title: "{description}" + description: "{description}" + color: "45B7AF" + fields: [] + + SPAWNER_DROP_PAGE_ITEMS: + title: "{description}" + description: "{description}" + color: "138D75" + fields: [] + + COMMAND_EXECUTE_PLAYER: + title: "{description}" + description: "{description}" + color: "5865F2" + fields: [] + + COMMAND_EXECUTE_CONSOLE: + title: "{description}" + description: "{description}" + color: "3B5998" + fields: [] + + COMMAND_EXECUTE_RCON: + title: "{description}" + description: "{description}" + color: "7289DA" + fields: [] + + SPAWNER_EGG_CHANGE: + title: "{description}" + description: "{description}" + color: "E91E63" + fields: [] \ No newline at end of file diff --git a/core/src/main/resources/language/de_DE/messages.yml b/core/src/main/resources/language/de_DE/messages.yml index 2e93d374..afff734e 100644 --- a/core/src/main/resources/language/de_DE/messages.yml +++ b/core/src/main/resources/language/de_DE/messages.yml @@ -273,4 +273,156 @@ no_priceable_items: spawner_management: removed: message: "&#e6e6faꜱᴘᴀᴡɴᴇʀ &#ff5252ᴇʀꜰᴏʟɢʀᴇɪᴄʜ ᴇɴᴛꜰᴇʀɴᴛ&#e6e6fa!" - sound: entity.item.break \ No newline at end of file + sound: entity.item.break + +# ------------------------------------------------------ +# Spawner Logging Messages +# ------------------------------------------------------ +# These messages are used for logging spawner events +# Placeholders: {player}, {location}, {world}, {x}, {y}, {z}, {entity}, {time}, and metadata fields +# Use {newline} for line breaks in messages +logging: + events: + SPAWNER_PLACE: "Spawner platziert" + SPAWNER_BREAK: "Spawner zerstört" + SPAWNER_EXPLODE: "Spawner durch Explosion zerstört" + SPAWNER_STACK_HAND: "Spawner von Hand gestapelt" + SPAWNER_STACK_GUI: "Spawner über GUI gestapelt" + SPAWNER_DESTACK_GUI: "Spawner über GUI entstapelt" + SPAWNER_GUI_OPEN: "Spawner-GUI geöffnet" + SPAWNER_STORAGE_OPEN: "Lager-GUI geöffnet" + SPAWNER_STACKER_OPEN: "Stapler-GUI geöffnet" + SPAWNER_EXP_CLAIM: "Erfahrung beansprucht" + SPAWNER_SELL_ALL: "Gegenstände verkauft" + SPAWNER_ITEM_TAKE_ALL: "Alle Gegenstände aus dem Lager genommen" + SPAWNER_ITEM_DROP: "Gegenstand aus dem Lager fallen gelassen" + SPAWNER_ITEMS_SORT: "Gegenstände im Lager sortiert" + SPAWNER_ITEM_FILTER: "Gegenstandsfilter umgeschaltet" + SPAWNER_DROP_PAGE_ITEMS: "Seitengegenstände fallen gelassen" + COMMAND_EXECUTE_PLAYER: "Befehl vom Spieler ausgeführt" + COMMAND_EXECUTE_CONSOLE: "Befehl von der Konsole ausgeführt" + COMMAND_EXECUTE_RCON: "Befehl von RCON ausgeführt" + SPAWNER_EGG_CHANGE: "Spawner-Entitätstyp geändert" + + # Discord embed configurations for each event type + # Supports all placeholders from logging events + discord_embeds: + SPAWNER_PLACE: + title: "{description}" + description: "{description}" + color: "57F287" + fields: [] + + SPAWNER_BREAK: + title: "{description}" + description: "{description}" + color: "ED4245" + fields: [] + + SPAWNER_EXPLODE: + title: "{description}" + description: "{description}" + color: "FF6B6B" + fields: [] + + SPAWNER_STACK_HAND: + title: "{description}" + description: "{description}" + color: "FEE75C" + fields: [] + + SPAWNER_STACK_GUI: + title: "{description}" + description: "{description}" + color: "F1C40F" + fields: [] + + SPAWNER_DESTACK_GUI: + title: "{description}" + description: "{description}" + color: "E67E22" + fields: [] + + SPAWNER_GUI_OPEN: + title: "{description}" + description: "{description}" + color: "9B59B6" + fields: [] + + SPAWNER_STORAGE_OPEN: + title: "{description}" + description: "{description}" + color: "8E44AD" + fields: [] + + SPAWNER_STACKER_OPEN: + title: "{description}" + description: "{description}" + color: "BB8FCE" + fields: [] + + SPAWNER_EXP_CLAIM: + title: "{description}" + description: "{description}" + color: "2ECC71" + fields: [] + + SPAWNER_SELL_ALL: + title: "{description}" + description: "{description}" + color: "27AE60" + fields: [] + + SPAWNER_ITEM_TAKE_ALL: + title: "{description}" + description: "{description}" + color: "1ABC9C" + fields: [] + + SPAWNER_ITEM_DROP: + title: "{description}" + description: "{description}" + color: "16A085" + fields: [] + + SPAWNER_ITEMS_SORT: + title: "{description}" + description: "{description}" + color: "48C9B0" + fields: [] + + SPAWNER_ITEM_FILTER: + title: "{description}" + description: "{description}" + color: "45B7AF" + fields: [] + + SPAWNER_DROP_PAGE_ITEMS: + title: "{description}" + description: "{description}" + color: "138D75" + fields: [] + + COMMAND_EXECUTE_PLAYER: + title: "{description}" + description: "{description}" + color: "5865F2" + fields: [] + + COMMAND_EXECUTE_CONSOLE: + title: "{description}" + description: "{description}" + color: "3B5998" + fields: [] + + COMMAND_EXECUTE_RCON: + title: "{description}" + description: "{description}" + color: "7289DA" + fields: [] + + SPAWNER_EGG_CHANGE: + title: "{description}" + description: "{description}" + color: "E91E63" + fields: [] \ No newline at end of file diff --git a/core/src/main/resources/language/en_US/messages.yml b/core/src/main/resources/language/en_US/messages.yml index b2339144..516f36f2 100644 --- a/core/src/main/resources/language/en_US/messages.yml +++ b/core/src/main/resources/language/en_US/messages.yml @@ -273,4 +273,187 @@ no_priceable_items: spawner_management: removed: message: "&#e6e6faꜱᴘᴀᴡɴᴇʀ &#ff5252ʀᴇᴍᴏᴠᴇᴅ &#e6e6faꜱᴜᴄᴄᴇꜱꜱꜰᴜʟʟʏ!" - sound: entity.item.break \ No newline at end of file + sound: entity.item.break + +# ------------------------------------------------------ +# Spawner Logging Messages +# ------------------------------------------------------ +# These messages are used for logging spawner events to files and console +# +# CUSTOMIZATION GUIDE: +# - Each event type has a customizable description +# - Descriptions support color codes (&#RRGGBB or &c style) +# - Placeholders available in logging context: +# {player} - Player who triggered the event +# {location} - Full location (world + coordinates) +# {world}, {x}, {y}, {z} - Individual location components +# {entity} - Entity type (for spawner-related events) +# {time} - Event timestamp +# Event-specific metadata fields (varies by event type) +# +# EXAMPLES: +# SPAWNER_PLACE: "Spawner placed by {player} at {location}" +# SPAWNER_BREAK: "Spawner broken by {player}" +# +logging: + events: + SPAWNER_PLACE: "Spawner placed" + SPAWNER_BREAK: "Spawner broken" + SPAWNER_EXPLODE: "Spawner destroyed by explosion" + SPAWNER_STACK_HAND: "Spawner stacked by hand" + SPAWNER_STACK_GUI: "Spawner stacked via GUI" + SPAWNER_DESTACK_GUI: "Spawner destacked via GUI" + SPAWNER_GUI_OPEN: "Spawner GUI opened" + SPAWNER_STORAGE_OPEN: "Storage GUI opened" + SPAWNER_STACKER_OPEN: "Stacker GUI opened" + SPAWNER_EXP_CLAIM: "Experience claimed" + SPAWNER_SELL_ALL: "Items sold" + SPAWNER_ITEM_TAKE_ALL: "All items taken from storage" + SPAWNER_ITEM_DROP: "Item dropped from storage" + SPAWNER_ITEMS_SORT: "Items sorted in storage" + SPAWNER_ITEM_FILTER: "Item filter toggled" + SPAWNER_DROP_PAGE_ITEMS: "Page items dropped" + COMMAND_EXECUTE_PLAYER: "Command executed by player" + COMMAND_EXECUTE_CONSOLE: "Command executed by console" + COMMAND_EXECUTE_RCON: "Command executed by RCON" + SPAWNER_EGG_CHANGE: "Spawner entity type changed" + + # Discord embed configurations for each event type + # Supports all placeholders: {player}, {location}, {world}, {x}, {y}, {z}, {entity}, {time}, {description}, {event_type} + # And all metadata fields specific to each event + # Use {newline} for line breaks in description or field values + # + # Example with custom fields: + # SPAWNER_PLACE: + # title: "🟢 Spawner Placed" + # description: "A spawner was placed{newline}Player: {player}{newline}Location: {location}" + # color: "57F287" + # fields: + # location_field: + # name: "📍 Location" + # value: "{world} ({x}, {y}, {z})" + # inline: true + # entity_field: + # name: "🐾 Entity Type" + # value: "{entity}" + # inline: true + discord_embeds: + SPAWNER_PLACE: + title: "{description}" + description: "{description}" + color: "57F287" + fields: [] + + SPAWNER_BREAK: + title: "{description}" + description: "{description}" + color: "ED4245" + fields: [] + + SPAWNER_EXPLODE: + title: "{description}" + description: "{description}" + color: "FF6B6B" + fields: [] + + SPAWNER_STACK_HAND: + title: "{description}" + description: "{description}" + color: "FEE75C" + fields: [] + + SPAWNER_STACK_GUI: + title: "{description}" + description: "{description}" + color: "F1C40F" + fields: [] + + SPAWNER_DESTACK_GUI: + title: "{description}" + description: "{description}" + color: "E67E22" + fields: [] + + SPAWNER_GUI_OPEN: + title: "{description}" + description: "{description}" + color: "9B59B6" + fields: [] + + SPAWNER_STORAGE_OPEN: + title: "{description}" + description: "{description}" + color: "8E44AD" + fields: [] + + SPAWNER_STACKER_OPEN: + title: "{description}" + description: "{description}" + color: "BB8FCE" + fields: [] + + SPAWNER_EXP_CLAIM: + title: "{description}" + description: "{description}" + color: "2ECC71" + fields: [] + + SPAWNER_SELL_ALL: + title: "{description}" + description: "{description}" + color: "27AE60" + fields: [] + + SPAWNER_ITEM_TAKE_ALL: + title: "{description}" + description: "{description}" + color: "1ABC9C" + fields: [] + + SPAWNER_ITEM_DROP: + title: "{description}" + description: "{description}" + color: "16A085" + fields: [] + + SPAWNER_ITEMS_SORT: + title: "{description}" + description: "{description}" + color: "48C9B0" + fields: [] + + SPAWNER_ITEM_FILTER: + title: "{description}" + description: "{description}" + color: "45B7AF" + fields: [] + + SPAWNER_DROP_PAGE_ITEMS: + title: "{description}" + description: "{description}" + color: "138D75" + fields: [] + + COMMAND_EXECUTE_PLAYER: + title: "{description}" + description: "{description}" + color: "5865F2" + fields: [] + + COMMAND_EXECUTE_CONSOLE: + title: "{description}" + description: "{description}" + color: "3B5998" + fields: [] + + COMMAND_EXECUTE_RCON: + title: "{description}" + description: "{description}" + color: "7289DA" + fields: [] + + SPAWNER_EGG_CHANGE: + title: "{description}" + description: "{description}" + color: "E91E63" + fields: [] \ No newline at end of file diff --git a/core/src/main/resources/language/vi_VN/messages.yml b/core/src/main/resources/language/vi_VN/messages.yml index 3761635e..f121fbe4 100644 --- a/core/src/main/resources/language/vi_VN/messages.yml +++ b/core/src/main/resources/language/vi_VN/messages.yml @@ -268,4 +268,156 @@ no_priceable_items: spawner_management: removed: message: "&#e6e6faLồɴɢ sᴘᴀᴡɴ #&#ab7afd%id% &#ff5252đã xóᴀ &#e6e6faᴛʜàɴʜ ᴄôɴɢ!" - sound: entity.item.break \ No newline at end of file + sound: entity.item.break + +# ------------------------------------------------------ +# Spawner Logging Messages +# ------------------------------------------------------ +# These messages are used for logging spawner events +# Placeholders: {player}, {location}, {world}, {x}, {y}, {z}, {entity}, {time}, and metadata fields +# Use {newline} for line breaks in messages +logging: + events: + SPAWNER_PLACE: "Đặt lồng spawn" + SPAWNER_BREAK: "Phá lồng spawn" + SPAWNER_EXPLODE: "Lồng spawn bị phá hủy do nổ" + SPAWNER_STACK_HAND: "Xếp lồng spawn bằng tay" + SPAWNER_STACK_GUI: "Xếp lồng spawn qua GUI" + SPAWNER_DESTACK_GUI: "Tháo lồng spawn qua GUI" + SPAWNER_GUI_OPEN: "Mở GUI lồng spawn" + SPAWNER_STORAGE_OPEN: "Mở GUI kho" + SPAWNER_STACKER_OPEN: "Mở GUI xếp chồng" + SPAWNER_EXP_CLAIM: "Nhận kinh nghiệm" + SPAWNER_SELL_ALL: "Bán vật phẩm" + SPAWNER_ITEM_TAKE_ALL: "Lấy tất cả vật phẩm từ kho" + SPAWNER_ITEM_DROP: "Thả vật phẩm từ kho" + SPAWNER_ITEMS_SORT: "Sắp xếp vật phẩm trong kho" + SPAWNER_ITEM_FILTER: "Chuyển đổi bộ lọc vật phẩm" + SPAWNER_DROP_PAGE_ITEMS: "Thả vật phẩm trang" + COMMAND_EXECUTE_PLAYER: "Lệnh được thực thi bởi người chơi" + COMMAND_EXECUTE_CONSOLE: "Lệnh được thực thi bởi console" + COMMAND_EXECUTE_RCON: "Lệnh được thực thi bởi RCON" + SPAWNER_EGG_CHANGE: "Thay đổi loại sinh vật lồng spawn" + + # Discord embed configurations for each event type + # Supports all placeholders from logging events + discord_embeds: + SPAWNER_PLACE: + title: "{description}" + description: "{description}" + color: "57F287" + fields: [] + + SPAWNER_BREAK: + title: "{description}" + description: "{description}" + color: "ED4245" + fields: [] + + SPAWNER_EXPLODE: + title: "{description}" + description: "{description}" + color: "FF6B6B" + fields: [] + + SPAWNER_STACK_HAND: + title: "{description}" + description: "{description}" + color: "FEE75C" + fields: [] + + SPAWNER_STACK_GUI: + title: "{description}" + description: "{description}" + color: "F1C40F" + fields: [] + + SPAWNER_DESTACK_GUI: + title: "{description}" + description: "{description}" + color: "E67E22" + fields: [] + + SPAWNER_GUI_OPEN: + title: "{description}" + description: "{description}" + color: "9B59B6" + fields: [] + + SPAWNER_STORAGE_OPEN: + title: "{description}" + description: "{description}" + color: "8E44AD" + fields: [] + + SPAWNER_STACKER_OPEN: + title: "{description}" + description: "{description}" + color: "BB8FCE" + fields: [] + + SPAWNER_EXP_CLAIM: + title: "{description}" + description: "{description}" + color: "2ECC71" + fields: [] + + SPAWNER_SELL_ALL: + title: "{description}" + description: "{description}" + color: "27AE60" + fields: [] + + SPAWNER_ITEM_TAKE_ALL: + title: "{description}" + description: "{description}" + color: "1ABC9C" + fields: [] + + SPAWNER_ITEM_DROP: + title: "{description}" + description: "{description}" + color: "16A085" + fields: [] + + SPAWNER_ITEMS_SORT: + title: "{description}" + description: "{description}" + color: "48C9B0" + fields: [] + + SPAWNER_ITEM_FILTER: + title: "{description}" + description: "{description}" + color: "45B7AF" + fields: [] + + SPAWNER_DROP_PAGE_ITEMS: + title: "{description}" + description: "{description}" + color: "138D75" + fields: [] + + COMMAND_EXECUTE_PLAYER: + title: "{description}" + description: "{description}" + color: "5865F2" + fields: [] + + COMMAND_EXECUTE_CONSOLE: + title: "{description}" + description: "{description}" + color: "3B5998" + fields: [] + + COMMAND_EXECUTE_RCON: + title: "{description}" + description: "{description}" + color: "7289DA" + fields: [] + + SPAWNER_EGG_CHANGE: + title: "{description}" + description: "{description}" + color: "E91E63" + fields: [] \ No newline at end of file