Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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<String, DiscordEmbedField> 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<String, DiscordEmbedField> fields;

public DiscordEmbedConfig(String title, String description, int color, Map<String, DiscordEmbedField> 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<String, DiscordEmbedField> 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;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<SimpleDateFormat> dateFormat =
Expand All @@ -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();
Expand All @@ -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);
}
}

Expand All @@ -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
Expand Down Expand Up @@ -145,7 +150,9 @@ private void writeLogEntries(List<SpawnerLogEntry> 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();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,19 @@ public Map<String, Object> 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("\"");
Expand Down Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -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<String, String> placeholders = buildPlaceholders(entry);
Map<String, String> 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
Expand All @@ -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<String, LoggingMessageService.DiscordEmbedField> 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()) {
Expand All @@ -60,22 +80,23 @@ public static DiscordEmbed buildEmbed(SpawnerLogEntry entry, DiscordWebhookConfi
return embed;
}

private static String buildCompactDescription(SpawnerLogEntry entry, Map<String, String> placeholders, DiscordWebhookConfig config) {
private static String buildCompactDescription(SpawnerLogEntry entry, Map<String, String> 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())
Expand Down Expand Up @@ -132,10 +153,10 @@ private static String formatCompactValue(Object value) {
return "`" + str + "`";
}

private static Map<String, String> buildPlaceholders(SpawnerLogEntry entry) {
private static Map<String, String> buildPlaceholders(SpawnerLogEntry entry, String localizedDescription) {
Map<String, String> 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())));

Expand Down Expand Up @@ -176,6 +197,10 @@ private static String replacePlaceholders(String text, Map<String, String> place
for (Map.Entry<String, String> entry : placeholders.entrySet()) {
result = result.replace("{" + entry.getKey() + "}", entry.getValue());
}

// Replace {newline} with actual newline
result = result.replace("{newline}", "\n");

return result;
}

Expand Down
Loading
Loading