diff --git a/README.md b/README.md index 4c44a36..f362910 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,13 @@ -# ServerStats Server Plugins +# Analyse Server Plugins -Analytics tracking plugins for Minecraft servers. Supports Paper, Velocity, and BungeeCord. +Analytics tracking plugins for Minecraft servers. Supports Spigot 1.8+, Paper, Velocity, and BungeeCord. ## Features - **Automatic Session Tracking** - Player joins, leaves, and playtime - **Heartbeat System** - Regular server health checks - **Custom Events API** - Fluent API for other plugins to track analytics -- **Multi-Platform** - Paper, BungeeCord, and Velocity support +- **Multi-Platform** - Spigot 1.8+, Paper, BungeeCord, and Velocity support - **ACF Commands** - Clean command system using [Annotation Command Framework](https://github.com/aikar/commands) ## Documentation @@ -27,32 +27,33 @@ Download the appropriate plugin for your server: | Platform | Download | |----------|----------| -| Paper/Spigot | `serverstats-paper-x.x.x.jar` | -| BungeeCord | `serverstats-bungeecord-x.x.x.jar` | -| Velocity | `serverstats-velocity-x.x.x.jar` | +| Spigot/Paper | `analyse-spigot-x.x.x.jar` | +| BungeeCord | `analyse-bungeecord-x.x.x.jar` | +| Velocity | `analyse-velocity-x.x.x.jar` | +| Hytale | `analyse-hytale-x.x.x.jar` | ### 2. Configure -Add your API key from [serverstats.net](https://serverstats.net): +Add your API key from [analyse.net](https://analyse.net): ```yaml -# Paper - plugins/ServerStats/config.yml +# Spigot/Paper - plugins/Analyse/config.yml api-key: "your-api-key-here" ``` ### 3. Verify -Run `/serverstats status` to check the connection. +Run `/analyse status` to check the connection. ## For Developers Track custom events from your plugin: ```java -import net.serverstats.api.ServerStats; +import net.analyse.api.Analyse; // Simple event -ServerStats.trackEvent("shop_purchase") +Analyse.trackEvent("shop_purchase") .withPlayer(player.getUniqueId(), player.getName()) .withData("item", "diamond_sword") .withValue(500.0) @@ -67,9 +68,10 @@ See the [Developer API Documentation](docs/api.md) for more examples. |--------|-------------| | `sdk` | Core SDK with HTTP client and data models | | `api` | Public API for other plugins to track events | -| `paper` | Plugin for Paper/Spigot servers | +| `spigot` | Plugin for Spigot 1.8+ and Paper servers | | `velocity` | Plugin for Velocity proxies | | `bungeecord` | Plugin for BungeeCord proxies | +| `hytale` | Plugin for Hytale servers | ## Building @@ -78,34 +80,36 @@ See the [Developer API Documentation](docs/api.md) for more examples. ``` Output JARs: -- `paper/build/libs/serverstats-paper-*.jar` -- `velocity/build/libs/serverstats-velocity-*.jar` -- `bungeecord/build/libs/serverstats-bungeecord-*.jar` + +- `modules/spigot/build/libs/analyse-spigot-*.jar` +- `modules/velocity/build/libs/analyse-velocity-*.jar` +- `modules/bungeecord/build/libs/analyse-bungeecord-*.jar` +- `modules/hytale/build/libs/analyse-hytale-*.jar` ## Requirements - **Java**: 21+ -- **Paper**: 1.21.4+ +- **Spigot/Paper**: Spigot 1.8+ or Paper (see module for tested API level) - **Velocity**: 3.4.0+ - **BungeeCord**: 1.21+ ## Commands ``` -/serverstats - Show plugin status -/serverstats status - Show plugin status -/serverstats reload - Reload configuration -/serverstats debug - Toggle debug mode -/serverstats event - Send a custom event -/serverstats help - Show help +/analyse - Show plugin status +/analyse status - Show plugin status +/analyse reload - Reload configuration (Spigot/Paper only) +/analyse debug - Toggle debug mode +/analyse event - Send a custom event +/analyse help - Show help ``` See [Commands Documentation](docs/commands.md) for details. ## Support -- Website: [serverstats.net](https://serverstats.net) -- API: [api.serverstats.net](https://api.serverstats.net) +- Website: [analyse.net](https://analyse.net) +- API: [api.analyse.net](https://api.analyse.net) ## License diff --git a/build.gradle b/build.gradle index 81bd003..b029c9c 100644 --- a/build.gradle +++ b/build.gradle @@ -11,18 +11,13 @@ allprojects { subprojects { apply plugin: 'java' - java { - sourceCompatibility = JavaVersion.VERSION_21 - targetCompatibility = JavaVersion.VERSION_21 - } - repositories { mavenCentral() maven { url = 'https://repo.papermc.io/repository/maven-public/' } maven { url = 'https://oss.sonatype.org/content/repositories/snapshots' } maven { url = 'https://s01.oss.sonatype.org/content/repositories/snapshots/' } maven { url = 'https://hub.spigotmc.org/nexus/content/repositories/snapshots/' } - maven { url = 'https://repo.aikar.co/content/groups/aikar/' } + maven { url = 'https://repo.aikar.co/content/groups/aikar/' } } dependencies { @@ -36,7 +31,7 @@ subprojects { } tasks.register('publishApi') { - dependsOn ':api:publish' + dependsOn ':modules:api:publish' description = 'Publishes only the API module to Nexus' group = 'publishing' } diff --git a/bungeecord/src/main/resources/bungee.yml b/bungeecord/src/main/resources/bungee.yml deleted file mode 100644 index 8a808e1..0000000 --- a/bungeecord/src/main/resources/bungee.yml +++ /dev/null @@ -1,6 +0,0 @@ -name: ServerStats -version: ${version} -main: com.serverstats.bungeecord.ServerStatsBungee -description: ServerStats tracking plugin -author: VertCode - diff --git a/docs/README.md b/docs/README.md index 0fdacd1..7cbb591 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,6 +1,6 @@ -# ServerStats Plugin Documentation +# Analyse Plugin Documentation -Welcome to the ServerStats plugin documentation. This guide covers installation, configuration, commands, and API usage for developers. +Welcome to the Analyse plugin documentation. This guide covers installation, configuration, commands, and API usage for developers. ## Table of Contents @@ -13,31 +13,31 @@ Welcome to the ServerStats plugin documentation. This guide covers installation, ## Overview -ServerStats is a comprehensive analytics plugin for Minecraft servers. It provides: +Analyse is a comprehensive analytics plugin for Minecraft servers. It provides: - **Player Session Tracking** - Automatically tracks player joins, leaves, and playtime - **Heartbeat System** - Regular server health checks with online player data - **Custom Events API** - Fluent static API for other plugins to track custom analytics events - **A/B Testing** - Built-in support for A/B tests with variant assignment and action execution -- **Multi-Platform Support** - Works on Paper, BungeeCord, and Velocity +- **Multi-Platform Support** - Works on Spigot 1.8+, Paper, BungeeCord, and Velocity ## Platforms | Platform | Server Type | Java Version | |----------|-------------|--------------| -| **Paper** | Single server / backend | Java 21+ | +| **Spigot / Paper** | Single server / backend | Java 21+ (runtime); Spigot API targets 1.8+ | | **BungeeCord** | Proxy | Java 21+ | | **Velocity** | Proxy | Java 21+ | ### Choosing the Right Version -- **Paper**: Use for standalone servers or backend servers behind a proxy +- **Spigot / Paper**: Use for standalone servers or backend servers behind a proxy - **BungeeCord/Velocity**: Use for proxy servers to track cross-server analytics ### Feature Comparison -| Feature | Paper | BungeeCord | Velocity | -|---------|-------|------------|----------| +| Feature | Spigot/Paper | BungeeCord | Velocity | +|---------|----------------|------------|----------| | Session Tracking | ✅ | ✅ | ✅ | | Heartbeat | ✅ | ✅ | ✅ | | Custom Events | ✅ | ✅ | ✅ | @@ -50,11 +50,11 @@ ServerStats is a comprehensive analytics plugin for Minecraft servers. It provid 1. Download the appropriate plugin jar for your platform 2. Place it in your `plugins` folder 3. Start the server to generate the config -4. Add your API key from [serverstats.net](https://serverstats.net) +4. Add your API key from [analyse.net](https://analyse.net) 5. Restart the server ```yaml -# Paper config.yml +# Spigot/Paper config.yml (plugins/Analyse/config.yml) api-key: "your-api-key-here" debug: false instance-id: "auto-generated" @@ -62,5 +62,5 @@ instance-id: "auto-generated" ## Support -- Website: [serverstats.net](https://serverstats.net) -- API Documentation: [api.serverstats.net](https://api.serverstats.net) +- Website: [analyse.net](https://analyse.net) +- API Documentation: [api.analyse.net](https://api.analyse.net) diff --git a/docs/api.md b/docs/api.md index 38a8ace..2c6f8f6 100644 --- a/docs/api.md +++ b/docs/api.md @@ -1,18 +1,18 @@ # Developer API -The ServerStats plugin provides a simple, fluent static API for other plugins to track custom analytics events and interact with A/B tests. +The Analyse plugin provides a simple, fluent static API for other plugins to track custom analytics events and interact with A/B tests. -## Maven/Gradle Setup +## Maven/Gradle setup ### Gradle (Kotlin DSL) ```kotlin repositories { - maven("https://repo.serverstats.net/releases") + maven("https://repo.analyse.net/releases") } dependencies { - compileOnly("net.serverstats:api:0.1.0") + compileOnly("net.analyse:analyse-api:0.7.3") } ``` @@ -20,11 +20,11 @@ dependencies { ```groovy repositories { - maven { url 'https://repo.serverstats.net/releases' } + maven { url 'https://repo.analyse.net/releases' } } dependencies { - compileOnly 'net.serverstats:api:0.1.0' + compileOnly 'net.analyse:analyse-api:0.7.3' } ``` @@ -32,33 +32,33 @@ dependencies { ```xml - serverstats - https://repo.serverstats.net/releases + analyse + https://repo.analyse.net/releases - net.serverstats - api - 0.1.0 + net.analyse + analyse-api + 0.7.3 provided ``` -## Quick Start +## Quick start ```java -import net.serverstats.api.ServerStats; +import net.analyse.api.Analyse; // Simple event -ServerStats.trackEvent("my_event").send(); +Analyse.trackEvent("my_event").send(); // Event with player -ServerStats.trackEvent("player_action") +Analyse.trackEvent("player_action") .withPlayer(player.getUniqueId(), player.getName()) .send(); // Event with data -ServerStats.trackEvent("shop_purchase") +Analyse.trackEvent("shop_purchase") .withPlayer(player.getUniqueId(), player.getName()) .withData("item", "diamond_sword") .withData("price", 500) @@ -68,7 +68,7 @@ ServerStats.trackEvent("shop_purchase") ## Custom Events API -### ServerStats Class +### Analyse class The main entry point for tracking events. @@ -77,10 +77,11 @@ The main entry point for tracking events. Creates a new event builder. ```java -EventBuilder builder = ServerStats.trackEvent("event_name"); +EventBuilder builder = Analyse.trackEvent("event_name"); ``` **Parameters:** + - `name` - The event name (lowercase with underscores recommended) **Returns:** An `EventBuilder` for configuring the event @@ -89,17 +90,17 @@ EventBuilder builder = ServerStats.trackEvent("event_name"); #### isAvailable() -Checks if ServerStats is ready to track events. +Checks if Analyse is ready to track events. ```java -if (ServerStats.isAvailable()) { - ServerStats.trackEvent("my_event").send(); +if (Analyse.isAvailable()) { + Analyse.trackEvent("my_event").send(); } ``` -**Returns:** `true` if ServerStats is initialized and connected +**Returns:** `true` if Analyse is initialized and connected -### EventBuilder Class +### EventBuilder class Fluent builder for configuring events. @@ -108,7 +109,7 @@ Fluent builder for configuring events. Associates the event with a player. ```java -ServerStats.trackEvent("login") +Analyse.trackEvent("login") .withPlayer(player.getUniqueId(), player.getName()) .send(); ``` @@ -118,7 +119,7 @@ ServerStats.trackEvent("login") Associates the event with a player using only UUID. ```java -ServerStats.trackEvent("achievement") +Analyse.trackEvent("achievement") .withPlayer(player.getUniqueId()) .send(); ``` @@ -128,7 +129,7 @@ ServerStats.trackEvent("achievement") Adds a custom data field to the event. ```java -ServerStats.trackEvent("purchase") +Analyse.trackEvent("purchase") .withData("item", "diamond_sword") .withData("quantity", 1) .withData("total_price", 500) @@ -145,7 +146,7 @@ eventData.put("quest_id", "dragon_slayer"); eventData.put("difficulty", "hard"); eventData.put("time_seconds", 3600); -ServerStats.trackEvent("quest_completed") +Analyse.trackEvent("quest_completed") .withData(eventData) .send(); ``` @@ -155,7 +156,7 @@ ServerStats.trackEvent("quest_completed") Sets a numeric value for aggregations (sum, average, etc.). ```java -ServerStats.trackEvent("coins_earned") +Analyse.trackEvent("coins_earned") .withPlayer(player.getUniqueId(), player.getName()) .withValue(1000.0) .send(); @@ -166,7 +167,7 @@ ServerStats.trackEvent("coins_earned") Sends the event asynchronously (fire and forget). ```java -ServerStats.trackEvent("server_start").send(); +Analyse.trackEvent("server_start").send(); ``` #### send(Consumer callback) @@ -174,7 +175,7 @@ ServerStats.trackEvent("server_start").send(); Sends the event with a callback for the response. ```java -ServerStats.trackEvent("important_event") +Analyse.trackEvent("important_event") .send(response -> { if (response != null && response.isSuccess()) { System.out.println("Event tracked: " + response.getEventId()); @@ -186,29 +187,29 @@ ServerStats.trackEvent("important_event") ## A/B Testing API -The ServerStats API provides built-in support for A/B testing. +The Analyse API provides built-in support for A/B testing. -### Get Active Tests +### Get active tests ```java -List tests = ServerStats.getActiveTests(); +List tests = Analyse.getActiveTests(); for (ABTest test : tests) { System.out.println("Test: " + test.getKey() + " - " + test.getName()); } ``` -### Check if Test is Active +### Check if test is active ```java -if (ServerStats.isTestActive("welcome_message_test")) { +if (Analyse.isTestActive("welcome_message_test")) { // Test is running } ``` -### Get Player's Variant +### Get player's variant ```java -String variant = ServerStats.getVariant(player.getUniqueId(), "welcome_message_test"); +String variant = Analyse.getVariant(player.getUniqueId(), "welcome_message_test"); if ("variant_a".equals(variant)) { // Show variant A experience } else if ("variant_b".equals(variant)) { @@ -216,10 +217,10 @@ if ("variant_a".equals(variant)) { } ``` -### Track Conversion +### Track conversion ```java -ServerStats.trackConversion( +Analyse.trackConversion( player.getUniqueId(), player.getName(), "welcome_message_test", @@ -227,7 +228,7 @@ ServerStats.trackConversion( ); ``` -### A/B Test Triggers +### A/B test triggers A/B tests can be triggered by: @@ -238,23 +239,23 @@ A/B tests can be triggered by: | `ON_COMMAND` | Executes when a specific command is run | | `ON_EVENT` | Executes when a specific custom event is tracked | -#### ON_EVENT Trigger +#### ON_EVENT trigger -The `ON_EVENT` trigger allows A/B tests to activate when you track a custom event with `ServerStats.trackEvent()`. This is useful for triggering experiments based on in-game milestones. +The `ON_EVENT` trigger allows A/B tests to activate when you track a custom event with `Analyse.trackEvent()`. This is useful for triggering experiments based on in-game milestones. ```java // When this event is tracked, any A/B test configured // with trigger "ON_EVENT" and event name "tutorial_completed" // will automatically execute its variant actions -ServerStats.trackEvent("tutorial_completed") +Analyse.trackEvent("tutorial_completed") .withPlayer(player.getUniqueId(), player.getName()) .withData("time_seconds", 300) .send(); ``` -**Example Use Case:** Reward players who complete the tutorial with different bonuses based on their A/B test variant. +**Example use case:** Reward players who complete the tutorial with different bonuses based on their A/B test variant. -### A/B Test Actions +### A/B test actions When a test triggers, it can execute actions for the assigned variant: @@ -263,17 +264,17 @@ When a test triggers, it can execute actions for the assigned variant: | `SEND_MESSAGE` | Sends a colored message to the player | All | | `RUN_COMMAND` | Executes a command as console or player | All | -## Complete Examples +## Complete examples -### Track Player Quest Completion +### Track player quest completion ```java public void onQuestComplete(Player player, Quest quest) { - if (!ServerStats.isAvailable()) { + if (!Analyse.isAvailable()) { return; } - ServerStats.trackEvent("quest_completed") + Analyse.trackEvent("quest_completed") .withPlayer(player.getUniqueId(), player.getName()) .withData("quest_id", quest.getId()) .withData("quest_name", quest.getName()) @@ -284,11 +285,11 @@ public void onQuestComplete(Player player, Quest quest) { } ``` -### Track Economy Transactions +### Track economy transactions ```java public void onTransaction(Player player, double amount, String type) { - ServerStats.trackEvent("economy_transaction") + Analyse.trackEvent("economy_transaction") .withPlayer(player.getUniqueId(), player.getName()) .withData("type", type) // "deposit", "withdraw", "transfer" .withData("currency", "coins") @@ -297,11 +298,11 @@ public void onTransaction(Player player, double amount, String type) { } ``` -### Track PvP Combat +### Track PvP combat ```java public void onPlayerKill(Player killer, Player victim) { - ServerStats.trackEvent("pvp_kill") + Analyse.trackEvent("pvp_kill") .withPlayer(killer.getUniqueId(), killer.getName()) .withData("victim_uuid", victim.getUniqueId().toString()) .withData("victim_name", victim.getName()) @@ -311,17 +312,17 @@ public void onPlayerKill(Player killer, Player victim) { } ``` -### Implement A/B Tested Feature +### Implement A/B tested feature ```java public void showWelcomeMessage(Player player) { - if (!ServerStats.isAvailable() || !ServerStats.isTestActive("welcome_test")) { + if (!Analyse.isAvailable() || !Analyse.isTestActive("welcome_test")) { // Default behavior player.sendMessage("Welcome to the server!"); return; } - String variant = ServerStats.getVariant(player.getUniqueId(), "welcome_test"); + String variant = Analyse.getVariant(player.getUniqueId(), "welcome_test"); switch (variant) { case "control" -> player.sendMessage("Welcome to the server!"); @@ -333,7 +334,7 @@ public void showWelcomeMessage(Player player) { } // Track that the player saw the welcome message - ServerStats.trackConversion( + Analyse.trackConversion( player.getUniqueId(), player.getName(), "welcome_test", @@ -342,11 +343,11 @@ public void showWelcomeMessage(Player player) { } ``` -### Track With Callback +### Track with callback ```java public void trackImportantEvent(Player player, String action) { - ServerStats.trackEvent("important_action") + Analyse.trackEvent("important_action") .withPlayer(player.getUniqueId(), player.getName()) .withData("action", action) .send(response -> { @@ -360,19 +361,19 @@ public void trackImportantEvent(Player player, String action) { } ``` -## Best Practices +## Best practices -### 1. Check Availability +### 1. Check availability -Always check if ServerStats is available before tracking: +Always check if Analyse is available before tracking: ```java -if (ServerStats.isAvailable()) { - ServerStats.trackEvent("my_event").send(); +if (Analyse.isAvailable()) { + Analyse.trackEvent("my_event").send(); } ``` -### 2. Use Consistent Event Names +### 2. Use consistent event names Use lowercase with underscores for event names: @@ -388,7 +389,7 @@ Use lowercase with underscores for event names: "PLAYER-DEATH" ``` -### 3. Meaningful Data Keys +### 3. Meaningful data keys Use descriptive, consistent key names: @@ -402,7 +403,7 @@ Use descriptive, consistent key names: .withData("q", 1) ``` -### 4. Use Values for Aggregations +### 4. Use values for aggregations Use `withValue()` for numeric data you want to aggregate (sum, average): @@ -414,7 +415,7 @@ Use `withValue()` for numeric data you want to aggregate (sum, average): .withValue(damageAmount) ``` -### 5. Don't Block the Main Thread +### 5. Don't block the main thread The `send()` method is asynchronous and won't block. Don't add callbacks that do heavy processing: @@ -430,35 +431,35 @@ The `send()` method is asynchronous and won't block. Don't add callbacks that do }); ``` -## Soft Dependency +## Soft dependency -To make ServerStats a soft dependency, check for its presence: +To make Analyse a soft dependency, check for its presence: ```java public class MyPlugin extends JavaPlugin { - private boolean serverstatsEnabled = false; + private boolean analyseEnabled = false; @Override public void onEnable() { - // Check if ServerStats is installed - if (getServer().getPluginManager().getPlugin("ServerStats") != null) { - serverstatsEnabled = true; - getLogger().info("ServerStats integration enabled"); + // Check if Analyse is installed + if (getServer().getPluginManager().getPlugin("Analyse") != null) { + analyseEnabled = true; + getLogger().info("Analyse integration enabled"); } } public void trackEvent(String name) { - if (serverstatsEnabled && ServerStats.isAvailable()) { - ServerStats.trackEvent(name).send(); + if (analyseEnabled && Analyse.isAvailable()) { + Analyse.trackEvent(name).send(); } } } ``` -Or use `plugin.yml` / `paper-plugin.yml` soft dependency: +Or use `plugin.yml` soft dependency: ```yaml name: MyPlugin -softdepend: [ServerStats] +softdepend: [Analyse] ``` diff --git a/docs/commands.md b/docs/commands.md index 413e1ee..12d2b4e 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -1,16 +1,16 @@ # Commands -The ServerStats plugin provides commands to manage the plugin and send test events. +The Analyse plugin provides commands to manage the plugin and send test events. ## Base Command ``` -/serverstats +/analyse ``` -**Aliases**: `/analytics`, `/anl` +**Aliases**: `/ss` (where registered) -**Permission**: `serverstats.command` +**Permission**: `analyse.netmand.status` (default command / status view) ## Subcommands @@ -19,57 +19,59 @@ The ServerStats plugin provides commands to manage the plugin and send test even Shows the current plugin status and connection information. ``` -/serverstats status +/analyse status ``` -**Permission**: `serverstats.command` +**Permission**: `analyse.netmand.status` **Output**: + ``` ────────────────────────────── - ServerStats v0.1.0 + Analyse v0.7.3 ────────────────────────────── Status: ● Connected - API: api.serverstats.net + API: api.analyse.net Players Tracked: 5 Debug: Disabled ────────────────────────────── ``` On proxy servers (BungeeCord/Velocity), additional info is shown: + ``` Servers Configured: 3 ``` -### Reload (Paper only) +### Reload (Spigot/Paper only) Reloads the plugin configuration from disk. ``` -/serverstats reload +/analyse reload ``` -**Permission**: `serverstats.command.reload` +**Permission**: `analyse.netmand.reload` ### Debug Toggles debug mode on/off. Debug mode provides verbose logging for troubleshooting. ``` -/serverstats debug +/analyse debug ``` -**Permission**: `serverstats.command.debug` +**Permission**: `analyse.netmand.debug` ### Event -Sends a custom event to the ServerStats API. Useful for testing. +Sends a custom event to the Analyse API. Useful for testing. ``` -/serverstats event [options] +/analyse event [options] ``` -**Permission**: `serverstats.command.event` +**Permission**: `analyse.netmand.event` #### Options @@ -83,19 +85,19 @@ Sends a custom event to the ServerStats API. Useful for testing. ```bash # Simple test event -/serverstats event test_event +/analyse event test_event # Event with player -/serverstats event player_action --player Steve +/analyse event player_action --player Steve # Event with value -/serverstats event purchase --value 500.00 +/analyse event purchase --value 500.00 # Event with custom data -/serverstats event shop_purchase --player Steve --value 100 --data item=diamond_sword --data quantity=1 +/analyse event shop_purchase --player Steve --value 100 --data item=diamond_sword --data quantity=1 # Complex event -/serverstats event quest_completed --player Steve --data quest_id=dragon_slayer --data difficulty=hard --value 1000 +/analyse event quest_completed --player Steve --data quest_id=dragon_slayer --data difficulty=hard --value 1000 ``` ### Help @@ -103,23 +105,25 @@ Sends a custom event to the ServerStats API. Useful for testing. Shows the help menu with all available commands. ``` -/serverstats help +/analyse help ``` -**Permission**: `serverstats.command` +**Permission**: `analyse.netmand.help` ## Permissions | Permission | Description | Default | |------------|-------------|---------| -| `serverstats.command` | Base permission for all commands | OP | -| `serverstats.command.reload` | Permission to reload configuration (Paper only) | OP | -| `serverstats.command.debug` | Permission to toggle debug mode | OP | -| `serverstats.command.event` | Permission to send custom events | OP | +| `analyse.netmand.status` | View status and default `/analyse` output | OP | +| `analyse.netmand.reload` | Reload configuration (Spigot/Paper only) | OP | +| `analyse.netmand.debug` | Toggle debug mode | OP | +| `analyse.netmand.event` | Send custom events | OP | +| `analyse.netmand.help` | Show help | OP | ## Tab Completion The plugin provides intelligent tab completion powered by ACF (Annotation Command Framework) for: + - Subcommand names - Player names (for `--player` option) - Example event names @@ -130,6 +134,6 @@ The plugin provides intelligent tab completion powered by ACF (Annotation Comman All commands work from the console without the leading slash: ``` -serverstats status -serverstats event server_restart --data reason=update +analyse status +analyse event server_restart --data reason=update ``` diff --git a/docs/configuration.md b/docs/configuration.md index 432fd0c..7c07948 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -2,13 +2,13 @@ This guide covers all configuration options for each platform. -## Paper Configuration +## Spigot / Paper configuration -Location: `plugins/ServerStats/config.yml` +Location: `plugins/Analyse/config.yml` (see `plugin.yml` in the Spigot/Paper module) ```yaml -# Your ServerStats API key -# Get this from your dashboard at https://serverstats.net +# Your Analyse API key +# Get this from your dashboard at https://analyse.net api-key: "your-api-key-here" # Enable debug mode for verbose logging @@ -20,17 +20,17 @@ debug: false instance-id: "auto-generated-uuid" ``` -### Configuration Options +### Configuration options | Option | Type | Default | Description | |--------|------|---------|-------------| -| `api-key` | String | `""` | Your ServerStats API key (required) | +| `api-key` | String | `""` | Your Analyse API key (required) | | `debug` | Boolean | `false` | Enable verbose debug logging | | `instance-id` | String | Auto | Unique identifier for this server | -## BungeeCord Configuration +## BungeeCord configuration -Location: `plugins/ServerStats/config.yml` +Location: `plugins/Analyse/config.yml` ```yaml # Enable debug mode @@ -54,16 +54,16 @@ servers: api-key: "creative-api-key" ``` -### BungeeCord-Specific Options +### BungeeCord-specific options | Option | Type | Description | |--------|------|-------------| | `default-server` | String | Server to use for static API calls | | `servers` | Map | Per-server API key configuration | -## Velocity Configuration +## Velocity configuration -Location: `plugins/serverstats/config.yml` +Location: `plugins/analyse/config.yml` (Velocity plugin id is `analyse`) ```yaml # Enable debug mode @@ -83,7 +83,7 @@ servers: api-key: "survival-api-key" ``` -## Proxy Server Mapping +## Proxy server mapping When using BungeeCord or Velocity, the plugin tracks which backend server each player is connected to. Configure an API key for each server you want to track: @@ -102,7 +102,7 @@ servers: If a player connects to a server without an API key configured, their session won't be tracked for that server. -## Environment Variables +## Environment variables You can use environment variables for sensitive configuration: @@ -110,12 +110,12 @@ You can use environment variables for sensitive configuration: api-key: ${ANALYSE_API_KEY} ``` -## Reloading Configuration +## Reloading configuration After making changes, reload the configuration: ``` -/serverstats reload +/analyse reload ``` -Note: Some changes (like adding new server entries on proxies) may require a full restart. +Note: Config reload is available on **Spigot/Paper** only. On proxies, some changes (like adding new server entries) may require a full restart. diff --git a/docs/installation.md b/docs/installation.md index e950265..8811ba6 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -1,80 +1,90 @@ # Installation -This guide covers installing the ServerStats plugin on different platforms. +This guide covers installing the Analyse plugin on different platforms. ## Requirements - **Java**: 21 or higher -- **Server Software**: Paper 1.21+, BungeeCord, or Velocity 3.x +- **Server software**: Spigot 1.8+, Paper, BungeeCord, or Velocity 3.x -## Paper Installation +## Spigot / Paper installation -1. Download `serverstats-paper-x.x.x.jar` from the releases +1. Download `analyse-spigot-x.x.x.jar` from the releases 2. Place the jar file in your server's `plugins` folder 3. Start the server to generate the configuration file -4. Edit `plugins/ServerStats/config.yml` with your API key -5. Restart the server or run `/serverstats reload` +4. Edit `plugins/Analyse/config.yml` with your API key +5. Restart the server or run `/analyse reload` + +### Spigot / Paper config location -### Paper Config Location ``` plugins/ -└── ServerStats/ +└── Analyse/ └── config.yml ``` -## BungeeCord Installation +## BungeeCord installation -1. Download `serverstats-bungeecord-x.x.x.jar` from the releases +1. Download `analyse-bungeecord-x.x.x.jar` from the releases 2. Place the jar file in your proxy's `plugins` folder 3. Start the proxy to generate the configuration file -4. Edit `plugins/ServerStats/config.yml` with your server API keys +4. Edit `plugins/Analyse/config.yml` with your server API keys 5. Restart the proxy -### BungeeCord Config Location +### BungeeCord config location + ``` plugins/ -└── ServerStats/ +└── Analyse/ └── config.yml ``` -## Velocity Installation +## Velocity installation -1. Download `serverstats-velocity-x.x.x.jar` from the releases +1. Download `analyse-velocity-x.x.x.jar` from the releases 2. Place the jar file in your proxy's `plugins` folder 3. Start the proxy to generate the configuration file -4. Edit `plugins/serverstats/config.yml` with your server API keys +4. Edit `plugins/analyse/config.yml` with your server API keys 5. Restart the proxy -### Velocity Config Location +### Velocity config location + ``` plugins/ -└── serverstats/ +└── analyse/ └── config.yml ``` -## Getting Your API Key +## Hytale installation -1. Log in to your [ServerStats Dashboard](https://serverstats.net) +1. Download `analyse-hytale-x.x.x.jar` from the releases +2. Install per Hytale server mod/plugin instructions for your environment +3. Configure using the generated config and your API key from [analyse.net](https://analyse.net) + +## Getting your API key + +1. Log in to your [Analyse dashboard](https://analyse.net) 2. Navigate to your server settings 3. Copy your API key 4. Paste it in your configuration file -## Verifying Installation +## Verifying installation -After configuration, run `/serverstats status` in-game or console to verify: +After configuration, run `/analyse status` in-game or console to verify: ``` ────────────────────────────── - ServerStats v0.1.0 + Analyse v0.7.3 ────────────────────────────── Status: ● Connected - API: api.serverstats.net + API: api.analyse.net Players Tracked: 10 Debug: Disabled ────────────────────────────── ``` If the status shows "Disconnected", check: + - Your API key is correct - The server has internet access - Firewall allows outbound HTTPS connections diff --git a/gradle.properties b/gradle.properties index 004458b..a92e5be 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ # Project -group=com.serverstats +group=net.analyse version=0.7.3 # Java diff --git a/api/build.gradle b/modules/api/build.gradle similarity index 81% rename from api/build.gradle rename to modules/api/build.gradle index 6074787..24d889a 100644 --- a/api/build.gradle +++ b/modules/api/build.gradle @@ -3,6 +3,10 @@ plugins { id 'maven-publish' } +tasks.withType(JavaCompile).configureEach { + options.release = 8 +} + dependencies { // Gson for plugin messaging serialization (provided by Minecraft servers at runtime) compileOnly "com.google.code.gson:gson:${project.property('gsonVersion')}" @@ -24,9 +28,9 @@ tasks.register('generateBuildConstants') { outputs.dir(outputDir) doLast { - def constantsFile = new File(outputDir, 'com/serverstats/api/BuildConstants.java') + def constantsFile = new File(outputDir, 'net/analyse/api/BuildConstants.java') constantsFile.parentFile.mkdirs() - constantsFile.text = """package com.serverstats.api; + constantsFile.text = """package net.analyse.api; /** * Auto-generated build constants from Gradle. @@ -52,14 +56,14 @@ publishing { maven(MavenPublication) { from components.java - groupId = 'com.serverstats' - artifactId = 'serverstats-api' + groupId = 'net.analyse' + artifactId = 'analyse-api' version = rootProject.version pom { - name = 'ServerStats API' - description = 'Public API for ServerStats analytics plugin' - url = 'https://serverstats.com' + name = 'Analyse API' + description = 'Public API for Analyse analytics plugin' + url = 'https://analyse.net' licenses { license { diff --git a/api/src/main/java/com/serverstats/api/ServerStats.java b/modules/api/src/main/java/net/analyse/api/Analyse.java similarity index 81% rename from api/src/main/java/com/serverstats/api/ServerStats.java rename to modules/api/src/main/java/net/analyse/api/Analyse.java index 37c93e7..c7eb02b 100644 --- a/api/src/main/java/com/serverstats/api/ServerStats.java +++ b/modules/api/src/main/java/net/analyse/api/Analyse.java @@ -1,22 +1,23 @@ -package com.serverstats.api; +package net.analyse.api; -import com.serverstats.api.manager.ABTestManager; -import com.serverstats.api.manager.SessionManager; -import com.serverstats.api.object.abtest.ABTest; -import com.serverstats.api.object.builder.EventBuilder; -import com.serverstats.api.platform.ServerStatsPlatform; +import net.analyse.api.manager.ABTestManager; +import net.analyse.api.manager.SessionManager; +import net.analyse.api.object.abtest.ABTest; +import net.analyse.api.object.builder.EventBuilder; +import net.analyse.api.platform.AnalysePlatform; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.UUID; /** - * Main entry point for the ServerStats API. + * Main entry point for the Analyse API. * Use this class to track custom analytics events and interact with A/B tests. * *

Event tracking example:

*
{@code
  * // Track a player completing a quest
- * ServerStats.trackEvent("quest_completed")
+ * Analyse.trackEvent("quest_completed")
  *     .withPlayer(player.getUniqueId(), player.getName())
  *     .withData("quest_id", "dragon_slayer")
  *     .withData("time_taken_seconds", 3600)
@@ -27,56 +28,56 @@
  * 

A/B testing example:

*
{@code
  * // Get the variant assigned to a player
- * String variant = ServerStats.getVariant(player.getUniqueId(), "welcome-rewards");
+ * String variant = Analyse.getVariant(player.getUniqueId(), "welcome-rewards");
  * if ("diamonds".equals(variant)) {
  *     giveWelcomeDiamonds(player);
  * }
  *
  * // Track a conversion event
- * ServerStats.trackConversion(player.getUniqueId(), player.getName(), "welcome-rewards", "first_purchase");
+ * Analyse.trackConversion(player.getUniqueId(), player.getName(), "welcome-rewards", "first_purchase");
  * }
* *

Accessing managers:

*
{@code
  * // Get the platform for advanced usage
- * ServerStatsPlatform platform = ServerStats.get();
+ * AnalysePlatform platform = Analyse.get();
  * SessionManager sessions = platform.getSessionManager();
  * ABTestManager abTests = platform.getABTestManager();
  * }
*/ -public final class ServerStats { +public final class Analyse { private static EventBuilder.EventSender eventSender; private static boolean apiConnected = false; private static String lastConnectionError = null; - private ServerStats() { + private Analyse() { } /** - * Get the ServerStats platform instance for advanced usage. + * Get the Analyse platform instance for advanced usage. * Use this to access managers and platform-specific functionality. * * @return The platform instance - * @throws IllegalStateException if ServerStats is not initialized + * @throws IllegalStateException if Analyse is not initialized */ - public static ServerStatsPlatform get() { - ServerStatsPlatform platform = ServerStatsProvider.getPlatform(); + public static AnalysePlatform get() { + AnalysePlatform platform = AnalyseProvider.getPlatform(); if (platform == null) { - throw new IllegalStateException("ServerStats is not initialized. Make sure the ServerStats plugin is enabled."); + throw new IllegalStateException("Analyse is not initialized. Make sure the Analyse plugin is enabled."); } return platform; } /** - * Check if ServerStats is available and ready to use. + * Check if Analyse is available and ready to use. * This checks if the plugin is initialized, not if the API connection is working. * - * @return true if ServerStats is initialized and ready + * @return true if Analyse is initialized and ready */ public static boolean isAvailable() { - return ServerStatsProvider.isRegistered(); + return AnalyseProvider.isRegistered(); } /** @@ -116,7 +117,7 @@ public static void setConnectionStatus(boolean connected, String errorMessage) { * @throws IllegalArgumentException if the name is null or blank */ public static EventBuilder trackEvent(String name) { - if (name == null || name.isBlank()) { + if (name == null || name.trim().isEmpty()) { throw new IllegalArgumentException("Event name cannot be null or blank"); } @@ -187,11 +188,11 @@ public static boolean isTestActive(String testKey) { */ public static List getActiveTests() { if (!isAvailable()) { - return List.of(); + return Collections.emptyList(); } ABTestManager manager = get().getABTestManager(); - return manager != null ? manager.getActiveTests() : List.of(); + return manager != null ? manager.getActiveTests() : Collections.emptyList(); } /** @@ -235,7 +236,7 @@ public static void trackConversion(UUID playerUuid, String playerUsername, Strin * Get the session manager * * @return The session manager - * @throws IllegalStateException if ServerStats is not initialized + * @throws IllegalStateException if Analyse is not initialized */ public static SessionManager sessions() { return get().getSessionManager(); @@ -245,7 +246,7 @@ public static SessionManager sessions() { * Get the A/B test manager * * @return The A/B test manager, or null if not available - * @throws IllegalStateException if ServerStats is not initialized + * @throws IllegalStateException if Analyse is not initialized */ public static ABTestManager abTests() { return get().getABTestManager(); diff --git a/api/src/main/java/com/serverstats/api/ServerStatsProvider.java b/modules/api/src/main/java/net/analyse/api/AnalyseProvider.java similarity index 56% rename from api/src/main/java/com/serverstats/api/ServerStatsProvider.java rename to modules/api/src/main/java/net/analyse/api/AnalyseProvider.java index 443c57b..1e426b8 100644 --- a/api/src/main/java/com/serverstats/api/ServerStatsProvider.java +++ b/modules/api/src/main/java/net/analyse/api/AnalyseProvider.java @@ -1,21 +1,21 @@ -package com.serverstats.api; +package net.analyse.api; -import com.serverstats.api.platform.ServerStatsPlatform; +import net.analyse.api.platform.AnalysePlatform; /** * Internal provider that holds the reference to the active platform plugin. - * This allows the static ServerStats API to access the underlying implementation. + * This allows the static Analyse API to access the underlying implementation. * - *

For plugin developers: Use {@link ServerStats} instead of this class.

+ *

For plugin developers: Use {@link Analyse} instead of this class.

* - *

For platform implementations: Call {@link #register(ServerStatsPlatform)} + *

For platform implementations: Call {@link #register(AnalysePlatform)} * in your onEnable and {@link #unregister()} in your onDisable.

*/ -public final class ServerStatsProvider { +public final class AnalyseProvider { - private static ServerStatsPlatform platform; + private static AnalysePlatform platform; - private ServerStatsProvider() { + private AnalyseProvider() { } /** @@ -24,12 +24,12 @@ private ServerStatsProvider() { * @param platform The platform implementation * @throws IllegalStateException if a platform is already registered */ - public static void register(ServerStatsPlatform platform) { - if (ServerStatsProvider.platform != null) { - throw new IllegalStateException("ServerStats platform is already registered"); + public static void register(AnalysePlatform platform) { + if (AnalyseProvider.platform != null) { + throw new IllegalStateException("Analyse platform is already registered"); } - ServerStatsProvider.platform = platform; + AnalyseProvider.platform = platform; } /** @@ -37,7 +37,7 @@ public static void register(ServerStatsPlatform platform) { */ public static void unregister() { platform = null; - ServerStats.setConnectionStatus(false, null); + Analyse.setConnectionStatus(false, null); } /** @@ -45,7 +45,7 @@ public static void unregister() { * * @return The platform implementation, or null if not registered */ - public static ServerStatsPlatform getPlatform() { + public static AnalysePlatform getPlatform() { return platform; } diff --git a/api/src/main/java/com/serverstats/api/addon/AbstractAddonManager.java b/modules/api/src/main/java/net/analyse/api/addon/AbstractAddonManager.java similarity index 98% rename from api/src/main/java/com/serverstats/api/addon/AbstractAddonManager.java rename to modules/api/src/main/java/net/analyse/api/addon/AbstractAddonManager.java index e5bee72..f7a1fcc 100644 --- a/api/src/main/java/com/serverstats/api/addon/AbstractAddonManager.java +++ b/modules/api/src/main/java/net/analyse/api/addon/AbstractAddonManager.java @@ -1,6 +1,6 @@ -package com.serverstats.api.addon; +package net.analyse.api.addon; -import com.serverstats.api.platform.ServerStatsPlatform; +import net.analyse.api.platform.AnalysePlatform; import java.io.File; import java.io.IOException; import java.net.URL; @@ -29,7 +29,7 @@ public abstract class AbstractAddonManager implements AddonManager { private static final String ADDON_FILE_EXTENSION = ".jar"; - private final ServerStatsPlatform platform; + private final AnalysePlatform platform; private final Path addonsFolder; private final Map loadedAddons = new LinkedHashMap<>(); private final Map addonClassLoaders = new HashMap<>(); @@ -39,11 +39,11 @@ public abstract class AbstractAddonManager implements AddonManager { /** * Create a new addon manager * - * @param platform The ServerStats platform instance + * @param platform The Analyse platform instance * @param addonsFolder The folder to load addons from * @param parentClassLoader The parent classloader for addon classloaders (should have access to server and other plugin classes) */ - public AbstractAddonManager(ServerStatsPlatform platform, Path addonsFolder, ClassLoader parentClassLoader) { + public AbstractAddonManager(AnalysePlatform platform, Path addonsFolder, ClassLoader parentClassLoader) { this.platform = platform; this.addonsFolder = addonsFolder; this.parentClassLoader = parentClassLoader; @@ -500,7 +500,7 @@ private boolean disableAddonInternal(LoadedAddonImpl loadedAddon) { * * @return The platform */ - protected ServerStatsPlatform getPlatform() { + protected AnalysePlatform getPlatform() { return platform; } diff --git a/api/src/main/java/com/serverstats/api/addon/Addon.java b/modules/api/src/main/java/net/analyse/api/addon/Addon.java similarity index 77% rename from api/src/main/java/com/serverstats/api/addon/Addon.java rename to modules/api/src/main/java/net/analyse/api/addon/Addon.java index 0aa4553..eb92c6d 100644 --- a/api/src/main/java/com/serverstats/api/addon/Addon.java +++ b/modules/api/src/main/java/net/analyse/api/addon/Addon.java @@ -1,15 +1,15 @@ -package com.serverstats.api.addon; +package net.analyse.api.addon; -import com.serverstats.api.platform.ServerStatsPlatform; +import net.analyse.api.platform.AnalysePlatform; import java.nio.file.Path; /** - * Base interface for all ServerStats addons. + * Base interface for all Analyse addons. * Addons must implement this interface and be annotated with {@link AddonInfo}. * *

Addon lifecycle:

*
    - *
  1. {@link #onLoad(ServerStatsPlatform, AddonLogger, Path)} - Called when addon is loaded
  2. + *
  3. {@link #onLoad(AnalysePlatform, AddonLogger, Path)} - Called when addon is loaded
  4. *
  5. {@link #onEnable()} - Called when addon is enabled
  6. *
  7. {@link #onDisable()} - Called when addon is disabled
  8. *
@@ -23,12 +23,12 @@ * ) * public class ExampleAddon implements Addon { * - * private ServerStatsPlatform platform; + * private AnalysePlatform platform; * private AddonLogger logger; * private Path dataFolder; * * @Override - * public void onLoad(ServerStatsPlatform platform, AddonLogger logger, Path dataFolder) { + * public void onLoad(AnalysePlatform platform, AddonLogger logger, Path dataFolder) { * this.platform = platform; * this.logger = logger; * this.dataFolder = dataFolder; @@ -52,11 +52,11 @@ public interface Addon { * Called when the addon is loaded. This is where you should store references * to the platform, logger, and data folder. * - * @param platform The ServerStats platform instance + * @param platform The Analyse platform instance * @param logger The addon's logger * @param dataFolder The addon's data folder for configuration files */ - void onLoad(ServerStatsPlatform platform, AddonLogger logger, Path dataFolder); + void onLoad(AnalysePlatform platform, AddonLogger logger, Path dataFolder); /** * Called when the addon is enabled. This is where you should register diff --git a/api/src/main/java/com/serverstats/api/addon/AddonInfo.java b/modules/api/src/main/java/net/analyse/api/addon/AddonInfo.java similarity index 95% rename from api/src/main/java/com/serverstats/api/addon/AddonInfo.java rename to modules/api/src/main/java/net/analyse/api/addon/AddonInfo.java index e9a4207..f7d417e 100644 --- a/api/src/main/java/com/serverstats/api/addon/AddonInfo.java +++ b/modules/api/src/main/java/net/analyse/api/addon/AddonInfo.java @@ -1,4 +1,4 @@ -package com.serverstats.api.addon; +package net.analyse.api.addon; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -6,7 +6,7 @@ import java.lang.annotation.Target; /** - * Annotation to define metadata for a ServerStats addon. + * Annotation to define metadata for a Analyse addon. * This annotation must be present on the main addon class. * *

Example usage:

diff --git a/api/src/main/java/com/serverstats/api/addon/AddonLogger.java b/modules/api/src/main/java/net/analyse/api/addon/AddonLogger.java similarity index 97% rename from api/src/main/java/com/serverstats/api/addon/AddonLogger.java rename to modules/api/src/main/java/net/analyse/api/addon/AddonLogger.java index 0ea9816..8e72dcd 100644 --- a/api/src/main/java/com/serverstats/api/addon/AddonLogger.java +++ b/modules/api/src/main/java/net/analyse/api/addon/AddonLogger.java @@ -1,4 +1,4 @@ -package com.serverstats.api.addon; +package net.analyse.api.addon; /** * Logger interface for addons to use for consistent logging. diff --git a/api/src/main/java/com/serverstats/api/addon/AddonManager.java b/modules/api/src/main/java/net/analyse/api/addon/AddonManager.java similarity index 98% rename from api/src/main/java/com/serverstats/api/addon/AddonManager.java rename to modules/api/src/main/java/net/analyse/api/addon/AddonManager.java index ebbb1f1..15bdeca 100644 --- a/api/src/main/java/com/serverstats/api/addon/AddonManager.java +++ b/modules/api/src/main/java/net/analyse/api/addon/AddonManager.java @@ -1,4 +1,4 @@ -package com.serverstats.api.addon; +package net.analyse.api.addon; import java.util.Collection; import java.util.Optional; diff --git a/api/src/main/java/com/serverstats/api/addon/LoadedAddon.java b/modules/api/src/main/java/net/analyse/api/addon/LoadedAddon.java similarity index 97% rename from api/src/main/java/com/serverstats/api/addon/LoadedAddon.java rename to modules/api/src/main/java/net/analyse/api/addon/LoadedAddon.java index 9aff539..d08a60b 100644 --- a/api/src/main/java/com/serverstats/api/addon/LoadedAddon.java +++ b/modules/api/src/main/java/net/analyse/api/addon/LoadedAddon.java @@ -1,4 +1,4 @@ -package com.serverstats.api.addon; +package net.analyse.api.addon; import java.nio.file.Path; diff --git a/api/src/main/java/com/serverstats/api/exception/ServerStatsException.java b/modules/api/src/main/java/net/analyse/api/exception/AnalyseException.java similarity index 72% rename from api/src/main/java/com/serverstats/api/exception/ServerStatsException.java rename to modules/api/src/main/java/net/analyse/api/exception/AnalyseException.java index c53f75b..4ec4db1 100644 --- a/api/src/main/java/com/serverstats/api/exception/ServerStatsException.java +++ b/modules/api/src/main/java/net/analyse/api/exception/AnalyseException.java @@ -1,9 +1,9 @@ -package com.serverstats.api.exception; +package net.analyse.api.exception; /** - * Exception thrown when an ServerStats API operation fails + * Exception thrown when an Analyse API operation fails */ -public class ServerStatsException extends Exception { +public class AnalyseException extends Exception { private final int statusCode; private final ErrorType errorType; @@ -14,7 +14,7 @@ public class ServerStatsException extends Exception { * @param statusCode The HTTP status code * @param message The error message */ - public ServerStatsException(int statusCode, String message) { + public AnalyseException(int statusCode, String message) { super(message); this.statusCode = statusCode; this.errorType = ErrorType.fromStatusCode(statusCode); @@ -26,7 +26,7 @@ public ServerStatsException(int statusCode, String message) { * @param message The error message * @param cause The underlying cause */ - public ServerStatsException(String message, Throwable cause) { + public AnalyseException(String message, Throwable cause) { super(message, cause); this.statusCode = 0; this.errorType = ErrorType.NETWORK_ERROR; @@ -96,14 +96,23 @@ public enum ErrorType { * @return The corresponding error type */ public static ErrorType fromStatusCode(int statusCode) { - return switch (statusCode) { - case 400 -> BAD_REQUEST; - case 401 -> UNAUTHORIZED; - case 404 -> NOT_FOUND; - case 429 -> RATE_LIMITED; - case 500, 502, 503, 504 -> SERVER_ERROR; - default -> UNKNOWN; - }; + switch (statusCode) { + case 400: + return BAD_REQUEST; + case 401: + return UNAUTHORIZED; + case 404: + return NOT_FOUND; + case 429: + return RATE_LIMITED; + case 500: + case 502: + case 503: + case 504: + return SERVER_ERROR; + default: + return UNKNOWN; + } } } } diff --git a/api/src/main/java/com/serverstats/api/manager/ABTestManager.java b/modules/api/src/main/java/net/analyse/api/manager/ABTestManager.java similarity index 94% rename from api/src/main/java/com/serverstats/api/manager/ABTestManager.java rename to modules/api/src/main/java/net/analyse/api/manager/ABTestManager.java index bef9857..69e8acd 100644 --- a/api/src/main/java/com/serverstats/api/manager/ABTestManager.java +++ b/modules/api/src/main/java/net/analyse/api/manager/ABTestManager.java @@ -1,6 +1,6 @@ -package com.serverstats.api.manager; +package net.analyse.api.manager; -import com.serverstats.api.object.abtest.ABTest; +import net.analyse.api.object.abtest.ABTest; import java.util.List; import java.util.UUID; diff --git a/api/src/main/java/com/serverstats/api/manager/SessionManager.java b/modules/api/src/main/java/net/analyse/api/manager/SessionManager.java similarity index 91% rename from api/src/main/java/com/serverstats/api/manager/SessionManager.java rename to modules/api/src/main/java/net/analyse/api/manager/SessionManager.java index 5aa57ee..dd3ffa4 100644 --- a/api/src/main/java/com/serverstats/api/manager/SessionManager.java +++ b/modules/api/src/main/java/net/analyse/api/manager/SessionManager.java @@ -1,6 +1,6 @@ -package com.serverstats.api.manager; +package net.analyse.api.manager; -import com.serverstats.api.session.PlayerSession; +import net.analyse.api.session.PlayerSession; import java.util.Collection; import java.util.Optional; import java.util.UUID; diff --git a/api/src/main/java/com/serverstats/api/messaging/ServerStatsMessageParser.java b/modules/api/src/main/java/net/analyse/api/messaging/AnalyseMessageParser.java similarity index 91% rename from api/src/main/java/com/serverstats/api/messaging/ServerStatsMessageParser.java rename to modules/api/src/main/java/net/analyse/api/messaging/AnalyseMessageParser.java index 96b6602..b444201 100644 --- a/api/src/main/java/com/serverstats/api/messaging/ServerStatsMessageParser.java +++ b/modules/api/src/main/java/net/analyse/api/messaging/AnalyseMessageParser.java @@ -1,4 +1,4 @@ -package com.serverstats.api.messaging; +package net.analyse.api.messaging; import com.google.gson.Gson; import com.google.gson.GsonBuilder; @@ -11,15 +11,15 @@ import java.util.UUID; /** - * Parser for ServerStats plugin messages. + * Parser for Analyse plugin messages. * Used by proxy plugins to parse incoming messages from backend servers. */ -public final class ServerStatsMessageParser { +public final class AnalyseMessageParser { private static final Gson GSON = new GsonBuilder().create(); private static final Type MAP_TYPE = new TypeToken>() {}.getType(); - private ServerStatsMessageParser() { + private AnalyseMessageParser() { } /** @@ -34,9 +34,9 @@ public static ParsedMessage parse(byte[] data) throws IOException { String type = in.readUTF(); - if (ServerStatsMessaging.TYPE_EVENT.equals(type)) { + if (AnalyseMessaging.TYPE_EVENT.equals(type)) { return parseEventMessage(in); - } else if (ServerStatsMessaging.TYPE_CONVERSION.equals(type)) { + } else if (AnalyseMessaging.TYPE_CONVERSION.equals(type)) { return parseConversionMessage(in); } else { throw new IOException("Unknown message type: " + type); @@ -117,7 +117,7 @@ public String getType() { * @return true if event message */ public boolean isEvent() { - return ServerStatsMessaging.TYPE_EVENT.equals(type); + return AnalyseMessaging.TYPE_EVENT.equals(type); } /** @@ -126,7 +126,7 @@ public boolean isEvent() { * @return true if conversion message */ public boolean isConversion() { - return ServerStatsMessaging.TYPE_CONVERSION.equals(type); + return AnalyseMessaging.TYPE_CONVERSION.equals(type); } } @@ -157,7 +157,7 @@ public EventMessage( Map data, Double value ) { - super(ServerStatsMessaging.TYPE_EVENT); + super(AnalyseMessaging.TYPE_EVENT); this.eventName = eventName; this.playerUuid = playerUuid; this.playerUsername = playerUsername; @@ -210,7 +210,7 @@ public ConversionMessage( String testKey, String conversionEvent ) { - super(ServerStatsMessaging.TYPE_CONVERSION); + super(AnalyseMessaging.TYPE_CONVERSION); this.playerUuid = playerUuid; this.playerUsername = playerUsername; this.testKey = testKey; diff --git a/api/src/main/java/com/serverstats/api/messaging/ServerStatsMessaging.java b/modules/api/src/main/java/net/analyse/api/messaging/AnalyseMessaging.java similarity index 91% rename from api/src/main/java/com/serverstats/api/messaging/ServerStatsMessaging.java rename to modules/api/src/main/java/net/analyse/api/messaging/AnalyseMessaging.java index 316bff1..8c958be 100644 --- a/api/src/main/java/com/serverstats/api/messaging/ServerStatsMessaging.java +++ b/modules/api/src/main/java/net/analyse/api/messaging/AnalyseMessaging.java @@ -1,4 +1,4 @@ -package com.serverstats.api.messaging; +package net.analyse.api.messaging; import com.google.gson.Gson; import com.google.gson.GsonBuilder; @@ -10,13 +10,13 @@ import java.util.UUID; /** - * Utility class for sending ServerStats events via plugin messaging. + * Utility class for sending Analyse events via plugin messaging. * Use this on backend servers to send events through the proxy. * *

Example usage on a Paper backend server:

*
{@code
  * // Send an event through the proxy
- * byte[] message = ServerStatsMessaging.createEventMessage(
+ * byte[] message = AnalyseMessaging.createEventMessage(
  *     "crate_opened",
  *     player.getUniqueId(),
  *     player.getName(),
@@ -24,15 +24,15 @@
  *     100.0
  * );
  *
- * player.sendPluginMessage(plugin, ServerStatsMessaging.CHANNEL, message);
+ * player.sendPluginMessage(plugin, AnalyseMessaging.CHANNEL, message);
  * }
*/ -public final class ServerStatsMessaging { +public final class AnalyseMessaging { /** - * The plugin messaging channel for ServerStats events + * The plugin messaging channel for Analyse events */ - public static final String CHANNEL = "serverstats:events"; + public static final String CHANNEL = "analyse:events"; /** * Message type for custom events @@ -46,7 +46,7 @@ public final class ServerStatsMessaging { private static final Gson GSON = new GsonBuilder().create(); - private ServerStatsMessaging() { + private AnalyseMessaging() { } /** diff --git a/api/src/main/java/com/serverstats/api/object/abtest/ABTest.java b/modules/api/src/main/java/net/analyse/api/object/abtest/ABTest.java similarity index 98% rename from api/src/main/java/com/serverstats/api/object/abtest/ABTest.java rename to modules/api/src/main/java/net/analyse/api/object/abtest/ABTest.java index 41438f8..2739ae8 100644 --- a/api/src/main/java/com/serverstats/api/object/abtest/ABTest.java +++ b/modules/api/src/main/java/net/analyse/api/object/abtest/ABTest.java @@ -1,4 +1,4 @@ -package com.serverstats.api.object.abtest; +package net.analyse.api.object.abtest; import java.util.List; import java.util.UUID; diff --git a/api/src/main/java/com/serverstats/api/object/abtest/Variant.java b/modules/api/src/main/java/net/analyse/api/object/abtest/Variant.java similarity index 92% rename from api/src/main/java/com/serverstats/api/object/abtest/Variant.java rename to modules/api/src/main/java/net/analyse/api/object/abtest/Variant.java index e4fcd2f..8737f01 100644 --- a/api/src/main/java/com/serverstats/api/object/abtest/Variant.java +++ b/modules/api/src/main/java/net/analyse/api/object/abtest/Variant.java @@ -1,4 +1,4 @@ -package com.serverstats.api.object.abtest; +package net.analyse.api.object.abtest; /** * Represents a variant in an A/B test diff --git a/api/src/main/java/com/serverstats/api/object/builder/EventBuilder.java b/modules/api/src/main/java/net/analyse/api/object/builder/EventBuilder.java similarity index 85% rename from api/src/main/java/com/serverstats/api/object/builder/EventBuilder.java rename to modules/api/src/main/java/net/analyse/api/object/builder/EventBuilder.java index 8ded4ce..59cd0eb 100644 --- a/api/src/main/java/com/serverstats/api/object/builder/EventBuilder.java +++ b/modules/api/src/main/java/net/analyse/api/object/builder/EventBuilder.java @@ -1,8 +1,8 @@ -package com.serverstats.api.object.builder; +package net.analyse.api.object.builder; -import com.serverstats.api.ServerStats; -import com.serverstats.api.ServerStatsProvider; -import com.serverstats.api.platform.ServerStatsPlatform; +import net.analyse.api.Analyse; +import net.analyse.api.AnalyseProvider; +import net.analyse.api.platform.AnalysePlatform; import java.util.HashMap; import java.util.Map; import java.util.UUID; @@ -10,11 +10,11 @@ /** * Fluent builder for constructing and sending custom events. - * Use {@link ServerStats#trackEvent(String)} to create a new builder. + * Use {@link Analyse#trackEvent(String)} to create a new builder. * *

Example:

*
{@code
- * ServerStats.trackEvent("purchase")
+ * Analyse.trackEvent("purchase")
  *     .withPlayer(player.getUniqueId(), player.getName())
  *     .withData("item", "diamond_sword")
  *     .withData("price", 100)
@@ -163,15 +163,15 @@ public void send() {
    * @param callback Optional callback to receive success (true) or failure (false)
    */
   public void send(Consumer callback) {
-    ServerStatsPlatform platform = ServerStatsProvider.getPlatform();
+    AnalysePlatform platform = AnalyseProvider.getPlatform();
     if (platform == null) {
-      throw new IllegalStateException("ServerStats is not initialized. Make sure the ServerStats plugin is enabled.");
+      throw new IllegalStateException("Analyse is not initialized. Make sure the Analyse plugin is enabled.");
     }
 
     // Delegate to internal sender - this will be set by the platform implementation
-    EventSender sender = ServerStats.getEventSender();
+    EventSender sender = Analyse.getEventSender();
     if (sender == null) {
-      throw new IllegalStateException("ServerStats event sender is not available. Check your configuration.");
+      throw new IllegalStateException("Analyse event sender is not available. Check your configuration.");
     }
 
     sender.send(this, callback);
diff --git a/api/src/main/java/com/serverstats/api/platform/ServerStatsPlatform.java b/modules/api/src/main/java/net/analyse/api/platform/AnalysePlatform.java
similarity index 78%
rename from api/src/main/java/com/serverstats/api/platform/ServerStatsPlatform.java
rename to modules/api/src/main/java/net/analyse/api/platform/AnalysePlatform.java
index b76a9e5..3ff6600 100644
--- a/api/src/main/java/com/serverstats/api/platform/ServerStatsPlatform.java
+++ b/modules/api/src/main/java/net/analyse/api/platform/AnalysePlatform.java
@@ -1,24 +1,24 @@
-package com.serverstats.api.platform;
+package net.analyse.api.platform;
 
-import com.serverstats.api.addon.AddonManager;
-import com.serverstats.api.manager.ABTestManager;
-import com.serverstats.api.manager.SessionManager;
+import net.analyse.api.addon.AddonManager;
+import net.analyse.api.manager.ABTestManager;
+import net.analyse.api.manager.SessionManager;
 
 /**
  * Interface for platform-specific plugin implementations.
  * Each platform (Paper, BungeeCord, Velocity) implements this to provide
  * access to managers and logging.
  *
- * 

Other plugins should use {@link com.serverstats.api.ServerStats} for most operations, + *

Other plugins should use {@link net.analyse.api.Analyse} for most operations, * but can access this interface for advanced functionality:

*
{@code
- * ServerStatsPlatform platform = ServerStats.get();
+ * AnalysePlatform platform = Analyse.get();
  * SessionManager sessions = platform.getSessionManager();
  * ABTestManager abTests = platform.getABTestManager();
  * AddonManager addons = platform.getAddonManager();
  * }
*/ -public interface ServerStatsPlatform { +public interface AnalysePlatform { /** * Get the session manager for accessing player sessions diff --git a/api/src/main/java/com/serverstats/api/session/PlayerSession.java b/modules/api/src/main/java/net/analyse/api/session/PlayerSession.java similarity index 96% rename from api/src/main/java/com/serverstats/api/session/PlayerSession.java rename to modules/api/src/main/java/net/analyse/api/session/PlayerSession.java index edb4e2e..e29b9ab 100644 --- a/api/src/main/java/com/serverstats/api/session/PlayerSession.java +++ b/modules/api/src/main/java/net/analyse/api/session/PlayerSession.java @@ -1,4 +1,4 @@ -package com.serverstats.api.session; +package net.analyse.api.session; import java.time.Instant; import java.util.UUID; diff --git a/bungeecord/build.gradle b/modules/bungeecord/build.gradle similarity index 78% rename from bungeecord/build.gradle rename to modules/bungeecord/build.gradle index 91d4091..41b3e06 100644 --- a/bungeecord/build.gradle +++ b/modules/bungeecord/build.gradle @@ -3,15 +3,19 @@ plugins { id 'com.gradleup.shadow' } +tasks.withType(JavaCompile).configureEach { + options.release = 8 +} + dependencies { - implementation project(':api') - implementation project(':sdk') + implementation project(':modules:api') + implementation project(':modules:sdk') implementation "co.aikar:acf-bungee:${project.property('acfVersion')}" compileOnly "net.md-5:bungeecord-api:${project.property('bungeecordVersion')}" } tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { - archiveBaseName.set('serverstats-bungeecord') + archiveBaseName.set('analyse-bungeecord') archiveClassifier.set('') // BungeeCord already includes Gson, so exclude it dependencies { diff --git a/bungeecord/src/main/java/com/serverstats/bungeecord/ServerStatsBungee.java b/modules/bungeecord/src/main/java/net/analyse/bungeecord/AnalyseBungee.java similarity index 72% rename from bungeecord/src/main/java/com/serverstats/bungeecord/ServerStatsBungee.java rename to modules/bungeecord/src/main/java/net/analyse/bungeecord/AnalyseBungee.java index f73f6e1..ce6d1d5 100644 --- a/bungeecord/src/main/java/com/serverstats/bungeecord/ServerStatsBungee.java +++ b/modules/bungeecord/src/main/java/net/analyse/bungeecord/AnalyseBungee.java @@ -1,44 +1,45 @@ -package com.serverstats.bungeecord; +package net.analyse.bungeecord; import co.aikar.commands.BungeeCommandManager; -import com.serverstats.api.ServerStats; -import com.serverstats.api.ServerStatsProvider; -import com.serverstats.api.BuildConstants; -import com.serverstats.api.addon.AddonManager; -import com.serverstats.api.exception.ServerStatsException; -import com.serverstats.api.object.builder.EventBuilder; -import com.serverstats.api.platform.ServerStatsPlatform; -import com.serverstats.api.messaging.ServerStatsMessaging; -import com.serverstats.bungeecord.addon.BungeeAddonManager; -import com.serverstats.bungeecord.manager.ABTestManager; -import com.serverstats.bungeecord.command.ServerStatsCommand; -import com.serverstats.bungeecord.config.ServerStatsBungeeConfig; -import com.serverstats.bungeecord.listener.ActivityListener; -import com.serverstats.bungeecord.listener.PlayerListener; -import com.serverstats.bungeecord.listener.PluginMessageListener; -import com.serverstats.bungeecord.manager.SessionManager; -import com.serverstats.bungeecord.task.HeartbeatTask; -import com.serverstats.bungeecord.update.BungeeUpdateChecker; -import com.serverstats.sdk.ServerStatsCallback; -import com.serverstats.sdk.ServerStatsClient; -import com.serverstats.sdk.request.EventRequest; -import com.serverstats.sdk.response.EventResponse; +import net.analyse.api.Analyse; +import net.analyse.api.AnalyseProvider; +import net.analyse.api.BuildConstants; +import net.analyse.api.addon.AddonManager; +import net.analyse.api.exception.AnalyseException; +import net.analyse.api.object.builder.EventBuilder; +import net.analyse.api.platform.AnalysePlatform; +import net.analyse.api.messaging.AnalyseMessaging; +import net.analyse.bungeecord.addon.BungeeAddonManager; +import net.analyse.bungeecord.manager.ABTestManager; +import net.analyse.bungeecord.command.AnalyseCommand; +import net.analyse.bungeecord.config.AnalyseBungeeConfig; +import net.analyse.bungeecord.listener.ActivityListener; +import net.analyse.bungeecord.listener.PlayerListener; +import net.analyse.bungeecord.listener.PluginMessageListener; +import net.analyse.bungeecord.manager.SessionManager; +import net.analyse.bungeecord.task.HeartbeatTask; +import net.analyse.bungeecord.update.BungeeUpdateChecker; +import net.analyse.sdk.AnalyseCallback; +import net.analyse.sdk.AnalyseClient; +import net.analyse.sdk.request.EventRequest; +import net.analyse.sdk.response.EventResponse; import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.api.plugin.Plugin; import net.md_5.bungee.api.scheduler.ScheduledTask; +import java.io.File; import java.io.IOException; import java.net.InetSocketAddress; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; /** - * ServerStats plugin for BungeeCord proxy + * Analyse plugin for BungeeCord proxy */ -public class ServerStatsBungee extends Plugin implements ServerStatsPlatform { +public class AnalyseBungee extends Plugin implements AnalysePlatform { private static final int HEARTBEAT_INTERVAL_SECONDS = 30; - private ServerStatsBungeeConfig pluginConfig; + private AnalyseBungeeConfig pluginConfig; private SessionManager sessionManager; private ABTestManager abTestManager; private BungeeAddonManager addonManager; @@ -48,7 +49,10 @@ public class ServerStatsBungee extends Plugin implements ServerStatsPlatform { @Override public void onEnable() { - getLogger().info("Initializing ServerStats..."); + getLogger().info("Initializing Analyse..."); + + // Migrate old "ServerStats" data folder if it exists + migrateDataFolder(); // Load configuration if (!loadConfig()) { @@ -66,16 +70,16 @@ public void onEnable() { getProxy().getPluginManager().registerListener(this, new ActivityListener(this)); // Register plugin message channel for backend server communication - getProxy().registerChannel(ServerStatsMessaging.CHANNEL); + getProxy().registerChannel(AnalyseMessaging.CHANNEL); getProxy().getPluginManager().registerListener(this, new PluginMessageListener(this)); - getLogger().info("Registered plugin message channel: " + ServerStatsMessaging.CHANNEL); + getLogger().info("Registered plugin message channel: " + AnalyseMessaging.CHANNEL); // Register with the API provider if a default server is configured if (playerListener.getDefaultClient() != null) { - ServerStatsProvider.register(this); + AnalyseProvider.register(this); - // Set up the event sender for ServerStats.trackEvent() - ServerStats.setEventSender(this::sendEvent); + // Set up the event sender for Analyse.trackEvent() + Analyse.setEventSender(this::sendEvent); // Initialize A/B test manager abTestManager = new ABTestManager(this); @@ -84,7 +88,7 @@ public void onEnable() { // Register commands using ACF BungeeCommandManager commandManager = new BungeeCommandManager(this); - commandManager.registerCommand(new ServerStatsCommand(this)); + commandManager.registerCommand(new AnalyseCommand(this)); // Start heartbeat task (after playerListener is initialized) startHeartbeatTask(); @@ -103,7 +107,7 @@ public void onEnable() { addonManager.loadAddons(); addonManager.enableAddons(); - getLogger().info(String.format("ServerStats initialized with %d server(s) configured", + getLogger().info(String.format("Analyse initialized with %d server(s) configured", pluginConfig.getServers().size())); } @@ -114,7 +118,7 @@ public void onEnable() { * @param callback Optional callback for result */ private void sendEvent(EventBuilder event, Consumer callback) { - ServerStatsClient client = getClient(); + AnalyseClient client = getClient(); if (client == null) { if (callback != null) { callback.accept(false); @@ -139,7 +143,7 @@ private void sendEvent(EventBuilder event, Consumer callback) { event.getValue() ); - client.trackEvent(request, new ServerStatsCallback<>() { + client.trackEvent(request, new AnalyseCallback() { @Override public void onSuccess(EventResponse response) { if (isDebugEnabled()) { @@ -153,7 +157,7 @@ public void onSuccess(EventResponse response) { } @Override - public void onError(ServerStatsException exception) { + public void onError(AnalyseException exception) { logWarning(String.format("Failed to track event '%s': %s", event.getName(), exception.getMessage())); @@ -202,7 +206,7 @@ private void initializeOnlinePlayers() { @Override public void onDisable() { - getLogger().info("Shutting down ServerStats..."); + getLogger().info("Shutting down Analyse..."); // Disable all addons first if (addonManager != null) { @@ -210,10 +214,10 @@ public void onDisable() { } // Unregister from the API provider - ServerStatsProvider.unregister(); + AnalyseProvider.unregister(); // Clear the event sender - ServerStats.setEventSender(null); + Analyse.setEventSender(null); // Stop A/B test manager if (abTestManager != null) { @@ -230,7 +234,22 @@ public void onDisable() { playerListener.shutdown(); } - getLogger().info("ServerStats shutdown complete"); + getLogger().info("Analyse shutdown complete"); + } + + /** + * Migrate the data folder from the old "ServerStats" name to "Analyse". + * Automatically renames plugins/ServerStats to plugins/Analyse if it exists. + */ + private void migrateDataFolder() { + File oldFolder = new File(getDataFolder().getParentFile(), "ServerStats"); + if (oldFolder.exists() && oldFolder.isDirectory() && !getDataFolder().exists()) { + if (oldFolder.renameTo(getDataFolder())) { + getLogger().info("Migrated data folder from ServerStats to Analyse"); + } else { + getLogger().warning("Failed to migrate data folder from ServerStats to Analyse. Please rename it manually."); + } + } } /** @@ -240,7 +259,7 @@ public void onDisable() { */ private boolean loadConfig() { try { - pluginConfig = ServerStatsBungeeConfig.load(getDataFolder().toPath()); + pluginConfig = AnalyseBungeeConfig.load(getDataFolder().toPath()); } catch (IOException e) { getLogger().severe(String.format("Failed to load configuration: %s", e.getMessage())); return false; @@ -291,7 +310,7 @@ public void debug(String format, Object... args) { } } - // ========== ServerStatsPlatform Interface Methods ========== + // ========== AnalysePlatform Interface Methods ========== @Override public SessionManager getSessionManager() { @@ -335,16 +354,16 @@ public String getVersion() { * * @return The plugin config */ - public ServerStatsBungeeConfig getPluginConfig() { + public AnalyseBungeeConfig getPluginConfig() { return pluginConfig; } /** * Get the SDK client (from player listener) * - * @return The ServerStats client, or null + * @return The Analyse client, or null */ - public ServerStatsClient getClient() { + public AnalyseClient getClient() { return playerListener != null ? playerListener.getDefaultClient() : null; } diff --git a/bungeecord/src/main/java/com/serverstats/bungeecord/addon/BungeeAddonLogger.java b/modules/bungeecord/src/main/java/net/analyse/bungeecord/addon/BungeeAddonLogger.java similarity index 87% rename from bungeecord/src/main/java/com/serverstats/bungeecord/addon/BungeeAddonLogger.java rename to modules/bungeecord/src/main/java/net/analyse/bungeecord/addon/BungeeAddonLogger.java index fdd4685..4192a32 100644 --- a/bungeecord/src/main/java/com/serverstats/bungeecord/addon/BungeeAddonLogger.java +++ b/modules/bungeecord/src/main/java/net/analyse/bungeecord/addon/BungeeAddonLogger.java @@ -1,7 +1,7 @@ -package com.serverstats.bungeecord.addon; +package net.analyse.bungeecord.addon; -import com.serverstats.api.addon.AddonLogger; -import com.serverstats.bungeecord.ServerStatsBungee; +import net.analyse.api.addon.AddonLogger; +import net.analyse.bungeecord.AnalyseBungee; import java.util.logging.Level; /** @@ -9,7 +9,7 @@ */ public class BungeeAddonLogger implements AddonLogger { - private final ServerStatsBungee plugin; + private final AnalyseBungee plugin; private final String prefix; /** @@ -18,7 +18,7 @@ public class BungeeAddonLogger implements AddonLogger { * @param plugin The main plugin instance * @param addonName The addon display name */ - public BungeeAddonLogger(ServerStatsBungee plugin, String addonName) { + public BungeeAddonLogger(AnalyseBungee plugin, String addonName) { this.plugin = plugin; this.prefix = "[" + addonName + "] "; } diff --git a/bungeecord/src/main/java/com/serverstats/bungeecord/addon/BungeeAddonManager.java b/modules/bungeecord/src/main/java/net/analyse/bungeecord/addon/BungeeAddonManager.java similarity index 80% rename from bungeecord/src/main/java/com/serverstats/bungeecord/addon/BungeeAddonManager.java rename to modules/bungeecord/src/main/java/net/analyse/bungeecord/addon/BungeeAddonManager.java index 85ec18e..da50922 100644 --- a/bungeecord/src/main/java/com/serverstats/bungeecord/addon/BungeeAddonManager.java +++ b/modules/bungeecord/src/main/java/net/analyse/bungeecord/addon/BungeeAddonManager.java @@ -1,8 +1,8 @@ -package com.serverstats.bungeecord.addon; +package net.analyse.bungeecord.addon; -import com.serverstats.api.addon.AbstractAddonManager; -import com.serverstats.api.addon.AddonLogger; -import com.serverstats.bungeecord.ServerStatsBungee; +import net.analyse.api.addon.AbstractAddonManager; +import net.analyse.api.addon.AddonLogger; +import net.analyse.bungeecord.AnalyseBungee; import java.util.logging.Level; /** @@ -10,14 +10,14 @@ */ public class BungeeAddonManager extends AbstractAddonManager { - private final ServerStatsBungee plugin; + private final AnalyseBungee plugin; /** * Create a new BungeeCord addon manager * * @param plugin The main plugin instance */ - public BungeeAddonManager(ServerStatsBungee plugin) { + public BungeeAddonManager(AnalyseBungee plugin) { super(plugin, plugin.getDataFolder().toPath().resolve("addons"), plugin.getClass().getClassLoader()); this.plugin = plugin; } diff --git a/bungeecord/src/main/java/com/serverstats/bungeecord/command/ServerStatsCommand.java b/modules/bungeecord/src/main/java/net/analyse/bungeecord/command/AnalyseCommand.java similarity index 80% rename from bungeecord/src/main/java/com/serverstats/bungeecord/command/ServerStatsCommand.java rename to modules/bungeecord/src/main/java/net/analyse/bungeecord/command/AnalyseCommand.java index dc9223d..31310b7 100644 --- a/bungeecord/src/main/java/com/serverstats/bungeecord/command/ServerStatsCommand.java +++ b/modules/bungeecord/src/main/java/net/analyse/bungeecord/command/AnalyseCommand.java @@ -1,4 +1,4 @@ -package com.serverstats.bungeecord.command; +package net.analyse.bungeecord.command; import co.aikar.commands.BaseCommand; import co.aikar.commands.annotation.CommandAlias; @@ -8,18 +8,18 @@ import co.aikar.commands.annotation.Description; import co.aikar.commands.annotation.Subcommand; import co.aikar.commands.annotation.Syntax; -import com.serverstats.api.ServerStats; -import com.serverstats.api.BuildConstants; -import com.serverstats.api.addon.LoadedAddon; -import com.serverstats.api.exception.ServerStatsException; -import com.serverstats.api.object.builder.EventBuilder; -import com.serverstats.bungeecord.ServerStatsBungee; -import com.serverstats.bungeecord.object.session.PlayerSession; -import com.serverstats.bungeecord.util.ComponentUtil; -import com.serverstats.sdk.ServerStatsCallback; -import com.serverstats.sdk.request.PlayerInfoRequest; -import com.serverstats.sdk.response.PlayerInfoResponse; -import com.serverstats.sdk.response.ServerInfoResponse; +import net.analyse.api.Analyse; +import net.analyse.api.BuildConstants; +import net.analyse.api.addon.LoadedAddon; +import net.analyse.api.exception.AnalyseException; +import net.analyse.api.object.builder.EventBuilder; +import net.analyse.bungeecord.AnalyseBungee; +import net.analyse.bungeecord.object.session.PlayerSession; +import net.analyse.bungeecord.util.ComponentUtil; +import net.analyse.sdk.AnalyseCallback; +import net.analyse.sdk.request.PlayerInfoRequest; +import net.analyse.sdk.response.PlayerInfoResponse; +import net.analyse.sdk.response.ServerInfoResponse; import net.md_5.bungee.api.CommandSender; import net.md_5.bungee.api.connection.ProxiedPlayer; import java.time.Duration; @@ -29,14 +29,14 @@ import java.util.Map; /** - * Main command handler for the ServerStats plugin using ACF + * Main command handler for the Analyse plugin using ACF */ -@CommandAlias("serverstats|analyse|ss") -public class ServerStatsCommand extends BaseCommand { +@CommandAlias("analyse|analyse|ss") +public class AnalyseCommand extends BaseCommand { - private final ServerStatsBungee plugin; + private final AnalyseBungee plugin; - public ServerStatsCommand(ServerStatsBungee plugin) { + public AnalyseCommand(AnalyseBungee plugin) { this.plugin = plugin; } @@ -44,7 +44,7 @@ public ServerStatsCommand(ServerStatsBungee plugin) { @Description("Show plugin info") public void onDefault(CommandSender sender) { // Check if user has admin permission - if (sender.hasPermission("serverstats.command.status")) { + if (sender.hasPermission("analyse.netmand.status")) { showStatus(sender); } else { showPublicInfo(sender); @@ -53,7 +53,7 @@ public void onDefault(CommandSender sender) { @Subcommand("status") @Description("Show plugin status") - @CommandPermission("serverstats.command.status") + @CommandPermission("analyse.netmand.status") public void onStatus(CommandSender sender) { showStatus(sender); } @@ -65,11 +65,11 @@ public void onStatus(CommandSender sender) { */ private void showPublicInfo(CommandSender sender) { StringBuilder message = new StringBuilder(); - message.append("#3498db&l「 ServerStats 」&r\n"); - message.append(" #5dade2┃ &7This server uses &fServerStats &7to track\n"); + message.append("#3498db&l「 Analyse 」&r\n"); + message.append(" #5dade2┃ &7This server uses &fAnalyse &7to track\n"); message.append(" #5dade2┃ &7player analytics and sessions.&r\n"); message.append("&r\n"); - message.append(" &7→ &fserverstats.com&r\n"); + message.append(" &7→ &fanalyse.net&r\n"); send(sender, message.toString()); } @@ -79,18 +79,18 @@ private void showPublicInfo(CommandSender sender) { * @param sender The command sender */ private void showStatus(CommandSender sender) { - boolean connected = ServerStats.isConnected(); + boolean connected = Analyse.isConnected(); int trackedPlayers = plugin.getSessionManager().getSessionCount(); boolean debugEnabled = plugin.isDebugEnabled(); int configuredServers = plugin.getPluginConfig().getServers().size(); StringBuilder message = new StringBuilder(); - message.append("#3498db&l「 ServerStats &r&fv").append(BuildConstants.VERSION).append(" #3498db&l」&r\n"); + message.append("#3498db&l「 Analyse &r&fv").append(BuildConstants.VERSION).append(" #3498db&l」&r\n"); message.append(" #5dade2┃ &fStatus: ").append(connected ? "&a● Connected" : "&c● Disconnected").append("&r\n"); - if (!connected && ServerStats.getLastConnectionError() != null) { - message.append(" #5dade2┃ &fError: &c").append(ServerStats.getLastConnectionError()).append("&r\n"); + if (!connected && Analyse.getLastConnectionError() != null) { + message.append(" #5dade2┃ &fError: &c").append(Analyse.getLastConnectionError()).append("&r\n"); } - message.append(" #5dade2┃ &fAPI: &7api.serverstats.com&r\n"); + message.append(" #5dade2┃ &fAPI: &7api.analyse.net&r\n"); message.append(" #5dade2┃ &fServers Configured: &7").append(configuredServers).append("&r\n"); message.append(" #5dade2┃ &fPlayers Tracked: &7").append(trackedPlayers).append("&r\n"); message.append(" #5dade2┃ &fDebug: ").append(debugEnabled ? "&aEnabled" : "&7Disabled").append("&r\n"); @@ -99,7 +99,7 @@ private void showStatus(CommandSender sender) { @Subcommand("debug") @Description("Toggle debug mode") - @CommandPermission("serverstats.command.debug") + @CommandPermission("analyse.netmand.debug") public void onDebug(CommandSender sender) { boolean newState = !plugin.getPluginConfig().isDebug(); plugin.getPluginConfig().setDebug(newState); @@ -113,17 +113,17 @@ public void onDebug(CommandSender sender) { @Subcommand("event") @Description("Send a custom event") - @CommandPermission("serverstats.command.event") + @CommandPermission("analyse.netmand.event") @Syntax(" [--player ] [--value ] [--data ...]") @CommandCompletion("test_event|custom_event @players") public void onEvent(CommandSender sender, String[] args) { if (args.length == 0) { - send(sender, "&cUsage: /serverstats event [--player ] [--value ] [--data key=value...]"); + send(sender, "&cUsage: /analyse event [--player ] [--value ] [--data key=value...]"); return; } - if (!ServerStats.isAvailable()) { - send(sender, "&cServerStats is not connected. Make sure a default server is configured."); + if (!Analyse.isAvailable()) { + send(sender, "&cAnalyse is not connected. Make sure a default server is configured."); return; } @@ -161,7 +161,7 @@ public void onEvent(CommandSender sender, String[] args) { } // Build the event - EventBuilder builder = ServerStats.trackEvent(eventName); + EventBuilder builder = Analyse.trackEvent(eventName); // Add player if specified if (playerName != null) { @@ -209,12 +209,12 @@ public void onEvent(CommandSender sender, String[] args) { @Subcommand("info") @Description("View server or player analytics") - @CommandPermission("serverstats.command.info") + @CommandPermission("analyse.netmand.info") @Syntax("[player]") @CommandCompletion("@players") public void onInfo(CommandSender sender, String[] args) { - if (!ServerStats.isAvailable()) { - send(sender, "&cServerStats is not connected. Make sure a default server is configured."); + if (!Analyse.isAvailable()) { + send(sender, "&cAnalyse is not connected. Make sure a default server is configured."); return; } @@ -237,7 +237,7 @@ private void showServerInfo(CommandSender sender) { int onlinePlayers = plugin.getProxy().getOnlineCount(); // Fetch additional data from API - plugin.getClient().getServerInfo(new ServerStatsCallback<>() { + plugin.getClient().getServerInfo(new AnalyseCallback() { @Override public void onSuccess(ServerInfoResponse response) { plugin.getProxy().getScheduler().runAsync(plugin, () -> { @@ -259,7 +259,7 @@ public void onSuccess(ServerInfoResponse response) { } @Override - public void onError(ServerStatsException exception) { + public void onError(AnalyseException exception) { plugin.getProxy().getScheduler().runAsync(plugin, () -> { StringBuilder message = new StringBuilder(); message.append("#3498db&l「 Server Analytics 」&r\n"); @@ -288,7 +288,7 @@ private void showPlayerInfo(CommandSender sender, String playerName) { PlayerSession session = plugin.getSessionManager().getSession(player.getUniqueId()).orElse(null); // Fetch additional data from API - plugin.getClient().getPlayerInfo(new PlayerInfoRequest(player.getUniqueId()), new ServerStatsCallback<>() { + plugin.getClient().getPlayerInfo(new PlayerInfoRequest(player.getUniqueId()), new AnalyseCallback() { @Override public void onSuccess(PlayerInfoResponse response) { plugin.getProxy().getScheduler().runAsync(plugin, () -> { @@ -297,7 +297,7 @@ public void onSuccess(PlayerInfoResponse response) { } @Override - public void onError(ServerStatsException exception) { + public void onError(AnalyseException exception) { plugin.getProxy().getScheduler().runAsync(plugin, () -> { send(sender, buildPlayerInfoMessage(player.getName(), session, null)); }); @@ -385,16 +385,16 @@ private String formatDuration(Duration duration) { @Subcommand("addons") @Description("List all loaded addons") - @CommandPermission("serverstats.command.addons") + @CommandPermission("analyse.netmand.addons") public void onAddons(CommandSender sender) { Collection addons = plugin.getAddonManager().getLoadedAddons(); StringBuilder message = new StringBuilder(); - message.append("#3498db&l「 ServerStats Addons 」&r\n"); + message.append("#3498db&l「 Analyse Addons 」&r\n"); if (addons.isEmpty()) { message.append(" &7No addons loaded.&r\n"); - message.append(" &7Place addon JARs in &fplugins/ServerStats/addons/&r\n"); + message.append(" &7Place addon JARs in &fplugins/Analyse/addons/&r\n"); } else { for (LoadedAddon addon : addons) { String status = addon.isEnabled() ? "&a● Enabled" : "&c● Disabled"; @@ -414,7 +414,7 @@ public void onAddons(CommandSender sender) { @Subcommand("addons reload") @Description("Reload all addons or a specific addon") - @CommandPermission("serverstats.command.addons.reload") + @CommandPermission("analyse.netmand.addons.reload") @Syntax("[addon]") public void onAddonsReload(CommandSender sender, String[] args) { if (args.length == 0) { @@ -439,7 +439,7 @@ public void onAddonsReload(CommandSender sender, String[] args) { @Subcommand("addons enable") @Description("Enable an addon") - @CommandPermission("serverstats.command.addons.enable") + @CommandPermission("analyse.netmand.addons.enable") @Syntax("") public void onAddonsEnable(CommandSender sender, String addonId) { if (!plugin.getAddonManager().isAddonLoaded(addonId)) { @@ -461,7 +461,7 @@ public void onAddonsEnable(CommandSender sender, String addonId) { @Subcommand("addons disable") @Description("Disable an addon") - @CommandPermission("serverstats.command.addons.disable") + @CommandPermission("analyse.netmand.addons.disable") @Syntax("") public void onAddonsDisable(CommandSender sender, String addonId) { if (!plugin.getAddonManager().isAddonLoaded(addonId)) { @@ -483,19 +483,19 @@ public void onAddonsDisable(CommandSender sender, String addonId) { @Subcommand("help") @Description("Show help information") - @CommandPermission("serverstats.command.help") + @CommandPermission("analyse.netmand.help") public void onHelp(CommandSender sender) { StringBuilder message = new StringBuilder(); - message.append("#3498db&l「 ServerStats Commands 」&r\n"); - message.append(" #5dade2┃ &f/serverstats &7- Show plugin info&r\n"); - message.append(" #5dade2┃ &f/serverstats status &7- Show plugin status&r\n"); - message.append(" #5dade2┃ &f/serverstats info &7- View server analytics&r\n"); - message.append(" #5dade2┃ &f/serverstats info &7- View player analytics&r\n"); - message.append(" #5dade2┃ &f/serverstats debug &7- Toggle debug mode&r\n"); - message.append(" #5dade2┃ &f/serverstats event &7- Send custom event&r\n"); - message.append(" #5dade2┃ &f/serverstats addons &7- List loaded addons&r\n"); - message.append(" #5dade2┃ &f/serverstats addons reload [id] &7- Reload addons&r\n"); - message.append(" #5dade2┃ &f/serverstats help &7- Show this help&r\n"); + message.append("#3498db&l「 Analyse Commands 」&r\n"); + message.append(" #5dade2┃ &f/analyse &7- Show plugin info&r\n"); + message.append(" #5dade2┃ &f/analyse status &7- Show plugin status&r\n"); + message.append(" #5dade2┃ &f/analyse info &7- View server analytics&r\n"); + message.append(" #5dade2┃ &f/analyse info &7- View player analytics&r\n"); + message.append(" #5dade2┃ &f/analyse debug &7- Toggle debug mode&r\n"); + message.append(" #5dade2┃ &f/analyse event &7- Send custom event&r\n"); + message.append(" #5dade2┃ &f/analyse addons &7- List loaded addons&r\n"); + message.append(" #5dade2┃ &f/analyse addons reload [id] &7- Reload addons&r\n"); + message.append(" #5dade2┃ &f/analyse help &7- Show this help&r\n"); send(sender, message.toString()); } diff --git a/bungeecord/src/main/java/com/serverstats/bungeecord/config/ServerStatsBungeeConfig.java b/modules/bungeecord/src/main/java/net/analyse/bungeecord/config/AnalyseBungeeConfig.java similarity index 82% rename from bungeecord/src/main/java/com/serverstats/bungeecord/config/ServerStatsBungeeConfig.java rename to modules/bungeecord/src/main/java/net/analyse/bungeecord/config/AnalyseBungeeConfig.java index 2ad9d7b..85c1e77 100644 --- a/bungeecord/src/main/java/com/serverstats/bungeecord/config/ServerStatsBungeeConfig.java +++ b/modules/bungeecord/src/main/java/net/analyse/bungeecord/config/AnalyseBungeeConfig.java @@ -1,4 +1,4 @@ -package com.serverstats.bungeecord.config; +package net.analyse.bungeecord.config; import com.google.gson.Gson; import com.google.gson.GsonBuilder; @@ -17,18 +17,28 @@ * Configuration for the BungeeCord plugin */ @Getter -public class ServerStatsBungeeConfig { +public class AnalyseBungeeConfig { private static final String CONFIG_FILE = "config.json"; - private static final transient Map DEFAULT_EVENTS = Map.of( - "command", true, - "chat", true, - "serverSwitch", true - ); + private static final transient Map DEFAULT_EVENTS = createDefaultEvents(); + + /** + * Build the default event toggles map used when merging config + * + * @return A new map with built-in event keys and default enabled flags + */ + private static Map createDefaultEvents() { + Map map = new HashMap<>(); + map.put("command", true); + map.put("chat", true); + map.put("serverSwitch", true); + return map; + } @Setter private boolean debug = false; + private boolean development = false; private String bedrockPrefix = "."; private String instanceId = "default"; private String defaultServer = null; @@ -57,7 +67,7 @@ public ServerConfig(String apiKey) { * @return The loaded configuration * @throws IOException If the config cannot be read or written */ - public static ServerStatsBungeeConfig load(Path dataDirectory) throws IOException { + public static AnalyseBungeeConfig load(Path dataDirectory) throws IOException { Gson gson = new GsonBuilder().setPrettyPrinting().create(); Path configPath = dataDirectory.resolve(CONFIG_FILE); @@ -68,7 +78,7 @@ public static ServerStatsBungeeConfig load(Path dataDirectory) throws IOExceptio // Create default config if it doesn't exist if (!Files.exists(configPath)) { - ServerStatsBungeeConfig defaultConfig = createDefault(); + AnalyseBungeeConfig defaultConfig = createDefault(); try (Writer writer = Files.newBufferedWriter(configPath, StandardCharsets.UTF_8)) { gson.toJson(defaultConfig, writer); } @@ -77,9 +87,9 @@ public static ServerStatsBungeeConfig load(Path dataDirectory) throws IOExceptio } // Load existing config and fill in any missing event defaults - ServerStatsBungeeConfig config; + AnalyseBungeeConfig config; try (Reader reader = Files.newBufferedReader(configPath, StandardCharsets.UTF_8)) { - config = gson.fromJson(reader, ServerStatsBungeeConfig.class); + config = gson.fromJson(reader, AnalyseBungeeConfig.class); } if (config.fillMissingEventDefaults()) { @@ -96,8 +106,8 @@ public static ServerStatsBungeeConfig load(Path dataDirectory) throws IOExceptio * * @return The default configuration */ - private static ServerStatsBungeeConfig createDefault() { - ServerStatsBungeeConfig config = new ServerStatsBungeeConfig(); + private static AnalyseBungeeConfig createDefault() { + AnalyseBungeeConfig config = new AnalyseBungeeConfig(); config.debug = false; config.bedrockPrefix = "."; config.instanceId = "default"; @@ -130,7 +140,7 @@ public String getApiKeyForServer(String serverName) { */ public boolean isServerConfigured(String serverName) { String apiKey = getApiKeyForServer(serverName); - return apiKey != null && !apiKey.isBlank() && !apiKey.startsWith("anl_your_"); + return apiKey != null && !apiKey.trim().isEmpty() && !apiKey.startsWith("anl_your_"); } /** diff --git a/bungeecord/src/main/java/com/serverstats/bungeecord/listener/ActivityListener.java b/modules/bungeecord/src/main/java/net/analyse/bungeecord/listener/ActivityListener.java similarity index 69% rename from bungeecord/src/main/java/com/serverstats/bungeecord/listener/ActivityListener.java rename to modules/bungeecord/src/main/java/net/analyse/bungeecord/listener/ActivityListener.java index 3ba19ee..dd04970 100644 --- a/bungeecord/src/main/java/com/serverstats/bungeecord/listener/ActivityListener.java +++ b/modules/bungeecord/src/main/java/net/analyse/bungeecord/listener/ActivityListener.java @@ -1,11 +1,11 @@ -package com.serverstats.bungeecord.listener; - -import com.serverstats.bungeecord.ServerStatsBungee; -import com.serverstats.sdk.ServerStatsCallback; -import com.serverstats.sdk.ServerStatsClient; -import com.serverstats.api.exception.ServerStatsException; -import com.serverstats.sdk.request.EventRequest; -import com.serverstats.sdk.response.EventResponse; +package net.analyse.bungeecord.listener; + +import net.analyse.bungeecord.AnalyseBungee; +import net.analyse.sdk.AnalyseCallback; +import net.analyse.sdk.AnalyseClient; +import net.analyse.api.exception.AnalyseException; +import net.analyse.sdk.request.EventRequest; +import net.analyse.sdk.response.EventResponse; import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.api.connection.Server; import net.md_5.bungee.api.event.ChatEvent; @@ -22,9 +22,9 @@ */ public class ActivityListener implements Listener { - private final ServerStatsBungee plugin; + private final AnalyseBungee plugin; - public ActivityListener(ServerStatsBungee plugin) { + public ActivityListener(AnalyseBungee plugin) { this.plugin = plugin; } @@ -34,10 +34,11 @@ public void onChat(ChatEvent event) { return; } - if (!(event.getSender() instanceof ProxiedPlayer player)) { + if (!(event.getSender() instanceof ProxiedPlayer)) { return; } + ProxiedPlayer player = (ProxiedPlayer) event.getSender(); UUID uuid = player.getUniqueId(); String username = player.getName(); String message = event.getMessage(); @@ -59,18 +60,18 @@ public void onChat(ChatEvent event) { String rawCommand = message.substring(1); String command = rawCommand.split(" ")[0]; - sendEvent(serverName, "plugin.command", uuid, username, Map.of( - "command", command, - "rawCommand", rawCommand - )); + Map commandData = new HashMap<>(); + commandData.put("command", command); + commandData.put("rawCommand", rawCommand); + sendEvent(serverName, "plugin.command", uuid, username, commandData); } else { if (!isEnabled("chat")) { return; } - sendEvent(serverName, "plugin.chat", uuid, username, Map.of( - "message", message - )); + Map chatData = new HashMap<>(); + chatData.put("message", message); + sendEvent(serverName, "plugin.chat", uuid, username, chatData); } } @@ -97,10 +98,10 @@ public void onServerSwitch(ServerSwitchEvent event) { String to = currentServer.getInfo().getName(); - sendEvent(to, "plugin.server_switch", uuid, username, Map.of( - "from", from, - "to", to - )); + Map switchData = new HashMap<>(); + switchData.put("from", from); + switchData.put("to", to); + sendEvent(to, "plugin.server_switch", uuid, username, switchData); } /** @@ -114,22 +115,22 @@ public void onServerSwitch(ServerSwitchEvent event) { */ private void sendEvent(String serverName, String eventName, UUID playerUuid, String playerUsername, Map data) { - Optional clientOpt = plugin.getPlayerListener().getClientForServer(serverName); - if (clientOpt.isEmpty()) { + Optional clientOpt = plugin.getPlayerListener().getClientForServer(serverName); + if (!clientOpt.isPresent()) { return; } - ServerStatsClient client = clientOpt.get(); + AnalyseClient client = clientOpt.get(); EventRequest request = new EventRequest(eventName, playerUuid, playerUsername, new HashMap<>(data), null); - client.trackEvent(request, new ServerStatsCallback<>() { + client.trackEvent(request, new AnalyseCallback() { @Override public void onSuccess(EventResponse response) { plugin.debug("Activity event '%s' sent for %s on %s", eventName, playerUsername, serverName); } @Override - public void onError(ServerStatsException exception) { + public void onError(AnalyseException exception) { plugin.getLogger().warning(String.format("Failed to send activity event '%s' for %s: %s", eventName, playerUsername, exception.getMessage())); } diff --git a/bungeecord/src/main/java/com/serverstats/bungeecord/listener/PlayerListener.java b/modules/bungeecord/src/main/java/net/analyse/bungeecord/listener/PlayerListener.java similarity index 76% rename from bungeecord/src/main/java/com/serverstats/bungeecord/listener/PlayerListener.java rename to modules/bungeecord/src/main/java/net/analyse/bungeecord/listener/PlayerListener.java index ad880cb..fe58d03 100644 --- a/bungeecord/src/main/java/com/serverstats/bungeecord/listener/PlayerListener.java +++ b/modules/bungeecord/src/main/java/net/analyse/bungeecord/listener/PlayerListener.java @@ -1,17 +1,17 @@ -package com.serverstats.bungeecord.listener; - -import com.serverstats.bungeecord.ServerStatsBungee; -import com.serverstats.bungeecord.manager.SessionManager; -import com.serverstats.bungeecord.object.session.PlayerSession; -import com.serverstats.sdk.ServerStatsCallback; -import com.serverstats.sdk.ServerStatsClient; -import com.serverstats.api.exception.ServerStatsException; -import com.serverstats.sdk.config.ServerStatsConfig; -import com.serverstats.sdk.request.JoinRequest; -import com.serverstats.sdk.request.LeaveRequest; -import com.serverstats.sdk.util.ProtocolVersionUtil; -import com.serverstats.sdk.response.JoinResponse; -import com.serverstats.sdk.response.LeaveResponse; +package net.analyse.bungeecord.listener; + +import net.analyse.bungeecord.AnalyseBungee; +import net.analyse.bungeecord.manager.SessionManager; +import net.analyse.bungeecord.object.session.PlayerSession; +import net.analyse.sdk.AnalyseCallback; +import net.analyse.sdk.AnalyseClient; +import net.analyse.api.exception.AnalyseException; +import net.analyse.sdk.config.AnalyseConfig; +import net.analyse.sdk.request.JoinRequest; +import net.analyse.sdk.request.LeaveRequest; +import net.analyse.sdk.util.ProtocolVersionUtil; +import net.analyse.sdk.response.JoinResponse; +import net.analyse.sdk.response.LeaveResponse; import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.api.event.PlayerDisconnectEvent; import net.md_5.bungee.api.event.PostLoginEvent; @@ -30,12 +30,12 @@ */ public class PlayerListener implements Listener { - private final ServerStatsBungee plugin; + private final AnalyseBungee plugin; private final Logger logger; private final SessionManager sessionManager; - private final Map serverClients = new HashMap<>(); + private final Map serverClients = new HashMap<>(); - public PlayerListener(ServerStatsBungee plugin) { + public PlayerListener(AnalyseBungee plugin) { this.plugin = plugin; this.logger = plugin.getLogger(); this.sessionManager = plugin.getSessionManager(); @@ -50,9 +50,10 @@ public PlayerListener(ServerStatsBungee plugin) { private void initializeClients() { plugin.getPluginConfig().getServers().forEach((serverName, serverConfig) -> { String apiKey = serverConfig.getApiKey(); - if (apiKey != null && !apiKey.isBlank() && !apiKey.startsWith("anl_your_")) { - ServerStatsConfig config = new ServerStatsConfig(apiKey); - serverClients.put(serverName, new ServerStatsClient(config)); + if (apiKey != null && !apiKey.trim().isEmpty() && !apiKey.startsWith("anl_your_")) { + boolean development = plugin.getPluginConfig().isDevelopment(); + AnalyseConfig config = new AnalyseConfig(apiKey, development); + serverClients.put(serverName, new AnalyseClient(config)); logger.info(String.format("Initialized analytics client for server: %s", serverName)); } }); @@ -64,7 +65,7 @@ private void initializeClients() { * @param serverName The server name * @return The client, or empty if not configured */ - public Optional getClientForServer(String serverName) { + public Optional getClientForServer(String serverName) { return Optional.ofNullable(serverClients.get(serverName)); } @@ -73,13 +74,22 @@ public Optional getClientForServer(String serverName) { * * @return The default client, or null if not configured */ - public ServerStatsClient getDefaultClient() { + public AnalyseClient getDefaultClient() { + // Try the explicitly configured default server first String defaultServer = plugin.getPluginConfig().getDefaultServer(); - if (defaultServer == null || defaultServer.isBlank()) { - return null; + if (defaultServer != null && !defaultServer.trim().isEmpty()) { + AnalyseClient client = serverClients.get(defaultServer); + if (client != null) { + return client; + } + } + + // Fall back to the first available client + if (!serverClients.isEmpty()) { + return serverClients.values().iterator().next(); } - return serverClients.get(defaultServer); + return null; } @EventHandler @@ -107,7 +117,7 @@ public void onServerConnected(ServerConnectedEvent event) { String newServerName = event.getServer().getInfo().getName(); Optional sessionOpt = sessionManager.getSession(uuid); - if (sessionOpt.isEmpty()) { + if (!sessionOpt.isPresent()) { logger.warning(String.format("No session found for player %s on server connect", username)); return; } @@ -132,7 +142,7 @@ public void onPlayerDisconnect(PlayerDisconnectEvent event) { String username = player.getName(); Optional sessionOpt = sessionManager.removeSession(uuid); - if (sessionOpt.isEmpty()) { + if (!sessionOpt.isPresent()) { return; } @@ -157,13 +167,13 @@ public void onPlayerDisconnect(PlayerDisconnectEvent event) { */ private void sendJoinEvent(UUID uuid, String username, PlayerSession session, String serverName, int protocolVersion) { - Optional clientOpt = getClientForServer(serverName); - if (clientOpt.isEmpty()) { + Optional clientOpt = getClientForServer(serverName); + if (!clientOpt.isPresent()) { plugin.debug("Server %s not configured, skipping join event for %s", serverName, username); return; } - ServerStatsClient client = clientOpt.get(); + AnalyseClient client = clientOpt.get(); // Check if player is a Bedrock player boolean isBedrock = plugin.getPluginConfig().isBedrock(username); @@ -174,7 +184,7 @@ private void sendJoinEvent(UUID uuid, String username, PlayerSession session, St JoinRequest request = new JoinRequest(uuid, username, session.getHostname(), session.getIp(), isBedrock, playerVersion); - client.join(request, new ServerStatsCallback<>() { + client.join(request, new AnalyseCallback() { @Override public void onSuccess(JoinResponse response) { session.setCurrentSession(serverName, response.getSessionId()); @@ -183,7 +193,7 @@ public void onSuccess(JoinResponse response) { } @Override - public void onError(ServerStatsException exception) { + public void onError(AnalyseException exception) { logger.warning(String.format("Failed to send join event for %s on %s: %s", username, serverName, exception.getMessage())); } @@ -198,15 +208,15 @@ private void sendLeaveEvent(UUID uuid, String username, PlayerSession session, S return; } - Optional clientOpt = getClientForServer(serverName); - if (clientOpt.isEmpty()) { + Optional clientOpt = getClientForServer(serverName); + if (!clientOpt.isPresent()) { return; } - ServerStatsClient client = clientOpt.get(); + AnalyseClient client = clientOpt.get(); LeaveRequest request = new LeaveRequest(session.getSessionId()); - client.leave(request, new ServerStatsCallback<>() { + client.leave(request, new AnalyseCallback() { @Override public void onSuccess(LeaveResponse response) { plugin.debug("Leave event sent for %s on %s (duration: %ds)", @@ -214,7 +224,7 @@ public void onSuccess(LeaveResponse response) { } @Override - public void onError(ServerStatsException exception) { + public void onError(AnalyseException exception) { logger.warning(String.format("Failed to send leave event for %s on %s: %s", username, serverName, exception.getMessage())); } @@ -259,7 +269,7 @@ public void sendJoinEventForExistingPlayer(ProxiedPlayer player, String serverNa String username = player.getName(); Optional sessionOpt = sessionManager.getSession(uuid); - if (sessionOpt.isEmpty()) { + if (!sessionOpt.isPresent()) { logger.warning(String.format("No session found for existing player %s", username)); return; } @@ -280,7 +290,7 @@ public void reinitialize() { * Shutdown all API clients */ public void shutdown() { - serverClients.values().forEach(ServerStatsClient::shutdown); + serverClients.values().forEach(AnalyseClient::shutdown); serverClients.clear(); } } diff --git a/bungeecord/src/main/java/com/serverstats/bungeecord/listener/PluginMessageListener.java b/modules/bungeecord/src/main/java/net/analyse/bungeecord/listener/PluginMessageListener.java similarity index 78% rename from bungeecord/src/main/java/com/serverstats/bungeecord/listener/PluginMessageListener.java rename to modules/bungeecord/src/main/java/net/analyse/bungeecord/listener/PluginMessageListener.java index 31c0993..880b28f 100644 --- a/bungeecord/src/main/java/com/serverstats/bungeecord/listener/PluginMessageListener.java +++ b/modules/bungeecord/src/main/java/net/analyse/bungeecord/listener/PluginMessageListener.java @@ -1,12 +1,13 @@ -package com.serverstats.bungeecord.listener; - -import com.serverstats.api.ServerStats; -import com.serverstats.api.messaging.ServerStatsMessageParser; -import com.serverstats.api.messaging.ServerStatsMessageParser.ConversionMessage; -import com.serverstats.api.messaging.ServerStatsMessageParser.EventMessage; -import com.serverstats.api.messaging.ServerStatsMessageParser.ParsedMessage; -import com.serverstats.api.messaging.ServerStatsMessaging; -import com.serverstats.bungeecord.ServerStatsBungee; +package net.analyse.bungeecord.listener; + +import net.analyse.api.Analyse; +import net.analyse.api.object.builder.EventBuilder; +import net.analyse.api.messaging.AnalyseMessageParser; +import net.analyse.api.messaging.AnalyseMessageParser.ConversionMessage; +import net.analyse.api.messaging.AnalyseMessageParser.EventMessage; +import net.analyse.api.messaging.AnalyseMessageParser.ParsedMessage; +import net.analyse.api.messaging.AnalyseMessaging; +import net.analyse.bungeecord.AnalyseBungee; import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.api.connection.Server; import net.md_5.bungee.api.event.PluginMessageEvent; @@ -20,14 +21,14 @@ */ public class PluginMessageListener implements Listener { - private final ServerStatsBungee plugin; + private final AnalyseBungee plugin; /** * Create a new plugin message listener * * @param plugin The plugin instance */ - public PluginMessageListener(ServerStatsBungee plugin) { + public PluginMessageListener(AnalyseBungee plugin) { this.plugin = plugin; } @@ -39,7 +40,7 @@ public void onPluginMessage(PluginMessageEvent event) { } // Only handle our channel - if (!event.getTag().equals(ServerStatsMessaging.CHANNEL)) { + if (!event.getTag().equals(AnalyseMessaging.CHANNEL)) { return; } @@ -53,7 +54,7 @@ public void onPluginMessage(PluginMessageEvent event) { plugin.debug("Received plugin message from %s on server %s", player.getName(), serverName); try { - ParsedMessage message = ServerStatsMessageParser.parse(event.getData()); + ParsedMessage message = AnalyseMessageParser.parse(event.getData()); handleMessage(message, player, serverName); } catch (IOException e) { plugin.getLogger().warning(String.format("Failed to parse plugin message from %s: %s", @@ -83,8 +84,8 @@ private void handleMessage(ParsedMessage message, ProxiedPlayer player, String s * @param serverName The source server */ private void handleEventMessage(EventMessage message, String serverName) { - if (!ServerStats.isAvailable()) { - plugin.getLogger().warning("Received event message but ServerStats is not available"); + if (!Analyse.isAvailable()) { + plugin.getLogger().warning("Received event message but Analyse is not available"); return; } @@ -92,7 +93,7 @@ private void handleEventMessage(EventMessage message, String serverName) { message.getEventName(), message.getPlayerUsername(), serverName); // Build and send the event - var builder = ServerStats.trackEvent(message.getEventName()) + EventBuilder builder = Analyse.trackEvent(message.getEventName()) .withPlayer(message.getPlayerUuid(), message.getPlayerUsername()); if (message.getData() != null) { @@ -124,8 +125,8 @@ private void handleEventMessage(EventMessage message, String serverName) { * @param serverName The source server */ private void handleConversionMessage(ConversionMessage message, String serverName) { - if (!ServerStats.isAvailable()) { - plugin.getLogger().warning("Received conversion message but ServerStats is not available"); + if (!Analyse.isAvailable()) { + plugin.getLogger().warning("Received conversion message but Analyse is not available"); return; } @@ -133,7 +134,7 @@ private void handleConversionMessage(ConversionMessage message, String serverNam message.getTestKey(), message.getConversionEvent(), message.getPlayerUsername(), serverName); - ServerStats.trackConversion( + Analyse.trackConversion( message.getPlayerUuid(), message.getPlayerUsername(), message.getTestKey(), diff --git a/bungeecord/src/main/java/com/serverstats/bungeecord/manager/ABTestManager.java b/modules/bungeecord/src/main/java/net/analyse/bungeecord/manager/ABTestManager.java similarity index 64% rename from bungeecord/src/main/java/com/serverstats/bungeecord/manager/ABTestManager.java rename to modules/bungeecord/src/main/java/net/analyse/bungeecord/manager/ABTestManager.java index ab7a247..f445c3d 100644 --- a/bungeecord/src/main/java/com/serverstats/bungeecord/manager/ABTestManager.java +++ b/modules/bungeecord/src/main/java/net/analyse/bungeecord/manager/ABTestManager.java @@ -1,17 +1,18 @@ -package com.serverstats.bungeecord.manager; - -import com.serverstats.api.exception.ServerStatsException; -import com.serverstats.api.object.abtest.ABTest; -import com.serverstats.bungeecord.ServerStatsBungee; -import com.serverstats.bungeecord.object.action.BungeeAction; -import com.serverstats.sdk.ServerStatsCallback; -import com.serverstats.sdk.ServerStatsClient; -import com.serverstats.sdk.object.abtest.Variant; -import com.serverstats.sdk.object.action.ActionData; -import com.serverstats.sdk.request.ConversionRequest; -import com.serverstats.sdk.response.ABTestsResponse; -import com.serverstats.sdk.response.ConversionResponse; +package net.analyse.bungeecord.manager; + +import net.analyse.api.exception.AnalyseException; +import net.analyse.api.object.abtest.ABTest; +import net.analyse.bungeecord.AnalyseBungee; +import net.analyse.bungeecord.object.action.BungeeAction; +import net.analyse.sdk.AnalyseCallback; +import net.analyse.sdk.AnalyseClient; +import net.analyse.sdk.object.abtest.Variant; +import net.analyse.sdk.object.action.ActionData; +import net.analyse.sdk.request.ConversionRequest; +import net.analyse.sdk.response.ABTestsResponse; +import net.analyse.sdk.response.ConversionResponse; import net.md_5.bungee.api.connection.ProxiedPlayer; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.UUID; @@ -22,14 +23,14 @@ * Manages A/B tests for the BungeeCord plugin. * Supports SEND_MESSAGE and RUN_COMMAND actions on proxies. */ -public class ABTestManager implements com.serverstats.api.manager.ABTestManager { +public class ABTestManager implements net.analyse.api.manager.ABTestManager { private static final long SYNC_INTERVAL_MINUTES = 5; - private final ServerStatsBungee plugin; - private final Map testsCache = new ConcurrentHashMap<>(); + private final AnalyseBungee plugin; + private final Map testsCache = new ConcurrentHashMap<>(); - public ABTestManager(ServerStatsBungee plugin) { + public ABTestManager(AnalyseBungee plugin) { this.plugin = plugin; } @@ -63,17 +64,17 @@ public void stop() { * Sync tests from the API */ private void syncTests() { - ServerStatsClient client = plugin.getClient(); + AnalyseClient client = plugin.getClient(); if (client == null) { return; } - client.getABTests(new ServerStatsCallback<>() { + client.getABTests(new AnalyseCallback() { @Override public void onSuccess(ABTestsResponse response) { if (response.isSuccess() && response.getTests() != null) { testsCache.clear(); - for (com.serverstats.sdk.object.abtest.ABTest test : response.getTests()) { + for (net.analyse.sdk.object.abtest.ABTest test : response.getTests()) { if (test.isActive()) { testsCache.put(test.getKey(), test); } @@ -86,7 +87,7 @@ public void onSuccess(ABTestsResponse response) { } @Override - public void onError(ServerStatsException exception) { + public void onError(AnalyseException exception) { plugin.logWarning(String.format("Failed to sync A/B tests: %s", exception.getMessage())); } }); @@ -94,8 +95,8 @@ public void onError(ServerStatsException exception) { @Override @SuppressWarnings("unchecked") - public List getActiveTests() { - return List.copyOf(testsCache.values()); + public List getActiveTests() { + return new ArrayList<>(testsCache.values()); } @Override @@ -105,12 +106,12 @@ public ABTest getTest(String testKey) { @Override public String getVariant(UUID playerUuid, String testKey) { - com.serverstats.sdk.object.abtest.ABTest test = testsCache.get(testKey); + net.analyse.sdk.object.abtest.ABTest test = testsCache.get(testKey); if (test == null) { return null; } - com.serverstats.api.object.abtest.Variant variant = test.assignVariant(playerUuid); + net.analyse.api.object.abtest.Variant variant = test.assignVariant(playerUuid); return variant != null ? variant.getKey() : null; } @@ -129,15 +130,15 @@ public boolean isTestActive(String testKey) { public void processJoin(ProxiedPlayer player, boolean firstJoin) { ABTest.Trigger trigger = firstJoin ? ABTest.Trigger.FIRST_JOIN : ABTest.Trigger.EVERY_JOIN; - for (com.serverstats.sdk.object.abtest.ABTest test : testsCache.values()) { + for (net.analyse.sdk.object.abtest.ABTest test : testsCache.values()) { if (!test.matchesTrigger(trigger)) { continue; } // Assign variant and execute actions - var variant = test.assignVariant(player.getUniqueId()); + net.analyse.api.object.abtest.Variant variant = test.assignVariant(player.getUniqueId()); if (variant != null && variant.hasActions()) { - executeActions(player, test, (com.serverstats.sdk.object.abtest.Variant) variant); + executeActions(player, test, (net.analyse.sdk.object.abtest.Variant) variant); } } } @@ -149,15 +150,15 @@ public void processJoin(ProxiedPlayer player, boolean firstJoin) { * @param eventName The event name */ public void processEvent(ProxiedPlayer player, String eventName) { - for (com.serverstats.sdk.object.abtest.ABTest test : testsCache.values()) { + for (net.analyse.sdk.object.abtest.ABTest test : testsCache.values()) { if (!test.matchesEvent(eventName)) { continue; } // Assign variant and execute actions - var variant = test.assignVariant(player.getUniqueId()); + net.analyse.api.object.abtest.Variant variant = test.assignVariant(player.getUniqueId()); if (variant != null && variant.hasActions()) { - executeActions(player, test, (com.serverstats.sdk.object.abtest.Variant) variant); + executeActions(player, test, (net.analyse.sdk.object.abtest.Variant) variant); } } } @@ -169,8 +170,8 @@ public void processEvent(ProxiedPlayer player, String eventName) { * @param test The A/B test * @param variant The assigned variant */ - private void executeActions(ProxiedPlayer player, com.serverstats.sdk.object.abtest.ABTest test, - com.serverstats.sdk.object.abtest.Variant variant) { + private void executeActions(ProxiedPlayer player, net.analyse.sdk.object.abtest.ABTest test, + net.analyse.sdk.object.abtest.Variant variant) { if (plugin.isDebugEnabled()) { plugin.logInfo(String.format("[DEBUG] Player %s assigned to variant '%s' for test '%s'", player.getName(), variant.getKey(), test.getKey())); @@ -186,24 +187,24 @@ private void executeActions(ProxiedPlayer player, com.serverstats.sdk.object.abt @Override public void trackConversion(UUID playerUuid, String playerUsername, String testKey, String eventName) { - com.serverstats.sdk.object.abtest.ABTest test = testsCache.get(testKey); + net.analyse.sdk.object.abtest.ABTest test = testsCache.get(testKey); if (test == null) { return; } - ServerStatsClient client = plugin.getClient(); + AnalyseClient client = plugin.getClient(); if (client == null) { return; } - var variant = test.assignVariant(playerUuid); + net.analyse.api.object.abtest.Variant variant = test.assignVariant(playerUuid); String variantKey = variant != null ? variant.getKey() : null; ConversionRequest request = new ConversionRequest( testKey, variantKey, playerUuid, playerUsername, eventName, null ); - client.trackConversion(request, new ServerStatsCallback<>() { + client.trackConversion(request, new AnalyseCallback() { @Override public void onSuccess(ConversionResponse response) { if (plugin.isDebugEnabled()) { @@ -213,7 +214,7 @@ public void onSuccess(ConversionResponse response) { } @Override - public void onError(ServerStatsException exception) { + public void onError(AnalyseException exception) { plugin.logWarning(String.format("Failed to track conversion: %s", exception.getMessage())); } }); diff --git a/velocity/src/main/java/com/serverstats/velocity/manager/SessionManager.java b/modules/bungeecord/src/main/java/net/analyse/bungeecord/manager/SessionManager.java similarity index 87% rename from velocity/src/main/java/com/serverstats/velocity/manager/SessionManager.java rename to modules/bungeecord/src/main/java/net/analyse/bungeecord/manager/SessionManager.java index 6c24bc1..2308f05 100644 --- a/velocity/src/main/java/com/serverstats/velocity/manager/SessionManager.java +++ b/modules/bungeecord/src/main/java/net/analyse/bungeecord/manager/SessionManager.java @@ -1,6 +1,6 @@ -package com.serverstats.velocity.manager; +package net.analyse.bungeecord.manager; -import com.serverstats.velocity.object.session.PlayerSession; +import net.analyse.bungeecord.object.session.PlayerSession; import java.util.Collection; import java.util.Map; import java.util.Optional; @@ -10,7 +10,7 @@ /** * Thread-safe manager for player sessions */ -public class SessionManager implements com.serverstats.api.manager.SessionManager { +public class SessionManager implements net.analyse.api.manager.SessionManager { private final Map sessions = new ConcurrentHashMap<>(); diff --git a/bungeecord/src/main/java/com/serverstats/bungeecord/object/action/BungeeAction.java b/modules/bungeecord/src/main/java/net/analyse/bungeecord/object/action/BungeeAction.java similarity index 69% rename from bungeecord/src/main/java/com/serverstats/bungeecord/object/action/BungeeAction.java rename to modules/bungeecord/src/main/java/net/analyse/bungeecord/object/action/BungeeAction.java index 6273a58..5eddff0 100644 --- a/bungeecord/src/main/java/com/serverstats/bungeecord/object/action/BungeeAction.java +++ b/modules/bungeecord/src/main/java/net/analyse/bungeecord/object/action/BungeeAction.java @@ -1,8 +1,8 @@ -package com.serverstats.bungeecord.object.action; +package net.analyse.bungeecord.object.action; -import com.serverstats.bungeecord.ServerStatsBungee; -import com.serverstats.sdk.object.action.Action; -import com.serverstats.sdk.object.action.ActionData; +import net.analyse.bungeecord.AnalyseBungee; +import net.analyse.sdk.object.action.Action; +import net.analyse.sdk.object.action.ActionData; import net.md_5.bungee.api.connection.ProxiedPlayer; /** @@ -11,10 +11,10 @@ */ public abstract class BungeeAction implements Action { - protected final ServerStatsBungee plugin; + protected final AnalyseBungee plugin; protected final ActionData data; - protected BungeeAction(ServerStatsBungee plugin, ActionData data) { + protected BungeeAction(AnalyseBungee plugin, ActionData data) { this.plugin = plugin; this.data = data; } @@ -26,15 +26,19 @@ protected BungeeAction(ServerStatsBungee plugin, ActionData data) { * @param data The action data from the API * @return The appropriate BungeeAction, or null if type is unsupported */ - public static BungeeAction create(ServerStatsBungee plugin, ActionData data) { + public static BungeeAction create(AnalyseBungee plugin, ActionData data) { if (data == null || data.getType() == null) { return null; } - return switch (data.getType()) { - case SEND_MESSAGE -> new SendMessageAction(plugin, data); - case RUN_COMMAND -> new RunCommandAction(plugin, data); - }; + switch (data.getType()) { + case SEND_MESSAGE: + return new SendMessageAction(plugin, data); + case RUN_COMMAND: + return new RunCommandAction(plugin, data); + default: + return null; + } } /** diff --git a/bungeecord/src/main/java/com/serverstats/bungeecord/object/action/RunCommandAction.java b/modules/bungeecord/src/main/java/net/analyse/bungeecord/object/action/RunCommandAction.java similarity index 77% rename from bungeecord/src/main/java/com/serverstats/bungeecord/object/action/RunCommandAction.java rename to modules/bungeecord/src/main/java/net/analyse/bungeecord/object/action/RunCommandAction.java index 5ca85e4..6b1716d 100644 --- a/bungeecord/src/main/java/com/serverstats/bungeecord/object/action/RunCommandAction.java +++ b/modules/bungeecord/src/main/java/net/analyse/bungeecord/object/action/RunCommandAction.java @@ -1,8 +1,8 @@ -package com.serverstats.bungeecord.object.action; +package net.analyse.bungeecord.object.action; -import com.serverstats.bungeecord.ServerStatsBungee; -import com.serverstats.sdk.object.action.ActionData; -import com.serverstats.sdk.object.action.ActionType; +import net.analyse.bungeecord.AnalyseBungee; +import net.analyse.sdk.object.action.ActionData; +import net.analyse.sdk.object.action.ActionType; import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.api.connection.ProxiedPlayer; @@ -12,7 +12,7 @@ */ public class RunCommandAction extends BungeeAction { - public RunCommandAction(ServerStatsBungee plugin, ActionData data) { + public RunCommandAction(AnalyseBungee plugin, ActionData data) { super(plugin, data); } @@ -24,7 +24,7 @@ public ActionType getType() { @Override public void execute(ProxiedPlayer player) { String command = data.getString("command"); - if (command == null || command.isBlank()) { + if (command == null || command.trim().isEmpty()) { return; } diff --git a/bungeecord/src/main/java/com/serverstats/bungeecord/object/action/SendMessageAction.java b/modules/bungeecord/src/main/java/net/analyse/bungeecord/object/action/SendMessageAction.java similarity index 64% rename from bungeecord/src/main/java/com/serverstats/bungeecord/object/action/SendMessageAction.java rename to modules/bungeecord/src/main/java/net/analyse/bungeecord/object/action/SendMessageAction.java index 8366262..f692c51 100644 --- a/bungeecord/src/main/java/com/serverstats/bungeecord/object/action/SendMessageAction.java +++ b/modules/bungeecord/src/main/java/net/analyse/bungeecord/object/action/SendMessageAction.java @@ -1,9 +1,9 @@ -package com.serverstats.bungeecord.object.action; +package net.analyse.bungeecord.object.action; -import com.serverstats.bungeecord.ServerStatsBungee; -import com.serverstats.bungeecord.util.ComponentUtil; -import com.serverstats.sdk.object.action.ActionData; -import com.serverstats.sdk.object.action.ActionType; +import net.analyse.bungeecord.AnalyseBungee; +import net.analyse.bungeecord.util.ComponentUtil; +import net.analyse.sdk.object.action.ActionData; +import net.analyse.sdk.object.action.ActionType; import net.md_5.bungee.api.connection.ProxiedPlayer; /** @@ -12,7 +12,7 @@ */ public class SendMessageAction extends BungeeAction { - public SendMessageAction(ServerStatsBungee plugin, ActionData data) { + public SendMessageAction(AnalyseBungee plugin, ActionData data) { super(plugin, data); } @@ -24,7 +24,7 @@ public ActionType getType() { @Override public void execute(ProxiedPlayer player) { String message = data.getString("message"); - if (message == null || message.isBlank()) { + if (message == null || message.trim().isEmpty()) { return; } diff --git a/bungeecord/src/main/java/com/serverstats/bungeecord/object/session/PlayerSession.java b/modules/bungeecord/src/main/java/net/analyse/bungeecord/object/session/PlayerSession.java similarity index 87% rename from bungeecord/src/main/java/com/serverstats/bungeecord/object/session/PlayerSession.java rename to modules/bungeecord/src/main/java/net/analyse/bungeecord/object/session/PlayerSession.java index 1dac70c..88cd0e7 100644 --- a/bungeecord/src/main/java/com/serverstats/bungeecord/object/session/PlayerSession.java +++ b/modules/bungeecord/src/main/java/net/analyse/bungeecord/object/session/PlayerSession.java @@ -1,4 +1,4 @@ -package com.serverstats.bungeecord.object.session; +package net.analyse.bungeecord.object.session; import lombok.Getter; import java.time.Instant; @@ -8,7 +8,7 @@ * Stores session data for a connected player */ @Getter -public class PlayerSession implements com.serverstats.api.session.PlayerSession { +public class PlayerSession implements net.analyse.api.session.PlayerSession { private final UUID playerUuid; private final String hostname; @@ -52,6 +52,6 @@ public void clearSession() { @Override public boolean hasActiveSession() { - return sessionId != null && !sessionId.isBlank(); + return sessionId != null && !sessionId.trim().isEmpty(); } } diff --git a/bungeecord/src/main/java/com/serverstats/bungeecord/task/HeartbeatTask.java b/modules/bungeecord/src/main/java/net/analyse/bungeecord/task/HeartbeatTask.java similarity index 65% rename from bungeecord/src/main/java/com/serverstats/bungeecord/task/HeartbeatTask.java rename to modules/bungeecord/src/main/java/net/analyse/bungeecord/task/HeartbeatTask.java index 1d705ed..01e2cd5 100644 --- a/bungeecord/src/main/java/com/serverstats/bungeecord/task/HeartbeatTask.java +++ b/modules/bungeecord/src/main/java/net/analyse/bungeecord/task/HeartbeatTask.java @@ -1,20 +1,21 @@ -package com.serverstats.bungeecord.task; +package net.analyse.bungeecord.task; -import com.serverstats.api.ServerStats; -import com.serverstats.bungeecord.ServerStatsBungee; -import com.serverstats.bungeecord.listener.PlayerListener; -import com.serverstats.bungeecord.object.session.PlayerSession; -import com.serverstats.sdk.ServerStatsCallback; -import com.serverstats.sdk.ServerStatsClient; -import com.serverstats.api.exception.ServerStatsException; -import com.serverstats.sdk.request.HeartbeatRequest; -import com.serverstats.sdk.request.PlayerInfo; -import com.serverstats.sdk.request.ServerType; -import com.serverstats.sdk.response.HeartbeatResponse; +import net.analyse.api.Analyse; +import net.analyse.bungeecord.AnalyseBungee; +import net.analyse.bungeecord.listener.PlayerListener; +import net.analyse.bungeecord.object.session.PlayerSession; +import net.analyse.sdk.AnalyseCallback; +import net.analyse.sdk.AnalyseClient; +import net.analyse.api.exception.AnalyseException; +import net.analyse.sdk.request.HeartbeatRequest; +import net.analyse.sdk.request.PlayerInfo; +import net.analyse.sdk.request.ServerType; +import net.analyse.sdk.response.HeartbeatResponse; import net.md_5.bungee.api.config.ServerInfo; import net.md_5.bungee.api.connection.ProxiedPlayer; import java.util.List; import java.util.Optional; +import java.util.stream.Collectors; import java.util.logging.Logger; /** @@ -22,11 +23,11 @@ */ public class HeartbeatTask implements Runnable { - private final ServerStatsBungee plugin; + private final AnalyseBungee plugin; private final Logger logger; private final PlayerListener playerListener; - public HeartbeatTask(ServerStatsBungee plugin, PlayerListener playerListener) { + public HeartbeatTask(AnalyseBungee plugin, PlayerListener playerListener) { this.plugin = plugin; this.logger = plugin.getLogger(); this.playerListener = playerListener; @@ -44,8 +45,8 @@ public void run() { * @param serverName The server name */ private void sendHeartbeatForServer(String serverName) { - Optional clientOpt = playerListener.getClientForServer(serverName); - if (clientOpt.isEmpty()) { + Optional clientOpt = playerListener.getClientForServer(serverName); + if (!clientOpt.isPresent()) { return; } @@ -55,26 +56,26 @@ private void sendHeartbeatForServer(String serverName) { return; } - ServerStatsClient client = clientOpt.get(); + AnalyseClient client = clientOpt.get(); // Collect player info with hostnames for players on this server List onlinePlayers = serverInfo.getPlayers().stream() .map(this::createPlayerInfo) - .toList(); + .collect(Collectors.toList()); String instanceId = plugin.getPluginConfig().getInstanceId(); HeartbeatRequest request = new HeartbeatRequest(instanceId, ServerType.MINECRAFT, onlinePlayers); - client.heartbeat(request, new ServerStatsCallback<>() { + client.heartbeat(request, new AnalyseCallback() { @Override public void onSuccess(HeartbeatResponse response) { - ServerStats.setConnectionStatus(true, null); + Analyse.setConnectionStatus(true, null); plugin.debug("Heartbeat sent for %s (%d players)", serverName, response.getOnlineCount()); } @Override - public void onError(ServerStatsException exception) { - ServerStats.setConnectionStatus(false, exception.getMessage()); + public void onError(AnalyseException exception) { + Analyse.setConnectionStatus(false, exception.getMessage()); logger.warning(String.format("Failed to send heartbeat for %s: %s", serverName, exception.getMessage())); } diff --git a/bungeecord/src/main/java/com/serverstats/bungeecord/update/BungeeUpdateChecker.java b/modules/bungeecord/src/main/java/net/analyse/bungeecord/update/BungeeUpdateChecker.java similarity index 87% rename from bungeecord/src/main/java/com/serverstats/bungeecord/update/BungeeUpdateChecker.java rename to modules/bungeecord/src/main/java/net/analyse/bungeecord/update/BungeeUpdateChecker.java index f244197..dce20cb 100644 --- a/bungeecord/src/main/java/com/serverstats/bungeecord/update/BungeeUpdateChecker.java +++ b/modules/bungeecord/src/main/java/net/analyse/bungeecord/update/BungeeUpdateChecker.java @@ -1,7 +1,7 @@ -package com.serverstats.bungeecord.update; +package net.analyse.bungeecord.update; -import com.serverstats.bungeecord.ServerStatsBungee; -import com.serverstats.sdk.update.UpdateChecker; +import net.analyse.bungeecord.AnalyseBungee; +import net.analyse.sdk.update.UpdateChecker; import java.util.concurrent.TimeUnit; /** @@ -11,7 +11,7 @@ public class BungeeUpdateChecker { private static final long CHECK_INTERVAL_MINUTES = 30; - private final ServerStatsBungee plugin; + private final AnalyseBungee plugin; private final UpdateChecker checker; /** @@ -20,7 +20,7 @@ public class BungeeUpdateChecker { * @param plugin The plugin instance * @param currentVersion The current plugin version */ - public BungeeUpdateChecker(ServerStatsBungee plugin, String currentVersion) { + public BungeeUpdateChecker(AnalyseBungee plugin, String currentVersion) { this.plugin = plugin; this.checker = new UpdateChecker(plugin.getClient(), currentVersion, "bungeecord"); } @@ -52,7 +52,7 @@ private void check() { @Override public void onUpdateAvailable(String currentVersion, String newVersion, String downloadUrl) { plugin.logInfo("╔════════════════════════════════════════════════════════════╗"); - plugin.logInfo("║ A new version of ServerStats is available! ║"); + plugin.logInfo("║ A new version of Analyse is available! ║"); plugin.logInfo("║ Current: " + padRight(currentVersion, 20) + " Latest: " + padRight(newVersion, 20) + "║"); plugin.logInfo("║ Download: " + padRight(downloadUrl, 47) + "║"); plugin.logInfo("╚════════════════════════════════════════════════════════════╝"); diff --git a/bungeecord/src/main/java/com/serverstats/bungeecord/util/ComponentUtil.java b/modules/bungeecord/src/main/java/net/analyse/bungeecord/util/ComponentUtil.java similarity index 98% rename from bungeecord/src/main/java/com/serverstats/bungeecord/util/ComponentUtil.java rename to modules/bungeecord/src/main/java/net/analyse/bungeecord/util/ComponentUtil.java index 8dba0db..4472bca 100644 --- a/bungeecord/src/main/java/com/serverstats/bungeecord/util/ComponentUtil.java +++ b/modules/bungeecord/src/main/java/net/analyse/bungeecord/util/ComponentUtil.java @@ -1,4 +1,4 @@ -package com.serverstats.bungeecord.util; +package net.analyse.bungeecord.util; import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.chat.BaseComponent; @@ -90,7 +90,7 @@ public static BaseComponent[] parse(String text, Object... placeholders) { private static String convertHexColors(String text) { // Convert &#FFFFFF format Matcher matcher = HEX_PATTERN.matcher(text); - StringBuilder result = new StringBuilder(); + StringBuffer result = new StringBuffer(); while (matcher.find()) { String hex = matcher.group(1); matcher.appendReplacement(result, convertHexToLegacy(hex)); @@ -100,7 +100,7 @@ private static String convertHexColors(String text) { // Convert standalone #FFFFFF format matcher = STANDALONE_HEX_PATTERN.matcher(text); - result = new StringBuilder(); + result = new StringBuffer(); while (matcher.find()) { String hex = matcher.group(1); matcher.appendReplacement(result, convertHexToLegacy(hex)); diff --git a/modules/bungeecord/src/main/resources/bungee.yml b/modules/bungeecord/src/main/resources/bungee.yml new file mode 100644 index 0000000..162dce9 --- /dev/null +++ b/modules/bungeecord/src/main/resources/bungee.yml @@ -0,0 +1,5 @@ +name: Analyse +version: ${version} +main: net.analyse.bungeecord.AnalyseBungee +description: Analyse tracking plugin +author: VertCode Development diff --git a/hytale/build.gradle b/modules/hytale/build.gradle similarity index 75% rename from hytale/build.gradle rename to modules/hytale/build.gradle index 1d397a0..81e9f8d 100644 --- a/hytale/build.gradle +++ b/modules/hytale/build.gradle @@ -1,16 +1,20 @@ - plugins { id 'java' id 'com.gradleup.shadow' } +tasks.withType(JavaCompile).configureEach { + options.release = 21 +} + repositories { maven { url 'https://maven.hytale.com/release/' } + maven { url 'https://maven.hytale.com/pre-release/' } } dependencies { - implementation project(':api') - implementation project(':sdk') + implementation project(':modules:api') + implementation project(':modules:sdk') compileOnly 'com.hypixel.hytale:Server:2026.01.24-6e2d4fc36' // MiniMessage for text formatting @@ -21,11 +25,11 @@ dependencies { } tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { - archiveBaseName.set('serverstats-hytale') + archiveBaseName.set('analyse-hytale') archiveClassifier.set('') // Relocate Adventure/MiniMessage to avoid conflicts - relocate 'net.kyori', 'com.serverstats.libs.kyori' + relocate 'net.kyori', 'net.analyse.libs.kyori' } tasks.named('build') { diff --git a/hytale/src/main/java/com/serverstats/hytale/HytalePlugin.java b/modules/hytale/src/main/java/net/analyse/hytale/HytalePlugin.java similarity index 75% rename from hytale/src/main/java/com/serverstats/hytale/HytalePlugin.java rename to modules/hytale/src/main/java/net/analyse/hytale/HytalePlugin.java index 2e519f4..2605d30 100644 --- a/hytale/src/main/java/com/serverstats/hytale/HytalePlugin.java +++ b/modules/hytale/src/main/java/net/analyse/hytale/HytalePlugin.java @@ -1,4 +1,4 @@ -package com.serverstats.hytale; +package net.analyse.hytale; import com.hypixel.hytale.server.core.event.events.player.PlayerDisconnectEvent; import com.hypixel.hytale.server.core.event.events.player.PlayerReadyEvent; @@ -6,27 +6,28 @@ import com.hypixel.hytale.server.core.plugin.JavaPluginInit; import com.hypixel.hytale.server.core.universe.PlayerRef; import com.hypixel.hytale.server.core.universe.Universe; -import com.serverstats.api.ServerStats; -import com.serverstats.api.ServerStatsProvider; -import com.serverstats.api.addon.AddonManager; -import com.serverstats.api.exception.ServerStatsException; -import com.serverstats.api.object.builder.EventBuilder; -import com.serverstats.api.platform.ServerStatsPlatform; -import com.serverstats.hytale.addon.HytaleAddonManager; -import com.serverstats.hytale.command.ServerStatsCommand; -import com.serverstats.hytale.config.ServerStatsHytaleConfig; -import com.serverstats.hytale.listener.PlayerListener; -import com.serverstats.hytale.manager.ABTestManager; -import com.serverstats.hytale.manager.SessionManager; -import com.serverstats.hytale.task.HeartbeatTask; -import com.serverstats.hytale.update.HytaleUpdateChecker; -import com.serverstats.sdk.ServerStatsCallback; -import com.serverstats.sdk.ServerStatsClient; -import com.serverstats.sdk.config.ServerStatsConfig; -import com.serverstats.sdk.request.EventRequest; -import com.serverstats.sdk.request.JoinRequest; -import com.serverstats.sdk.response.EventResponse; -import com.serverstats.sdk.response.JoinResponse; +import net.analyse.api.Analyse; +import net.analyse.api.AnalyseProvider; +import net.analyse.api.addon.AddonManager; +import net.analyse.api.exception.AnalyseException; +import net.analyse.api.object.builder.EventBuilder; +import net.analyse.api.platform.AnalysePlatform; +import net.analyse.hytale.addon.HytaleAddonManager; +import net.analyse.hytale.command.AnalyseCommand; +import net.analyse.hytale.config.AnalyseHytaleConfig; +import net.analyse.hytale.listener.PlayerListener; +import net.analyse.hytale.manager.ABTestManager; +import net.analyse.hytale.manager.SessionManager; +import net.analyse.hytale.task.HeartbeatTask; +import net.analyse.hytale.update.HytaleUpdateChecker; +import net.analyse.sdk.AnalyseCallback; +import net.analyse.sdk.AnalyseClient; +import net.analyse.sdk.config.AnalyseConfig; +import net.analyse.sdk.request.EventRequest; +import net.analyse.sdk.request.JoinRequest; +import net.analyse.sdk.response.EventResponse; +import net.analyse.sdk.response.JoinResponse; +import java.io.File; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.util.UUID; @@ -38,16 +39,16 @@ import javax.annotation.Nonnull; /** - * ServerStats plugin for Hytale servers + * Analyse plugin for Hytale servers */ -public class HytalePlugin extends JavaPlugin implements ServerStatsPlatform { +public class HytalePlugin extends JavaPlugin implements AnalysePlatform { - private ServerStatsHytaleConfig pluginConfig; + private AnalyseHytaleConfig pluginConfig; private SessionManager sessionManager; private ABTestManager abTestManager; private HytaleAddonManager addonManager; private HytaleUpdateChecker updateChecker; - private ServerStatsClient client; + private AnalyseClient client; private ScheduledExecutorService scheduler; private ScheduledFuture heartbeatTask; private boolean configValid = false; @@ -61,10 +62,13 @@ public HytalePlugin(@Nonnull JavaPluginInit init) { @Override protected void setup() { super.setup(); - getLogger().atInfo().log("Loading ServerStats..."); + getLogger().atInfo().log("Loading Analyse..."); + + // Migrate old "ServerStats" data folder if it exists + migrateDataFolder(); // Load configuration - pluginConfig = ServerStatsHytaleConfig.load(this); + pluginConfig = AnalyseHytaleConfig.load(this); // Validate configuration if (!pluginConfig.isValid()) { @@ -78,6 +82,22 @@ protected void setup() { getLogger().atInfo().log("Configuration loaded successfully!"); } + /** + * Migrate the data folder from the old "ServerStats" name to "Analyse". + * Automatically renames the old folder if it exists. + */ + private void migrateDataFolder() { + File dataDir = getDataDirectory().toFile(); + File oldFolder = new File(dataDir.getParentFile(), "ServerStats"); + if (oldFolder.exists() && oldFolder.isDirectory() && !dataDir.exists()) { + if (oldFolder.renameTo(dataDir)) { + getLogger().atInfo().log("Migrated data folder from ServerStats to Analyse"); + } else { + getLogger().atWarning().log("Failed to migrate data folder from ServerStats to Analyse. Please rename it manually."); + } + } + } + @Override protected void start() { super.start(); @@ -86,23 +106,24 @@ protected void start() { if (!configValid) { getLogger() .atSevere() - .log("Cannot enable ServerStats - invalid configuration!"); + .log("Cannot enable Analyse - invalid configuration!"); return; } - getLogger().atInfo().log("Enabling ServerStats..."); + getLogger().atInfo().log("Enabling Analyse..."); // Initialize SDK client - ServerStatsConfig sdkConfig = new ServerStatsConfig( - pluginConfig.getApiKey() + AnalyseConfig sdkConfig = new AnalyseConfig( + pluginConfig.getApiKey(), + pluginConfig.isDevelopment() ); - client = new ServerStatsClient(sdkConfig); + client = new AnalyseClient(sdkConfig); - // Register with the API provider so other plugins can use ServerStats.get() - ServerStatsProvider.register(this); + // Register with the API provider so other plugins can use Analyse.get() + AnalyseProvider.register(this); - // Set up the event sender for ServerStats.trackEvent() - ServerStats.setEventSender(this::sendEvent); + // Set up the event sender for Analyse.trackEvent() + Analyse.setEventSender(this::sendEvent); // Initialize session manager sessionManager = new SessionManager(); @@ -118,7 +139,7 @@ protected void start() { ); // Register commands - getCommandRegistry().registerCommand(new ServerStatsCommand(this)); + getCommandRegistry().registerCommand(new AnalyseCommand(this)); // Start heartbeat task (every 30 seconds) scheduler = Executors.newScheduledThreadPool(3); @@ -145,7 +166,7 @@ protected void start() { addonManager.loadAddons(); addonManager.enableAddons(); - getLogger().atInfo().log("ServerStats enabled successfully!"); + getLogger().atInfo().log("Analyse enabled successfully!"); } /** @@ -166,7 +187,7 @@ private void sendEvent(EventBuilder event, Consumer callback) { client.trackEvent( request, - new ServerStatsCallback<>() { + new AnalyseCallback<>() { @Override public void onSuccess(EventResponse response) { if (isDebugEnabled()) { @@ -185,7 +206,7 @@ public void onSuccess(EventResponse response) { } @Override - public void onError(ServerStatsException exception) { + public void onError(AnalyseException exception) { logWarning( String.format( "Failed to track event '%s': %s", @@ -245,7 +266,7 @@ private void initializeOnlinePlayers() { client.join( request, - new ServerStatsCallback<>() { + new AnalyseCallback<>() { @Override public void onSuccess(JoinResponse response) { sessionManager @@ -261,7 +282,7 @@ public void onSuccess(JoinResponse response) { } @Override - public void onError(ServerStatsException exception) { + public void onError(AnalyseException exception) { getLogger() .atWarning() .log( @@ -300,7 +321,7 @@ private String getPlayerIp(PlayerRef playerRef) { @Override protected void shutdown() { - getLogger().atInfo().log("Disabling ServerStats..."); + getLogger().atInfo().log("Disabling Analyse..."); // Disable all addons first if (addonManager != null) { @@ -308,10 +329,10 @@ protected void shutdown() { } // Unregister from the API provider - ServerStatsProvider.unregister(); + AnalyseProvider.unregister(); // Clear the event sender - ServerStats.setEventSender(null); + Analyse.setEventSender(null); // Stop A/B test manager if (abTestManager != null) { @@ -338,7 +359,7 @@ protected void shutdown() { client.shutdown(); } - getLogger().atInfo().log("ServerStats disabled"); + getLogger().atInfo().log("Analyse disabled"); super.shutdown(); } @@ -365,7 +386,7 @@ public void debug(String format, Object... args) { } } - // ========== ServerStatsPlatform Interface Methods ========== + // ========== AnalysePlatform Interface Methods ========== @Override public SessionManager getSessionManager() { @@ -432,16 +453,16 @@ public String getVersion() { * * @return The plugin config */ - public ServerStatsHytaleConfig getPluginConfig() { + public AnalyseHytaleConfig getPluginConfig() { return pluginConfig; } /** * Get the SDK client * - * @return The ServerStats client + * @return The Analyse client */ - public ServerStatsClient getClient() { + public AnalyseClient getClient() { return client; } diff --git a/hytale/src/main/java/com/serverstats/hytale/addon/HytaleAddonLogger.java b/modules/hytale/src/main/java/net/analyse/hytale/addon/HytaleAddonLogger.java similarity index 92% rename from hytale/src/main/java/com/serverstats/hytale/addon/HytaleAddonLogger.java rename to modules/hytale/src/main/java/net/analyse/hytale/addon/HytaleAddonLogger.java index d3e164d..0151f18 100644 --- a/hytale/src/main/java/com/serverstats/hytale/addon/HytaleAddonLogger.java +++ b/modules/hytale/src/main/java/net/analyse/hytale/addon/HytaleAddonLogger.java @@ -1,7 +1,7 @@ -package com.serverstats.hytale.addon; +package net.analyse.hytale.addon; -import com.serverstats.api.addon.AddonLogger; -import com.serverstats.hytale.HytalePlugin; +import net.analyse.api.addon.AddonLogger; +import net.analyse.hytale.HytalePlugin; /** * Hytale implementation of AddonLogger that prefixes messages with the addon name. diff --git a/hytale/src/main/java/com/serverstats/hytale/addon/HytaleAddonManager.java b/modules/hytale/src/main/java/net/analyse/hytale/addon/HytaleAddonManager.java similarity index 86% rename from hytale/src/main/java/com/serverstats/hytale/addon/HytaleAddonManager.java rename to modules/hytale/src/main/java/net/analyse/hytale/addon/HytaleAddonManager.java index 7ae37bf..10ccf66 100644 --- a/hytale/src/main/java/com/serverstats/hytale/addon/HytaleAddonManager.java +++ b/modules/hytale/src/main/java/net/analyse/hytale/addon/HytaleAddonManager.java @@ -1,8 +1,8 @@ -package com.serverstats.hytale.addon; +package net.analyse.hytale.addon; -import com.serverstats.api.addon.AbstractAddonManager; -import com.serverstats.api.addon.AddonLogger; -import com.serverstats.hytale.HytalePlugin; +import net.analyse.api.addon.AbstractAddonManager; +import net.analyse.api.addon.AddonLogger; +import net.analyse.hytale.HytalePlugin; import java.nio.file.Path; /** diff --git a/hytale/src/main/java/com/serverstats/hytale/command/ServerStatsCommand.java b/modules/hytale/src/main/java/net/analyse/hytale/command/AnalyseCommand.java similarity index 83% rename from hytale/src/main/java/com/serverstats/hytale/command/ServerStatsCommand.java rename to modules/hytale/src/main/java/net/analyse/hytale/command/AnalyseCommand.java index fa21202..ec9f84c 100644 --- a/hytale/src/main/java/com/serverstats/hytale/command/ServerStatsCommand.java +++ b/modules/hytale/src/main/java/net/analyse/hytale/command/AnalyseCommand.java @@ -1,4 +1,4 @@ -package com.serverstats.hytale.command; +package net.analyse.hytale.command; import com.hypixel.hytale.server.core.Message; import com.hypixel.hytale.server.core.command.system.AbstractCommand; @@ -7,17 +7,17 @@ import com.hypixel.hytale.server.core.command.system.ParseResult; import com.hypixel.hytale.server.core.command.system.ParserContext; -import com.serverstats.api.ServerStats; -import com.serverstats.api.addon.LoadedAddon; -import com.serverstats.api.exception.ServerStatsException; -import com.serverstats.api.object.builder.EventBuilder; -import com.serverstats.hytale.HytalePlugin; -import com.serverstats.hytale.object.session.PlayerSession; -import com.serverstats.hytale.util.ComponentUtil; -import com.serverstats.sdk.ServerStatsCallback; -import com.serverstats.sdk.request.PlayerInfoRequest; -import com.serverstats.sdk.response.PlayerInfoResponse; -import com.serverstats.sdk.response.ServerInfoResponse; +import net.analyse.api.Analyse; +import net.analyse.api.addon.LoadedAddon; +import net.analyse.api.exception.AnalyseException; +import net.analyse.api.object.builder.EventBuilder; +import net.analyse.hytale.HytalePlugin; +import net.analyse.hytale.object.session.PlayerSession; +import net.analyse.hytale.util.ComponentUtil; +import net.analyse.sdk.AnalyseCallback; +import net.analyse.sdk.request.PlayerInfoRequest; +import net.analyse.sdk.response.PlayerInfoResponse; +import net.analyse.sdk.response.ServerInfoResponse; import com.hypixel.hytale.server.core.universe.PlayerRef; import javax.annotation.Nonnull; @@ -30,14 +30,14 @@ import java.util.concurrent.CompletableFuture; /** - * Main command handler for the ServerStats plugin + * Main command handler for the Analyse plugin */ -public class ServerStatsCommand extends AbstractCommand { +public class AnalyseCommand extends AbstractCommand { private final HytalePlugin plugin; - public ServerStatsCommand(HytalePlugin plugin) { - super("serverstats", "ServerStats analytics plugin command"); + public AnalyseCommand(HytalePlugin plugin) { + super("analyse", "Analyse analytics plugin command"); addAliases("analyse", "ss"); setAllowsExtraArguments(true); this.plugin = plugin; @@ -115,11 +115,11 @@ private void onStatus(CommandSender sender) { */ private void showPublicInfo(CommandSender sender) { StringBuilder message = new StringBuilder(); - message.append("#3498db&l「 ServerStats 」&r\n"); - message.append(" #5dade2┃ &7This server uses &fServerStats &7to track\n"); + message.append("#3498db&l「 Analyse 」&r\n"); + message.append(" #5dade2┃ &7This server uses &fAnalyse &7to track\n"); message.append(" #5dade2┃ &7player analytics and sessions.&r\n"); message.append("&r\n"); - message.append(" &7→ &fserverstats.com&r\n"); + message.append(" &7→ &fanalyse.net&r\n"); send(sender, message.toString()); } @@ -129,17 +129,17 @@ private void showPublicInfo(CommandSender sender) { * @param sender The command sender */ private void showStatus(CommandSender sender) { - boolean connected = ServerStats.isConnected(); + boolean connected = Analyse.isConnected(); int trackedPlayers = plugin.getSessionManager().getSessionCount(); boolean debugEnabled = plugin.isDebugEnabled(); StringBuilder message = new StringBuilder(); - message.append("#3498db&l「 ServerStats &r&fv").append(plugin.getVersion()).append(" #3498db&l」&r\n"); + message.append("#3498db&l「 Analyse &r&fv").append(plugin.getVersion()).append(" #3498db&l」&r\n"); message.append(" #5dade2┃ &fStatus: ").append(connected ? "&a● Connected" : "&c● Disconnected").append("&r\n"); - if (!connected && ServerStats.getLastConnectionError() != null) { - message.append(" #5dade2┃ &fError: &c").append(ServerStats.getLastConnectionError()).append("&r\n"); + if (!connected && Analyse.getLastConnectionError() != null) { + message.append(" #5dade2┃ &fError: &c").append(Analyse.getLastConnectionError()).append("&r\n"); } - message.append(" #5dade2┃ &fAPI: &7api.serverstats.com&r\n"); + message.append(" #5dade2┃ &fAPI: &7api.analyse.net&r\n"); message.append(" #5dade2┃ &fPlayers Tracked: &7").append(trackedPlayers).append("&r\n"); message.append(" #5dade2┃ &fDebug: ").append(debugEnabled ? "&aEnabled" : "&7Disabled").append("&r\n"); send(sender, message.toString()); @@ -169,12 +169,12 @@ private void onDebug(CommandSender sender) { */ private void onEvent(CommandSender sender, String[] args) { if (args.length == 0) { - send(sender, "&cUsage: /serverstats event [--value ] [--data key=value...]"); + send(sender, "&cUsage: /analyse event [--value ] [--data key=value...]"); return; } - if (!ServerStats.isAvailable()) { - send(sender, "&cServerStats is not connected. Cannot send events."); + if (!Analyse.isAvailable()) { + send(sender, "&cAnalyse is not connected. Cannot send events."); return; } @@ -210,7 +210,7 @@ private void onEvent(CommandSender sender, String[] args) { } // Build the event - EventBuilder builder = ServerStats.trackEvent(eventName); + EventBuilder builder = Analyse.trackEvent(eventName); // Add value if specified if (value != null) { @@ -246,8 +246,8 @@ private void onEvent(CommandSender sender, String[] args) { * @param args The command arguments */ private void onInfo(CommandSender sender, String[] args) { - if (!ServerStats.isAvailable()) { - send(sender, "&cServerStats is not connected."); + if (!Analyse.isAvailable()) { + send(sender, "&cAnalyse is not connected."); return; } @@ -270,7 +270,7 @@ private void showServerInfo(CommandSender sender) { int onlinePlayers = plugin.getUniverse().getPlayers().size(); // Fetch additional data from API - plugin.getClient().getServerInfo(new ServerStatsCallback<>() { + plugin.getClient().getServerInfo(new AnalyseCallback<>() { @Override public void onSuccess(ServerInfoResponse response) { StringBuilder message = new StringBuilder(); @@ -290,7 +290,7 @@ public void onSuccess(ServerInfoResponse response) { } @Override -public void onError(ServerStatsException exception) { +public void onError(AnalyseException exception) { StringBuilder message = new StringBuilder(); message.append("#3498db&l「 Server Analytics 」&r\n"); message.append(" #5dade2┃ &fOnline Players: &7").append(onlinePlayers).append("&r\n"); @@ -326,14 +326,14 @@ private void showPlayerInfo(CommandSender sender, String playerName) { String username = player.getUsername(); // Fetch additional data from API - plugin.getClient().getPlayerInfo(new PlayerInfoRequest(player.getUuid()), new ServerStatsCallback<>() { + plugin.getClient().getPlayerInfo(new PlayerInfoRequest(player.getUuid()), new AnalyseCallback<>() { @Override public void onSuccess(PlayerInfoResponse response) { send(sender, buildPlayerInfoMessage(username, session, response)); } @Override - public void onError(ServerStatsException exception) { + public void onError(AnalyseException exception) { send(sender, buildPlayerInfoMessage(username, session, null)); } }); @@ -426,7 +426,7 @@ private void onAddons(CommandSender sender, String[] args) { Collection addons = plugin.getAddonManager().getLoadedAddons(); StringBuilder message = new StringBuilder(); - message.append("#3498db&l「 ServerStats Addons 」&r\n"); + message.append("#3498db&l「 Analyse Addons 」&r\n"); if (addons.isEmpty()) { message.append(" &7No addons loaded.&r\n"); @@ -477,7 +477,7 @@ private void onAddons(CommandSender sender, String[] args) { } case "enable" -> { if (actionArgs.length == 0) { - send(sender, "&cUsage: /serverstats addons enable "); + send(sender, "&cUsage: /analyse addons enable "); return; } String addonId = actionArgs[0]; @@ -497,7 +497,7 @@ private void onAddons(CommandSender sender, String[] args) { } case "disable" -> { if (actionArgs.length == 0) { - send(sender, "&cUsage: /serverstats addons disable "); + send(sender, "&cUsage: /analyse addons disable "); return; } String addonId = actionArgs[0]; @@ -515,7 +515,7 @@ private void onAddons(CommandSender sender, String[] args) { send(sender, "&cFailed to disable addon '" + addonId + "'."); } } - default -> send(sender, "&cUnknown addon command. Use: /serverstats addons [reload|enable|disable]"); + default -> send(sender, "&cUnknown addon command. Use: /analyse addons [reload|enable|disable]"); } } @@ -526,16 +526,16 @@ private void onAddons(CommandSender sender, String[] args) { */ private void onHelp(CommandSender sender) { StringBuilder message = new StringBuilder(); - message.append("#3498db&l「 ServerStats Commands 」&r\n"); - message.append(" #5dade2┃ &f/serverstats &7- Show plugin info&r\n"); - message.append(" #5dade2┃ &f/serverstats status &7- Show plugin status&r\n"); - message.append(" #5dade2┃ &f/serverstats info &7- View server analytics&r\n"); - message.append(" #5dade2┃ &f/serverstats info &7- View player analytics&r\n"); - message.append(" #5dade2┃ &f/serverstats debug &7- Toggle debug mode&r\n"); - message.append(" #5dade2┃ &f/serverstats event &7- Send custom event&r\n"); - message.append(" #5dade2┃ &f/serverstats addons &7- List loaded addons&r\n"); - message.append(" #5dade2┃ &f/serverstats addons reload [id] &7- Reload addons&r\n"); - message.append(" #5dade2┃ &f/serverstats help &7- Show this help&r\n"); + message.append("#3498db&l「 Analyse Commands 」&r\n"); + message.append(" #5dade2┃ &f/analyse &7- Show plugin info&r\n"); + message.append(" #5dade2┃ &f/analyse status &7- Show plugin status&r\n"); + message.append(" #5dade2┃ &f/analyse info &7- View server analytics&r\n"); + message.append(" #5dade2┃ &f/analyse info &7- View player analytics&r\n"); + message.append(" #5dade2┃ &f/analyse debug &7- Toggle debug mode&r\n"); + message.append(" #5dade2┃ &f/analyse event &7- Send custom event&r\n"); + message.append(" #5dade2┃ &f/analyse addons &7- List loaded addons&r\n"); + message.append(" #5dade2┃ &f/analyse addons reload [id] &7- Reload addons&r\n"); + message.append(" #5dade2┃ &f/analyse help &7- Show this help&r\n"); send(sender, message.toString()); } diff --git a/hytale/src/main/java/com/serverstats/hytale/config/ServerStatsHytaleConfig.java b/modules/hytale/src/main/java/net/analyse/hytale/config/AnalyseHytaleConfig.java similarity index 82% rename from hytale/src/main/java/com/serverstats/hytale/config/ServerStatsHytaleConfig.java rename to modules/hytale/src/main/java/net/analyse/hytale/config/AnalyseHytaleConfig.java index d46c0ed..91fdf00 100644 --- a/hytale/src/main/java/com/serverstats/hytale/config/ServerStatsHytaleConfig.java +++ b/modules/hytale/src/main/java/net/analyse/hytale/config/AnalyseHytaleConfig.java @@ -1,4 +1,4 @@ -package com.serverstats.hytale.config; +package net.analyse.hytale.config; import com.google.gson.Gson; import com.google.gson.GsonBuilder; @@ -15,11 +15,12 @@ * Configuration for the Hytale plugin */ @Getter -public class ServerStatsHytaleConfig { +public class AnalyseHytaleConfig { private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); private boolean debug; + private boolean development; private String apiKey; private String instanceId; @@ -29,19 +30,19 @@ public class ServerStatsHytaleConfig { * @param plugin The plugin instance * @return The loaded configuration */ - public static ServerStatsHytaleConfig load(JavaPlugin plugin) { + public static AnalyseHytaleConfig load(JavaPlugin plugin) { Path configPath = plugin.getDataDirectory().resolve("config.json"); // If config doesn't exist, create default if (!Files.exists(configPath)) { - ServerStatsHytaleConfig defaultConfig = createDefault(); + AnalyseHytaleConfig defaultConfig = createDefault(); defaultConfig.save(configPath); return defaultConfig; } // Load existing config try (Reader reader = Files.newBufferedReader(configPath, StandardCharsets.UTF_8)) { - return GSON.fromJson(reader, ServerStatsHytaleConfig.class); + return GSON.fromJson(reader, AnalyseHytaleConfig.class); } catch (IOException e) { plugin.getLogger().atWarning().log("Failed to load config.json, using defaults: %s", e.getMessage()); return createDefault(); @@ -53,9 +54,10 @@ public static ServerStatsHytaleConfig load(JavaPlugin plugin) { * * @return The default config */ - private static ServerStatsHytaleConfig createDefault() { - ServerStatsHytaleConfig config = new ServerStatsHytaleConfig(); + private static AnalyseHytaleConfig createDefault() { + AnalyseHytaleConfig config = new AnalyseHytaleConfig(); config.debug = false; + config.development = false; config.apiKey = ""; config.instanceId = "default"; return config; diff --git a/hytale/src/main/java/com/serverstats/hytale/listener/PlayerListener.java b/modules/hytale/src/main/java/net/analyse/hytale/listener/PlayerListener.java similarity index 87% rename from hytale/src/main/java/com/serverstats/hytale/listener/PlayerListener.java rename to modules/hytale/src/main/java/net/analyse/hytale/listener/PlayerListener.java index d09f836..6b43ab2 100644 --- a/hytale/src/main/java/com/serverstats/hytale/listener/PlayerListener.java +++ b/modules/hytale/src/main/java/net/analyse/hytale/listener/PlayerListener.java @@ -1,4 +1,4 @@ -package com.serverstats.hytale.listener; +package net.analyse.hytale.listener; import com.hypixel.hytale.component.Ref; import com.hypixel.hytale.component.Store; @@ -9,16 +9,16 @@ import com.hypixel.hytale.server.core.io.PacketHandler; import com.hypixel.hytale.server.core.universe.PlayerRef; import com.hypixel.hytale.server.core.universe.world.storage.EntityStore; -import com.serverstats.api.exception.ServerStatsException; -import com.serverstats.hytale.HytalePlugin; -import com.serverstats.hytale.manager.SessionManager; -import com.serverstats.hytale.object.session.PlayerSession; -import com.serverstats.sdk.ServerStatsCallback; -import com.serverstats.sdk.ServerStatsClient; -import com.serverstats.sdk.request.JoinRequest; -import com.serverstats.sdk.request.LeaveRequest; -import com.serverstats.sdk.response.JoinResponse; -import com.serverstats.sdk.response.LeaveResponse; +import net.analyse.api.exception.AnalyseException; +import net.analyse.hytale.HytalePlugin; +import net.analyse.hytale.manager.SessionManager; +import net.analyse.hytale.object.session.PlayerSession; +import net.analyse.sdk.AnalyseCallback; +import net.analyse.sdk.AnalyseClient; +import net.analyse.sdk.request.JoinRequest; +import net.analyse.sdk.request.LeaveRequest; +import net.analyse.sdk.response.JoinResponse; +import net.analyse.sdk.response.LeaveResponse; import io.netty.handler.codec.quic.QuicStreamChannel; import java.net.InetSocketAddress; import java.net.SocketAddress; @@ -32,9 +32,9 @@ public class PlayerListener { private final HytalePlugin plugin; private final SessionManager sessionManager; - private final ServerStatsClient client; + private final AnalyseClient client; - public PlayerListener(HytalePlugin plugin, ServerStatsClient client) { + public PlayerListener(HytalePlugin plugin, AnalyseClient client) { this.plugin = plugin; this.sessionManager = plugin.getSessionManager(); this.client = client; @@ -67,7 +67,7 @@ public void onPlayerReady(PlayerReadyEvent event) { // Send join event to the API JoinRequest request = new JoinRequest(playerUuid, playerName, hostname, ip, false); - client.join(request, new ServerStatsCallback<>() { + client.join(request, new AnalyseCallback<>() { @Override public void onSuccess(JoinResponse response) { sessionManager.getSession(playerUuid).ifPresent(session -> session.setSessionId(response.getSessionId())); @@ -75,7 +75,7 @@ public void onSuccess(JoinResponse response) { } @Override - public void onError(ServerStatsException exception) { + public void onError(AnalyseException exception) { plugin.logWarning(String.format("Failed to send join event for %s: %s", playerName, exception.getMessage())); } }); @@ -107,7 +107,7 @@ public void onPlayerDisconnect(PlayerDisconnectEvent event) { client.leave( request, - new ServerStatsCallback<>() { + new AnalyseCallback<>() { @Override public void onSuccess(LeaveResponse response) { plugin.debug( @@ -118,7 +118,7 @@ public void onSuccess(LeaveResponse response) { } @Override - public void onError(ServerStatsException exception) { + public void onError(AnalyseException exception) { plugin.logWarning( String.format( "Failed to send leave event for %s: %s", diff --git a/hytale/src/main/java/com/serverstats/hytale/manager/ABTestManager.java b/modules/hytale/src/main/java/net/analyse/hytale/manager/ABTestManager.java similarity index 73% rename from hytale/src/main/java/com/serverstats/hytale/manager/ABTestManager.java rename to modules/hytale/src/main/java/net/analyse/hytale/manager/ABTestManager.java index ba2a265..53076bb 100644 --- a/hytale/src/main/java/com/serverstats/hytale/manager/ABTestManager.java +++ b/modules/hytale/src/main/java/net/analyse/hytale/manager/ABTestManager.java @@ -1,15 +1,15 @@ -package com.serverstats.hytale.manager; +package net.analyse.hytale.manager; import com.hypixel.hytale.server.core.universe.PlayerRef; -import com.serverstats.api.exception.ServerStatsException; -import com.serverstats.api.object.abtest.ABTest; -import com.serverstats.hytale.HytalePlugin; -import com.serverstats.hytale.object.action.HytaleAction; -import com.serverstats.sdk.ServerStatsCallback; -import com.serverstats.sdk.object.action.ActionData; -import com.serverstats.sdk.request.ConversionRequest; -import com.serverstats.sdk.response.ABTestsResponse; -import com.serverstats.sdk.response.ConversionResponse; +import net.analyse.api.exception.AnalyseException; +import net.analyse.api.object.abtest.ABTest; +import net.analyse.hytale.HytalePlugin; +import net.analyse.hytale.object.action.HytaleAction; +import net.analyse.sdk.AnalyseCallback; +import net.analyse.sdk.object.action.ActionData; +import net.analyse.sdk.request.ConversionRequest; +import net.analyse.sdk.response.ABTestsResponse; +import net.analyse.sdk.response.ConversionResponse; import java.util.List; import java.util.Map; @@ -23,13 +23,13 @@ * Manages A/B tests for the Hytale plugin. * Handles fetching, caching, and executing tests. */ -public class ABTestManager implements com.serverstats.api.manager.ABTestManager { +public class ABTestManager implements net.analyse.api.manager.ABTestManager { private static final long SYNC_INTERVAL_MINUTES = 5; private final HytalePlugin plugin; private final ScheduledExecutorService scheduler; - private final Map testsCache = new ConcurrentHashMap<>(); + private final Map testsCache = new ConcurrentHashMap<>(); private ScheduledFuture syncTask; public ABTestManager(HytalePlugin plugin, ScheduledExecutorService scheduler) { @@ -75,12 +75,12 @@ private void syncTests() { return; } - plugin.getClient().getABTests(new ServerStatsCallback<>() { + plugin.getClient().getABTests(new AnalyseCallback<>() { @Override public void onSuccess(ABTestsResponse response) { if (response.isSuccess() && response.getTests() != null) { testsCache.clear(); - for (com.serverstats.sdk.object.abtest.ABTest test : response.getTests()) { + for (net.analyse.sdk.object.abtest.ABTest test : response.getTests()) { if (test.isActive()) { testsCache.put(test.getKey(), test); } @@ -93,7 +93,7 @@ public void onSuccess(ABTestsResponse response) { } @Override - public void onError(ServerStatsException exception) { + public void onError(AnalyseException exception) { plugin.logWarning(String.format("Failed to sync A/B tests: %s", exception.getMessage())); } }); @@ -101,7 +101,7 @@ public void onError(ServerStatsException exception) { @Override @SuppressWarnings("unchecked") - public List getActiveTests() { + public List getActiveTests() { return List.copyOf(testsCache.values()); } @@ -112,7 +112,7 @@ public ABTest getTest(String testKey) { @Override public String getVariant(UUID playerUuid, String testKey) { - com.serverstats.sdk.object.abtest.ABTest test = testsCache.get(testKey); + net.analyse.sdk.object.abtest.ABTest test = testsCache.get(testKey); if (test == null) { return null; } @@ -136,7 +136,7 @@ public boolean isTestActive(String testKey) { public void processJoin(PlayerRef playerRef, boolean firstJoin) { ABTest.Trigger trigger = firstJoin ? ABTest.Trigger.FIRST_JOIN : ABTest.Trigger.EVERY_JOIN; - for (com.serverstats.sdk.object.abtest.ABTest test : testsCache.values()) { + for (net.analyse.sdk.object.abtest.ABTest test : testsCache.values()) { if (!test.matchesTrigger(trigger)) { continue; } @@ -144,7 +144,7 @@ public void processJoin(PlayerRef playerRef, boolean firstJoin) { // Assign variant and execute actions var variant = test.assignVariant(playerRef.getUuid()); if (variant != null && variant.hasActions()) { - executeActions(playerRef, test, (com.serverstats.sdk.object.abtest.Variant) variant); + executeActions(playerRef, test, (net.analyse.sdk.object.abtest.Variant) variant); } } } @@ -156,7 +156,7 @@ public void processJoin(PlayerRef playerRef, boolean firstJoin) { * @param eventName The event name */ public void processEvent(PlayerRef playerRef, String eventName) { - for (com.serverstats.sdk.object.abtest.ABTest test : testsCache.values()) { + for (net.analyse.sdk.object.abtest.ABTest test : testsCache.values()) { if (!test.matchesEvent(eventName)) { continue; } @@ -164,7 +164,7 @@ public void processEvent(PlayerRef playerRef, String eventName) { // Assign variant and execute actions var variant = test.assignVariant(playerRef.getUuid()); if (variant != null && variant.hasActions()) { - executeActions(playerRef, test, (com.serverstats.sdk.object.abtest.Variant) variant); + executeActions(playerRef, test, (net.analyse.sdk.object.abtest.Variant) variant); } } } @@ -176,8 +176,8 @@ public void processEvent(PlayerRef playerRef, String eventName) { * @param test The A/B test * @param variant The assigned variant */ - private void executeActions(PlayerRef playerRef, com.serverstats.sdk.object.abtest.ABTest test, - com.serverstats.sdk.object.abtest.Variant variant) { + private void executeActions(PlayerRef playerRef, net.analyse.sdk.object.abtest.ABTest test, + net.analyse.sdk.object.abtest.Variant variant) { if (plugin.isDebugEnabled()) { plugin.logInfo(String.format("[DEBUG] Player %s assigned to variant '%s' for test '%s'", playerRef.getUsername(), variant.getKey(), test.getKey())); @@ -193,7 +193,7 @@ private void executeActions(PlayerRef playerRef, com.serverstats.sdk.object.abte @Override public void trackConversion(UUID playerUuid, String playerUsername, String testKey, String eventName) { - com.serverstats.sdk.object.abtest.ABTest test = testsCache.get(testKey); + net.analyse.sdk.object.abtest.ABTest test = testsCache.get(testKey); if (test == null) { return; } @@ -205,7 +205,7 @@ public void trackConversion(UUID playerUuid, String playerUsername, String testK testKey, variantKey, playerUuid, playerUsername, eventName, null ); - plugin.getClient().trackConversion(request, new ServerStatsCallback<>() { + plugin.getClient().trackConversion(request, new AnalyseCallback<>() { @Override public void onSuccess(ConversionResponse response) { if (plugin.isDebugEnabled()) { @@ -215,7 +215,7 @@ public void onSuccess(ConversionResponse response) { } @Override - public void onError(ServerStatsException exception) { + public void onError(AnalyseException exception) { plugin.logWarning(String.format("Failed to track conversion: %s", exception.getMessage())); } }); diff --git a/paper/src/main/java/com/serverstats/paper/manager/SessionManager.java b/modules/hytale/src/main/java/net/analyse/hytale/manager/SessionManager.java similarity index 89% rename from paper/src/main/java/com/serverstats/paper/manager/SessionManager.java rename to modules/hytale/src/main/java/net/analyse/hytale/manager/SessionManager.java index d849554..a200168 100644 --- a/paper/src/main/java/com/serverstats/paper/manager/SessionManager.java +++ b/modules/hytale/src/main/java/net/analyse/hytale/manager/SessionManager.java @@ -1,6 +1,6 @@ -package com.serverstats.paper.manager; +package net.analyse.hytale.manager; -import com.serverstats.paper.object.session.PlayerSession; +import net.analyse.hytale.object.session.PlayerSession; import java.util.Collection; import java.util.Map; import java.util.Optional; @@ -10,7 +10,7 @@ /** * Thread-safe manager for player sessions */ -public class SessionManager implements com.serverstats.api.manager.SessionManager { +public class SessionManager implements net.analyse.api.manager.SessionManager { private final Map sessions = new ConcurrentHashMap<>(); diff --git a/hytale/src/main/java/com/serverstats/hytale/object/action/HytaleAction.java b/modules/hytale/src/main/java/net/analyse/hytale/object/action/HytaleAction.java similarity index 89% rename from hytale/src/main/java/com/serverstats/hytale/object/action/HytaleAction.java rename to modules/hytale/src/main/java/net/analyse/hytale/object/action/HytaleAction.java index eac6fa5..17a0e27 100644 --- a/hytale/src/main/java/com/serverstats/hytale/object/action/HytaleAction.java +++ b/modules/hytale/src/main/java/net/analyse/hytale/object/action/HytaleAction.java @@ -1,9 +1,9 @@ -package com.serverstats.hytale.object.action; +package net.analyse.hytale.object.action; import com.hypixel.hytale.server.core.universe.PlayerRef; -import com.serverstats.hytale.HytalePlugin; -import com.serverstats.sdk.object.action.Action; -import com.serverstats.sdk.object.action.ActionData; +import net.analyse.hytale.HytalePlugin; +import net.analyse.sdk.object.action.Action; +import net.analyse.sdk.object.action.ActionData; /** * Base class for Hytale-specific A/B test actions. diff --git a/hytale/src/main/java/com/serverstats/hytale/object/action/RunCommandAction.java b/modules/hytale/src/main/java/net/analyse/hytale/object/action/RunCommandAction.java similarity index 80% rename from hytale/src/main/java/com/serverstats/hytale/object/action/RunCommandAction.java rename to modules/hytale/src/main/java/net/analyse/hytale/object/action/RunCommandAction.java index 0610c16..7b89e08 100644 --- a/hytale/src/main/java/com/serverstats/hytale/object/action/RunCommandAction.java +++ b/modules/hytale/src/main/java/net/analyse/hytale/object/action/RunCommandAction.java @@ -1,10 +1,10 @@ -package com.serverstats.hytale.object.action; +package net.analyse.hytale.object.action; import com.hypixel.hytale.server.core.universe.PlayerRef; -import com.serverstats.hytale.HytalePlugin; -import com.serverstats.sdk.object.action.ActionData; -import com.serverstats.sdk.object.action.ActionType; +import net.analyse.hytale.HytalePlugin; +import net.analyse.sdk.object.action.ActionData; +import net.analyse.sdk.object.action.ActionType; /** * Action that runs a command. diff --git a/hytale/src/main/java/com/serverstats/hytale/object/action/SendMessageAction.java b/modules/hytale/src/main/java/net/analyse/hytale/object/action/SendMessageAction.java similarity index 78% rename from hytale/src/main/java/com/serverstats/hytale/object/action/SendMessageAction.java rename to modules/hytale/src/main/java/net/analyse/hytale/object/action/SendMessageAction.java index 751e1c1..364afbc 100644 --- a/hytale/src/main/java/com/serverstats/hytale/object/action/SendMessageAction.java +++ b/modules/hytale/src/main/java/net/analyse/hytale/object/action/SendMessageAction.java @@ -1,11 +1,11 @@ -package com.serverstats.hytale.object.action; +package net.analyse.hytale.object.action; import com.hypixel.hytale.server.core.Message; import com.hypixel.hytale.server.core.universe.PlayerRef; -import com.serverstats.hytale.HytalePlugin; -import com.serverstats.hytale.util.ComponentUtil; -import com.serverstats.sdk.object.action.ActionData; -import com.serverstats.sdk.object.action.ActionType; +import net.analyse.hytale.HytalePlugin; +import net.analyse.hytale.util.ComponentUtil; +import net.analyse.sdk.object.action.ActionData; +import net.analyse.sdk.object.action.ActionType; import net.kyori.adventure.text.Component; /** diff --git a/paper/src/main/java/com/serverstats/paper/object/session/PlayerSession.java b/modules/hytale/src/main/java/net/analyse/hytale/object/session/PlayerSession.java similarity index 88% rename from paper/src/main/java/com/serverstats/paper/object/session/PlayerSession.java rename to modules/hytale/src/main/java/net/analyse/hytale/object/session/PlayerSession.java index 880f41d..b34d37d 100644 --- a/paper/src/main/java/com/serverstats/paper/object/session/PlayerSession.java +++ b/modules/hytale/src/main/java/net/analyse/hytale/object/session/PlayerSession.java @@ -1,4 +1,4 @@ -package com.serverstats.paper.object.session; +package net.analyse.hytale.object.session; import lombok.Getter; import java.time.Instant; @@ -8,7 +8,7 @@ * Stores session data for a connected player */ @Getter -public class PlayerSession implements com.serverstats.api.session.PlayerSession { +public class PlayerSession implements net.analyse.api.session.PlayerSession { private final UUID playerUuid; private final String hostname; diff --git a/hytale/src/main/java/com/serverstats/hytale/task/HeartbeatTask.java b/modules/hytale/src/main/java/net/analyse/hytale/task/HeartbeatTask.java similarity index 67% rename from hytale/src/main/java/com/serverstats/hytale/task/HeartbeatTask.java rename to modules/hytale/src/main/java/net/analyse/hytale/task/HeartbeatTask.java index 4dd0e18..da6df8a 100644 --- a/hytale/src/main/java/com/serverstats/hytale/task/HeartbeatTask.java +++ b/modules/hytale/src/main/java/net/analyse/hytale/task/HeartbeatTask.java @@ -1,19 +1,19 @@ -package com.serverstats.hytale.task; +package net.analyse.hytale.task; import com.hypixel.hytale.server.core.universe.PlayerRef; import com.hypixel.hytale.server.core.universe.Universe; import java.util.List; import java.util.Optional; -import com.serverstats.api.ServerStats; -import com.serverstats.api.exception.ServerStatsException; -import com.serverstats.hytale.HytalePlugin; -import com.serverstats.hytale.object.session.PlayerSession; -import com.serverstats.sdk.ServerStatsCallback; -import com.serverstats.sdk.ServerStatsClient; -import com.serverstats.sdk.request.HeartbeatRequest; -import com.serverstats.sdk.request.PlayerInfo; -import com.serverstats.sdk.request.ServerType; -import com.serverstats.sdk.response.HeartbeatResponse; +import net.analyse.api.Analyse; +import net.analyse.api.exception.AnalyseException; +import net.analyse.hytale.HytalePlugin; +import net.analyse.hytale.object.session.PlayerSession; +import net.analyse.sdk.AnalyseCallback; +import net.analyse.sdk.AnalyseClient; +import net.analyse.sdk.request.HeartbeatRequest; +import net.analyse.sdk.request.PlayerInfo; +import net.analyse.sdk.request.ServerType; +import net.analyse.sdk.response.HeartbeatResponse; /** * Sends periodic heartbeats to the API with online players @@ -21,9 +21,9 @@ public class HeartbeatTask implements Runnable { private final HytalePlugin plugin; - private final ServerStatsClient client; + private final AnalyseClient client; - public HeartbeatTask(HytalePlugin plugin, ServerStatsClient client) { + public HeartbeatTask(HytalePlugin plugin, AnalyseClient client) { this.plugin = plugin; this.client = client; } @@ -43,10 +43,10 @@ public void run() { client.heartbeat( request, - new ServerStatsCallback<>() { + new AnalyseCallback<>() { @Override public void onSuccess(HeartbeatResponse response) { - ServerStats.setConnectionStatus(true, null); + Analyse.setConnectionStatus(true, null); plugin.debug( "Heartbeat sent (%d players)", response.getOnlineCount() @@ -54,8 +54,8 @@ public void onSuccess(HeartbeatResponse response) { } @Override - public void onError(ServerStatsException exception) { - ServerStats.setConnectionStatus(false, exception.getMessage()); + public void onError(AnalyseException exception) { + Analyse.setConnectionStatus(false, exception.getMessage()); plugin.logWarning( String.format( "Failed to send heartbeat: %s", diff --git a/hytale/src/main/java/com/serverstats/hytale/update/HytaleUpdateChecker.java b/modules/hytale/src/main/java/net/analyse/hytale/update/HytaleUpdateChecker.java similarity index 94% rename from hytale/src/main/java/com/serverstats/hytale/update/HytaleUpdateChecker.java rename to modules/hytale/src/main/java/net/analyse/hytale/update/HytaleUpdateChecker.java index f5f7f95..90093b7 100644 --- a/hytale/src/main/java/com/serverstats/hytale/update/HytaleUpdateChecker.java +++ b/modules/hytale/src/main/java/net/analyse/hytale/update/HytaleUpdateChecker.java @@ -1,7 +1,7 @@ -package com.serverstats.hytale.update; +package net.analyse.hytale.update; -import com.serverstats.hytale.HytalePlugin; -import com.serverstats.sdk.update.UpdateChecker; +import net.analyse.hytale.HytalePlugin; +import net.analyse.sdk.update.UpdateChecker; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; @@ -71,7 +71,7 @@ public void check(boolean force) { public void onUpdateAvailable(String currentVersion, String newVersion, String downloadUrl) { // Log to console plugin.logInfo("╔════════════════════════════════════════════════════════════╗"); - plugin.logInfo("║ A new version of ServerStats is available! ║"); + plugin.logInfo("║ A new version of Analyse is available! ║"); plugin.logInfo("║ Current: " + padRight(currentVersion, 20) + " Latest: " + padRight(newVersion, 20) + "║"); plugin.logInfo("║ Download: " + padRight(downloadUrl, 47) + "║"); plugin.logInfo("╚════════════════════════════════════════════════════════════╝"); diff --git a/hytale/src/main/java/com/serverstats/hytale/util/ComponentUtil.java b/modules/hytale/src/main/java/net/analyse/hytale/util/ComponentUtil.java similarity index 99% rename from hytale/src/main/java/com/serverstats/hytale/util/ComponentUtil.java rename to modules/hytale/src/main/java/net/analyse/hytale/util/ComponentUtil.java index a974950..95dc943 100644 --- a/hytale/src/main/java/com/serverstats/hytale/util/ComponentUtil.java +++ b/modules/hytale/src/main/java/net/analyse/hytale/util/ComponentUtil.java @@ -1,4 +1,4 @@ -package com.serverstats.hytale.util; +package net.analyse.hytale.util; import com.hypixel.hytale.server.core.Message; import java.util.Map; diff --git a/hytale/src/main/resources/config.json b/modules/hytale/src/main/resources/config.json similarity index 100% rename from hytale/src/main/resources/config.json rename to modules/hytale/src/main/resources/config.json diff --git a/hytale/src/main/resources/manifest.json b/modules/hytale/src/main/resources/manifest.json similarity index 61% rename from hytale/src/main/resources/manifest.json rename to modules/hytale/src/main/resources/manifest.json index 47b41b1..e6fe83d 100644 --- a/hytale/src/main/resources/manifest.json +++ b/modules/hytale/src/main/resources/manifest.json @@ -1,14 +1,14 @@ { "Group": "Hytale", - "Name": "ServerStats", + "Name": "Analyse", "Version": "${version}", "Description": "Analytics plugin for Hytale servers", - "Authors": [{"Name": "VertCode"}], - "Website": "https://serverstats.com", + "Authors": [{"Name": "VertCode Development"}], + "Website": "https://analyse.net", "ServerVersion": "*", "Dependencies": {}, "OptionalDependencies": {}, "DisabledByDefault": false, - "Main": "com.serverstats.hytale.HytalePlugin", + "Main": "net.analyse.hytale.HytalePlugin", "IncludesAssetPack": false } diff --git a/sdk/build.gradle b/modules/sdk/build.gradle similarity index 70% rename from sdk/build.gradle rename to modules/sdk/build.gradle index cd4a892..d0d2c01 100644 --- a/sdk/build.gradle +++ b/modules/sdk/build.gradle @@ -2,8 +2,12 @@ plugins { id 'java-library' } +tasks.withType(JavaCompile).configureEach { + options.release = 8 +} + dependencies { - api project(':api') + api project(':modules:api') api "com.google.code.gson:gson:${project.property('gsonVersion')}" api "com.squareup.okhttp3:okhttp:${project.property('okhttpVersion')}" compileOnly 'org.jetbrains:annotations:24.1.0' diff --git a/sdk/src/main/java/com/serverstats/sdk/ServerStatsCallback.java b/modules/sdk/src/main/java/net/analyse/sdk/AnalyseCallback.java similarity index 65% rename from sdk/src/main/java/com/serverstats/sdk/ServerStatsCallback.java rename to modules/sdk/src/main/java/net/analyse/sdk/AnalyseCallback.java index 8510bee..80106f3 100644 --- a/sdk/src/main/java/com/serverstats/sdk/ServerStatsCallback.java +++ b/modules/sdk/src/main/java/net/analyse/sdk/AnalyseCallback.java @@ -1,13 +1,13 @@ -package com.serverstats.sdk; +package net.analyse.sdk; -import com.serverstats.api.exception.ServerStatsException; +import net.analyse.api.exception.AnalyseException; /** * Callback interface for async API responses * * @param The response type */ -public interface ServerStatsCallback { +public interface AnalyseCallback { /** * Called when the API request succeeds @@ -21,6 +21,6 @@ public interface ServerStatsCallback { * * @param exception The exception that occurred */ - void onError(ServerStatsException exception); + void onError(AnalyseException exception); } diff --git a/sdk/src/main/java/com/serverstats/sdk/ServerStatsClient.java b/modules/sdk/src/main/java/net/analyse/sdk/AnalyseClient.java similarity index 62% rename from sdk/src/main/java/com/serverstats/sdk/ServerStatsClient.java rename to modules/sdk/src/main/java/net/analyse/sdk/AnalyseClient.java index 607b43c..b9f19cc 100644 --- a/sdk/src/main/java/com/serverstats/sdk/ServerStatsClient.java +++ b/modules/sdk/src/main/java/net/analyse/sdk/AnalyseClient.java @@ -1,27 +1,27 @@ -package com.serverstats.sdk; - -import com.serverstats.sdk.config.ServerStatsConfig; -import com.serverstats.sdk.http.ServerStatsHttpClient; -import com.serverstats.sdk.request.ConversionRequest; -import com.serverstats.sdk.request.EventRequest; -import com.serverstats.sdk.request.HeartbeatRequest; -import com.serverstats.sdk.request.JoinRequest; -import com.serverstats.sdk.request.LeaveRequest; -import com.serverstats.sdk.request.PlayerInfoRequest; -import com.serverstats.sdk.response.ABTestsResponse; -import com.serverstats.sdk.response.ConversionResponse; -import com.serverstats.sdk.response.EventResponse; -import com.serverstats.sdk.response.HeartbeatResponse; -import com.serverstats.sdk.response.JoinResponse; -import com.serverstats.sdk.response.LeaveResponse; -import com.serverstats.sdk.response.PlayerInfoResponse; -import com.serverstats.sdk.response.ServerInfoResponse; -import com.serverstats.sdk.response.VersionResponse; +package net.analyse.sdk; + +import net.analyse.sdk.config.AnalyseConfig; +import net.analyse.sdk.http.AnalyseHttpClient; +import net.analyse.sdk.request.ConversionRequest; +import net.analyse.sdk.request.EventRequest; +import net.analyse.sdk.request.HeartbeatRequest; +import net.analyse.sdk.request.JoinRequest; +import net.analyse.sdk.request.LeaveRequest; +import net.analyse.sdk.request.PlayerInfoRequest; +import net.analyse.sdk.response.ABTestsResponse; +import net.analyse.sdk.response.ConversionResponse; +import net.analyse.sdk.response.EventResponse; +import net.analyse.sdk.response.HeartbeatResponse; +import net.analyse.sdk.response.JoinResponse; +import net.analyse.sdk.response.LeaveResponse; +import net.analyse.sdk.response.PlayerInfoResponse; +import net.analyse.sdk.response.ServerInfoResponse; +import net.analyse.sdk.response.VersionResponse; /** - * Main client for interacting with the ServerStats API + * Main client for interacting with the Analyse API */ -public class ServerStatsClient { +public class AnalyseClient { private static final String ENDPOINT_JOIN = "/v1/plugin/join"; private static final String ENDPOINT_LEAVE = "/v1/plugin/leave"; @@ -33,15 +33,15 @@ public class ServerStatsClient { private static final String ENDPOINT_SERVER_INFO = "/v1/plugin/info"; private static final String ENDPOINT_PLAYER_INFO = "/v1/plugin/player"; - private final ServerStatsHttpClient httpClient; + private final AnalyseHttpClient httpClient; /** * Create a new client with the given configuration * * @param config The SDK configuration */ - public ServerStatsClient(ServerStatsConfig config) { - this.httpClient = new ServerStatsHttpClient(config); + public AnalyseClient(AnalyseConfig config) { + this.httpClient = new AnalyseHttpClient(config); } /** @@ -50,7 +50,7 @@ public ServerStatsClient(ServerStatsConfig config) { * @param request The join request containing player details * @param callback The callback to invoke on success or failure */ - public void join(JoinRequest request, ServerStatsCallback callback) { + public void join(JoinRequest request, AnalyseCallback callback) { httpClient.post(ENDPOINT_JOIN, request, JoinResponse.class, callback); } @@ -60,7 +60,7 @@ public void join(JoinRequest request, ServerStatsCallback callback * @param request The leave request containing the session ID * @param callback The callback to invoke on success or failure */ - public void leave(LeaveRequest request, ServerStatsCallback callback) { + public void leave(LeaveRequest request, AnalyseCallback callback) { httpClient.post(ENDPOINT_LEAVE, request, LeaveResponse.class, callback); } @@ -70,7 +70,7 @@ public void leave(LeaveRequest request, ServerStatsCallback callb * @param request The heartbeat request containing online player UUIDs * @param callback The callback to invoke on success or failure */ - public void heartbeat(HeartbeatRequest request, ServerStatsCallback callback) { + public void heartbeat(HeartbeatRequest request, AnalyseCallback callback) { httpClient.post(ENDPOINT_HEARTBEAT, request, HeartbeatResponse.class, callback); } @@ -80,7 +80,7 @@ public void heartbeat(HeartbeatRequest request, ServerStatsCallback callback) { + public void trackEvent(EventRequest request, AnalyseCallback callback) { httpClient.post(ENDPOINT_EVENT, request, EventResponse.class, callback); } @@ -89,7 +89,7 @@ public void trackEvent(EventRequest request, ServerStatsCallback * * @param callback The callback to invoke on success or failure */ - public void getABTests(ServerStatsCallback callback) { + public void getABTests(AnalyseCallback callback) { httpClient.get(ENDPOINT_AB_TESTS, ABTestsResponse.class, callback); } @@ -99,7 +99,7 @@ public void getABTests(ServerStatsCallback callback) { * @param request The conversion request containing test and event details * @param callback The callback to invoke on success or failure */ - public void trackConversion(ConversionRequest request, ServerStatsCallback callback) { + public void trackConversion(ConversionRequest request, AnalyseCallback callback) { httpClient.post(ENDPOINT_CONVERSION, request, ConversionResponse.class, callback); } @@ -108,7 +108,7 @@ public void trackConversion(ConversionRequest request, ServerStatsCallback callback) { + public void checkVersion(AnalyseCallback callback) { httpClient.get(ENDPOINT_VERSION, VersionResponse.class, callback); } @@ -117,7 +117,7 @@ public void checkVersion(ServerStatsCallback callback) { * * @param callback The callback to invoke on success or failure */ - public void getServerInfo(ServerStatsCallback callback) { + public void getServerInfo(AnalyseCallback callback) { httpClient.get(ENDPOINT_SERVER_INFO, ServerInfoResponse.class, callback); } @@ -127,7 +127,7 @@ public void getServerInfo(ServerStatsCallback callback) { * @param request The player info request containing the player UUID * @param callback The callback to invoke on success or failure */ - public void getPlayerInfo(PlayerInfoRequest request, ServerStatsCallback callback) { + public void getPlayerInfo(PlayerInfoRequest request, AnalyseCallback callback) { String endpoint = ENDPOINT_PLAYER_INFO + "/" + request.getUuid(); httpClient.get(endpoint, PlayerInfoResponse.class, callback); } diff --git a/modules/sdk/src/main/java/net/analyse/sdk/config/AnalyseConfig.java b/modules/sdk/src/main/java/net/analyse/sdk/config/AnalyseConfig.java new file mode 100644 index 0000000..a153466 --- /dev/null +++ b/modules/sdk/src/main/java/net/analyse/sdk/config/AnalyseConfig.java @@ -0,0 +1,40 @@ +package net.analyse.sdk.config; + +import lombok.Getter; + +/** + * Configuration for the Analyse SDK + */ +@Getter +public class AnalyseConfig { + + private static final String API_URL = "https://api.analyse.net"; + private static final String STAGING_API_URL = "https://staging.analyse.net"; + + private final String apiUrl; + private final String apiKey; + + /** + * Create a new configuration + * + * @param apiKey The API key for authentication + */ + public AnalyseConfig(String apiKey) { + this(apiKey, false); + } + + /** + * Create a new configuration with optional development mode + * + * @param apiKey The API key for authentication + * @param development Whether to use the staging API + */ + public AnalyseConfig(String apiKey, boolean development) { + if (apiKey == null || apiKey.trim().isEmpty()) { + throw new IllegalArgumentException("API key cannot be null or blank"); + } + + this.apiUrl = development ? STAGING_API_URL : API_URL; + this.apiKey = apiKey; + } +} diff --git a/sdk/src/main/java/com/serverstats/sdk/http/ServerStatsHttpClient.java b/modules/sdk/src/main/java/net/analyse/sdk/http/AnalyseHttpClient.java similarity index 71% rename from sdk/src/main/java/com/serverstats/sdk/http/ServerStatsHttpClient.java rename to modules/sdk/src/main/java/net/analyse/sdk/http/AnalyseHttpClient.java index 321326e..8f500f3 100644 --- a/sdk/src/main/java/com/serverstats/sdk/http/ServerStatsHttpClient.java +++ b/modules/sdk/src/main/java/net/analyse/sdk/http/AnalyseHttpClient.java @@ -1,10 +1,10 @@ -package com.serverstats.sdk.http; +package net.analyse.sdk.http; import com.google.gson.Gson; import com.google.gson.GsonBuilder; -import com.serverstats.sdk.ServerStatsCallback; -import com.serverstats.api.exception.ServerStatsException; -import com.serverstats.sdk.config.ServerStatsConfig; +import net.analyse.sdk.AnalyseCallback; +import net.analyse.api.exception.AnalyseException; +import net.analyse.sdk.config.AnalyseConfig; import okhttp3.Call; import okhttp3.Callback; import okhttp3.MediaType; @@ -18,23 +18,23 @@ import java.util.concurrent.TimeUnit; /** - * HTTP client for making async requests to the ServerStats API + * HTTP client for making async requests to the Analyse API */ -public class ServerStatsHttpClient { +public class AnalyseHttpClient { private static final MediaType JSON = MediaType.get("application/json; charset=utf-8"); private static final int TIMEOUT_SECONDS = 10; private final OkHttpClient httpClient; private final Gson gson; - private final ServerStatsConfig config; + private final AnalyseConfig config; /** * Create a new HTTP client with the given configuration * * @param config The SDK configuration */ - public ServerStatsHttpClient(ServerStatsConfig config) { + public AnalyseHttpClient(AnalyseConfig config) { this.config = config; this.gson = new GsonBuilder().create(); this.httpClient = new OkHttpClient.Builder() @@ -53,14 +53,14 @@ public ServerStatsHttpClient(ServerStatsConfig config) { * @param callback The callback to invoke on success or failure * @param The response type */ - public void post(String endpoint, Object requestBody, Class responseClass, ServerStatsCallback callback) { + public void post(String endpoint, Object requestBody, Class responseClass, AnalyseCallback callback) { String url = config.getApiUrl() + endpoint; String json = gson.toJson(requestBody); String apiKey = config.getApiKey(); // Validate API key before making request - if (apiKey == null || apiKey.isBlank()) { - callback.onError(new ServerStatsException(401, "API key is not configured")); + if (apiKey == null || apiKey.trim().isEmpty()) { + callback.onError(new AnalyseException(401, "API key is not configured")); return; } @@ -75,7 +75,7 @@ public void post(String endpoint, Object requestBody, Class responseClass httpClient.newCall(request).enqueue(new Callback() { @Override public void onFailure(@NotNull Call call, @NotNull IOException e) { - callback.onError(new ServerStatsException("Network error: " + e.getMessage(), e)); + callback.onError(new AnalyseException("Network error: " + e.getMessage(), e)); } @Override @@ -83,12 +83,12 @@ public void onResponse(@NotNull Call call, @NotNull Response response) { try (ResponseBody body = response.body()) { if (!response.isSuccessful()) { String errorMessage = body != null ? body.string() : "Unknown error"; - callback.onError(new ServerStatsException(response.code(), errorMessage)); + callback.onError(new AnalyseException(response.code(), errorMessage)); return; } if (body == null) { - callback.onError(new ServerStatsException(500, "Empty response body")); + callback.onError(new AnalyseException(500, "Empty response body")); return; } @@ -96,9 +96,9 @@ public void onResponse(@NotNull Call call, @NotNull Response response) { T result = gson.fromJson(responseJson, responseClass); callback.onSuccess(result); } catch (IOException e) { - callback.onError(new ServerStatsException("Failed to read response: " + e.getMessage(), e)); + callback.onError(new AnalyseException("Failed to read response: " + e.getMessage(), e)); } catch (Exception e) { - callback.onError(new ServerStatsException("Failed to parse response: " + e.getMessage(), e)); + callback.onError(new AnalyseException("Failed to parse response: " + e.getMessage(), e)); } } }); @@ -112,13 +112,13 @@ public void onResponse(@NotNull Call call, @NotNull Response response) { * @param callback The callback to invoke on success or failure * @param The response type */ - public void get(String endpoint, Class responseClass, ServerStatsCallback callback) { + public void get(String endpoint, Class responseClass, AnalyseCallback callback) { String url = config.getApiUrl() + endpoint; String apiKey = config.getApiKey(); // Validate API key before making request - if (apiKey == null || apiKey.isBlank()) { - callback.onError(new ServerStatsException(401, "API key is not configured")); + if (apiKey == null || apiKey.trim().isEmpty()) { + callback.onError(new AnalyseException(401, "API key is not configured")); return; } @@ -132,7 +132,7 @@ public void get(String endpoint, Class responseClass, ServerStatsCallback httpClient.newCall(request).enqueue(new Callback() { @Override public void onFailure(@NotNull Call call, @NotNull IOException e) { - callback.onError(new ServerStatsException("Network error: " + e.getMessage(), e)); + callback.onError(new AnalyseException("Network error: " + e.getMessage(), e)); } @Override @@ -140,12 +140,12 @@ public void onResponse(@NotNull Call call, @NotNull Response response) { try (ResponseBody body = response.body()) { if (!response.isSuccessful()) { String errorMessage = body != null ? body.string() : "Unknown error"; - callback.onError(new ServerStatsException(response.code(), errorMessage)); + callback.onError(new AnalyseException(response.code(), errorMessage)); return; } if (body == null) { - callback.onError(new ServerStatsException(500, "Empty response body")); + callback.onError(new AnalyseException(500, "Empty response body")); return; } @@ -153,9 +153,9 @@ public void onResponse(@NotNull Call call, @NotNull Response response) { T result = gson.fromJson(responseJson, responseClass); callback.onSuccess(result); } catch (IOException e) { - callback.onError(new ServerStatsException("Failed to read response: " + e.getMessage(), e)); + callback.onError(new AnalyseException("Failed to read response: " + e.getMessage(), e)); } catch (Exception e) { - callback.onError(new ServerStatsException("Failed to parse response: " + e.getMessage(), e)); + callback.onError(new AnalyseException("Failed to parse response: " + e.getMessage(), e)); } } }); diff --git a/sdk/src/main/java/com/serverstats/sdk/object/abtest/ABTest.java b/modules/sdk/src/main/java/net/analyse/sdk/object/abtest/ABTest.java similarity index 81% rename from sdk/src/main/java/com/serverstats/sdk/object/abtest/ABTest.java rename to modules/sdk/src/main/java/net/analyse/sdk/object/abtest/ABTest.java index fa66072..c56cdd3 100644 --- a/sdk/src/main/java/com/serverstats/sdk/object/abtest/ABTest.java +++ b/modules/sdk/src/main/java/net/analyse/sdk/object/abtest/ABTest.java @@ -1,4 +1,4 @@ -package com.serverstats.sdk.object.abtest; +package net.analyse.sdk.object.abtest; import lombok.Getter; import java.util.List; @@ -8,7 +8,7 @@ * Concrete implementation of an A/B test configuration */ @Getter -public class ABTest implements com.serverstats.api.object.abtest.ABTest { +public class ABTest implements net.analyse.api.object.abtest.ABTest { private String id; private String key; @@ -27,7 +27,7 @@ public List getVariants() { } @Override - public com.serverstats.api.object.abtest.Variant assignVariant(UUID playerUuid) { + public net.analyse.api.object.abtest.Variant assignVariant(UUID playerUuid) { if (variants == null || variants.isEmpty()) { return null; } @@ -50,7 +50,7 @@ public com.serverstats.api.object.abtest.Variant assignVariant(UUID playerUuid) } @Override - public com.serverstats.api.object.abtest.Variant getVariant(String variantKey) { + public net.analyse.api.object.abtest.Variant getVariant(String variantKey) { if (variants == null) { return null; } diff --git a/sdk/src/main/java/com/serverstats/sdk/object/abtest/Variant.java b/modules/sdk/src/main/java/net/analyse/sdk/object/abtest/Variant.java similarity index 65% rename from sdk/src/main/java/com/serverstats/sdk/object/abtest/Variant.java rename to modules/sdk/src/main/java/net/analyse/sdk/object/abtest/Variant.java index 47813c6..4686996 100644 --- a/sdk/src/main/java/com/serverstats/sdk/object/abtest/Variant.java +++ b/modules/sdk/src/main/java/net/analyse/sdk/object/abtest/Variant.java @@ -1,14 +1,14 @@ -package com.serverstats.sdk.object.abtest; +package net.analyse.sdk.object.abtest; import lombok.Getter; -import com.serverstats.sdk.object.action.ActionData; +import net.analyse.sdk.object.action.ActionData; import java.util.List; /** * Concrete implementation of a variant in an A/B test */ @Getter -public class Variant implements com.serverstats.api.object.abtest.Variant { +public class Variant implements net.analyse.api.object.abtest.Variant { private String key; private String name; diff --git a/sdk/src/main/java/com/serverstats/sdk/object/action/Action.java b/modules/sdk/src/main/java/net/analyse/sdk/object/action/Action.java similarity index 91% rename from sdk/src/main/java/com/serverstats/sdk/object/action/Action.java rename to modules/sdk/src/main/java/net/analyse/sdk/object/action/Action.java index 2bfad31..7140283 100644 --- a/sdk/src/main/java/com/serverstats/sdk/object/action/Action.java +++ b/modules/sdk/src/main/java/net/analyse/sdk/object/action/Action.java @@ -1,4 +1,4 @@ -package com.serverstats.sdk.object.action; +package net.analyse.sdk.object.action; /** * Interface for executable A/B test actions. diff --git a/sdk/src/main/java/com/serverstats/sdk/object/action/ActionData.java b/modules/sdk/src/main/java/net/analyse/sdk/object/action/ActionData.java similarity index 85% rename from sdk/src/main/java/com/serverstats/sdk/object/action/ActionData.java rename to modules/sdk/src/main/java/net/analyse/sdk/object/action/ActionData.java index 4b6cd6f..eb51103 100644 --- a/sdk/src/main/java/com/serverstats/sdk/object/action/ActionData.java +++ b/modules/sdk/src/main/java/net/analyse/sdk/object/action/ActionData.java @@ -1,4 +1,4 @@ -package com.serverstats.sdk.object.action; +package net.analyse.sdk.object.action; import lombok.Getter; import java.util.Map; @@ -41,7 +41,8 @@ public boolean getBoolean(String key, boolean defaultValue) { } Object value = data.get(key); - if (value instanceof Boolean bool) { + if (value instanceof Boolean) { + Boolean bool = (Boolean) value; return bool; } @@ -61,11 +62,13 @@ public int getInt(String key, int defaultValue) { } Object value = data.get(key); - if (value instanceof Number number) { + if (value instanceof Number) { + Number number = (Number) value; return number.intValue(); } - if (value instanceof String str) { + if (value instanceof String) { + String str = (String) value; try { return Integer.parseInt(str); } catch (NumberFormatException e) { diff --git a/sdk/src/main/java/com/serverstats/sdk/object/action/ActionType.java b/modules/sdk/src/main/java/net/analyse/sdk/object/action/ActionType.java similarity index 75% rename from sdk/src/main/java/com/serverstats/sdk/object/action/ActionType.java rename to modules/sdk/src/main/java/net/analyse/sdk/object/action/ActionType.java index 30382bf..185dd39 100644 --- a/sdk/src/main/java/com/serverstats/sdk/object/action/ActionType.java +++ b/modules/sdk/src/main/java/net/analyse/sdk/object/action/ActionType.java @@ -1,4 +1,4 @@ -package com.serverstats.sdk.object.action; +package net.analyse.sdk.object.action; /** * Types of actions that can be executed for A/B test variants diff --git a/sdk/src/main/java/com/serverstats/sdk/request/ConversionRequest.java b/modules/sdk/src/main/java/net/analyse/sdk/request/ConversionRequest.java similarity index 89% rename from sdk/src/main/java/com/serverstats/sdk/request/ConversionRequest.java rename to modules/sdk/src/main/java/net/analyse/sdk/request/ConversionRequest.java index f5278e4..008d7ca 100644 --- a/sdk/src/main/java/com/serverstats/sdk/request/ConversionRequest.java +++ b/modules/sdk/src/main/java/net/analyse/sdk/request/ConversionRequest.java @@ -1,4 +1,4 @@ -package com.serverstats.sdk.request; +package net.analyse.sdk.request; import lombok.Getter; import java.util.Map; @@ -29,10 +29,10 @@ public class ConversionRequest { */ public ConversionRequest(String testKey, String variantKey, UUID playerUuid, String playerUsername, String eventName, Map data) { - if (testKey == null || testKey.isBlank()) { + if (testKey == null || testKey.trim().isEmpty()) { throw new IllegalArgumentException("Test key cannot be null or blank"); } - if (eventName == null || eventName.isBlank()) { + if (eventName == null || eventName.trim().isEmpty()) { throw new IllegalArgumentException("Event name cannot be null or blank"); } diff --git a/sdk/src/main/java/com/serverstats/sdk/request/EventRequest.java b/modules/sdk/src/main/java/net/analyse/sdk/request/EventRequest.java similarity index 93% rename from sdk/src/main/java/com/serverstats/sdk/request/EventRequest.java rename to modules/sdk/src/main/java/net/analyse/sdk/request/EventRequest.java index 6f2fe39..c80f694 100644 --- a/sdk/src/main/java/com/serverstats/sdk/request/EventRequest.java +++ b/modules/sdk/src/main/java/net/analyse/sdk/request/EventRequest.java @@ -1,4 +1,4 @@ -package com.serverstats.sdk.request; +package net.analyse.sdk.request; import lombok.Getter; import java.util.Map; @@ -26,7 +26,7 @@ public class EventRequest { * @param value Numeric value for aggregations (optional) */ public EventRequest(String name, UUID playerUuid, String playerUsername, Map data, Double value) { - if (name == null || name.isBlank()) { + if (name == null || name.trim().isEmpty()) { throw new IllegalArgumentException("Event name cannot be null or blank"); } diff --git a/sdk/src/main/java/com/serverstats/sdk/request/HeartbeatRequest.java b/modules/sdk/src/main/java/net/analyse/sdk/request/HeartbeatRequest.java similarity index 88% rename from sdk/src/main/java/com/serverstats/sdk/request/HeartbeatRequest.java rename to modules/sdk/src/main/java/net/analyse/sdk/request/HeartbeatRequest.java index c58acaf..215d9f3 100644 --- a/sdk/src/main/java/com/serverstats/sdk/request/HeartbeatRequest.java +++ b/modules/sdk/src/main/java/net/analyse/sdk/request/HeartbeatRequest.java @@ -1,4 +1,4 @@ -package com.serverstats.sdk.request; +package net.analyse.sdk.request; import lombok.Getter; import java.util.List; @@ -28,7 +28,7 @@ public HeartbeatRequest(String instanceId, ServerType serverType, List() { + client.checkVersion(new AnalyseCallback() { @Override public void onSuccess(VersionResponse response) { if (!response.isSuccess() || response.getPlatforms() == null) { @@ -102,7 +102,7 @@ public void onSuccess(VersionResponse response) { } @Override - public void onError(ServerStatsException exception) { + public void onError(AnalyseException exception) { listener.onCheckFailed(exception.getMessage()); } }); diff --git a/sdk/src/main/java/com/serverstats/sdk/util/ProtocolVersionUtil.java b/modules/sdk/src/main/java/net/analyse/sdk/util/ProtocolVersionUtil.java similarity index 98% rename from sdk/src/main/java/com/serverstats/sdk/util/ProtocolVersionUtil.java rename to modules/sdk/src/main/java/net/analyse/sdk/util/ProtocolVersionUtil.java index 2952dfa..dd0ff06 100644 --- a/sdk/src/main/java/com/serverstats/sdk/util/ProtocolVersionUtil.java +++ b/modules/sdk/src/main/java/net/analyse/sdk/util/ProtocolVersionUtil.java @@ -1,4 +1,4 @@ -package com.serverstats.sdk.util; +package net.analyse.sdk.util; import java.util.Map; import java.util.NavigableMap; diff --git a/modules/spigot/build.gradle b/modules/spigot/build.gradle new file mode 100644 index 0000000..77d4c83 --- /dev/null +++ b/modules/spigot/build.gradle @@ -0,0 +1,46 @@ +plugins { + id 'java' + id 'com.gradleup.shadow' +} + +tasks.withType(JavaCompile).configureEach { + options.release = 8 +} + +dependencies { + implementation project(':modules:api') + implementation project(':modules:sdk') + implementation "co.aikar:acf-bukkit:${project.property('acfVersion')}" + compileOnly 'org.spigotmc:spigot-api:1.8.8-R0.1-SNAPSHOT' + + // Adventure platform adapter (auto-detects Paper native vs Spigot legacy) + implementation 'net.kyori:adventure-api:4.17.0' + implementation 'net.kyori:adventure-text-minimessage:4.17.0' + implementation 'net.kyori:adventure-text-serializer-legacy:4.17.0' + implementation 'net.kyori:adventure-platform-bukkit:4.4.1' +} + +tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { + archiveBaseName.set('analyse-spigot') + archiveClassifier.set('') + + relocate 'net.kyori', 'net.analyse.libs.kyori' + relocate 'co.aikar.commands', 'net.analyse.libs.acf' + relocate 'co.aikar.locales', 'net.analyse.libs.locales' +} + +tasks.named('build') { + dependsOn tasks.named('shadowJar') +} + +processResources { + def props = [version: version] + inputs.properties props + filteringCharset 'UTF-8' + filesMatching('plugin.yml') { + expand props + } + filesMatching('paper-plugin.yml') { + expand props + } +} diff --git a/paper/src/main/java/com/serverstats/paper/ServerStatsPlugin.java b/modules/spigot/src/main/java/net/analyse/spigot/AnalysePlugin.java similarity index 64% rename from paper/src/main/java/com/serverstats/paper/ServerStatsPlugin.java rename to modules/spigot/src/main/java/net/analyse/spigot/AnalysePlugin.java index 9f718b6..ad9bb26 100644 --- a/paper/src/main/java/com/serverstats/paper/ServerStatsPlugin.java +++ b/modules/spigot/src/main/java/net/analyse/spigot/AnalysePlugin.java @@ -1,73 +1,96 @@ -package com.serverstats.paper; - -import co.aikar.commands.PaperCommandManager; -import com.serverstats.api.ServerStats; -import com.serverstats.api.ServerStatsProvider; -import com.serverstats.api.BuildConstants; -import com.serverstats.api.addon.AddonManager; -import com.serverstats.api.exception.ServerStatsException; -import com.serverstats.api.object.builder.EventBuilder; -import com.serverstats.api.platform.ServerStatsPlatform; -import com.serverstats.paper.addon.PaperAddonManager; -import com.serverstats.paper.manager.ABTestManager; -import com.serverstats.paper.command.ServerStatsCommand; -import com.serverstats.paper.config.ServerStatsPaperConfig; -import com.serverstats.paper.listener.ActivityListener; -import com.serverstats.paper.listener.PlayerListener; -import com.serverstats.paper.manager.SessionManager; -import com.serverstats.paper.task.HeartbeatTask; -import com.serverstats.paper.update.PaperUpdateChecker; -import com.serverstats.paper.util.SchedulerUtil; -import com.serverstats.sdk.ServerStatsCallback; -import com.serverstats.sdk.ServerStatsClient; -import com.serverstats.sdk.config.ServerStatsConfig; -import com.serverstats.sdk.request.EventRequest; -import com.serverstats.sdk.request.JoinRequest; -import com.serverstats.sdk.response.EventResponse; -import com.serverstats.sdk.response.JoinResponse; +package net.analyse.spigot; + +import co.aikar.commands.BukkitCommandManager; +import net.analyse.api.Analyse; +import net.analyse.api.AnalyseProvider; +import net.analyse.api.BuildConstants; +import net.analyse.api.addon.AddonManager; +import net.analyse.api.exception.AnalyseException; +import net.analyse.api.object.builder.EventBuilder; +import net.analyse.api.platform.AnalysePlatform; +import net.analyse.spigot.addon.SpigotAddonManager; +import net.analyse.spigot.manager.ABTestManager; +import net.analyse.spigot.command.AnalyseCommand; +import net.analyse.spigot.config.AnalyseSpigotConfig; +import net.analyse.spigot.listener.ActivityListener; +import net.analyse.spigot.listener.PlayerListener; +import net.analyse.spigot.manager.SessionManager; +import net.analyse.spigot.task.HeartbeatTask; +import net.analyse.spigot.update.SpigotUpdateChecker; +import net.analyse.spigot.util.MessageUtil; +import net.analyse.spigot.util.SchedulerUtil; +import net.analyse.sdk.AnalyseCallback; +import net.analyse.sdk.AnalyseClient; +import net.analyse.sdk.config.AnalyseConfig; +import net.analyse.sdk.request.EventRequest; +import net.analyse.sdk.request.JoinRequest; +import net.analyse.sdk.response.EventResponse; +import net.analyse.sdk.response.JoinResponse; import org.bukkit.entity.Player; import org.bukkit.plugin.java.JavaPlugin; +import java.io.File; import java.net.InetSocketAddress; import java.util.UUID; import java.util.function.Consumer; /** - * ServerStats plugin for Paper/Spigot/Bukkit servers + * Analyse plugin for Paper/Spigot/Bukkit servers */ -public class ServerStatsPlugin extends JavaPlugin implements ServerStatsPlatform { +public class AnalysePlugin extends JavaPlugin implements AnalysePlatform { - private ServerStatsPaperConfig pluginConfig; + private AnalyseSpigotConfig pluginConfig; private SessionManager sessionManager; private ABTestManager abTestManager; - private PaperAddonManager addonManager; - private ServerStatsClient client; + private SpigotAddonManager addonManager; + private AnalyseClient client; private SchedulerUtil.CancellableTask heartbeatTask; - private PaperUpdateChecker updateChecker; + private SpigotUpdateChecker updateChecker; private PlayerListener playerListener; private boolean initialized = false; @Override public void onLoad() { - getLogger().info("Loading ServerStats..."); + getLogger().info("Loading Analyse..."); + + // Migrate old "ServerStats" data folder if it exists + migrateDataFolder(); // Load configuration - pluginConfig = new ServerStatsPaperConfig(this); + pluginConfig = new AnalyseSpigotConfig(this); // Validate configuration if (!pluginConfig.isValid()) { - getLogger().warning("Invalid configuration! Please set your API key in config.yml and run /serverstats reload"); + getLogger().warning("Invalid configuration! Please set your API key in config.yml and run /analyse reload"); } else { getLogger().info("Configuration loaded successfully!"); } } + /** + * Migrate the data folder from the old "ServerStats" name to "Analyse". + * Automatically renames plugins/ServerStats to plugins/Analyse if it exists. + */ + private void migrateDataFolder() { + File oldFolder = new File(getDataFolder().getParentFile(), "ServerStats"); + if (oldFolder.exists() && oldFolder.isDirectory() && !getDataFolder().exists()) { + if (oldFolder.renameTo(getDataFolder())) { + getLogger().info("Migrated data folder from ServerStats to Analyse"); + } else { + getLogger().warning("Failed to migrate data folder from ServerStats to Analyse. Please rename it manually."); + } + } + } + @Override public void onEnable() { - getLogger().info("Enabling ServerStats..."); + getLogger().info("Enabling Analyse..."); + + // Initialize the cross-version messaging system + MessageUtil.init(this); // Register commands using ACF (always available so reload command works) - PaperCommandManager commandManager = new PaperCommandManager(this); - commandManager.registerCommand(new ServerStatsCommand(this)); + BukkitCommandManager commandManager = new BukkitCommandManager(this); + commandManager.registerCommand(new AnalyseCommand(this)); // Initialize session manager (always needed) sessionManager = new SessionManager(); @@ -81,32 +104,32 @@ public void onEnable() { // Try to initialize if config is valid if (pluginConfig.isValid()) { - initializeServerStats(); + initializeAnalyse(); } else { - getLogger().warning("ServerStats is running in limited mode. Set a valid API key and run /serverstats reload"); + getLogger().warning("Analyse is running in limited mode. Set a valid API key and run /analyse reload"); } } /** - * Initialize or reinitialize the ServerStats functionality. + * Initialize or reinitialize the Analyse functionality. * Called on startup if config is valid, and on reload when config becomes valid. */ - public void initializeServerStats() { + public void initializeAnalyse() { // Shutdown existing components if reinitializing - shutdownServerStats(); + shutdownAnalyse(); // Initialize SDK client - ServerStatsConfig sdkConfig = new ServerStatsConfig(pluginConfig.getApiKey()); - client = new ServerStatsClient(sdkConfig); + AnalyseConfig sdkConfig = new AnalyseConfig(pluginConfig.getApiKey(), pluginConfig.isDevelopment()); + client = new AnalyseClient(sdkConfig); // Update the player listener with the new client playerListener.setClient(client); - // Register with the API provider so other plugins can use ServerStats.get() - ServerStatsProvider.register(this); + // Register with the API provider so other plugins can use Analyse.get() + AnalyseProvider.register(this); - // Set up the event sender for ServerStats.trackEvent() - ServerStats.setEventSender(this::sendEvent); + // Set up the event sender for Analyse.trackEvent() + Analyse.setEventSender(this::sendEvent); // Start heartbeat task (every 30 seconds = 600 ticks) // Uses sync timer because HeartbeatTask collects player data on main thread, then sends async @@ -123,26 +146,26 @@ public void initializeServerStats() { abTestManager.start(); // Initialize update checker - updateChecker = new PaperUpdateChecker(this, BuildConstants.VERSION); + updateChecker = new SpigotUpdateChecker(this, BuildConstants.VERSION); updateChecker.start(); // Initialize sessions for players already online (in case of reload) initializeOnlinePlayers(); // Initialize addon manager and load addons - addonManager = new PaperAddonManager(this); + addonManager = new SpigotAddonManager(this); addonManager.loadAddons(); addonManager.enableAddons(); initialized = true; - getLogger().info("ServerStats initialized successfully!"); + getLogger().info("Analyse initialized successfully!"); } /** - * Shutdown ServerStats functionality without disabling the plugin. + * Shutdown Analyse functionality without disabling the plugin. * Called before reinitializing or when the plugin is disabled. */ - private void shutdownServerStats() { + private void shutdownAnalyse() { if (!initialized) { return; } @@ -154,10 +177,10 @@ private void shutdownServerStats() { } // Unregister from the API provider - ServerStatsProvider.unregister(); + AnalyseProvider.unregister(); // Clear the event sender - ServerStats.setEventSender(null); + Analyse.setEventSender(null); // Stop A/B test manager if (abTestManager != null) { @@ -192,11 +215,11 @@ private void shutdownServerStats() { } /** - * Check if ServerStats is fully initialized and functional + * Check if Analyse is fully initialized and functional * * @return true if initialized with a valid API key */ - public boolean isInitialized() { + public boolean isAnalyseReady() { return initialized; } @@ -236,7 +259,7 @@ private void sendEvent(EventBuilder event, Consumer callback) { event.getValue() ); - client.trackEvent(request, new ServerStatsCallback<>() { + client.trackEvent(request, new AnalyseCallback() { @Override public void onSuccess(EventResponse response) { if (isDebugEnabled()) { @@ -250,7 +273,7 @@ public void onSuccess(EventResponse response) { } @Override - public void onError(ServerStatsException exception) { + public void onError(AnalyseException exception) { logWarning(String.format("Failed to track event '%s': %s", event.getName(), exception.getMessage())); @@ -277,10 +300,15 @@ private void initializeOnlinePlayers() { UUID uuid = player.getUniqueId(); // Get hostname from player's virtual host (may be null after reload) + // Uses reflection since getVirtualHost() is Paper-only String hostname = "unknown"; - InetSocketAddress virtualHost = player.getVirtualHost(); - if (virtualHost != null) { - hostname = virtualHost.getHostName(); + try { + java.lang.reflect.Method method = player.getClass().getMethod("getVirtualHost"); + InetSocketAddress virtualHost = (InetSocketAddress) method.invoke(player); + if (virtualHost != null) { + hostname = virtualHost.getHostName(); + } + } catch (Exception ignored) { } // Get player's IP address @@ -300,7 +328,7 @@ private void initializeOnlinePlayers() { // Send join event to the API JoinRequest request = new JoinRequest(uuid, username, hostname, ip, isBedrock); - client.join(request, new ServerStatsCallback<>() { + client.join(request, new AnalyseCallback() { @Override public void onSuccess(JoinResponse response) { sessionManager.getSession(uuid).ifPresent(session -> session.setSessionId(response.getSessionId())); @@ -309,7 +337,7 @@ public void onSuccess(JoinResponse response) { } @Override - public void onError(ServerStatsException exception) { + public void onError(AnalyseException exception) { getLogger().warning(String.format("Failed to send join event for existing player %s: %s", username, exception.getMessage())); } @@ -319,9 +347,10 @@ public void onError(ServerStatsException exception) { @Override public void onDisable() { - getLogger().info("Disabling ServerStats..."); - shutdownServerStats(); - getLogger().info("ServerStats disabled"); + getLogger().info("Disabling Analyse..."); + shutdownAnalyse(); + MessageUtil.close(); + getLogger().info("Analyse disabled"); } /** @@ -347,7 +376,7 @@ public void debug(String format, Object... args) { } } - // ========== ServerStatsPlatform Interface Methods ========== + // ========== AnalysePlatform Interface Methods ========== @Override public SessionManager getSessionManager() { @@ -391,16 +420,16 @@ public String getVersion() { * * @return The plugin config */ - public ServerStatsPaperConfig getPluginConfig() { + public AnalyseSpigotConfig getPluginConfig() { return pluginConfig; } /** * Get the SDK client * - * @return The ServerStats client + * @return The Analyse client */ - public ServerStatsClient getClient() { + public AnalyseClient getClient() { return client; } @@ -409,7 +438,7 @@ public ServerStatsClient getClient() { * * @return The update checker */ - public PaperUpdateChecker getUpdateChecker() { + public SpigotUpdateChecker getUpdateChecker() { return updateChecker; } } diff --git a/paper/src/main/java/com/serverstats/paper/addon/PaperAddonClassLoader.java b/modules/spigot/src/main/java/net/analyse/spigot/addon/PaperAddonClassLoader.java similarity index 98% rename from paper/src/main/java/com/serverstats/paper/addon/PaperAddonClassLoader.java rename to modules/spigot/src/main/java/net/analyse/spigot/addon/PaperAddonClassLoader.java index 13221b0..80ea770 100644 --- a/paper/src/main/java/com/serverstats/paper/addon/PaperAddonClassLoader.java +++ b/modules/spigot/src/main/java/net/analyse/spigot/addon/PaperAddonClassLoader.java @@ -1,4 +1,4 @@ -package com.serverstats.paper.addon; +package net.analyse.spigot.addon; import org.bukkit.Bukkit; import org.bukkit.plugin.Plugin; diff --git a/paper/src/main/java/com/serverstats/paper/addon/PaperAddonLogger.java b/modules/spigot/src/main/java/net/analyse/spigot/addon/SpigotAddonLogger.java similarity index 85% rename from paper/src/main/java/com/serverstats/paper/addon/PaperAddonLogger.java rename to modules/spigot/src/main/java/net/analyse/spigot/addon/SpigotAddonLogger.java index ab1f4d4..b8fd78b 100644 --- a/paper/src/main/java/com/serverstats/paper/addon/PaperAddonLogger.java +++ b/modules/spigot/src/main/java/net/analyse/spigot/addon/SpigotAddonLogger.java @@ -1,15 +1,15 @@ -package com.serverstats.paper.addon; +package net.analyse.spigot.addon; -import com.serverstats.api.addon.AddonLogger; -import com.serverstats.paper.ServerStatsPlugin; +import net.analyse.api.addon.AddonLogger; +import net.analyse.spigot.AnalysePlugin; import java.util.logging.Level; /** * Paper implementation of AddonLogger that prefixes messages with the addon name. */ -public class PaperAddonLogger implements AddonLogger { +public class SpigotAddonLogger implements AddonLogger { - private final ServerStatsPlugin plugin; + private final AnalysePlugin plugin; private final String prefix; /** @@ -18,7 +18,7 @@ public class PaperAddonLogger implements AddonLogger { * @param plugin The main plugin instance * @param addonName The addon display name */ - public PaperAddonLogger(ServerStatsPlugin plugin, String addonName) { + public SpigotAddonLogger(AnalysePlugin plugin, String addonName) { this.plugin = plugin; this.prefix = "[" + addonName + "] "; } diff --git a/paper/src/main/java/com/serverstats/paper/addon/PaperAddonManager.java b/modules/spigot/src/main/java/net/analyse/spigot/addon/SpigotAddonManager.java similarity index 77% rename from paper/src/main/java/com/serverstats/paper/addon/PaperAddonManager.java rename to modules/spigot/src/main/java/net/analyse/spigot/addon/SpigotAddonManager.java index b57f9bd..1da2a81 100644 --- a/paper/src/main/java/com/serverstats/paper/addon/PaperAddonManager.java +++ b/modules/spigot/src/main/java/net/analyse/spigot/addon/SpigotAddonManager.java @@ -1,8 +1,8 @@ -package com.serverstats.paper.addon; +package net.analyse.spigot.addon; -import com.serverstats.api.addon.AbstractAddonManager; -import com.serverstats.api.addon.AddonLogger; -import com.serverstats.paper.ServerStatsPlugin; +import net.analyse.api.addon.AbstractAddonManager; +import net.analyse.api.addon.AddonLogger; +import net.analyse.spigot.AnalysePlugin; import java.net.URL; import java.net.URLClassLoader; @@ -11,16 +11,16 @@ /** * Paper implementation of the addon manager. */ -public class PaperAddonManager extends AbstractAddonManager { +public class SpigotAddonManager extends AbstractAddonManager { - private final ServerStatsPlugin plugin; + private final AnalysePlugin plugin; /** * Create a new Paper addon manager * * @param plugin The main plugin instance */ - public PaperAddonManager(ServerStatsPlugin plugin) { + public SpigotAddonManager(AnalysePlugin plugin) { super(plugin, plugin.getDataFolder().toPath().resolve("addons"), plugin.getClass().getClassLoader()); this.plugin = plugin; } @@ -33,7 +33,7 @@ protected URLClassLoader createAddonClassLoader(URL[] urls, ClassLoader parent) @Override protected AddonLogger createAddonLogger(String addonId, String addonName) { - return new PaperAddonLogger(plugin, addonName); + return new SpigotAddonLogger(plugin, addonName); } @Override diff --git a/paper/src/main/java/com/serverstats/paper/command/ServerStatsCommand.java b/modules/spigot/src/main/java/net/analyse/spigot/command/AnalyseCommand.java similarity index 79% rename from paper/src/main/java/com/serverstats/paper/command/ServerStatsCommand.java rename to modules/spigot/src/main/java/net/analyse/spigot/command/AnalyseCommand.java index 6d65548..f201007 100644 --- a/paper/src/main/java/com/serverstats/paper/command/ServerStatsCommand.java +++ b/modules/spigot/src/main/java/net/analyse/spigot/command/AnalyseCommand.java @@ -1,4 +1,4 @@ -package com.serverstats.paper.command; +package net.analyse.spigot.command; import co.aikar.commands.BaseCommand; import co.aikar.commands.annotation.CommandAlias; @@ -8,19 +8,19 @@ import co.aikar.commands.annotation.Description; import co.aikar.commands.annotation.Subcommand; import co.aikar.commands.annotation.Syntax; -import com.serverstats.api.ServerStats; -import com.serverstats.api.BuildConstants; -import com.serverstats.api.addon.LoadedAddon; -import com.serverstats.api.exception.ServerStatsException; -import com.serverstats.api.object.builder.EventBuilder; -import com.serverstats.paper.ServerStatsPlugin; -import com.serverstats.paper.object.session.PlayerSession; -import com.serverstats.paper.util.ComponentUtil; -import com.serverstats.paper.util.SchedulerUtil; -import com.serverstats.sdk.ServerStatsCallback; -import com.serverstats.sdk.request.PlayerInfoRequest; -import com.serverstats.sdk.response.PlayerInfoResponse; -import com.serverstats.sdk.response.ServerInfoResponse; +import net.analyse.api.Analyse; +import net.analyse.api.BuildConstants; +import net.analyse.api.addon.LoadedAddon; +import net.analyse.api.exception.AnalyseException; +import net.analyse.api.object.builder.EventBuilder; +import net.analyse.spigot.AnalysePlugin; +import net.analyse.spigot.object.session.PlayerSession; +import net.analyse.spigot.util.MessageUtil; +import net.analyse.spigot.util.SchedulerUtil; +import net.analyse.sdk.AnalyseCallback; +import net.analyse.sdk.request.PlayerInfoRequest; +import net.analyse.sdk.response.PlayerInfoResponse; +import net.analyse.sdk.response.ServerInfoResponse; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @@ -31,14 +31,14 @@ import java.util.Map; /** - * Main command handler for the ServerStats plugin using ACF + * Main command handler for the Analyse plugin using ACF */ -@CommandAlias("serverstats|analyse|ss") -public class ServerStatsCommand extends BaseCommand { +@CommandAlias("analyse|analyse|ss") +public class AnalyseCommand extends BaseCommand { - private final ServerStatsPlugin plugin; + private final AnalysePlugin plugin; - public ServerStatsCommand(ServerStatsPlugin plugin) { + public AnalyseCommand(AnalysePlugin plugin) { this.plugin = plugin; } @@ -46,7 +46,7 @@ public ServerStatsCommand(ServerStatsPlugin plugin) { @Description("Show plugin info") public void onDefault(CommandSender sender) { // Check if user has admin permission - if (sender.hasPermission("serverstats.command.status")) { + if (sender.hasPermission("analyse.netmand.status")) { showStatus(sender); } else { showPublicInfo(sender); @@ -55,7 +55,7 @@ public void onDefault(CommandSender sender) { @Subcommand("status") @Description("Show plugin status") - @CommandPermission("serverstats.command.status") + @CommandPermission("analyse.netmand.status") public void onStatus(CommandSender sender) { showStatus(sender); } @@ -67,11 +67,11 @@ public void onStatus(CommandSender sender) { */ private void showPublicInfo(CommandSender sender) { StringBuilder message = new StringBuilder(); - message.append("#3498db&l「 ServerStats 」&r\n"); - message.append(" #5dade2┃ &7This server uses &fServerStats &7to track\n"); + message.append("#3498db&l「 Analyse 」&r\n"); + message.append(" #5dade2┃ &7This server uses &fAnalyse &7to track\n"); message.append(" #5dade2┃ &7player analytics and sessions.&r\n"); message.append("&r\n"); - message.append(" &7→ &fserverstats.com&r\n"); + message.append(" &7→ &fanalyse.net&r\n"); send(sender, message.toString()); } @@ -81,23 +81,23 @@ private void showPublicInfo(CommandSender sender) { * @param sender The command sender */ private void showStatus(CommandSender sender) { - boolean initialized = plugin.isInitialized(); - boolean apiConnected = ServerStats.isConnected(); + boolean initialized = plugin.isAnalyseReady(); + boolean apiConnected = Analyse.isConnected(); int trackedPlayers = plugin.getSessionManager().getSessionCount(); boolean debugEnabled = plugin.isDebugEnabled(); StringBuilder message = new StringBuilder(); - message.append("#3498db&l「 ServerStats &r&fv").append(BuildConstants.VERSION).append(" #3498db&l」&r\n"); + message.append("#3498db&l「 Analyse &r&fv").append(BuildConstants.VERSION).append(" #3498db&l」&r\n"); if (!initialized) { message.append(" #5dade2┃ &fStatus: &c● Not Initialized&r\n"); - message.append(" #5dade2┃ &7Set a valid API key and run &f/serverstats reload&r\n"); + message.append(" #5dade2┃ &7Set a valid API key and run &f/analyse reload&r\n"); } else { message.append(" #5dade2┃ &fStatus: ").append(apiConnected ? "&a● Connected" : "&c● Disconnected").append("&r\n"); - if (!apiConnected && ServerStats.getLastConnectionError() != null) { - message.append(" #5dade2┃ &fError: &c").append(ServerStats.getLastConnectionError()).append("&r\n"); + if (!apiConnected && Analyse.getLastConnectionError() != null) { + message.append(" #5dade2┃ &fError: &c").append(Analyse.getLastConnectionError()).append("&r\n"); } - message.append(" #5dade2┃ &fAPI: &7api.serverstats.com&r\n"); + message.append(" #5dade2┃ &fAPI: &7api.analyse.net&r\n"); message.append(" #5dade2┃ &fPlayers Tracked: &7").append(trackedPlayers).append("&r\n"); } @@ -107,7 +107,7 @@ private void showStatus(CommandSender sender) { @Subcommand("reload") @Description("Reload configuration") - @CommandPermission("serverstats.command.reload") + @CommandPermission("analyse.netmand.reload") public void onReload(CommandSender sender) { // Reload the Bukkit config file plugin.reloadConfig(); @@ -117,9 +117,9 @@ public void onReload(CommandSender sender) { // Check if the config is now valid if (plugin.getPluginConfig().isValid()) { - // Reinitialize ServerStats with the new config - plugin.initializeServerStats(); - send(sender, "&aServerStats configuration reloaded and initialized successfully."); + // Reinitialize Analyse with the new config + plugin.initializeAnalyse(); + send(sender, "&aAnalyse configuration reloaded and initialized successfully."); } else { send(sender, "&cConfiguration reloaded, but API key is invalid. Please set a valid API key in config.yml"); } @@ -127,7 +127,7 @@ public void onReload(CommandSender sender) { @Subcommand("debug") @Description("Toggle debug mode") - @CommandPermission("serverstats.command.debug") + @CommandPermission("analyse.netmand.debug") public void onDebug(CommandSender sender) { boolean newState = !plugin.getPluginConfig().isDebug(); plugin.getPluginConfig().setDebug(newState); @@ -141,17 +141,17 @@ public void onDebug(CommandSender sender) { @Subcommand("event") @Description("Send a custom event") - @CommandPermission("serverstats.command.event") + @CommandPermission("analyse.netmand.event") @Syntax(" [--player ] [--value ] [--data ...]") @CommandCompletion("test_event|custom_event @players") public void onEvent(CommandSender sender, String[] args) { if (args.length == 0) { - send(sender, "&cUsage: /serverstats event [--player ] [--value ] [--data key=value...]"); + send(sender, "&cUsage: /analyse event [--player ] [--value ] [--data key=value...]"); return; } - if (!ServerStats.isAvailable()) { - send(sender, "&cServerStats is not connected. Cannot send events."); + if (!Analyse.isAvailable()) { + send(sender, "&cAnalyse is not connected. Cannot send events."); return; } @@ -190,7 +190,7 @@ public void onEvent(CommandSender sender, String[] args) { } // Build the event - EventBuilder builder = ServerStats.trackEvent(eventName); + EventBuilder builder = Analyse.trackEvent(eventName); // Add player if specified if (playerName != null) { @@ -240,12 +240,12 @@ public void onEvent(CommandSender sender, String[] args) { @Subcommand("info") @Description("View server or player analytics") - @CommandPermission("serverstats.command.info") + @CommandPermission("analyse.netmand.info") @Syntax("[player]") @CommandCompletion("@players") public void onInfo(CommandSender sender, String[] args) { - if (!ServerStats.isAvailable()) { - send(sender, "&cServerStats is not connected."); + if (!Analyse.isAvailable()) { + send(sender, "&cAnalyse is not connected."); return; } @@ -268,7 +268,7 @@ private void showServerInfo(CommandSender sender) { int onlinePlayers = Bukkit.getOnlinePlayers().size(); // Fetch additional data from API - plugin.getClient().getServerInfo(new ServerStatsCallback<>() { + plugin.getClient().getServerInfo(new AnalyseCallback() { @Override public void onSuccess(ServerInfoResponse response) { SchedulerUtil.runSync(plugin, () -> { @@ -290,7 +290,7 @@ public void onSuccess(ServerInfoResponse response) { } @Override - public void onError(ServerStatsException exception) { + public void onError(AnalyseException exception) { SchedulerUtil.runSync(plugin, () -> { StringBuilder message = new StringBuilder(); message.append("#3498db&l「 Server Analytics 」&r\n"); @@ -319,7 +319,7 @@ private void showPlayerInfo(CommandSender sender, String playerName) { PlayerSession session = plugin.getSessionManager().getSession(player.getUniqueId()).orElse(null); // Fetch additional data from API - plugin.getClient().getPlayerInfo(new PlayerInfoRequest(player.getUniqueId()), new ServerStatsCallback<>() { + plugin.getClient().getPlayerInfo(new PlayerInfoRequest(player.getUniqueId()), new AnalyseCallback() { @Override public void onSuccess(PlayerInfoResponse response) { SchedulerUtil.runSync(plugin, () -> { @@ -328,7 +328,7 @@ public void onSuccess(PlayerInfoResponse response) { } @Override - public void onError(ServerStatsException exception) { + public void onError(AnalyseException exception) { SchedulerUtil.runSync(plugin, () -> { send(sender, buildPlayerInfoMessage(player.getName(), session, null)); }); @@ -413,16 +413,16 @@ private String formatDuration(Duration duration) { @Subcommand("addons") @Description("List all loaded addons") - @CommandPermission("serverstats.command.addons") + @CommandPermission("analyse.netmand.addons") public void onAddons(CommandSender sender) { Collection addons = plugin.getAddonManager().getLoadedAddons(); StringBuilder message = new StringBuilder(); - message.append("#3498db&l「 ServerStats Addons 」&r\n"); + message.append("#3498db&l「 Analyse Addons 」&r\n"); if (addons.isEmpty()) { message.append(" &7No addons loaded.&r\n"); - message.append(" &7Place addon JARs in &fplugins/ServerStats/addons/&r\n"); + message.append(" &7Place addon JARs in &fplugins/Analyse/addons/&r\n"); } else { for (LoadedAddon addon : addons) { String status = addon.isEnabled() ? "&a● Enabled" : "&c● Disabled"; @@ -442,7 +442,7 @@ public void onAddons(CommandSender sender) { @Subcommand("addons reload") @Description("Reload all addons or a specific addon") - @CommandPermission("serverstats.command.addons.reload") + @CommandPermission("analyse.netmand.addons.reload") @Syntax("[addon]") public void onAddonsReload(CommandSender sender, String[] args) { if (args.length == 0) { @@ -469,7 +469,7 @@ public void onAddonsReload(CommandSender sender, String[] args) { @Subcommand("addons enable") @Description("Enable an addon") - @CommandPermission("serverstats.command.addons.enable") + @CommandPermission("analyse.netmand.addons.enable") @Syntax("") public void onAddonsEnable(CommandSender sender, String addonId) { if (!plugin.getAddonManager().isAddonLoaded(addonId)) { @@ -491,7 +491,7 @@ public void onAddonsEnable(CommandSender sender, String addonId) { @Subcommand("addons disable") @Description("Disable an addon") - @CommandPermission("serverstats.command.addons.disable") + @CommandPermission("analyse.netmand.addons.disable") @Syntax("") public void onAddonsDisable(CommandSender sender, String addonId) { if (!plugin.getAddonManager().isAddonLoaded(addonId)) { @@ -513,20 +513,20 @@ public void onAddonsDisable(CommandSender sender, String addonId) { @Subcommand("help") @Description("Show help information") - @CommandPermission("serverstats.command.help") + @CommandPermission("analyse.netmand.help") public void onHelp(CommandSender sender) { StringBuilder message = new StringBuilder(); - message.append("#3498db&l「 ServerStats Commands 」&r\n"); - message.append(" #5dade2┃ &f/serverstats &7- Show plugin info&r\n"); - message.append(" #5dade2┃ &f/serverstats status &7- Show plugin status&r\n"); - message.append(" #5dade2┃ &f/serverstats info &7- View server analytics&r\n"); - message.append(" #5dade2┃ &f/serverstats info &7- View player analytics&r\n"); - message.append(" #5dade2┃ &f/serverstats reload &7- Reload configuration&r\n"); - message.append(" #5dade2┃ &f/serverstats debug &7- Toggle debug mode&r\n"); - message.append(" #5dade2┃ &f/serverstats event &7- Send custom event&r\n"); - message.append(" #5dade2┃ &f/serverstats addons &7- List loaded addons&r\n"); - message.append(" #5dade2┃ &f/serverstats addons reload [id] &7- Reload addons&r\n"); - message.append(" #5dade2┃ &f/serverstats help &7- Show this help&r\n"); + message.append("#3498db&l「 Analyse Commands 」&r\n"); + message.append(" #5dade2┃ &f/analyse &7- Show plugin info&r\n"); + message.append(" #5dade2┃ &f/analyse status &7- Show plugin status&r\n"); + message.append(" #5dade2┃ &f/analyse info &7- View server analytics&r\n"); + message.append(" #5dade2┃ &f/analyse info &7- View player analytics&r\n"); + message.append(" #5dade2┃ &f/analyse reload &7- Reload configuration&r\n"); + message.append(" #5dade2┃ &f/analyse debug &7- Toggle debug mode&r\n"); + message.append(" #5dade2┃ &f/analyse event &7- Send custom event&r\n"); + message.append(" #5dade2┃ &f/analyse addons &7- List loaded addons&r\n"); + message.append(" #5dade2┃ &f/analyse addons reload [id] &7- Reload addons&r\n"); + message.append(" #5dade2┃ &f/analyse help &7- Show this help&r\n"); send(sender, message.toString()); } @@ -537,6 +537,6 @@ public void onHelp(CommandSender sender) { * @param message The message with color codes */ private void send(CommandSender sender, String message) { - sender.sendMessage(ComponentUtil.parse(message)); + MessageUtil.sendMessage(sender, message); } } diff --git a/paper/src/main/java/com/serverstats/paper/config/ServerStatsPaperConfig.java b/modules/spigot/src/main/java/net/analyse/spigot/config/AnalyseSpigotConfig.java similarity index 79% rename from paper/src/main/java/com/serverstats/paper/config/ServerStatsPaperConfig.java rename to modules/spigot/src/main/java/net/analyse/spigot/config/AnalyseSpigotConfig.java index 74cb03c..5773e05 100644 --- a/paper/src/main/java/com/serverstats/paper/config/ServerStatsPaperConfig.java +++ b/modules/spigot/src/main/java/net/analyse/spigot/config/AnalyseSpigotConfig.java @@ -1,4 +1,4 @@ -package com.serverstats.paper.config; +package net.analyse.spigot.config; import lombok.Getter; import org.bukkit.configuration.ConfigurationSection; @@ -11,19 +11,24 @@ * Configuration for the Paper plugin */ @Getter -public class ServerStatsPaperConfig { +public class AnalyseSpigotConfig { - private static final Map DEFAULT_EVENTS = Map.of( - "chat", true, - "command", true, - "block-place", false, - "block-break", false, - "death", false, - "kill-entity", false - ); + private static final Map DEFAULT_EVENTS; + + static { + Map defaults = new HashMap<>(); + defaults.put("chat", true); + defaults.put("command", true); + defaults.put("block-place", false); + defaults.put("block-break", false); + defaults.put("death", false); + defaults.put("kill-entity", false); + DEFAULT_EVENTS = defaults; + } private final JavaPlugin plugin; private boolean debug; + private boolean development; private String apiKey; private String bedrockPrefix; private String instanceId; @@ -34,7 +39,7 @@ public class ServerStatsPaperConfig { * * @param plugin The plugin instance */ - public ServerStatsPaperConfig(JavaPlugin plugin) { + public AnalyseSpigotConfig(JavaPlugin plugin) { this.plugin = plugin; plugin.saveDefaultConfig(); loadValues(); @@ -47,6 +52,7 @@ private void loadValues() { FileConfiguration config = plugin.getConfig(); this.debug = config.getBoolean("debug", false); + this.development = config.getBoolean("development", false); this.apiKey = config.getString("api-key", ""); this.bedrockPrefix = config.getString("bedrock-prefix", "."); this.instanceId = config.getString("instance-id", "default"); @@ -81,7 +87,7 @@ public void reload() { * @return true if the API key is configured */ public boolean isValid() { - return apiKey != null && !apiKey.isBlank() && !apiKey.startsWith("anl_your_"); + return apiKey != null && !apiKey.trim().isEmpty() && !apiKey.startsWith("anl_your_"); } /** diff --git a/paper/src/main/java/com/serverstats/paper/listener/ActivityListener.java b/modules/spigot/src/main/java/net/analyse/spigot/listener/ActivityListener.java similarity index 82% rename from paper/src/main/java/com/serverstats/paper/listener/ActivityListener.java rename to modules/spigot/src/main/java/net/analyse/spigot/listener/ActivityListener.java index 85ca39a..50682e5 100644 --- a/paper/src/main/java/com/serverstats/paper/listener/ActivityListener.java +++ b/modules/spigot/src/main/java/net/analyse/spigot/listener/ActivityListener.java @@ -1,8 +1,9 @@ -package com.serverstats.paper.listener; +package net.analyse.spigot.listener; -import com.serverstats.api.ServerStats; -import com.serverstats.paper.ServerStatsPlugin; -import com.serverstats.paper.config.ServerStatsPaperConfig; +import net.analyse.api.Analyse; +import net.analyse.api.object.builder.EventBuilder; +import net.analyse.spigot.AnalysePlugin; +import net.analyse.spigot.config.AnalyseSpigotConfig; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -23,9 +24,9 @@ */ public class ActivityListener implements Listener { - private final ServerStatsPlugin plugin; + private final AnalysePlugin plugin; - public ActivityListener(ServerStatsPlugin plugin) { + public ActivityListener(AnalysePlugin plugin) { this.plugin = plugin; } @@ -40,7 +41,7 @@ public void onChat(AsyncPlayerChatEvent event) { String username = player.getName(); String message = event.getMessage(); - ServerStats.trackEvent("plugin.chat") + Analyse.trackEvent("plugin.chat") .withPlayer(uuid, username) .withData("message", message) .send(); @@ -60,7 +61,7 @@ public void onCommand(PlayerCommandPreprocessEvent event) { String rawCommand = event.getMessage().substring(1); String command = rawCommand.split(" ")[0]; - ServerStats.trackEvent("plugin.command") + Analyse.trackEvent("plugin.command") .withPlayer(uuid, username) .withData("command", command) .withData("rawCommand", rawCommand) @@ -78,7 +79,7 @@ public void onBlockPlace(BlockPlaceEvent event) { String username = player.getName(); String blockType = event.getBlock().getType().name(); - ServerStats.trackEvent("plugin.block_place") + Analyse.trackEvent("plugin.block_place") .withPlayer(uuid, username) .withData("block_type", blockType) .send(); @@ -95,7 +96,7 @@ public void onBlockBreak(BlockBreakEvent event) { String username = player.getName(); String blockType = event.getBlock().getType().name(); - ServerStats.trackEvent("plugin.block_break") + Analyse.trackEvent("plugin.block_break") .withPlayer(uuid, username) .withData("block_type", blockType) .send(); @@ -114,12 +115,13 @@ public void onDeath(PlayerDeathEvent event) { EntityDamageEvent lastDamage = player.getLastDamageCause(); String cause = lastDamage != null ? lastDamage.getCause().name() : "UNKNOWN"; - var builder = ServerStats.trackEvent("plugin.death") + EventBuilder builder = Analyse.trackEvent("plugin.death") .withPlayer(uuid, username) .withData("cause", cause); // Include killer info if killed by an entity - if (lastDamage instanceof EntityDamageByEntityEvent entityDamage) { + if (lastDamage instanceof EntityDamageByEntityEvent) { + EntityDamageByEntityEvent entityDamage = (EntityDamageByEntityEvent) lastDamage; Entity killer = entityDamage.getDamager(); builder.withData("killer", killer instanceof Player ? killer.getName() : killer.getType().name()); } @@ -143,12 +145,13 @@ public void onEntityDeath(EntityDeathEvent event) { Entity victim = event.getEntity(); String entityType = victim.getType().name(); - var builder = ServerStats.trackEvent("plugin.kill_entity") + EventBuilder builder = Analyse.trackEvent("plugin.kill_entity") .withPlayer(uuid, username) .withData("entity_type", entityType); // Include name if the victim is a player - if (victim instanceof Player victimPlayer) { + if (victim instanceof Player) { + Player victimPlayer = (Player) victim; builder.withData("entity_name", victimPlayer.getName()); } @@ -162,11 +165,11 @@ public void onEntityDeath(EntityDeathEvent event) { * @return true if the event should be tracked */ private boolean isEnabled(String key) { - if (!plugin.isInitialized()) { + if (!plugin.isAnalyseReady()) { return false; } - ServerStatsPaperConfig config = plugin.getPluginConfig(); + AnalyseSpigotConfig config = plugin.getPluginConfig(); return config.isEventEnabled(key); } } diff --git a/paper/src/main/java/com/serverstats/paper/listener/PlayerListener.java b/modules/spigot/src/main/java/net/analyse/spigot/listener/PlayerListener.java similarity index 71% rename from paper/src/main/java/com/serverstats/paper/listener/PlayerListener.java rename to modules/spigot/src/main/java/net/analyse/spigot/listener/PlayerListener.java index 9ff8ef6..8ce60da 100644 --- a/paper/src/main/java/com/serverstats/paper/listener/PlayerListener.java +++ b/modules/spigot/src/main/java/net/analyse/spigot/listener/PlayerListener.java @@ -1,17 +1,17 @@ -package com.serverstats.paper.listener; - -import com.serverstats.paper.ServerStatsPlugin; -import com.serverstats.paper.manager.SessionManager; -import com.serverstats.paper.object.session.PlayerSession; -import com.serverstats.sdk.util.ProtocolVersionUtil; -import com.serverstats.paper.util.SchedulerUtil; -import com.serverstats.sdk.ServerStatsCallback; -import com.serverstats.sdk.ServerStatsClient; -import com.serverstats.api.exception.ServerStatsException; -import com.serverstats.sdk.request.JoinRequest; -import com.serverstats.sdk.request.LeaveRequest; -import com.serverstats.sdk.response.JoinResponse; -import com.serverstats.sdk.response.LeaveResponse; +package net.analyse.spigot.listener; + +import net.analyse.spigot.AnalysePlugin; +import net.analyse.spigot.manager.SessionManager; +import net.analyse.spigot.object.session.PlayerSession; +import net.analyse.sdk.util.ProtocolVersionUtil; +import net.analyse.spigot.util.SchedulerUtil; +import net.analyse.sdk.AnalyseCallback; +import net.analyse.sdk.AnalyseClient; +import net.analyse.api.exception.AnalyseException; +import net.analyse.sdk.request.JoinRequest; +import net.analyse.sdk.request.LeaveRequest; +import net.analyse.sdk.response.JoinResponse; +import net.analyse.sdk.response.LeaveResponse; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; @@ -19,6 +19,7 @@ import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerLoginEvent; import org.bukkit.event.player.PlayerQuitEvent; +import java.lang.reflect.Method; import java.util.Optional; import java.util.UUID; import java.util.logging.Logger; @@ -28,12 +29,18 @@ */ public class PlayerListener implements Listener { - private final ServerStatsPlugin plugin; + private final AnalysePlugin plugin; private final Logger logger; private final SessionManager sessionManager; - private ServerStatsClient client; + private AnalyseClient client; - public PlayerListener(ServerStatsPlugin plugin, ServerStatsClient client) { + /** + * Creates a listener that forwards player lifecycle events using the given plugin and client. + * + * @param plugin The Analyse plugin instance + * @param client The SDK client, or null if not yet initialized + */ + public PlayerListener(AnalysePlugin plugin, AnalyseClient client) { this.plugin = plugin; this.logger = plugin.getLogger(); this.sessionManager = plugin.getSessionManager(); @@ -45,7 +52,7 @@ public PlayerListener(ServerStatsPlugin plugin, ServerStatsClient client) { * * @param client The new client instance, or null to disable */ - public void setClient(ServerStatsClient client) { + public void setClient(AnalyseClient client) { this.client = client; } @@ -60,7 +67,7 @@ public void onPlayerLogin(PlayerLoginEvent event) { // Get hostname from the connection String hostname = event.getHostname(); - if (hostname == null || hostname.isBlank()) { + if (hostname == null || hostname.trim().isEmpty()) { hostname = "unknown"; } @@ -85,7 +92,7 @@ public void onPlayerJoin(PlayerJoinEvent event) { String username = player.getName(); Optional sessionOpt = sessionManager.getSession(uuid); - if (sessionOpt.isEmpty()) { + if (!sessionOpt.isPresent()) { logger.warning(String.format("No session found for player %s on join", username)); return; } @@ -98,14 +105,14 @@ public void onPlayerJoin(PlayerJoinEvent event) { boolean isBedrock = plugin.getPluginConfig().isBedrock(username); // Convert protocol version to "1.x.y" string for the API (Java clients only; Bedrock may still send "1.?") - int protocolVersion = player.getProtocolVersion(); + int protocolVersion = getProtocolVersion(player); String playerVersion = ProtocolVersionUtil.toVersionString(protocolVersion); // Send join event to the API JoinRequest request = new JoinRequest(uuid, username, session.getHostname(), session.getIp(), isBedrock, playerVersion); - client.join(request, new ServerStatsCallback<>() { + client.join(request, new AnalyseCallback() { @Override public void onSuccess(JoinResponse response) { session.setSessionId(response.getSessionId()); @@ -114,7 +121,7 @@ public void onSuccess(JoinResponse response) { } @Override - public void onError(ServerStatsException exception) { + public void onError(AnalyseException exception) { logger.warning(String.format("Failed to send join event for %s: %s", username, exception.getMessage())); } @@ -128,7 +135,7 @@ public void onError(ServerStatsException exception) { } // Notify admins about updates on join - if (player.hasPermission("serverstats.admin") && plugin.getUpdateChecker() != null) { + if (player.hasPermission("analyse.admin") && plugin.getUpdateChecker() != null) { if (plugin.getUpdateChecker().isUpdateAvailable()) { // Delay slightly so it appears after other join messages // Use entity scheduler for Folia compatibility @@ -153,7 +160,7 @@ public void onPlayerQuit(PlayerQuitEvent event) { String username = player.getName(); Optional sessionOpt = sessionManager.removeSession(uuid); - if (sessionOpt.isEmpty()) { + if (!sessionOpt.isPresent()) { return; } @@ -170,20 +177,41 @@ public void onPlayerQuit(PlayerQuitEvent event) { // Send leave event to the API LeaveRequest request = new LeaveRequest(session.getSessionId()); - client.leave(request, new ServerStatsCallback<>() { + client.leave(request, new AnalyseCallback() { @Override public void onSuccess(LeaveResponse response) { plugin.debug("Leave event sent for %s (duration: %ds)", username, response.getDuration()); } @Override - public void onError(ServerStatsException exception) { + public void onError(AnalyseException exception) { logger.warning(String.format("Failed to send leave event for %s: %s", username, exception.getMessage())); } }); } + /** + * Resolves the player's protocol version via reflection when {@code Player#getProtocolVersion()} + * exists (e.g. Paper); returns -1 on Spigot 1.8 or if reflection fails. + * + * @param player The connected player + * @return The protocol version, or -1 if not available + */ + private int getProtocolVersion(Player player) { + try { + Method method = player.getClass().getMethod("getProtocolVersion"); + Object result = method.invoke(player); + if (result instanceof Integer) { + return (Integer) result; + } + + return -1; + } catch (Exception e) { + return -1; + } + } + /** * Get the player's IP address from the login event * diff --git a/paper/src/main/java/com/serverstats/paper/manager/ABTestManager.java b/modules/spigot/src/main/java/net/analyse/spigot/manager/ABTestManager.java similarity index 65% rename from paper/src/main/java/com/serverstats/paper/manager/ABTestManager.java rename to modules/spigot/src/main/java/net/analyse/spigot/manager/ABTestManager.java index a69eb5a..240d79f 100644 --- a/paper/src/main/java/com/serverstats/paper/manager/ABTestManager.java +++ b/modules/spigot/src/main/java/net/analyse/spigot/manager/ABTestManager.java @@ -1,16 +1,17 @@ -package com.serverstats.paper.manager; - -import com.serverstats.api.exception.ServerStatsException; -import com.serverstats.api.object.abtest.ABTest; -import com.serverstats.paper.ServerStatsPlugin; -import com.serverstats.paper.object.action.PaperAction; -import com.serverstats.paper.util.SchedulerUtil; -import com.serverstats.sdk.ServerStatsCallback; -import com.serverstats.sdk.object.action.ActionData; -import com.serverstats.sdk.request.ConversionRequest; -import com.serverstats.sdk.response.ABTestsResponse; -import com.serverstats.sdk.response.ConversionResponse; +package net.analyse.spigot.manager; + +import net.analyse.api.exception.AnalyseException; +import net.analyse.api.object.abtest.ABTest; +import net.analyse.spigot.AnalysePlugin; +import net.analyse.spigot.object.action.SpigotAction; +import net.analyse.spigot.util.SchedulerUtil; +import net.analyse.sdk.AnalyseCallback; +import net.analyse.sdk.object.action.ActionData; +import net.analyse.sdk.request.ConversionRequest; +import net.analyse.sdk.response.ABTestsResponse; +import net.analyse.sdk.response.ConversionResponse; import org.bukkit.entity.Player; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.UUID; @@ -20,15 +21,15 @@ * Manages A/B tests for the Paper plugin. * Handles fetching, caching, and executing tests. */ -public class ABTestManager implements com.serverstats.api.manager.ABTestManager { +public class ABTestManager implements net.analyse.api.manager.ABTestManager { private static final long SYNC_INTERVAL_TICKS = 20 * 60 * 5; // 5 minutes - private final ServerStatsPlugin plugin; - private final Map testsCache = new ConcurrentHashMap<>(); + private final AnalysePlugin plugin; + private final Map testsCache = new ConcurrentHashMap<>(); private SchedulerUtil.CancellableTask syncTask; - public ABTestManager(ServerStatsPlugin plugin) { + public ABTestManager(AnalysePlugin plugin) { this.plugin = plugin; } @@ -70,12 +71,12 @@ private void syncTests() { return; } - plugin.getClient().getABTests(new ServerStatsCallback<>() { + plugin.getClient().getABTests(new AnalyseCallback() { @Override public void onSuccess(ABTestsResponse response) { if (response.isSuccess() && response.getTests() != null) { testsCache.clear(); - for (com.serverstats.sdk.object.abtest.ABTest test : response.getTests()) { + for (net.analyse.sdk.object.abtest.ABTest test : response.getTests()) { if (test.isActive()) { testsCache.put(test.getKey(), test); } @@ -88,7 +89,7 @@ public void onSuccess(ABTestsResponse response) { } @Override - public void onError(ServerStatsException exception) { + public void onError(AnalyseException exception) { plugin.logWarning(String.format("Failed to sync A/B tests: %s", exception.getMessage())); } }); @@ -96,8 +97,8 @@ public void onError(ServerStatsException exception) { @Override @SuppressWarnings("unchecked") - public List getActiveTests() { - return List.copyOf(testsCache.values()); + public List getActiveTests() { + return new ArrayList<>(testsCache.values()); } @Override @@ -107,12 +108,12 @@ public ABTest getTest(String testKey) { @Override public String getVariant(UUID playerUuid, String testKey) { - com.serverstats.sdk.object.abtest.ABTest test = testsCache.get(testKey); + net.analyse.sdk.object.abtest.ABTest test = testsCache.get(testKey); if (test == null) { return null; } - var variant = test.assignVariant(playerUuid); + net.analyse.api.object.abtest.Variant variant = test.assignVariant(playerUuid); return variant != null ? variant.getKey() : null; } @@ -131,15 +132,15 @@ public boolean isTestActive(String testKey) { public void processJoin(Player player, boolean firstJoin) { ABTest.Trigger trigger = firstJoin ? ABTest.Trigger.FIRST_JOIN : ABTest.Trigger.EVERY_JOIN; - for (com.serverstats.sdk.object.abtest.ABTest test : testsCache.values()) { + for (net.analyse.sdk.object.abtest.ABTest test : testsCache.values()) { if (!test.matchesTrigger(trigger)) { continue; } // Assign variant and execute actions - var variant = test.assignVariant(player.getUniqueId()); + net.analyse.api.object.abtest.Variant variant = test.assignVariant(player.getUniqueId()); if (variant != null && variant.hasActions()) { - executeActions(player, test, (com.serverstats.sdk.object.abtest.Variant) variant); + executeActions(player, test, (net.analyse.sdk.object.abtest.Variant) variant); } } } @@ -152,15 +153,15 @@ public void processJoin(Player player, boolean firstJoin) { * @return true if the command should be cancelled */ public boolean processCommand(Player player, String command) { - for (com.serverstats.sdk.object.abtest.ABTest test : testsCache.values()) { + for (net.analyse.sdk.object.abtest.ABTest test : testsCache.values()) { if (!test.matchesCommand(command)) { continue; } // Assign variant and execute actions - var variant = test.assignVariant(player.getUniqueId()); + net.analyse.api.object.abtest.Variant variant = test.assignVariant(player.getUniqueId()); if (variant != null && variant.hasActions()) { - executeActions(player, test, (com.serverstats.sdk.object.abtest.Variant) variant); + executeActions(player, test, (net.analyse.sdk.object.abtest.Variant) variant); } // Return whether to cancel the original command @@ -177,15 +178,15 @@ public boolean processCommand(Player player, String command) { * @param eventName The event name */ public void processEvent(Player player, String eventName) { - for (com.serverstats.sdk.object.abtest.ABTest test : testsCache.values()) { + for (net.analyse.sdk.object.abtest.ABTest test : testsCache.values()) { if (!test.matchesEvent(eventName)) { continue; } // Assign variant and execute actions - var variant = test.assignVariant(player.getUniqueId()); + net.analyse.api.object.abtest.Variant variant = test.assignVariant(player.getUniqueId()); if (variant != null && variant.hasActions()) { - executeActions(player, test, (com.serverstats.sdk.object.abtest.Variant) variant); + executeActions(player, test, (net.analyse.sdk.object.abtest.Variant) variant); } } } @@ -197,15 +198,15 @@ public void processEvent(Player player, String eventName) { * @param test The A/B test * @param variant The assigned variant */ - private void executeActions(Player player, com.serverstats.sdk.object.abtest.ABTest test, - com.serverstats.sdk.object.abtest.Variant variant) { + private void executeActions(Player player, net.analyse.sdk.object.abtest.ABTest test, + net.analyse.sdk.object.abtest.Variant variant) { if (plugin.isDebugEnabled()) { plugin.logInfo(String.format("[DEBUG] Player %s assigned to variant '%s' for test '%s'", player.getName(), variant.getKey(), test.getKey())); } for (ActionData actionData : variant.getActions()) { - PaperAction action = PaperAction.create(plugin, actionData); + SpigotAction action = SpigotAction.create(plugin, actionData); if (action != null) { action.execute(player); } @@ -214,19 +215,19 @@ private void executeActions(Player player, com.serverstats.sdk.object.abtest.ABT @Override public void trackConversion(UUID playerUuid, String playerUsername, String testKey, String eventName) { - com.serverstats.sdk.object.abtest.ABTest test = testsCache.get(testKey); + net.analyse.sdk.object.abtest.ABTest test = testsCache.get(testKey); if (test == null) { return; } - var variant = test.assignVariant(playerUuid); + net.analyse.api.object.abtest.Variant variant = test.assignVariant(playerUuid); String variantKey = variant != null ? variant.getKey() : null; ConversionRequest request = new ConversionRequest( testKey, variantKey, playerUuid, playerUsername, eventName, null ); - plugin.getClient().trackConversion(request, new ServerStatsCallback<>() { + plugin.getClient().trackConversion(request, new AnalyseCallback() { @Override public void onSuccess(ConversionResponse response) { if (plugin.isDebugEnabled()) { @@ -236,7 +237,7 @@ public void onSuccess(ConversionResponse response) { } @Override - public void onError(ServerStatsException exception) { + public void onError(AnalyseException exception) { plugin.logWarning(String.format("Failed to track conversion: %s", exception.getMessage())); } }); diff --git a/hytale/src/main/java/com/serverstats/hytale/manager/SessionManager.java b/modules/spigot/src/main/java/net/analyse/spigot/manager/SessionManager.java similarity index 89% rename from hytale/src/main/java/com/serverstats/hytale/manager/SessionManager.java rename to modules/spigot/src/main/java/net/analyse/spigot/manager/SessionManager.java index 66a4e42..185e7cf 100644 --- a/hytale/src/main/java/com/serverstats/hytale/manager/SessionManager.java +++ b/modules/spigot/src/main/java/net/analyse/spigot/manager/SessionManager.java @@ -1,6 +1,6 @@ -package com.serverstats.hytale.manager; +package net.analyse.spigot.manager; -import com.serverstats.hytale.object.session.PlayerSession; +import net.analyse.spigot.object.session.PlayerSession; import java.util.Collection; import java.util.Map; import java.util.Optional; @@ -10,7 +10,7 @@ /** * Thread-safe manager for player sessions */ -public class SessionManager implements com.serverstats.api.manager.SessionManager { +public class SessionManager implements net.analyse.api.manager.SessionManager { private final Map sessions = new ConcurrentHashMap<>(); diff --git a/paper/src/main/java/com/serverstats/paper/object/action/RunCommandAction.java b/modules/spigot/src/main/java/net/analyse/spigot/object/action/RunCommandAction.java similarity index 78% rename from paper/src/main/java/com/serverstats/paper/object/action/RunCommandAction.java rename to modules/spigot/src/main/java/net/analyse/spigot/object/action/RunCommandAction.java index bfd5905..d9dba3e 100644 --- a/paper/src/main/java/com/serverstats/paper/object/action/RunCommandAction.java +++ b/modules/spigot/src/main/java/net/analyse/spigot/object/action/RunCommandAction.java @@ -1,9 +1,9 @@ -package com.serverstats.paper.object.action; +package net.analyse.spigot.object.action; -import com.serverstats.paper.ServerStatsPlugin; -import com.serverstats.paper.util.SchedulerUtil; -import com.serverstats.sdk.object.action.ActionData; -import com.serverstats.sdk.object.action.ActionType; +import net.analyse.spigot.AnalysePlugin; +import net.analyse.spigot.util.SchedulerUtil; +import net.analyse.sdk.object.action.ActionData; +import net.analyse.sdk.object.action.ActionType; import org.bukkit.Bukkit; import org.bukkit.entity.Player; @@ -11,9 +11,9 @@ * Action that runs a command. * Can be executed as console or as the player. */ -public class RunCommandAction extends PaperAction { +public class RunCommandAction extends SpigotAction { - public RunCommandAction(ServerStatsPlugin plugin, ActionData data) { + public RunCommandAction(AnalysePlugin plugin, ActionData data) { super(plugin, data); } @@ -25,7 +25,7 @@ public ActionType getType() { @Override public void execute(Player player) { String command = data.getString("command"); - if (command == null || command.isBlank()) { + if (command == null || command.trim().isEmpty()) { return; } diff --git a/paper/src/main/java/com/serverstats/paper/object/action/SendMessageAction.java b/modules/spigot/src/main/java/net/analyse/spigot/object/action/SendMessageAction.java similarity index 55% rename from paper/src/main/java/com/serverstats/paper/object/action/SendMessageAction.java rename to modules/spigot/src/main/java/net/analyse/spigot/object/action/SendMessageAction.java index d34f288..51953b4 100644 --- a/paper/src/main/java/com/serverstats/paper/object/action/SendMessageAction.java +++ b/modules/spigot/src/main/java/net/analyse/spigot/object/action/SendMessageAction.java @@ -1,18 +1,18 @@ -package com.serverstats.paper.object.action; +package net.analyse.spigot.object.action; -import com.serverstats.paper.ServerStatsPlugin; -import com.serverstats.paper.util.ComponentUtil; -import com.serverstats.sdk.object.action.ActionData; -import com.serverstats.sdk.object.action.ActionType; +import net.analyse.spigot.AnalysePlugin; +import net.analyse.spigot.util.MessageUtil; +import net.analyse.sdk.object.action.ActionData; +import net.analyse.sdk.object.action.ActionType; import org.bukkit.entity.Player; /** * Action that sends a message to the player. * Supports MiniMessage, hex colors, and legacy color codes. */ -public class SendMessageAction extends PaperAction { +public class SendMessageAction extends SpigotAction { - public SendMessageAction(ServerStatsPlugin plugin, ActionData data) { + public SendMessageAction(AnalysePlugin plugin, ActionData data) { super(plugin, data); } @@ -24,15 +24,15 @@ public ActionType getType() { @Override public void execute(Player player) { String message = data.getString("message"); - if (message == null || message.isBlank()) { + if (message == null || message.trim().isEmpty()) { return; } // Parse with full color support and placeholders - player.sendMessage(ComponentUtil.parse(message, + MessageUtil.sendMessage(player, message, "player", player.getName(), "uuid", player.getUniqueId().toString() - )); + ); debug("Sent message to %s: %s", player.getName(), message); } diff --git a/paper/src/main/java/com/serverstats/paper/object/action/PaperAction.java b/modules/spigot/src/main/java/net/analyse/spigot/object/action/SpigotAction.java similarity index 59% rename from paper/src/main/java/com/serverstats/paper/object/action/PaperAction.java rename to modules/spigot/src/main/java/net/analyse/spigot/object/action/SpigotAction.java index ac1287f..47badc8 100644 --- a/paper/src/main/java/com/serverstats/paper/object/action/PaperAction.java +++ b/modules/spigot/src/main/java/net/analyse/spigot/object/action/SpigotAction.java @@ -1,40 +1,44 @@ -package com.serverstats.paper.object.action; +package net.analyse.spigot.object.action; -import com.serverstats.paper.ServerStatsPlugin; -import com.serverstats.sdk.object.action.Action; -import com.serverstats.sdk.object.action.ActionData; +import net.analyse.spigot.AnalysePlugin; +import net.analyse.sdk.object.action.Action; +import net.analyse.sdk.object.action.ActionData; import org.bukkit.entity.Player; /** * Base class for Paper-specific A/B test actions. * Provides common functionality for all Paper actions. */ -public abstract class PaperAction implements Action { +public abstract class SpigotAction implements Action { - protected final ServerStatsPlugin plugin; + protected final AnalysePlugin plugin; protected final ActionData data; - protected PaperAction(ServerStatsPlugin plugin, ActionData data) { + protected SpigotAction(AnalysePlugin plugin, ActionData data) { this.plugin = plugin; this.data = data; } /** - * Create a PaperAction from ActionData + * Create a SpigotAction from ActionData * * @param plugin The plugin instance * @param data The action data from the API - * @return The appropriate PaperAction, or null if type is unknown + * @return The appropriate SpigotAction, or null if type is unknown */ - public static PaperAction create(ServerStatsPlugin plugin, ActionData data) { + public static SpigotAction create(AnalysePlugin plugin, ActionData data) { if (data == null || data.getType() == null) { return null; } - return switch (data.getType()) { - case SEND_MESSAGE -> new SendMessageAction(plugin, data); - case RUN_COMMAND -> new RunCommandAction(plugin, data); - }; + switch (data.getType()) { + case SEND_MESSAGE: + return new SendMessageAction(plugin, data); + case RUN_COMMAND: + return new RunCommandAction(plugin, data); + default: + return null; + } } /** diff --git a/hytale/src/main/java/com/serverstats/hytale/object/session/PlayerSession.java b/modules/spigot/src/main/java/net/analyse/spigot/object/session/PlayerSession.java similarity index 83% rename from hytale/src/main/java/com/serverstats/hytale/object/session/PlayerSession.java rename to modules/spigot/src/main/java/net/analyse/spigot/object/session/PlayerSession.java index b48d745..7caad25 100644 --- a/hytale/src/main/java/com/serverstats/hytale/object/session/PlayerSession.java +++ b/modules/spigot/src/main/java/net/analyse/spigot/object/session/PlayerSession.java @@ -1,4 +1,4 @@ -package com.serverstats.hytale.object.session; +package net.analyse.spigot.object.session; import lombok.Getter; import java.time.Instant; @@ -8,7 +8,7 @@ * Stores session data for a connected player */ @Getter -public class PlayerSession implements com.serverstats.api.session.PlayerSession { +public class PlayerSession implements net.analyse.api.session.PlayerSession { private final UUID playerUuid; private final String hostname; @@ -41,6 +41,6 @@ public void setSessionId(String sessionId) { @Override public boolean hasActiveSession() { - return sessionId != null && !sessionId.isBlank(); + return sessionId != null && !sessionId.trim().isEmpty(); } } diff --git a/paper/src/main/java/com/serverstats/paper/task/HeartbeatTask.java b/modules/spigot/src/main/java/net/analyse/spigot/task/HeartbeatTask.java similarity index 63% rename from paper/src/main/java/com/serverstats/paper/task/HeartbeatTask.java rename to modules/spigot/src/main/java/net/analyse/spigot/task/HeartbeatTask.java index e604acc..1c3318e 100644 --- a/paper/src/main/java/com/serverstats/paper/task/HeartbeatTask.java +++ b/modules/spigot/src/main/java/net/analyse/spigot/task/HeartbeatTask.java @@ -1,18 +1,19 @@ -package com.serverstats.paper.task; +package net.analyse.spigot.task; -import com.serverstats.api.ServerStats; -import com.serverstats.paper.ServerStatsPlugin; -import com.serverstats.paper.object.session.PlayerSession; -import com.serverstats.paper.util.SchedulerUtil; -import com.serverstats.sdk.ServerStatsCallback; -import com.serverstats.sdk.ServerStatsClient; -import com.serverstats.api.exception.ServerStatsException; -import com.serverstats.sdk.request.HeartbeatRequest; -import com.serverstats.sdk.request.PlayerInfo; -import com.serverstats.sdk.request.ServerType; -import com.serverstats.sdk.response.HeartbeatResponse; +import net.analyse.api.Analyse; +import net.analyse.spigot.AnalysePlugin; +import net.analyse.spigot.object.session.PlayerSession; +import net.analyse.spigot.util.SchedulerUtil; +import net.analyse.sdk.AnalyseCallback; +import net.analyse.sdk.AnalyseClient; +import net.analyse.api.exception.AnalyseException; +import net.analyse.sdk.request.HeartbeatRequest; +import net.analyse.sdk.request.PlayerInfo; +import net.analyse.sdk.request.ServerType; +import net.analyse.sdk.response.HeartbeatResponse; import org.bukkit.Bukkit; import org.bukkit.entity.Player; +import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.logging.Logger; @@ -23,11 +24,11 @@ */ public class HeartbeatTask implements Runnable { - private final ServerStatsPlugin plugin; + private final AnalysePlugin plugin; private final Logger logger; - private final ServerStatsClient client; + private final AnalyseClient client; - public HeartbeatTask(ServerStatsPlugin plugin, ServerStatsClient client) { + public HeartbeatTask(AnalysePlugin plugin, AnalyseClient client) { this.plugin = plugin; this.logger = plugin.getLogger(); this.client = client; @@ -45,25 +46,26 @@ public void run() { */ private void collectAndSendHeartbeat() { // Collect player info with hostnames for all online players - List onlinePlayers = Bukkit.getOnlinePlayers().stream() - .map(this::createPlayerInfo) - .toList(); + List onlinePlayers = new ArrayList(); + for (Player player : Bukkit.getOnlinePlayers()) { + onlinePlayers.add(createPlayerInfo(player)); + } String instanceId = plugin.getPluginConfig().getInstanceId(); HeartbeatRequest request = new HeartbeatRequest(instanceId, ServerType.MINECRAFT, onlinePlayers); // Send the API request asynchronously SchedulerUtil.runAsync(plugin, () -> { - client.heartbeat(request, new ServerStatsCallback<>() { + client.heartbeat(request, new AnalyseCallback() { @Override public void onSuccess(HeartbeatResponse response) { - ServerStats.setConnectionStatus(true, null); + Analyse.setConnectionStatus(true, null); plugin.debug("Heartbeat sent (%d players)", response.getOnlineCount()); } @Override - public void onError(ServerStatsException exception) { - ServerStats.setConnectionStatus(false, exception.getMessage()); + public void onError(AnalyseException exception) { + Analyse.setConnectionStatus(false, exception.getMessage()); logger.warning(String.format("Failed to send heartbeat: %s", exception.getMessage())); } }); diff --git a/paper/src/main/java/com/serverstats/paper/update/PaperUpdateChecker.java b/modules/spigot/src/main/java/net/analyse/spigot/update/SpigotUpdateChecker.java similarity index 77% rename from paper/src/main/java/com/serverstats/paper/update/PaperUpdateChecker.java rename to modules/spigot/src/main/java/net/analyse/spigot/update/SpigotUpdateChecker.java index 90d1e8b..ffe9cb7 100644 --- a/paper/src/main/java/com/serverstats/paper/update/PaperUpdateChecker.java +++ b/modules/spigot/src/main/java/net/analyse/spigot/update/SpigotUpdateChecker.java @@ -1,20 +1,20 @@ -package com.serverstats.paper.update; +package net.analyse.spigot.update; -import com.serverstats.paper.ServerStatsPlugin; -import com.serverstats.paper.util.ComponentUtil; -import com.serverstats.paper.util.SchedulerUtil; -import com.serverstats.sdk.update.UpdateChecker; +import net.analyse.spigot.AnalysePlugin; +import net.analyse.spigot.util.MessageUtil; +import net.analyse.spigot.util.SchedulerUtil; +import net.analyse.sdk.update.UpdateChecker; import org.bukkit.entity.Player; /** * Paper-specific update checker with console and in-game notifications */ -public class PaperUpdateChecker { +public class SpigotUpdateChecker { private static final long CHECK_INTERVAL_TICKS = 20 * 60 * 30; // 30 minutes - private static final String ADMIN_PERMISSION = "serverstats.admin"; + private static final String ADMIN_PERMISSION = "analyse.admin"; - private final ServerStatsPlugin plugin; + private final AnalysePlugin plugin; private final UpdateChecker checker; private SchedulerUtil.CancellableTask task; @@ -24,7 +24,7 @@ public class PaperUpdateChecker { * @param plugin The plugin instance * @param currentVersion The current plugin version */ - public PaperUpdateChecker(ServerStatsPlugin plugin, String currentVersion) { + public SpigotUpdateChecker(AnalysePlugin plugin, String currentVersion) { this.plugin = plugin; this.checker = new UpdateChecker(plugin.getClient(), currentVersion, "paper"); } @@ -68,7 +68,7 @@ public void check(boolean force) { public void onUpdateAvailable(String currentVersion, String newVersion, String downloadUrl) { // Log to console plugin.logInfo("╔════════════════════════════════════════════════════════════╗"); - plugin.logInfo("║ A new version of ServerStats is available! ║"); + plugin.logInfo("║ A new version of Analyse is available! ║"); plugin.logInfo("║ Current: " + padRight(currentVersion, 20) + " Latest: " + padRight(newVersion, 20) + "║"); plugin.logInfo("║ Download: " + padRight(downloadUrl, 47) + "║"); plugin.logInfo("╚════════════════════════════════════════════════════════════╝"); @@ -119,12 +119,12 @@ private void notifyAdmins(String currentVersion, String newVersion, String downl * @param downloadUrl The download URL */ public void sendUpdateMessage(Player player, String currentVersion, String newVersion, String downloadUrl) { - player.sendMessage(ComponentUtil.parse(" ")); - player.sendMessage(ComponentUtil.parse("ServerStats » A new version is available!")); - player.sendMessage(ComponentUtil.parse("Current: %current% Latest: %latest%", - "current", currentVersion, "latest", newVersion)); - player.sendMessage(ComponentUtil.parse("Download: %url%", "url", downloadUrl)); - player.sendMessage(ComponentUtil.parse(" ")); + MessageUtil.sendMessage(player, " "); + MessageUtil.sendMessage(player, "Analyse » A new version is available!"); + MessageUtil.sendMessage(player, "Current: %current% Latest: %latest%", + "current", currentVersion, "latest", newVersion); + MessageUtil.sendMessage(player, "Download: %url%", "url", downloadUrl); + MessageUtil.sendMessage(player, " "); } /** diff --git a/velocity/src/main/java/com/serverstats/velocity/util/ComponentUtil.java b/modules/spigot/src/main/java/net/analyse/spigot/util/ComponentUtil.java similarity index 84% rename from velocity/src/main/java/com/serverstats/velocity/util/ComponentUtil.java rename to modules/spigot/src/main/java/net/analyse/spigot/util/ComponentUtil.java index 5a3c7b2..08b9351 100644 --- a/velocity/src/main/java/com/serverstats/velocity/util/ComponentUtil.java +++ b/modules/spigot/src/main/java/net/analyse/spigot/util/ComponentUtil.java @@ -1,7 +1,8 @@ -package com.serverstats.velocity.util; +package net.analyse.spigot.util; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.minimessage.MiniMessage; +import java.util.HashMap; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -27,30 +28,32 @@ public final class ComponentUtil { ); // Legacy color code mappings - private static final Map LEGACY_COLORS = Map.ofEntries( - Map.entry("&0", ""), - Map.entry("&1", ""), - Map.entry("&2", ""), - Map.entry("&3", ""), - Map.entry("&4", ""), - Map.entry("&5", ""), - Map.entry("&6", ""), - Map.entry("&7", ""), - Map.entry("&8", ""), - Map.entry("&9", ""), - Map.entry("&a", ""), - Map.entry("&b", ""), - Map.entry("&c", ""), - Map.entry("&d", ""), - Map.entry("&e", ""), - Map.entry("&f", ""), - Map.entry("&k", ""), - Map.entry("&l", ""), - Map.entry("&m", ""), - Map.entry("&n", ""), - Map.entry("&o", ""), - Map.entry("&r", "") - ); + private static final Map LEGACY_COLORS = new HashMap(); + + static { + LEGACY_COLORS.put("&0", ""); + LEGACY_COLORS.put("&1", ""); + LEGACY_COLORS.put("&2", ""); + LEGACY_COLORS.put("&3", ""); + LEGACY_COLORS.put("&4", ""); + LEGACY_COLORS.put("&5", ""); + LEGACY_COLORS.put("&6", ""); + LEGACY_COLORS.put("&7", ""); + LEGACY_COLORS.put("&8", ""); + LEGACY_COLORS.put("&9", ""); + LEGACY_COLORS.put("&a", ""); + LEGACY_COLORS.put("&b", ""); + LEGACY_COLORS.put("&c", ""); + LEGACY_COLORS.put("&d", ""); + LEGACY_COLORS.put("&e", ""); + LEGACY_COLORS.put("&f", ""); + LEGACY_COLORS.put("&k", ""); + LEGACY_COLORS.put("&l", ""); + LEGACY_COLORS.put("&m", ""); + LEGACY_COLORS.put("&n", ""); + LEGACY_COLORS.put("&o", ""); + LEGACY_COLORS.put("&r", ""); + } private ComponentUtil() { } @@ -117,7 +120,7 @@ public static Component parse(String text, Object... placeholders) { private static String convertHexColors(String text) { // Convert &#FFFFFF to <#FFFFFF> Matcher ampMatcher = AMPERSAND_HEX_PATTERN.matcher(text); - StringBuilder ampResult = new StringBuilder(); + StringBuffer ampResult = new StringBuffer(); while (ampMatcher.find()) { ampMatcher.appendReplacement(ampResult, "<#$1>"); } diff --git a/modules/spigot/src/main/java/net/analyse/spigot/util/MessageUtil.java b/modules/spigot/src/main/java/net/analyse/spigot/util/MessageUtil.java new file mode 100644 index 0000000..26027b4 --- /dev/null +++ b/modules/spigot/src/main/java/net/analyse/spigot/util/MessageUtil.java @@ -0,0 +1,74 @@ +package net.analyse.spigot.util; + +import net.kyori.adventure.platform.bukkit.BukkitAudiences; +import net.kyori.adventure.text.Component; +import org.bukkit.command.CommandSender; +import org.bukkit.plugin.Plugin; + +/** + * Messaging utility that uses adventure-platform-bukkit for cross-version support. + * On Paper: uses native Adventure rendering (full RGB, gradients, hover events). + * On Spigot: automatically converts to closest legacy ChatColor equivalent. + */ +public final class MessageUtil { + + private static BukkitAudiences audiences; + + private MessageUtil() { + } + + /** + * Initialize the messaging system. Must be called in onEnable(). + * + * @param plugin The plugin instance + */ + public static void init(Plugin plugin) { + audiences = BukkitAudiences.create(plugin); + } + + /** + * Send a parsed Component to a command sender + * + * @param sender The command sender + * @param component The component to send + */ + public static void sendMessage(CommandSender sender, Component component) { + if (audiences == null) { + return; + } + + audiences.sender(sender).sendMessage(component); + } + + /** + * Send a message with color code support to a command sender. + * Supports MiniMessage tags, legacy & codes, and hex colors. + * + * @param sender The command sender + * @param text The text to parse and send + */ + public static void sendMessage(CommandSender sender, String text) { + sendMessage(sender, ComponentUtil.parse(text)); + } + + /** + * Send a message with color code and placeholder support to a command sender + * + * @param sender The command sender + * @param text The text to parse and send + * @param placeholders Key-value pairs of placeholders (without %) + */ + public static void sendMessage(CommandSender sender, String text, Object... placeholders) { + sendMessage(sender, ComponentUtil.parse(text, placeholders)); + } + + /** + * Shut down the messaging system. Must be called in onDisable(). + */ + public static void close() { + if (audiences != null) { + audiences.close(); + audiences = null; + } + } +} diff --git a/modules/spigot/src/main/java/net/analyse/spigot/util/SchedulerUtil.java b/modules/spigot/src/main/java/net/analyse/spigot/util/SchedulerUtil.java new file mode 100644 index 0000000..f52542b --- /dev/null +++ b/modules/spigot/src/main/java/net/analyse/spigot/util/SchedulerUtil.java @@ -0,0 +1,325 @@ +package net.analyse.spigot.util; + +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; +import org.bukkit.Bukkit; +import org.bukkit.entity.Entity; +import org.bukkit.plugin.Plugin; +import org.bukkit.scheduler.BukkitTask; + +/** + * Utility class that abstracts scheduling to support both Paper/Spigot and Folia. + * Automatically detects the server type and uses the appropriate scheduler. + */ +public final class SchedulerUtil { + + private static final boolean IS_FOLIA; + + static { + boolean folia; + try { + Class.forName("io.papermc.paper.threadedregions.RegionizedServer"); + folia = true; + } catch (ClassNotFoundException e) { + folia = false; + } + IS_FOLIA = folia; + } + + /** + * Not used; prevents instantiation of this utility class. + */ + private SchedulerUtil() { + } + + /** + * Obtains the global region scheduler instance via reflection (Folia). + * + * @return The scheduler object + * @throws Exception if reflection fails + */ + private static Object getGlobalRegionSchedulerReflect() throws Exception { + return Bukkit.class.getMethod("getGlobalRegionScheduler").invoke(null); + } + + /** + * Obtains the async scheduler instance via reflection (Folia). + * + * @return The scheduler object + * @throws Exception if reflection fails + */ + private static Object getAsyncSchedulerReflect() throws Exception { + return Bukkit.class.getMethod("getAsyncScheduler").invoke(null); + } + + /** + * Obtains an entity's region scheduler via reflection (Folia). + * + * @param entity The entity + * @return The entity scheduler object + * @throws Exception if reflection fails + */ + private static Object getEntitySchedulerReflect(Entity entity) throws Exception { + return entity.getClass().getMethod("getScheduler").invoke(entity); + } + + /** + * Builds a consumer that ignores the scheduled-task argument and runs the given runnable. + * + * @param task The task to run + * @return Consumer suitable for Folia scheduler method parameters + */ + private static Consumer consumingRunnable(Runnable task) { + return scheduledTask -> task.run(); + } + + /** + * Returns a cancellable that invokes {@code cancel()} on a Folia scheduled task via reflection. + * + * @param scheduled The object returned by Folia's scheduler + * @return A wrapper that cancels via reflection + */ + private static CancellableTask newFoliaCancellable(final Object scheduled) { + return () -> { + try { + scheduled.getClass().getMethod("cancel").invoke(scheduled); + } catch (Exception ignored) { + } + }; + } + + /** + * Check if the server is running Folia + * + * @return true if running Folia + */ + public static boolean isFolia() { + return IS_FOLIA; + } + + /** + * Run a task on the main/global thread. + * On Paper/Spigot: runs on the main thread. + * On Folia: runs on the global region scheduler. + * + * @param plugin The plugin + * @param task The task to run + */ + public static void runSync(Plugin plugin, Runnable task) { + if (IS_FOLIA) { + try { + Object globalScheduler = getGlobalRegionSchedulerReflect(); + Consumer consumer = consumingRunnable(task); + globalScheduler.getClass() + .getMethod("run", Plugin.class, Consumer.class) + .invoke(globalScheduler, plugin, consumer); + } catch (Exception e) { + Bukkit.getScheduler().runTask(plugin, task); + } + } else { + Bukkit.getScheduler().runTask(plugin, task); + } + } + + /** + * Run a task on the main/global thread after a delay. + * On Paper/Spigot: runs on the main thread. + * On Folia: runs on the global region scheduler. + * + * @param plugin The plugin + * @param task The task to run + * @param delayTicks The delay in ticks + */ + public static void runSyncDelayed(Plugin plugin, Runnable task, long delayTicks) { + if (IS_FOLIA) { + try { + Object globalScheduler = getGlobalRegionSchedulerReflect(); + Consumer consumer = consumingRunnable(task); + globalScheduler.getClass() + .getMethod("runDelayed", Plugin.class, Consumer.class, long.class) + .invoke(globalScheduler, plugin, consumer, delayTicks); + } catch (Exception e) { + Bukkit.getScheduler().runTaskLater(plugin, task, delayTicks); + } + } else { + Bukkit.getScheduler().runTaskLater(plugin, task, delayTicks); + } + } + + /** + * Run a task tied to an entity's region thread. + * On Paper/Spigot: runs on the main thread. + * On Folia: runs on the entity's region scheduler. + * + * @param plugin The plugin + * @param entity The entity to run the task for + * @param task The task to run + * @param retired Runnable to execute if the entity is retired (removed) before the task runs + */ + public static void runForEntity(Plugin plugin, Entity entity, Runnable task, Runnable retired) { + if (IS_FOLIA) { + try { + Object entityScheduler = getEntitySchedulerReflect(entity); + Consumer consumer = consumingRunnable(task); + entityScheduler.getClass() + .getMethod("run", Plugin.class, Consumer.class, Runnable.class) + .invoke(entityScheduler, plugin, consumer, retired); + } catch (Exception e) { + Bukkit.getScheduler().runTask(plugin, task); + } + } else { + Bukkit.getScheduler().runTask(plugin, task); + } + } + + /** + * Run a task tied to an entity's region thread after a delay. + * On Paper/Spigot: runs on the main thread. + * On Folia: runs on the entity's region scheduler. + * + * @param plugin The plugin + * @param entity The entity to run the task for + * @param task The task to run + * @param retired Runnable to execute if the entity is retired (removed) before the task runs + * @param delayTicks The delay in ticks + */ + public static void runForEntityDelayed(Plugin plugin, Entity entity, Runnable task, Runnable retired, long delayTicks) { + if (IS_FOLIA) { + try { + Object entityScheduler = getEntitySchedulerReflect(entity); + Consumer consumer = consumingRunnable(task); + entityScheduler.getClass() + .getMethod("runDelayed", Plugin.class, Consumer.class, Runnable.class, long.class) + .invoke(entityScheduler, plugin, consumer, retired, delayTicks); + } catch (Exception e) { + Bukkit.getScheduler().runTaskLater(plugin, task, delayTicks); + } + } else { + Bukkit.getScheduler().runTaskLater(plugin, task, delayTicks); + } + } + + /** + * Run a task asynchronously. + * + * @param plugin The plugin + * @param task The task to run + */ + public static void runAsync(Plugin plugin, Runnable task) { + if (IS_FOLIA) { + try { + Object asyncScheduler = getAsyncSchedulerReflect(); + Consumer consumer = consumingRunnable(task); + asyncScheduler.getClass() + .getMethod("runNow", Plugin.class, Consumer.class) + .invoke(asyncScheduler, plugin, consumer); + } catch (Exception e) { + Bukkit.getScheduler().runTaskAsynchronously(plugin, task); + } + } else { + Bukkit.getScheduler().runTaskAsynchronously(plugin, task); + } + } + + /** + * Run a task asynchronously after a delay. + * + * @param plugin The plugin + * @param task The task to run + * @param delayTicks The delay in ticks (converted to milliseconds for Folia) + */ + public static void runAsyncDelayed(Plugin plugin, Runnable task, long delayTicks) { + if (IS_FOLIA) { + try { + // Convert ticks to milliseconds (1 tick = 50ms) + long delayMs = delayTicks * 50; + Object asyncScheduler = getAsyncSchedulerReflect(); + Consumer consumer = consumingRunnable(task); + asyncScheduler.getClass() + .getMethod("runDelayed", Plugin.class, Consumer.class, long.class, TimeUnit.class) + .invoke(asyncScheduler, plugin, consumer, delayMs, TimeUnit.MILLISECONDS); + } catch (Exception e) { + Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, task, delayTicks); + } + } else { + Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, task, delayTicks); + } + } + + /** + * Schedule a repeating async task. + * + * @param plugin The plugin + * @param task The task to run + * @param delayTicks Initial delay in ticks + * @param periodTicks Period between executions in ticks + * @return A cancellable task wrapper + */ + public static CancellableTask runAsyncTimer(Plugin plugin, Runnable task, long delayTicks, long periodTicks) { + if (IS_FOLIA) { + try { + // Convert ticks to milliseconds (1 tick = 50ms) + long delayMs = delayTicks * 50; + long periodMs = periodTicks * 50; + Object asyncScheduler = getAsyncSchedulerReflect(); + Consumer consumer = consumingRunnable(task); + Object scheduled = asyncScheduler.getClass() + .getMethod( + "runAtFixedRate", + Plugin.class, + Consumer.class, + long.class, + long.class, + TimeUnit.class) + .invoke(asyncScheduler, plugin, consumer, delayMs, periodMs, TimeUnit.MILLISECONDS); + return newFoliaCancellable(scheduled); + } catch (Exception e) { + BukkitTask bukkitTask = Bukkit.getScheduler().runTaskTimerAsynchronously(plugin, task, delayTicks, periodTicks); + return bukkitTask::cancel; + } + } else { + BukkitTask bukkitTask = Bukkit.getScheduler().runTaskTimerAsynchronously(plugin, task, delayTicks, periodTicks); + return bukkitTask::cancel; + } + } + + /** + * Schedule a repeating sync task on the global region. + * + * @param plugin The plugin + * @param task The task to run + * @param delayTicks Initial delay in ticks + * @param periodTicks Period between executions in ticks + * @return A cancellable task wrapper + */ + public static CancellableTask runSyncTimer(Plugin plugin, Runnable task, long delayTicks, long periodTicks) { + if (IS_FOLIA) { + try { + Object globalScheduler = getGlobalRegionSchedulerReflect(); + Consumer consumer = consumingRunnable(task); + Object scheduled = globalScheduler.getClass() + .getMethod("runAtFixedRate", Plugin.class, Consumer.class, long.class, long.class) + .invoke(globalScheduler, plugin, consumer, delayTicks, periodTicks); + return newFoliaCancellable(scheduled); + } catch (Exception e) { + BukkitTask bukkitTask = Bukkit.getScheduler().runTaskTimer(plugin, task, delayTicks, periodTicks); + return bukkitTask::cancel; + } + } else { + BukkitTask bukkitTask = Bukkit.getScheduler().runTaskTimer(plugin, task, delayTicks, periodTicks); + return bukkitTask::cancel; + } + } + + /** + * Interface for cancellable tasks to abstract between Bukkit and Folia + */ + @FunctionalInterface + public interface CancellableTask { + + /** + * Cancel the task + */ + void cancel(); + } +} diff --git a/paper/src/main/resources/config.yml b/modules/spigot/src/main/resources/config.yml similarity index 89% rename from paper/src/main/resources/config.yml rename to modules/spigot/src/main/resources/config.yml index 1a4ea96..3c10c5d 100644 --- a/paper/src/main/resources/config.yml +++ b/modules/spigot/src/main/resources/config.yml @@ -1,9 +1,9 @@ -# ServerStats Plugin Configuration +# Analyse Plugin Configuration # Enable debug logging for troubleshooting debug: false -# Your server's API key from the ServerStats dashboard +# Your server's API key from the Analyse dashboard api-key: "anl_your_api_key_here" # Bedrock player username prefix (used by Floodgate/Geyser) diff --git a/modules/spigot/src/main/resources/paper-plugin.yml b/modules/spigot/src/main/resources/paper-plugin.yml new file mode 100644 index 0000000..94cad9a --- /dev/null +++ b/modules/spigot/src/main/resources/paper-plugin.yml @@ -0,0 +1,21 @@ +name: Analyse +version: ${version} +main: net.analyse.spigot.AnalysePlugin +api-version: "1.21" +folia-supported: true +description: Analyse tracking plugin +author: VertCode Development + +permissions: + analyse.netmand: + description: Base permission for analyse commands + default: op + analyse.netmand.reload: + description: Permission to reload the plugin + default: op + analyse.netmand.debug: + description: Permission to toggle debug mode + default: op + analyse.netmand.event: + description: Permission to send custom events + default: op diff --git a/modules/spigot/src/main/resources/plugin.yml b/modules/spigot/src/main/resources/plugin.yml new file mode 100644 index 0000000..48828dd --- /dev/null +++ b/modules/spigot/src/main/resources/plugin.yml @@ -0,0 +1,19 @@ +name: Analyse +version: ${version} +main: net.analyse.spigot.AnalysePlugin +description: Analyse tracking plugin +author: VertCode Development + +permissions: + analyse.netmand: + description: Base permission for analyse commands + default: op + analyse.netmand.reload: + description: Permission to reload the plugin + default: op + analyse.netmand.debug: + description: Permission to toggle debug mode + default: op + analyse.netmand.event: + description: Permission to send custom events + default: op diff --git a/velocity/build.gradle b/modules/velocity/build.gradle similarity index 76% rename from velocity/build.gradle rename to modules/velocity/build.gradle index a9d490a..81788fa 100644 --- a/velocity/build.gradle +++ b/modules/velocity/build.gradle @@ -3,6 +3,10 @@ plugins { id 'com.gradleup.shadow' } +tasks.withType(JavaCompile).configureEach { + options.release = 17 +} + repositories { maven { name = 'papermc' @@ -11,15 +15,15 @@ repositories { } dependencies { - implementation project(':api') - implementation project(':sdk') + implementation project(':modules:api') + implementation project(':modules:sdk') implementation "co.aikar:acf-velocity:${project.property('acfVersion')}" compileOnly "com.velocitypowered:velocity-api:${project.property('velocityVersion')}" annotationProcessor "com.velocitypowered:velocity-api:${project.property('velocityVersion')}" } tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { - archiveBaseName.set('serverstats-velocity') + archiveBaseName.set('analyse-velocity') archiveClassifier.set('') } diff --git a/velocity/src/main/java/com/serverstats/velocity/ServerStatsVelocity.java b/modules/velocity/src/main/java/net/analyse/velocity/AnalyseVelocity.java similarity index 74% rename from velocity/src/main/java/com/serverstats/velocity/ServerStatsVelocity.java rename to modules/velocity/src/main/java/net/analyse/velocity/AnalyseVelocity.java index ba0dbd9..d258c9f 100644 --- a/velocity/src/main/java/com/serverstats/velocity/ServerStatsVelocity.java +++ b/modules/velocity/src/main/java/net/analyse/velocity/AnalyseVelocity.java @@ -1,4 +1,4 @@ -package com.serverstats.velocity; +package net.analyse.velocity; import com.google.inject.Inject; import com.velocitypowered.api.event.Subscribe; @@ -11,52 +11,53 @@ import com.velocitypowered.api.proxy.ProxyServer; import com.velocitypowered.api.scheduler.ScheduledTask; import co.aikar.commands.VelocityCommandManager; -import com.serverstats.api.ServerStats; -import com.serverstats.api.ServerStatsProvider; -import com.serverstats.api.BuildConstants; -import com.serverstats.api.addon.AddonManager; -import com.serverstats.api.exception.ServerStatsException; -import com.serverstats.api.object.builder.EventBuilder; -import com.serverstats.api.platform.ServerStatsPlatform; -import com.serverstats.sdk.ServerStatsCallback; -import com.serverstats.sdk.ServerStatsClient; -import com.serverstats.sdk.request.EventRequest; -import com.serverstats.sdk.response.EventResponse; -import com.serverstats.api.messaging.ServerStatsMessaging; -import com.serverstats.velocity.addon.VelocityAddonManager; -import com.serverstats.velocity.command.ServerStatsCommand; -import com.serverstats.velocity.config.ServerStatsVelocityConfig; -import com.serverstats.velocity.listener.ActivityListener; -import com.serverstats.velocity.listener.PlayerListener; -import com.serverstats.velocity.listener.PluginMessageListener; -import com.serverstats.velocity.manager.ABTestManager; -import com.serverstats.velocity.manager.SessionManager; -import com.serverstats.velocity.task.HeartbeatTask; -import com.serverstats.velocity.update.VelocityUpdateChecker; +import net.analyse.api.Analyse; +import net.analyse.api.AnalyseProvider; +import net.analyse.api.BuildConstants; +import net.analyse.api.addon.AddonManager; +import net.analyse.api.exception.AnalyseException; +import net.analyse.api.object.builder.EventBuilder; +import net.analyse.api.platform.AnalysePlatform; +import net.analyse.sdk.AnalyseCallback; +import net.analyse.sdk.AnalyseClient; +import net.analyse.sdk.request.EventRequest; +import net.analyse.sdk.response.EventResponse; +import net.analyse.api.messaging.AnalyseMessaging; +import net.analyse.velocity.addon.VelocityAddonManager; +import net.analyse.velocity.command.AnalyseCommand; +import net.analyse.velocity.config.AnalyseVelocityConfig; +import net.analyse.velocity.listener.ActivityListener; +import net.analyse.velocity.listener.PlayerListener; +import net.analyse.velocity.listener.PluginMessageListener; +import net.analyse.velocity.manager.ABTestManager; +import net.analyse.velocity.manager.SessionManager; +import net.analyse.velocity.task.HeartbeatTask; +import net.analyse.velocity.update.VelocityUpdateChecker; import org.slf4j.Logger; import java.io.IOException; import java.net.InetSocketAddress; +import java.nio.file.Files; import java.nio.file.Path; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; /** - * ServerStats plugin for Velocity proxy + * Analyse plugin for Velocity proxy */ @Plugin( - id = "serverstats", - name = "ServerStats", + id = "analyse", + name = "Analyse", version = BuildConstants.VERSION, description = "Analytics tracking plugin for Minecraft servers", - authors = {"VertCode"} + authors = {"VertCode Development"} ) -public class ServerStatsVelocity implements ServerStatsPlatform { +public class AnalyseVelocity implements AnalysePlatform { private final ProxyServer server; private final Logger logger; private final Path dataDirectory; - private ServerStatsVelocityConfig pluginConfig; + private AnalyseVelocityConfig pluginConfig; private SessionManager sessionManager; private ABTestManager abTestManager; private VelocityAddonManager addonManager; @@ -65,7 +66,7 @@ public class ServerStatsVelocity implements ServerStatsPlatform { private VelocityUpdateChecker updateChecker; @Inject - public ServerStatsVelocity(ProxyServer server, Logger logger, @DataDirectory Path dataDirectory) { + public AnalyseVelocity(ProxyServer server, Logger logger, @DataDirectory Path dataDirectory) { this.server = server; this.logger = logger; this.dataDirectory = dataDirectory; @@ -73,7 +74,10 @@ public ServerStatsVelocity(ProxyServer server, Logger logger, @DataDirectory Pat @Subscribe public void onProxyInitialize(ProxyInitializeEvent event) { - logger.info("Initializing ServerStats..."); + logger.info("Initializing Analyse..."); + + // Migrate old "serverstats" data folder if it exists + migrateDataFolder(); // Load configuration if (!loadConfig()) { @@ -92,17 +96,17 @@ public void onProxyInitialize(ProxyInitializeEvent event) { // Register plugin message channel for backend server communication server.getChannelRegistrar().register( - com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier.from(ServerStatsMessaging.CHANNEL) + com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier.from(AnalyseMessaging.CHANNEL) ); server.getEventManager().register(this, new PluginMessageListener(this)); - logger.info("Registered plugin message channel: " + ServerStatsMessaging.CHANNEL); + logger.info("Registered plugin message channel: " + AnalyseMessaging.CHANNEL); // Register with the API provider if at least one server is configured if (playerListener.hasAnyClient()) { - ServerStatsProvider.register(this); + AnalyseProvider.register(this); - // Set up the event sender for ServerStats.trackEvent() - ServerStats.setEventSender(this::sendEvent); + // Set up the event sender for Analyse.trackEvent() + Analyse.setEventSender(this::sendEvent); // Initialize A/B test manager abTestManager = new ABTestManager(this); @@ -111,7 +115,7 @@ public void onProxyInitialize(ProxyInitializeEvent event) { // Register commands using ACF VelocityCommandManager commandManager = new VelocityCommandManager(server, this); - commandManager.registerCommand(new ServerStatsCommand(this)); + commandManager.registerCommand(new AnalyseCommand(this)); // Start heartbeat task (after playerListener is initialized) startHeartbeatTask(); @@ -130,7 +134,7 @@ public void onProxyInitialize(ProxyInitializeEvent event) { addonManager.loadAddons(); addonManager.enableAddons(); - logger.info(String.format("ServerStats initialized with %d server(s) configured", + logger.info(String.format("Analyse initialized with %d server(s) configured", pluginConfig.getServers().size())); } @@ -141,7 +145,7 @@ public void onProxyInitialize(ProxyInitializeEvent event) { * @param callback Optional callback for result */ private void sendEvent(EventBuilder event, Consumer callback) { - ServerStatsClient client = getClient(); + AnalyseClient client = getClient(); if (client == null) { if (callback != null) { callback.accept(false); @@ -165,7 +169,7 @@ private void sendEvent(EventBuilder event, Consumer callback) { event.getValue() ); - client.trackEvent(request, new ServerStatsCallback<>() { + client.trackEvent(request, new AnalyseCallback<>() { @Override public void onSuccess(EventResponse response) { if (isDebugEnabled()) { @@ -179,7 +183,7 @@ public void onSuccess(EventResponse response) { } @Override - public void onError(ServerStatsException exception) { + public void onError(AnalyseException exception) { logWarning(String.format("Failed to track event '%s': %s", event.getName(), exception.getMessage())); @@ -226,7 +230,7 @@ private void initializeOnlinePlayers() { @Subscribe public void onProxyReload(ProxyReloadEvent event) { - logger.info("Reloading ServerStats configuration..."); + logger.info("Reloading Analyse configuration..."); // Cancel existing heartbeat task if (heartbeatTask != null) { @@ -252,13 +256,13 @@ public void onProxyReload(ProxyReloadEvent event) { // Restart heartbeat task startHeartbeatTask(); - logger.info(String.format("ServerStats reloaded with %d server(s) configured", + logger.info(String.format("Analyse reloaded with %d server(s) configured", pluginConfig.getServers().size())); } @Subscribe public void onProxyShutdown(ProxyShutdownEvent event) { - logger.info("Shutting down ServerStats..."); + logger.info("Shutting down Analyse..."); // Disable all addons first if (addonManager != null) { @@ -266,10 +270,10 @@ public void onProxyShutdown(ProxyShutdownEvent event) { } // Unregister from the API provider - ServerStatsProvider.unregister(); + AnalyseProvider.unregister(); // Clear the event sender - ServerStats.setEventSender(null); + Analyse.setEventSender(null); // Stop A/B test manager if (abTestManager != null) { @@ -291,7 +295,23 @@ public void onProxyShutdown(ProxyShutdownEvent event) { playerListener.shutdown(); } - logger.info("ServerStats shutdown complete"); + logger.info("Analyse shutdown complete"); + } + + /** + * Migrate the data folder from the old "serverstats" name to "analyse". + * Automatically renames plugins/serverstats to plugins/analyse if it exists. + */ + private void migrateDataFolder() { + Path oldFolder = dataDirectory.resolveSibling("serverstats"); + if (Files.exists(oldFolder) && Files.isDirectory(oldFolder) && !Files.exists(dataDirectory)) { + try { + Files.move(oldFolder, dataDirectory); + logger.info("Migrated data folder from serverstats to analyse"); + } catch (IOException e) { + logger.warn("Failed to migrate data folder from serverstats to analyse. Please rename it manually."); + } + } } /** @@ -301,7 +321,7 @@ public void onProxyShutdown(ProxyShutdownEvent event) { */ private boolean loadConfig() { try { - pluginConfig = ServerStatsVelocityConfig.load(dataDirectory); + pluginConfig = AnalyseVelocityConfig.load(dataDirectory); } catch (IOException e) { logger.error("Failed to load configuration", e); return false; @@ -349,7 +369,7 @@ public void debug(String format, Object... args) { } } - // ========== ServerStatsPlatform Interface Methods ========== + // ========== AnalysePlatform Interface Methods ========== @Override public SessionManager getSessionManager() { @@ -411,7 +431,7 @@ public Logger getLogger() { * * @return The plugin config */ - public ServerStatsVelocityConfig getPluginConfig() { + public AnalyseVelocityConfig getPluginConfig() { return pluginConfig; } @@ -419,9 +439,9 @@ public ServerStatsVelocityConfig getPluginConfig() { * Get an SDK client for API operations. * Uses the configured default server if set, otherwise returns any available client. * - * @return The ServerStats client, or null if none available + * @return The Analyse client, or null if none available */ - public ServerStatsClient getClient() { + public AnalyseClient getClient() { return playerListener != null ? playerListener.getAvailableClient() : null; } diff --git a/velocity/src/main/java/com/serverstats/velocity/addon/VelocityAddonLogger.java b/modules/velocity/src/main/java/net/analyse/velocity/addon/VelocityAddonLogger.java similarity index 86% rename from velocity/src/main/java/com/serverstats/velocity/addon/VelocityAddonLogger.java rename to modules/velocity/src/main/java/net/analyse/velocity/addon/VelocityAddonLogger.java index 6308cbd..09d8dde 100644 --- a/velocity/src/main/java/com/serverstats/velocity/addon/VelocityAddonLogger.java +++ b/modules/velocity/src/main/java/net/analyse/velocity/addon/VelocityAddonLogger.java @@ -1,7 +1,7 @@ -package com.serverstats.velocity.addon; +package net.analyse.velocity.addon; -import com.serverstats.api.addon.AddonLogger; -import com.serverstats.velocity.ServerStatsVelocity; +import net.analyse.api.addon.AddonLogger; +import net.analyse.velocity.AnalyseVelocity; import org.slf4j.Logger; /** @@ -10,7 +10,7 @@ public class VelocityAddonLogger implements AddonLogger { private final Logger logger; - private final ServerStatsVelocity plugin; + private final AnalyseVelocity plugin; private final String prefix; /** @@ -19,7 +19,7 @@ public class VelocityAddonLogger implements AddonLogger { * @param plugin The main plugin instance * @param addonName The addon display name */ - public VelocityAddonLogger(ServerStatsVelocity plugin, String addonName) { + public VelocityAddonLogger(AnalyseVelocity plugin, String addonName) { this.plugin = plugin; this.logger = plugin.getLogger(); this.prefix = "[" + addonName + "] "; diff --git a/velocity/src/main/java/com/serverstats/velocity/addon/VelocityAddonManager.java b/modules/velocity/src/main/java/net/analyse/velocity/addon/VelocityAddonManager.java similarity index 79% rename from velocity/src/main/java/com/serverstats/velocity/addon/VelocityAddonManager.java rename to modules/velocity/src/main/java/net/analyse/velocity/addon/VelocityAddonManager.java index c1e398e..45f7484 100644 --- a/velocity/src/main/java/com/serverstats/velocity/addon/VelocityAddonManager.java +++ b/modules/velocity/src/main/java/net/analyse/velocity/addon/VelocityAddonManager.java @@ -1,8 +1,8 @@ -package com.serverstats.velocity.addon; +package net.analyse.velocity.addon; -import com.serverstats.api.addon.AbstractAddonManager; -import com.serverstats.api.addon.AddonLogger; -import com.serverstats.velocity.ServerStatsVelocity; +import net.analyse.api.addon.AbstractAddonManager; +import net.analyse.api.addon.AddonLogger; +import net.analyse.velocity.AnalyseVelocity; import java.nio.file.Path; /** @@ -10,7 +10,7 @@ */ public class VelocityAddonManager extends AbstractAddonManager { - private final ServerStatsVelocity plugin; + private final AnalyseVelocity plugin; /** * Create a new Velocity addon manager @@ -18,7 +18,7 @@ public class VelocityAddonManager extends AbstractAddonManager { * @param plugin The main plugin instance * @param dataDirectory The plugin's data directory */ - public VelocityAddonManager(ServerStatsVelocity plugin, Path dataDirectory) { + public VelocityAddonManager(AnalyseVelocity plugin, Path dataDirectory) { super(plugin, dataDirectory.resolve("addons"), plugin.getClass().getClassLoader()); this.plugin = plugin; } diff --git a/velocity/src/main/java/com/serverstats/velocity/command/ServerStatsCommand.java b/modules/velocity/src/main/java/net/analyse/velocity/command/AnalyseCommand.java similarity index 80% rename from velocity/src/main/java/com/serverstats/velocity/command/ServerStatsCommand.java rename to modules/velocity/src/main/java/net/analyse/velocity/command/AnalyseCommand.java index 0f43072..3959488 100644 --- a/velocity/src/main/java/com/serverstats/velocity/command/ServerStatsCommand.java +++ b/modules/velocity/src/main/java/net/analyse/velocity/command/AnalyseCommand.java @@ -1,4 +1,4 @@ -package com.serverstats.velocity.command; +package net.analyse.velocity.command; import co.aikar.commands.BaseCommand; import co.aikar.commands.annotation.CommandAlias; @@ -10,18 +10,18 @@ import co.aikar.commands.annotation.Syntax; import com.velocitypowered.api.command.CommandSource; import com.velocitypowered.api.proxy.Player; -import com.serverstats.api.ServerStats; -import com.serverstats.api.addon.LoadedAddon; -import com.serverstats.api.exception.ServerStatsException; -import com.serverstats.api.object.builder.EventBuilder; -import com.serverstats.api.BuildConstants; -import com.serverstats.sdk.ServerStatsCallback; -import com.serverstats.sdk.request.PlayerInfoRequest; -import com.serverstats.sdk.response.PlayerInfoResponse; -import com.serverstats.sdk.response.ServerInfoResponse; -import com.serverstats.velocity.ServerStatsVelocity; -import com.serverstats.velocity.object.session.PlayerSession; -import com.serverstats.velocity.util.ComponentUtil; +import net.analyse.api.Analyse; +import net.analyse.api.addon.LoadedAddon; +import net.analyse.api.exception.AnalyseException; +import net.analyse.api.object.builder.EventBuilder; +import net.analyse.api.BuildConstants; +import net.analyse.sdk.AnalyseCallback; +import net.analyse.sdk.request.PlayerInfoRequest; +import net.analyse.sdk.response.PlayerInfoResponse; +import net.analyse.sdk.response.ServerInfoResponse; +import net.analyse.velocity.AnalyseVelocity; +import net.analyse.velocity.object.session.PlayerSession; +import net.analyse.velocity.util.ComponentUtil; import java.time.Duration; import java.time.Instant; import java.util.Collection; @@ -29,14 +29,14 @@ import java.util.Map; /** - * Main command handler for the ServerStats plugin using ACF + * Main command handler for the Analyse plugin using ACF */ -@CommandAlias("serverstats|analyse|ss") -public class ServerStatsCommand extends BaseCommand { +@CommandAlias("analyse|analyse|ss") +public class AnalyseCommand extends BaseCommand { - private final ServerStatsVelocity plugin; + private final AnalyseVelocity plugin; - public ServerStatsCommand(ServerStatsVelocity plugin) { + public AnalyseCommand(AnalyseVelocity plugin) { this.plugin = plugin; } @@ -44,7 +44,7 @@ public ServerStatsCommand(ServerStatsVelocity plugin) { @Description("Show plugin info") public void onDefault(CommandSource sender) { // Check if user has admin permission - if (sender.hasPermission("serverstats.command.status")) { + if (sender.hasPermission("analyse.netmand.status")) { showStatus(sender); } else { showPublicInfo(sender); @@ -53,7 +53,7 @@ public void onDefault(CommandSource sender) { @Subcommand("status") @Description("Show plugin status") - @CommandPermission("serverstats.command.status") + @CommandPermission("analyse.netmand.status") public void onStatus(CommandSource sender) { showStatus(sender); } @@ -65,11 +65,11 @@ public void onStatus(CommandSource sender) { */ private void showPublicInfo(CommandSource sender) { StringBuilder message = new StringBuilder(); - message.append("#3498db&l「 ServerStats 」&r\n"); - message.append(" #5dade2┃ &7This server uses &fServerStats &7to track\n"); + message.append("#3498db&l「 Analyse 」&r\n"); + message.append(" #5dade2┃ &7This server uses &fAnalyse &7to track\n"); message.append(" #5dade2┃ &7player analytics and sessions.&r\n"); message.append("&r\n"); - message.append(" &7→ &fserverstats.com&r\n"); + message.append(" &7→ &fanalyse.net&r\n"); send(sender, message.toString()); } @@ -79,18 +79,18 @@ private void showPublicInfo(CommandSource sender) { * @param sender The command sender */ private void showStatus(CommandSource sender) { - boolean connected = ServerStats.isConnected(); + boolean connected = Analyse.isConnected(); int trackedPlayers = plugin.getSessionManager().getSessionCount(); boolean debugEnabled = plugin.isDebugEnabled(); int configuredServers = plugin.getPluginConfig().getServers().size(); StringBuilder message = new StringBuilder(); - message.append("#3498db&l「 ServerStats &r&fv").append(BuildConstants.VERSION).append(" #3498db&l」&r\n"); + message.append("#3498db&l「 Analyse &r&fv").append(BuildConstants.VERSION).append(" #3498db&l」&r\n"); message.append(" #5dade2┃ &fStatus: ").append(connected ? "&a● Connected" : "&c● Disconnected").append("&r\n"); - if (!connected && ServerStats.getLastConnectionError() != null) { - message.append(" #5dade2┃ &fError: &c").append(ServerStats.getLastConnectionError()).append("&r\n"); + if (!connected && Analyse.getLastConnectionError() != null) { + message.append(" #5dade2┃ &fError: &c").append(Analyse.getLastConnectionError()).append("&r\n"); } - message.append(" #5dade2┃ &fAPI: &7api.serverstats.com&r\n"); + message.append(" #5dade2┃ &fAPI: &7api.analyse.net&r\n"); message.append(" #5dade2┃ &fServers Configured: &7").append(configuredServers).append("&r\n"); message.append(" #5dade2┃ &fPlayers Tracked: &7").append(trackedPlayers).append("&r\n"); message.append(" #5dade2┃ &fDebug: ").append(debugEnabled ? "&aEnabled" : "&7Disabled").append("&r\n"); @@ -99,7 +99,7 @@ private void showStatus(CommandSource sender) { @Subcommand("debug") @Description("Toggle debug mode") - @CommandPermission("serverstats.command.debug") + @CommandPermission("analyse.netmand.debug") public void onDebug(CommandSource sender) { boolean newState = !plugin.getPluginConfig().isDebug(); plugin.getPluginConfig().setDebug(newState); @@ -113,17 +113,17 @@ public void onDebug(CommandSource sender) { @Subcommand("event") @Description("Send a custom event") - @CommandPermission("serverstats.command.event") + @CommandPermission("analyse.netmand.event") @Syntax(" [--player ] [--value ] [--data ...]") @CommandCompletion("test_event|custom_event @players") public void onEvent(CommandSource sender, String[] args) { if (args.length == 0) { - send(sender, "&cUsage: /serverstats event [--player ] [--value ] [--data key=value...]"); + send(sender, "&cUsage: /analyse event [--player ] [--value ] [--data key=value...]"); return; } - if (!ServerStats.isAvailable()) { - send(sender, "&cServerStats is not connected. Make sure a default server is configured."); + if (!Analyse.isAvailable()) { + send(sender, "&cAnalyse is not connected. Make sure a default server is configured."); return; } @@ -161,7 +161,7 @@ public void onEvent(CommandSource sender, String[] args) { } // Build the event - EventBuilder builder = ServerStats.trackEvent(eventName); + EventBuilder builder = Analyse.trackEvent(eventName); // Add player if specified if (playerName != null) { @@ -207,12 +207,12 @@ public void onEvent(CommandSource sender, String[] args) { @Subcommand("info") @Description("View server or player analytics") - @CommandPermission("serverstats.command.info") + @CommandPermission("analyse.netmand.info") @Syntax("[player]") @CommandCompletion("@players") public void onInfo(CommandSource sender, String[] args) { - if (!ServerStats.isAvailable()) { - send(sender, "&cServerStats is not connected. Make sure a default server is configured."); + if (!Analyse.isAvailable()) { + send(sender, "&cAnalyse is not connected. Make sure a default server is configured."); return; } @@ -235,7 +235,7 @@ private void showServerInfo(CommandSource sender) { int onlinePlayers = plugin.getServer().getPlayerCount(); // Fetch additional data from API - plugin.getClient().getServerInfo(new ServerStatsCallback<>() { + plugin.getClient().getServerInfo(new AnalyseCallback<>() { @Override public void onSuccess(ServerInfoResponse response) { StringBuilder message = new StringBuilder(); @@ -255,7 +255,7 @@ public void onSuccess(ServerInfoResponse response) { } @Override - public void onError(ServerStatsException exception) { + public void onError(AnalyseException exception) { StringBuilder message = new StringBuilder(); message.append("#3498db&l「 Server Analytics 」&r\n"); message.append(" #5dade2┃ &fOnline Players: &7").append(onlinePlayers).append("&r\n"); @@ -282,14 +282,14 @@ private void showPlayerInfo(CommandSource sender, String playerName) { PlayerSession session = plugin.getSessionManager().getSession(player.getUniqueId()).orElse(null); // Fetch additional data from API - plugin.getClient().getPlayerInfo(new PlayerInfoRequest(player.getUniqueId()), new ServerStatsCallback<>() { + plugin.getClient().getPlayerInfo(new PlayerInfoRequest(player.getUniqueId()), new AnalyseCallback<>() { @Override public void onSuccess(PlayerInfoResponse response) { send(sender, buildPlayerInfoMessage(player.getUsername(), session, response)); } @Override - public void onError(ServerStatsException exception) { + public void onError(AnalyseException exception) { send(sender, buildPlayerInfoMessage(player.getUsername(), session, null)); } }); @@ -375,16 +375,16 @@ private String formatDuration(Duration duration) { @Subcommand("addons") @Description("List all loaded addons") - @CommandPermission("serverstats.command.addons") + @CommandPermission("analyse.netmand.addons") public void onAddons(CommandSource sender) { Collection addons = plugin.getAddonManager().getLoadedAddons(); StringBuilder message = new StringBuilder(); - message.append("#3498db&l「 ServerStats Addons 」&r\n"); + message.append("#3498db&l「 Analyse Addons 」&r\n"); if (addons.isEmpty()) { message.append(" &7No addons loaded.&r\n"); - message.append(" &7Place addon JARs in &fplugins/serverstats/addons/&r\n"); + message.append(" &7Place addon JARs in &fplugins/analyse/addons/&r\n"); } else { for (LoadedAddon addon : addons) { String status = addon.isEnabled() ? "&a● Enabled" : "&c● Disabled"; @@ -404,7 +404,7 @@ public void onAddons(CommandSource sender) { @Subcommand("addons reload") @Description("Reload all addons or a specific addon") - @CommandPermission("serverstats.command.addons.reload") + @CommandPermission("analyse.netmand.addons.reload") @Syntax("[addon]") public void onAddonsReload(CommandSource sender, String[] args) { if (args.length == 0) { @@ -429,7 +429,7 @@ public void onAddonsReload(CommandSource sender, String[] args) { @Subcommand("addons enable") @Description("Enable an addon") - @CommandPermission("serverstats.command.addons.enable") + @CommandPermission("analyse.netmand.addons.enable") @Syntax("") public void onAddonsEnable(CommandSource sender, String addonId) { if (!plugin.getAddonManager().isAddonLoaded(addonId)) { @@ -451,7 +451,7 @@ public void onAddonsEnable(CommandSource sender, String addonId) { @Subcommand("addons disable") @Description("Disable an addon") - @CommandPermission("serverstats.command.addons.disable") + @CommandPermission("analyse.netmand.addons.disable") @Syntax("") public void onAddonsDisable(CommandSource sender, String addonId) { if (!plugin.getAddonManager().isAddonLoaded(addonId)) { @@ -473,19 +473,19 @@ public void onAddonsDisable(CommandSource sender, String addonId) { @Subcommand("help") @Description("Show help information") - @CommandPermission("serverstats.command.help") + @CommandPermission("analyse.netmand.help") public void onHelp(CommandSource sender) { StringBuilder message = new StringBuilder(); - message.append("#3498db&l「 ServerStats Commands 」&r\n"); - message.append(" #5dade2┃ &f/serverstats &7- Show plugin info&r\n"); - message.append(" #5dade2┃ &f/serverstats status &7- Show plugin status&r\n"); - message.append(" #5dade2┃ &f/serverstats info &7- View server analytics&r\n"); - message.append(" #5dade2┃ &f/serverstats info &7- View player analytics&r\n"); - message.append(" #5dade2┃ &f/serverstats debug &7- Toggle debug mode&r\n"); - message.append(" #5dade2┃ &f/serverstats event &7- Send custom event&r\n"); - message.append(" #5dade2┃ &f/serverstats addons &7- List loaded addons&r\n"); - message.append(" #5dade2┃ &f/serverstats addons reload [id] &7- Reload addons&r\n"); - message.append(" #5dade2┃ &f/serverstats help &7- Show this help&r\n"); + message.append("#3498db&l「 Analyse Commands 」&r\n"); + message.append(" #5dade2┃ &f/analyse &7- Show plugin info&r\n"); + message.append(" #5dade2┃ &f/analyse status &7- Show plugin status&r\n"); + message.append(" #5dade2┃ &f/analyse info &7- View server analytics&r\n"); + message.append(" #5dade2┃ &f/analyse info &7- View player analytics&r\n"); + message.append(" #5dade2┃ &f/analyse debug &7- Toggle debug mode&r\n"); + message.append(" #5dade2┃ &f/analyse event &7- Send custom event&r\n"); + message.append(" #5dade2┃ &f/analyse addons &7- List loaded addons&r\n"); + message.append(" #5dade2┃ &f/analyse addons reload [id] &7- Reload addons&r\n"); + message.append(" #5dade2┃ &f/analyse help &7- Show this help&r\n"); send(sender, message.toString()); } diff --git a/velocity/src/main/java/com/serverstats/velocity/config/ServerStatsVelocityConfig.java b/modules/velocity/src/main/java/net/analyse/velocity/config/AnalyseVelocityConfig.java similarity index 90% rename from velocity/src/main/java/com/serverstats/velocity/config/ServerStatsVelocityConfig.java rename to modules/velocity/src/main/java/net/analyse/velocity/config/AnalyseVelocityConfig.java index 85a2551..1f7ae81 100644 --- a/velocity/src/main/java/com/serverstats/velocity/config/ServerStatsVelocityConfig.java +++ b/modules/velocity/src/main/java/net/analyse/velocity/config/AnalyseVelocityConfig.java @@ -1,4 +1,4 @@ -package com.serverstats.velocity.config; +package net.analyse.velocity.config; import com.google.gson.Gson; import com.google.gson.GsonBuilder; @@ -17,7 +17,7 @@ * Configuration for the Velocity plugin */ @Getter -public class ServerStatsVelocityConfig { +public class AnalyseVelocityConfig { private static final String CONFIG_FILE = "config.json"; @@ -28,6 +28,7 @@ public class ServerStatsVelocityConfig { @Setter private boolean debug = false; + private boolean development = false; private String bedrockPrefix = "."; private String instanceId = "default"; private String defaultServer = null; @@ -56,7 +57,7 @@ public ServerConfig(String apiKey) { * @return The loaded configuration * @throws IOException If the config cannot be read or written */ - public static ServerStatsVelocityConfig load(Path dataDirectory) throws IOException { + public static AnalyseVelocityConfig load(Path dataDirectory) throws IOException { Gson gson = new GsonBuilder().setPrettyPrinting().create(); Path configPath = dataDirectory.resolve(CONFIG_FILE); @@ -67,7 +68,7 @@ public static ServerStatsVelocityConfig load(Path dataDirectory) throws IOExcept // Create default config if it doesn't exist if (!Files.exists(configPath)) { - ServerStatsVelocityConfig defaultConfig = createDefault(); + AnalyseVelocityConfig defaultConfig = createDefault(); try (Writer writer = Files.newBufferedWriter(configPath, StandardCharsets.UTF_8)) { gson.toJson(defaultConfig, writer); } @@ -76,9 +77,9 @@ public static ServerStatsVelocityConfig load(Path dataDirectory) throws IOExcept } // Load existing config and fill in any missing event defaults - ServerStatsVelocityConfig config; + AnalyseVelocityConfig config; try (Reader reader = Files.newBufferedReader(configPath, StandardCharsets.UTF_8)) { - config = gson.fromJson(reader, ServerStatsVelocityConfig.class); + config = gson.fromJson(reader, AnalyseVelocityConfig.class); } if (config.fillMissingEventDefaults()) { @@ -95,8 +96,8 @@ public static ServerStatsVelocityConfig load(Path dataDirectory) throws IOExcept * * @return The default configuration */ - private static ServerStatsVelocityConfig createDefault() { - ServerStatsVelocityConfig config = new ServerStatsVelocityConfig(); + private static AnalyseVelocityConfig createDefault() { + AnalyseVelocityConfig config = new AnalyseVelocityConfig(); config.debug = false; config.bedrockPrefix = "."; config.instanceId = "default"; diff --git a/velocity/src/main/java/com/serverstats/velocity/listener/ActivityListener.java b/modules/velocity/src/main/java/net/analyse/velocity/listener/ActivityListener.java similarity index 81% rename from velocity/src/main/java/com/serverstats/velocity/listener/ActivityListener.java rename to modules/velocity/src/main/java/net/analyse/velocity/listener/ActivityListener.java index 2701ae0..b1034b8 100644 --- a/velocity/src/main/java/com/serverstats/velocity/listener/ActivityListener.java +++ b/modules/velocity/src/main/java/net/analyse/velocity/listener/ActivityListener.java @@ -1,16 +1,16 @@ -package com.serverstats.velocity.listener; +package net.analyse.velocity.listener; import com.velocitypowered.api.event.Subscribe; import com.velocitypowered.api.event.command.CommandExecuteEvent; import com.velocitypowered.api.event.player.ServerConnectedEvent; import com.velocitypowered.api.proxy.Player; import com.velocitypowered.api.proxy.server.RegisteredServer; -import com.serverstats.sdk.ServerStatsCallback; -import com.serverstats.sdk.ServerStatsClient; -import com.serverstats.api.exception.ServerStatsException; -import com.serverstats.sdk.request.EventRequest; -import com.serverstats.sdk.response.EventResponse; -import com.serverstats.velocity.ServerStatsVelocity; +import net.analyse.sdk.AnalyseCallback; +import net.analyse.sdk.AnalyseClient; +import net.analyse.api.exception.AnalyseException; +import net.analyse.sdk.request.EventRequest; +import net.analyse.sdk.response.EventResponse; +import net.analyse.velocity.AnalyseVelocity; import java.util.HashMap; import java.util.Map; import java.util.Optional; @@ -21,9 +21,9 @@ */ public class ActivityListener { - private final ServerStatsVelocity plugin; + private final AnalyseVelocity plugin; - public ActivityListener(ServerStatsVelocity plugin) { + public ActivityListener(AnalyseVelocity plugin) { this.plugin = plugin; } @@ -88,22 +88,22 @@ public void onServerConnected(ServerConnectedEvent event) { */ private void sendEvent(String serverName, String eventName, UUID playerUuid, String playerUsername, Map data) { - Optional clientOpt = plugin.getPlayerListener().getClientForServer(serverName); + Optional clientOpt = plugin.getPlayerListener().getClientForServer(serverName); if (clientOpt.isEmpty()) { return; } - ServerStatsClient client = clientOpt.get(); + AnalyseClient client = clientOpt.get(); EventRequest request = new EventRequest(eventName, playerUuid, playerUsername, new HashMap<>(data), null); - client.trackEvent(request, new ServerStatsCallback<>() { + client.trackEvent(request, new AnalyseCallback<>() { @Override public void onSuccess(EventResponse response) { plugin.debug("Activity event '%s' sent for %s on %s", eventName, playerUsername, serverName); } @Override - public void onError(ServerStatsException exception) { + public void onError(AnalyseException exception) { plugin.getLogger().warn(String.format("Failed to send activity event '%s' for %s: %s", eventName, playerUsername, exception.getMessage())); } diff --git a/velocity/src/main/java/com/serverstats/velocity/listener/PlayerListener.java b/modules/velocity/src/main/java/net/analyse/velocity/listener/PlayerListener.java similarity index 81% rename from velocity/src/main/java/com/serverstats/velocity/listener/PlayerListener.java rename to modules/velocity/src/main/java/net/analyse/velocity/listener/PlayerListener.java index 75d8708..c12026f 100644 --- a/velocity/src/main/java/com/serverstats/velocity/listener/PlayerListener.java +++ b/modules/velocity/src/main/java/net/analyse/velocity/listener/PlayerListener.java @@ -1,4 +1,4 @@ -package com.serverstats.velocity.listener; +package net.analyse.velocity.listener; import com.velocitypowered.api.event.Subscribe; import com.velocitypowered.api.event.connection.DisconnectEvent; @@ -6,18 +6,18 @@ import com.velocitypowered.api.event.player.ServerConnectedEvent; import com.velocitypowered.api.proxy.Player; import com.velocitypowered.api.proxy.server.RegisteredServer; -import com.serverstats.sdk.ServerStatsCallback; -import com.serverstats.sdk.ServerStatsClient; -import com.serverstats.api.exception.ServerStatsException; -import com.serverstats.sdk.config.ServerStatsConfig; -import com.serverstats.sdk.request.JoinRequest; -import com.serverstats.sdk.request.LeaveRequest; -import com.serverstats.sdk.util.ProtocolVersionUtil; -import com.serverstats.sdk.response.JoinResponse; -import com.serverstats.sdk.response.LeaveResponse; -import com.serverstats.velocity.ServerStatsVelocity; -import com.serverstats.velocity.manager.SessionManager; -import com.serverstats.velocity.object.session.PlayerSession; +import net.analyse.sdk.AnalyseCallback; +import net.analyse.sdk.AnalyseClient; +import net.analyse.api.exception.AnalyseException; +import net.analyse.sdk.config.AnalyseConfig; +import net.analyse.sdk.request.JoinRequest; +import net.analyse.sdk.request.LeaveRequest; +import net.analyse.sdk.util.ProtocolVersionUtil; +import net.analyse.sdk.response.JoinResponse; +import net.analyse.sdk.response.LeaveResponse; +import net.analyse.velocity.AnalyseVelocity; +import net.analyse.velocity.manager.SessionManager; +import net.analyse.velocity.object.session.PlayerSession; import org.slf4j.Logger; import java.net.InetSocketAddress; import java.util.HashMap; @@ -30,12 +30,12 @@ */ public class PlayerListener { - private final ServerStatsVelocity plugin; + private final AnalyseVelocity plugin; private final Logger logger; private final SessionManager sessionManager; - private final Map serverClients = new HashMap<>(); + private final Map serverClients = new HashMap<>(); - public PlayerListener(ServerStatsVelocity plugin) { + public PlayerListener(AnalyseVelocity plugin) { this.plugin = plugin; this.logger = plugin.getLogger(); this.sessionManager = plugin.getSessionManager(); @@ -51,8 +51,9 @@ private void initializeClients() { plugin.getPluginConfig().getServers().forEach((serverName, serverConfig) -> { String apiKey = serverConfig.getApiKey(); if (apiKey != null && !apiKey.isBlank() && !apiKey.startsWith("anl_your_")) { - ServerStatsConfig config = new ServerStatsConfig(apiKey); - serverClients.put(serverName, new ServerStatsClient(config)); + boolean development = plugin.getPluginConfig().isDevelopment(); + AnalyseConfig config = new AnalyseConfig(apiKey, development); + serverClients.put(serverName, new AnalyseClient(config)); logger.info(String.format("Initialized analytics client for server: %s", serverName)); } }); @@ -64,21 +65,21 @@ private void initializeClients() { * @param serverName The server name * @return The client, or empty if not configured */ - public Optional getClientForServer(String serverName) { + public Optional getClientForServer(String serverName) { return Optional.ofNullable(serverClients.get(serverName)); } /** - * Get an API client for use with the ServerStats API. + * Get an API client for use with the Analyse API. * Returns the configured default server's client if set, otherwise returns the first available client. * * @return An available client, or null if none configured */ - public ServerStatsClient getAvailableClient() { + public AnalyseClient getAvailableClient() { // Try configured default server first String defaultServer = plugin.getPluginConfig().getDefaultServer(); if (defaultServer != null && !defaultServer.isBlank()) { - ServerStatsClient client = serverClients.get(defaultServer); + AnalyseClient client = serverClients.get(defaultServer); if (client != null) { return client; } @@ -175,13 +176,13 @@ public void onDisconnect(DisconnectEvent event) { */ private void sendJoinEvent(UUID uuid, String username, PlayerSession session, String serverName, int protocolVersion) { - Optional clientOpt = getClientForServer(serverName); + Optional clientOpt = getClientForServer(serverName); if (clientOpt.isEmpty()) { plugin.debug("Server %s not configured, skipping join event for %s", serverName, username); return; } - ServerStatsClient client = clientOpt.get(); + AnalyseClient client = clientOpt.get(); // Check if player is a Bedrock player boolean isBedrock = plugin.getPluginConfig().isBedrock(username); @@ -192,7 +193,7 @@ private void sendJoinEvent(UUID uuid, String username, PlayerSession session, St JoinRequest request = new JoinRequest(uuid, username, session.getHostname(), session.getIp(), isBedrock, playerVersion); - client.join(request, new ServerStatsCallback<>() { + client.join(request, new AnalyseCallback<>() { @Override public void onSuccess(JoinResponse response) { session.setCurrentSession(serverName, response.getSessionId()); @@ -201,7 +202,7 @@ public void onSuccess(JoinResponse response) { } @Override - public void onError(ServerStatsException exception) { + public void onError(AnalyseException exception) { logger.warn(String.format("Failed to send join event for %s on %s: %s", username, serverName, exception.getMessage())); } @@ -216,15 +217,15 @@ private void sendLeaveEvent(UUID uuid, String username, PlayerSession session, S return; } - Optional clientOpt = getClientForServer(serverName); + Optional clientOpt = getClientForServer(serverName); if (clientOpt.isEmpty()) { return; } - ServerStatsClient client = clientOpt.get(); + AnalyseClient client = clientOpt.get(); LeaveRequest request = new LeaveRequest(session.getSessionId()); - client.leave(request, new ServerStatsCallback<>() { + client.leave(request, new AnalyseCallback<>() { @Override public void onSuccess(LeaveResponse response) { plugin.debug("Leave event sent for %s on %s (duration: %ds)", @@ -232,7 +233,7 @@ public void onSuccess(LeaveResponse response) { } @Override - public void onError(ServerStatsException exception) { + public void onError(AnalyseException exception) { logger.warn(String.format("Failed to send leave event for %s on %s: %s", username, serverName, exception.getMessage())); } @@ -283,7 +284,7 @@ public void reinitialize() { * Shutdown all API clients */ public void shutdown() { - serverClients.values().forEach(ServerStatsClient::shutdown); + serverClients.values().forEach(AnalyseClient::shutdown); serverClients.clear(); } } diff --git a/velocity/src/main/java/com/serverstats/velocity/listener/PluginMessageListener.java b/modules/velocity/src/main/java/net/analyse/velocity/listener/PluginMessageListener.java similarity index 76% rename from velocity/src/main/java/com/serverstats/velocity/listener/PluginMessageListener.java rename to modules/velocity/src/main/java/net/analyse/velocity/listener/PluginMessageListener.java index 28c59ec..83ff3eb 100644 --- a/velocity/src/main/java/com/serverstats/velocity/listener/PluginMessageListener.java +++ b/modules/velocity/src/main/java/net/analyse/velocity/listener/PluginMessageListener.java @@ -1,16 +1,16 @@ -package com.serverstats.velocity.listener; +package net.analyse.velocity.listener; import com.velocitypowered.api.event.Subscribe; import com.velocitypowered.api.event.connection.PluginMessageEvent; import com.velocitypowered.api.proxy.Player; import com.velocitypowered.api.proxy.ServerConnection; -import com.serverstats.api.ServerStats; -import com.serverstats.api.messaging.ServerStatsMessageParser; -import com.serverstats.api.messaging.ServerStatsMessageParser.ConversionMessage; -import com.serverstats.api.messaging.ServerStatsMessageParser.EventMessage; -import com.serverstats.api.messaging.ServerStatsMessageParser.ParsedMessage; -import com.serverstats.api.messaging.ServerStatsMessaging; -import com.serverstats.velocity.ServerStatsVelocity; +import net.analyse.api.Analyse; +import net.analyse.api.messaging.AnalyseMessageParser; +import net.analyse.api.messaging.AnalyseMessageParser.ConversionMessage; +import net.analyse.api.messaging.AnalyseMessageParser.EventMessage; +import net.analyse.api.messaging.AnalyseMessageParser.ParsedMessage; +import net.analyse.api.messaging.AnalyseMessaging; +import net.analyse.velocity.AnalyseVelocity; import java.io.IOException; /** @@ -19,14 +19,14 @@ */ public class PluginMessageListener { - private final ServerStatsVelocity plugin; + private final AnalyseVelocity plugin; /** * Create a new plugin message listener * * @param plugin The plugin instance */ - public PluginMessageListener(ServerStatsVelocity plugin) { + public PluginMessageListener(AnalyseVelocity plugin) { this.plugin = plugin; } @@ -38,7 +38,7 @@ public void onPluginMessage(PluginMessageEvent event) { } // Only handle our channel - if (!event.getIdentifier().getId().equals(ServerStatsMessaging.CHANNEL)) { + if (!event.getIdentifier().getId().equals(AnalyseMessaging.CHANNEL)) { return; } @@ -52,7 +52,7 @@ public void onPluginMessage(PluginMessageEvent event) { plugin.debug("Received plugin message from %s on server %s", player.getUsername(), serverName); try { - ParsedMessage message = ServerStatsMessageParser.parse(event.getData()); + ParsedMessage message = AnalyseMessageParser.parse(event.getData()); handleMessage(message, player, serverName); } catch (IOException e) { plugin.getLogger().warn(String.format("Failed to parse plugin message from %s: %s", @@ -82,8 +82,8 @@ private void handleMessage(ParsedMessage message, Player player, String serverNa * @param serverName The source server */ private void handleEventMessage(EventMessage message, String serverName) { - if (!ServerStats.isAvailable()) { - plugin.getLogger().warn("Received event message but ServerStats is not available"); + if (!Analyse.isAvailable()) { + plugin.getLogger().warn("Received event message but Analyse is not available"); return; } @@ -91,7 +91,7 @@ private void handleEventMessage(EventMessage message, String serverName) { message.getEventName(), message.getPlayerUsername(), serverName); // Build and send the event - var builder = ServerStats.trackEvent(message.getEventName()) + var builder = Analyse.trackEvent(message.getEventName()) .withPlayer(message.getPlayerUuid(), message.getPlayerUsername()); if (message.getData() != null) { @@ -123,8 +123,8 @@ private void handleEventMessage(EventMessage message, String serverName) { * @param serverName The source server */ private void handleConversionMessage(ConversionMessage message, String serverName) { - if (!ServerStats.isAvailable()) { - plugin.getLogger().warn("Received conversion message but ServerStats is not available"); + if (!Analyse.isAvailable()) { + plugin.getLogger().warn("Received conversion message but Analyse is not available"); return; } @@ -132,7 +132,7 @@ private void handleConversionMessage(ConversionMessage message, String serverNam message.getTestKey(), message.getConversionEvent(), message.getPlayerUsername(), serverName); - ServerStats.trackConversion( + Analyse.trackConversion( message.getPlayerUuid(), message.getPlayerUsername(), message.getTestKey(), diff --git a/velocity/src/main/java/com/serverstats/velocity/manager/ABTestManager.java b/modules/velocity/src/main/java/net/analyse/velocity/manager/ABTestManager.java similarity index 69% rename from velocity/src/main/java/com/serverstats/velocity/manager/ABTestManager.java rename to modules/velocity/src/main/java/net/analyse/velocity/manager/ABTestManager.java index f0a00b3..73f7cd7 100644 --- a/velocity/src/main/java/com/serverstats/velocity/manager/ABTestManager.java +++ b/modules/velocity/src/main/java/net/analyse/velocity/manager/ABTestManager.java @@ -1,16 +1,16 @@ -package com.serverstats.velocity.manager; +package net.analyse.velocity.manager; import com.velocitypowered.api.proxy.Player; -import com.serverstats.api.exception.ServerStatsException; -import com.serverstats.api.object.abtest.ABTest; -import com.serverstats.sdk.ServerStatsCallback; -import com.serverstats.sdk.ServerStatsClient; -import com.serverstats.sdk.object.action.ActionData; -import com.serverstats.sdk.request.ConversionRequest; -import com.serverstats.sdk.response.ABTestsResponse; -import com.serverstats.sdk.response.ConversionResponse; -import com.serverstats.velocity.ServerStatsVelocity; -import com.serverstats.velocity.object.action.VelocityAction; +import net.analyse.api.exception.AnalyseException; +import net.analyse.api.object.abtest.ABTest; +import net.analyse.sdk.AnalyseCallback; +import net.analyse.sdk.AnalyseClient; +import net.analyse.sdk.object.action.ActionData; +import net.analyse.sdk.request.ConversionRequest; +import net.analyse.sdk.response.ABTestsResponse; +import net.analyse.sdk.response.ConversionResponse; +import net.analyse.velocity.AnalyseVelocity; +import net.analyse.velocity.object.action.VelocityAction; import java.util.List; import java.util.Map; import java.util.UUID; @@ -21,14 +21,14 @@ * Manages A/B tests for the Velocity plugin. * Supports SEND_MESSAGE and RUN_COMMAND actions on proxies. */ -public class ABTestManager implements com.serverstats.api.manager.ABTestManager { +public class ABTestManager implements net.analyse.api.manager.ABTestManager { private static final long SYNC_INTERVAL_MINUTES = 5; - private final ServerStatsVelocity plugin; - private final Map testsCache = new ConcurrentHashMap<>(); + private final AnalyseVelocity plugin; + private final Map testsCache = new ConcurrentHashMap<>(); - public ABTestManager(ServerStatsVelocity plugin) { + public ABTestManager(AnalyseVelocity plugin) { this.plugin = plugin; } @@ -59,17 +59,17 @@ public void stop() { * Sync tests from the API */ private void syncTests() { - ServerStatsClient client = plugin.getClient(); + AnalyseClient client = plugin.getClient(); if (client == null) { return; } - client.getABTests(new ServerStatsCallback<>() { + client.getABTests(new AnalyseCallback<>() { @Override public void onSuccess(ABTestsResponse response) { if (response.isSuccess() && response.getTests() != null) { testsCache.clear(); - for (com.serverstats.sdk.object.abtest.ABTest test : response.getTests()) { + for (net.analyse.sdk.object.abtest.ABTest test : response.getTests()) { if (test.isActive()) { testsCache.put(test.getKey(), test); } @@ -82,7 +82,7 @@ public void onSuccess(ABTestsResponse response) { } @Override - public void onError(ServerStatsException exception) { + public void onError(AnalyseException exception) { plugin.logWarning(String.format("Failed to sync A/B tests: %s", exception.getMessage())); } }); @@ -90,7 +90,7 @@ public void onError(ServerStatsException exception) { @Override @SuppressWarnings("unchecked") - public List getActiveTests() { + public List getActiveTests() { return List.copyOf(testsCache.values()); } @@ -101,7 +101,7 @@ public ABTest getTest(String testKey) { @Override public String getVariant(UUID playerUuid, String testKey) { - com.serverstats.sdk.object.abtest.ABTest test = testsCache.get(testKey); + net.analyse.sdk.object.abtest.ABTest test = testsCache.get(testKey); if (test == null) { return null; } @@ -125,7 +125,7 @@ public boolean isTestActive(String testKey) { public void processJoin(Player player, boolean firstJoin) { ABTest.Trigger trigger = firstJoin ? ABTest.Trigger.FIRST_JOIN : ABTest.Trigger.EVERY_JOIN; - for (com.serverstats.sdk.object.abtest.ABTest test : testsCache.values()) { + for (net.analyse.sdk.object.abtest.ABTest test : testsCache.values()) { if (!test.matchesTrigger(trigger)) { continue; } @@ -133,7 +133,7 @@ public void processJoin(Player player, boolean firstJoin) { // Assign variant and execute actions var variant = test.assignVariant(player.getUniqueId()); if (variant != null && variant.hasActions()) { - executeActions(player, test, (com.serverstats.sdk.object.abtest.Variant) variant); + executeActions(player, test, (net.analyse.sdk.object.abtest.Variant) variant); } } } @@ -145,7 +145,7 @@ public void processJoin(Player player, boolean firstJoin) { * @param eventName The event name */ public void processEvent(Player player, String eventName) { - for (com.serverstats.sdk.object.abtest.ABTest test : testsCache.values()) { + for (net.analyse.sdk.object.abtest.ABTest test : testsCache.values()) { if (!test.matchesEvent(eventName)) { continue; } @@ -153,7 +153,7 @@ public void processEvent(Player player, String eventName) { // Assign variant and execute actions var variant = test.assignVariant(player.getUniqueId()); if (variant != null && variant.hasActions()) { - executeActions(player, test, (com.serverstats.sdk.object.abtest.Variant) variant); + executeActions(player, test, (net.analyse.sdk.object.abtest.Variant) variant); } } } @@ -165,8 +165,8 @@ public void processEvent(Player player, String eventName) { * @param test The A/B test * @param variant The assigned variant */ - private void executeActions(Player player, com.serverstats.sdk.object.abtest.ABTest test, - com.serverstats.sdk.object.abtest.Variant variant) { + private void executeActions(Player player, net.analyse.sdk.object.abtest.ABTest test, + net.analyse.sdk.object.abtest.Variant variant) { if (plugin.isDebugEnabled()) { plugin.logInfo(String.format("[DEBUG] Player %s assigned to variant '%s' for test '%s'", player.getUsername(), variant.getKey(), test.getKey())); @@ -182,12 +182,12 @@ private void executeActions(Player player, com.serverstats.sdk.object.abtest.ABT @Override public void trackConversion(UUID playerUuid, String playerUsername, String testKey, String eventName) { - com.serverstats.sdk.object.abtest.ABTest test = testsCache.get(testKey); + net.analyse.sdk.object.abtest.ABTest test = testsCache.get(testKey); if (test == null) { return; } - ServerStatsClient client = plugin.getClient(); + AnalyseClient client = plugin.getClient(); if (client == null) { return; } @@ -199,7 +199,7 @@ public void trackConversion(UUID playerUuid, String playerUsername, String testK testKey, variantKey, playerUuid, playerUsername, eventName, null ); - client.trackConversion(request, new ServerStatsCallback<>() { + client.trackConversion(request, new AnalyseCallback<>() { @Override public void onSuccess(ConversionResponse response) { if (plugin.isDebugEnabled()) { @@ -209,7 +209,7 @@ public void onSuccess(ConversionResponse response) { } @Override - public void onError(ServerStatsException exception) { + public void onError(AnalyseException exception) { plugin.logWarning(String.format("Failed to track conversion: %s", exception.getMessage())); } }); diff --git a/bungeecord/src/main/java/com/serverstats/bungeecord/manager/SessionManager.java b/modules/velocity/src/main/java/net/analyse/velocity/manager/SessionManager.java similarity index 87% rename from bungeecord/src/main/java/com/serverstats/bungeecord/manager/SessionManager.java rename to modules/velocity/src/main/java/net/analyse/velocity/manager/SessionManager.java index 0528200..b6a9748 100644 --- a/bungeecord/src/main/java/com/serverstats/bungeecord/manager/SessionManager.java +++ b/modules/velocity/src/main/java/net/analyse/velocity/manager/SessionManager.java @@ -1,6 +1,6 @@ -package com.serverstats.bungeecord.manager; +package net.analyse.velocity.manager; -import com.serverstats.bungeecord.object.session.PlayerSession; +import net.analyse.velocity.object.session.PlayerSession; import java.util.Collection; import java.util.Map; import java.util.Optional; @@ -10,7 +10,7 @@ /** * Thread-safe manager for player sessions */ -public class SessionManager implements com.serverstats.api.manager.SessionManager { +public class SessionManager implements net.analyse.api.manager.SessionManager { private final Map sessions = new ConcurrentHashMap<>(); diff --git a/velocity/src/main/java/com/serverstats/velocity/object/action/RunCommandAction.java b/modules/velocity/src/main/java/net/analyse/velocity/object/action/RunCommandAction.java similarity index 79% rename from velocity/src/main/java/com/serverstats/velocity/object/action/RunCommandAction.java rename to modules/velocity/src/main/java/net/analyse/velocity/object/action/RunCommandAction.java index b999dd9..4a40632 100644 --- a/velocity/src/main/java/com/serverstats/velocity/object/action/RunCommandAction.java +++ b/modules/velocity/src/main/java/net/analyse/velocity/object/action/RunCommandAction.java @@ -1,9 +1,9 @@ -package com.serverstats.velocity.object.action; +package net.analyse.velocity.object.action; import com.velocitypowered.api.proxy.Player; -import com.serverstats.sdk.object.action.ActionData; -import com.serverstats.sdk.object.action.ActionType; -import com.serverstats.velocity.ServerStatsVelocity; +import net.analyse.sdk.object.action.ActionData; +import net.analyse.sdk.object.action.ActionType; +import net.analyse.velocity.AnalyseVelocity; /** * Action that runs a command on the proxy. @@ -11,7 +11,7 @@ */ public class RunCommandAction extends VelocityAction { - public RunCommandAction(ServerStatsVelocity plugin, ActionData data) { + public RunCommandAction(AnalyseVelocity plugin, ActionData data) { super(plugin, data); } diff --git a/velocity/src/main/java/com/serverstats/velocity/object/action/SendMessageAction.java b/modules/velocity/src/main/java/net/analyse/velocity/object/action/SendMessageAction.java similarity index 69% rename from velocity/src/main/java/com/serverstats/velocity/object/action/SendMessageAction.java rename to modules/velocity/src/main/java/net/analyse/velocity/object/action/SendMessageAction.java index 57e4b54..d1bc554 100644 --- a/velocity/src/main/java/com/serverstats/velocity/object/action/SendMessageAction.java +++ b/modules/velocity/src/main/java/net/analyse/velocity/object/action/SendMessageAction.java @@ -1,10 +1,10 @@ -package com.serverstats.velocity.object.action; +package net.analyse.velocity.object.action; import com.velocitypowered.api.proxy.Player; -import com.serverstats.sdk.object.action.ActionData; -import com.serverstats.sdk.object.action.ActionType; -import com.serverstats.velocity.ServerStatsVelocity; -import com.serverstats.velocity.util.ComponentUtil; +import net.analyse.sdk.object.action.ActionData; +import net.analyse.sdk.object.action.ActionType; +import net.analyse.velocity.AnalyseVelocity; +import net.analyse.velocity.util.ComponentUtil; /** * Action that sends a message to the player. @@ -12,7 +12,7 @@ */ public class SendMessageAction extends VelocityAction { - public SendMessageAction(ServerStatsVelocity plugin, ActionData data) { + public SendMessageAction(AnalyseVelocity plugin, ActionData data) { super(plugin, data); } diff --git a/velocity/src/main/java/com/serverstats/velocity/object/action/VelocityAction.java b/modules/velocity/src/main/java/net/analyse/velocity/object/action/VelocityAction.java similarity index 78% rename from velocity/src/main/java/com/serverstats/velocity/object/action/VelocityAction.java rename to modules/velocity/src/main/java/net/analyse/velocity/object/action/VelocityAction.java index b11ed31..d11eacd 100644 --- a/velocity/src/main/java/com/serverstats/velocity/object/action/VelocityAction.java +++ b/modules/velocity/src/main/java/net/analyse/velocity/object/action/VelocityAction.java @@ -1,9 +1,9 @@ -package com.serverstats.velocity.object.action; +package net.analyse.velocity.object.action; import com.velocitypowered.api.proxy.Player; -import com.serverstats.sdk.object.action.Action; -import com.serverstats.sdk.object.action.ActionData; -import com.serverstats.velocity.ServerStatsVelocity; +import net.analyse.sdk.object.action.Action; +import net.analyse.sdk.object.action.ActionData; +import net.analyse.velocity.AnalyseVelocity; /** * Base class for Velocity-specific A/B test actions. @@ -11,10 +11,10 @@ */ public abstract class VelocityAction implements Action { - protected final ServerStatsVelocity plugin; + protected final AnalyseVelocity plugin; protected final ActionData data; - protected VelocityAction(ServerStatsVelocity plugin, ActionData data) { + protected VelocityAction(AnalyseVelocity plugin, ActionData data) { this.plugin = plugin; this.data = data; } @@ -26,7 +26,7 @@ protected VelocityAction(ServerStatsVelocity plugin, ActionData data) { * @param data The action data from the API * @return The appropriate VelocityAction, or null if type is unsupported */ - public static VelocityAction create(ServerStatsVelocity plugin, ActionData data) { + public static VelocityAction create(AnalyseVelocity plugin, ActionData data) { if (data == null || data.getType() == null) { return null; } diff --git a/velocity/src/main/java/com/serverstats/velocity/object/session/PlayerSession.java b/modules/velocity/src/main/java/net/analyse/velocity/object/session/PlayerSession.java similarity index 91% rename from velocity/src/main/java/com/serverstats/velocity/object/session/PlayerSession.java rename to modules/velocity/src/main/java/net/analyse/velocity/object/session/PlayerSession.java index a374244..fbdb5b2 100644 --- a/velocity/src/main/java/com/serverstats/velocity/object/session/PlayerSession.java +++ b/modules/velocity/src/main/java/net/analyse/velocity/object/session/PlayerSession.java @@ -1,4 +1,4 @@ -package com.serverstats.velocity.object.session; +package net.analyse.velocity.object.session; import lombok.Getter; import java.time.Instant; @@ -8,7 +8,7 @@ * Stores session data for a connected player */ @Getter -public class PlayerSession implements com.serverstats.api.session.PlayerSession { +public class PlayerSession implements net.analyse.api.session.PlayerSession { private final UUID playerUuid; private final String hostname; diff --git a/velocity/src/main/java/com/serverstats/velocity/task/HeartbeatTask.java b/modules/velocity/src/main/java/net/analyse/velocity/task/HeartbeatTask.java similarity index 67% rename from velocity/src/main/java/com/serverstats/velocity/task/HeartbeatTask.java rename to modules/velocity/src/main/java/net/analyse/velocity/task/HeartbeatTask.java index cd1231c..ed5dbd2 100644 --- a/velocity/src/main/java/com/serverstats/velocity/task/HeartbeatTask.java +++ b/modules/velocity/src/main/java/net/analyse/velocity/task/HeartbeatTask.java @@ -1,18 +1,18 @@ -package com.serverstats.velocity.task; +package net.analyse.velocity.task; -import com.serverstats.api.ServerStats; +import net.analyse.api.Analyse; import com.velocitypowered.api.proxy.Player; import com.velocitypowered.api.proxy.server.RegisteredServer; -import com.serverstats.sdk.ServerStatsCallback; -import com.serverstats.sdk.ServerStatsClient; -import com.serverstats.api.exception.ServerStatsException; -import com.serverstats.sdk.request.HeartbeatRequest; -import com.serverstats.sdk.request.PlayerInfo; -import com.serverstats.sdk.request.ServerType; -import com.serverstats.sdk.response.HeartbeatResponse; -import com.serverstats.velocity.ServerStatsVelocity; -import com.serverstats.velocity.listener.PlayerListener; -import com.serverstats.velocity.object.session.PlayerSession; +import net.analyse.sdk.AnalyseCallback; +import net.analyse.sdk.AnalyseClient; +import net.analyse.api.exception.AnalyseException; +import net.analyse.sdk.request.HeartbeatRequest; +import net.analyse.sdk.request.PlayerInfo; +import net.analyse.sdk.request.ServerType; +import net.analyse.sdk.response.HeartbeatResponse; +import net.analyse.velocity.AnalyseVelocity; +import net.analyse.velocity.listener.PlayerListener; +import net.analyse.velocity.object.session.PlayerSession; import org.slf4j.Logger; import java.util.List; import java.util.Optional; @@ -22,11 +22,11 @@ */ public class HeartbeatTask implements Runnable { - private final ServerStatsVelocity plugin; + private final AnalyseVelocity plugin; private final Logger logger; private final PlayerListener playerListener; - public HeartbeatTask(ServerStatsVelocity plugin, PlayerListener playerListener) { + public HeartbeatTask(AnalyseVelocity plugin, PlayerListener playerListener) { this.plugin = plugin; this.logger = plugin.getLogger(); this.playerListener = playerListener; @@ -44,7 +44,7 @@ public void run() { * @param serverName The server name */ private void sendHeartbeatForServer(String serverName) { - Optional clientOpt = playerListener.getClientForServer(serverName); + Optional clientOpt = playerListener.getClientForServer(serverName); if (clientOpt.isEmpty()) { return; } @@ -56,7 +56,7 @@ private void sendHeartbeatForServer(String serverName) { } RegisteredServer server = serverOpt.get(); - ServerStatsClient client = clientOpt.get(); + AnalyseClient client = clientOpt.get(); // Collect player info with hostnames for players on this server List onlinePlayers = server.getPlayersConnected().stream() @@ -66,16 +66,16 @@ private void sendHeartbeatForServer(String serverName) { String instanceId = plugin.getPluginConfig().getInstanceId(); HeartbeatRequest request = new HeartbeatRequest(instanceId, ServerType.MINECRAFT, onlinePlayers); - client.heartbeat(request, new ServerStatsCallback<>() { + client.heartbeat(request, new AnalyseCallback<>() { @Override public void onSuccess(HeartbeatResponse response) { - ServerStats.setConnectionStatus(true, null); + Analyse.setConnectionStatus(true, null); plugin.debug("Heartbeat sent for %s (%d players)", serverName, response.getOnlineCount()); } @Override - public void onError(ServerStatsException exception) { - ServerStats.setConnectionStatus(false, exception.getMessage()); + public void onError(AnalyseException exception) { + Analyse.setConnectionStatus(false, exception.getMessage()); logger.warn(String.format("Failed to send heartbeat for %s: %s", serverName, exception.getMessage())); } diff --git a/velocity/src/main/java/com/serverstats/velocity/update/VelocityUpdateChecker.java b/modules/velocity/src/main/java/net/analyse/velocity/update/VelocityUpdateChecker.java similarity index 88% rename from velocity/src/main/java/com/serverstats/velocity/update/VelocityUpdateChecker.java rename to modules/velocity/src/main/java/net/analyse/velocity/update/VelocityUpdateChecker.java index 65c98d4..c418860 100644 --- a/velocity/src/main/java/com/serverstats/velocity/update/VelocityUpdateChecker.java +++ b/modules/velocity/src/main/java/net/analyse/velocity/update/VelocityUpdateChecker.java @@ -1,8 +1,8 @@ -package com.serverstats.velocity.update; +package net.analyse.velocity.update; import com.velocitypowered.api.scheduler.ScheduledTask; -import com.serverstats.sdk.update.UpdateChecker; -import com.serverstats.velocity.ServerStatsVelocity; +import net.analyse.sdk.update.UpdateChecker; +import net.analyse.velocity.AnalyseVelocity; import java.util.concurrent.TimeUnit; /** @@ -12,7 +12,7 @@ public class VelocityUpdateChecker { private static final long CHECK_INTERVAL_MINUTES = 30; - private final ServerStatsVelocity plugin; + private final AnalyseVelocity plugin; private final UpdateChecker checker; private ScheduledTask task; @@ -22,7 +22,7 @@ public class VelocityUpdateChecker { * @param plugin The plugin instance * @param currentVersion The current plugin version */ - public VelocityUpdateChecker(ServerStatsVelocity plugin, String currentVersion) { + public VelocityUpdateChecker(AnalyseVelocity plugin, String currentVersion) { this.plugin = plugin; this.checker = new UpdateChecker(plugin.getClient(), currentVersion, "velocity"); } @@ -62,7 +62,7 @@ private void check() { @Override public void onUpdateAvailable(String currentVersion, String newVersion, String downloadUrl) { plugin.logInfo("╔════════════════════════════════════════════════════════════╗"); - plugin.logInfo("║ A new version of ServerStats is available! ║"); + plugin.logInfo("║ A new version of Analyse is available! ║"); plugin.logInfo("║ Current: " + padRight(currentVersion, 20) + " Latest: " + padRight(newVersion, 20) + "║"); plugin.logInfo("║ Download: " + padRight(downloadUrl, 47) + "║"); plugin.logInfo("╚════════════════════════════════════════════════════════════╝"); diff --git a/paper/src/main/java/com/serverstats/paper/util/ComponentUtil.java b/modules/velocity/src/main/java/net/analyse/velocity/util/ComponentUtil.java similarity index 99% rename from paper/src/main/java/com/serverstats/paper/util/ComponentUtil.java rename to modules/velocity/src/main/java/net/analyse/velocity/util/ComponentUtil.java index bc69639..6f4a244 100644 --- a/paper/src/main/java/com/serverstats/paper/util/ComponentUtil.java +++ b/modules/velocity/src/main/java/net/analyse/velocity/util/ComponentUtil.java @@ -1,4 +1,4 @@ -package com.serverstats.paper.util; +package net.analyse.velocity.util; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.minimessage.MiniMessage; diff --git a/paper/build.gradle b/paper/build.gradle deleted file mode 100644 index d8344dc..0000000 --- a/paper/build.gradle +++ /dev/null @@ -1,40 +0,0 @@ -plugins { - id 'java' - id 'com.gradleup.shadow' -} - -repositories { - maven { - name = 'papermc' - url = uri('https://repo.papermc.io/repository/maven-public/') - } -} - -dependencies { - implementation project(':api') - implementation project(':sdk') - implementation "co.aikar:acf-paper:${project.property('acfVersion')}" - compileOnly 'io.papermc.paper:paper-api:1.21.4-R0.1-SNAPSHOT' -} - -java { - toolchain.languageVersion.set(JavaLanguageVersion.of(21)) -} - -tasks.named('shadowJar', com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) { - archiveBaseName.set('serverstats-paper') - archiveClassifier.set('') -} - -tasks.named('build') { - dependsOn tasks.named('shadowJar') -} - -processResources { - def props = [version: version] - inputs.properties props - filteringCharset 'UTF-8' - filesMatching('paper-plugin.yml') { - expand props - } -} diff --git a/paper/src/main/java/com/serverstats/paper/util/SchedulerUtil.java b/paper/src/main/java/com/serverstats/paper/util/SchedulerUtil.java deleted file mode 100644 index b15bce2..0000000 --- a/paper/src/main/java/com/serverstats/paper/util/SchedulerUtil.java +++ /dev/null @@ -1,197 +0,0 @@ -package com.serverstats.paper.util; - -import org.bukkit.Bukkit; -import org.bukkit.entity.Entity; -import org.bukkit.plugin.Plugin; -import java.util.concurrent.TimeUnit; - -/** - * Utility class that abstracts scheduling to support both Paper/Spigot and Folia. - * Automatically detects the server type and uses the appropriate scheduler. - */ -public final class SchedulerUtil { - - private static final boolean IS_FOLIA; - - static { - boolean folia; - try { - Class.forName("io.papermc.paper.threadedregions.RegionizedServer"); - folia = true; - } catch (ClassNotFoundException e) { - folia = false; - } - IS_FOLIA = folia; - } - - private SchedulerUtil() { - // Utility class - } - - /** - * Check if the server is running Folia - * - * @return true if running Folia - */ - public static boolean isFolia() { - return IS_FOLIA; - } - - /** - * Run a task on the main/global thread. - * On Paper/Spigot: runs on the main thread. - * On Folia: runs on the global region scheduler. - * - * @param plugin The plugin - * @param task The task to run - */ - public static void runSync(Plugin plugin, Runnable task) { - if (IS_FOLIA) { - Bukkit.getGlobalRegionScheduler().run(plugin, scheduledTask -> task.run()); - } else { - Bukkit.getScheduler().runTask(plugin, task); - } - } - - /** - * Run a task on the main/global thread after a delay. - * On Paper/Spigot: runs on the main thread. - * On Folia: runs on the global region scheduler. - * - * @param plugin The plugin - * @param task The task to run - * @param delayTicks The delay in ticks - */ - public static void runSyncDelayed(Plugin plugin, Runnable task, long delayTicks) { - if (IS_FOLIA) { - Bukkit.getGlobalRegionScheduler().runDelayed(plugin, scheduledTask -> task.run(), delayTicks); - } else { - Bukkit.getScheduler().runTaskLater(plugin, task, delayTicks); - } - } - - /** - * Run a task tied to an entity's region thread. - * On Paper/Spigot: runs on the main thread. - * On Folia: runs on the entity's region scheduler. - * - * @param plugin The plugin - * @param entity The entity to run the task for - * @param task The task to run - * @param retired Runnable to execute if the entity is retired (removed) before the task runs - */ - public static void runForEntity(Plugin plugin, Entity entity, Runnable task, Runnable retired) { - if (IS_FOLIA) { - entity.getScheduler().run(plugin, scheduledTask -> task.run(), retired); - } else { - Bukkit.getScheduler().runTask(plugin, task); - } - } - - /** - * Run a task tied to an entity's region thread after a delay. - * On Paper/Spigot: runs on the main thread. - * On Folia: runs on the entity's region scheduler. - * - * @param plugin The plugin - * @param entity The entity to run the task for - * @param task The task to run - * @param retired Runnable to execute if the entity is retired (removed) before the task runs - * @param delayTicks The delay in ticks - */ - public static void runForEntityDelayed(Plugin plugin, Entity entity, Runnable task, Runnable retired, long delayTicks) { - if (IS_FOLIA) { - entity.getScheduler().runDelayed(plugin, scheduledTask -> task.run(), retired, delayTicks); - } else { - Bukkit.getScheduler().runTaskLater(plugin, task, delayTicks); - } - } - - /** - * Run a task asynchronously. - * - * @param plugin The plugin - * @param task The task to run - */ - public static void runAsync(Plugin plugin, Runnable task) { - if (IS_FOLIA) { - Bukkit.getAsyncScheduler().runNow(plugin, scheduledTask -> task.run()); - } else { - Bukkit.getScheduler().runTaskAsynchronously(plugin, task); - } - } - - /** - * Run a task asynchronously after a delay. - * - * @param plugin The plugin - * @param task The task to run - * @param delayTicks The delay in ticks (converted to milliseconds for Folia) - */ - public static void runAsyncDelayed(Plugin plugin, Runnable task, long delayTicks) { - if (IS_FOLIA) { - // Convert ticks to milliseconds (1 tick = 50ms) - long delayMs = delayTicks * 50; - Bukkit.getAsyncScheduler().runDelayed(plugin, scheduledTask -> task.run(), delayMs, TimeUnit.MILLISECONDS); - } else { - Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, task, delayTicks); - } - } - - /** - * Schedule a repeating async task. - * - * @param plugin The plugin - * @param task The task to run - * @param delayTicks Initial delay in ticks - * @param periodTicks Period between executions in ticks - * @return A cancellable task wrapper - */ - public static CancellableTask runAsyncTimer(Plugin plugin, Runnable task, long delayTicks, long periodTicks) { - if (IS_FOLIA) { - // Convert ticks to milliseconds (1 tick = 50ms) - long delayMs = delayTicks * 50; - long periodMs = periodTicks * 50; - var scheduled = Bukkit.getAsyncScheduler().runAtFixedRate( - plugin, scheduledTask -> task.run(), delayMs, periodMs, TimeUnit.MILLISECONDS - ); - return scheduled::cancel; - } else { - var bukkitTask = Bukkit.getScheduler().runTaskTimerAsynchronously(plugin, task, delayTicks, periodTicks); - return bukkitTask::cancel; - } - } - - /** - * Schedule a repeating sync task on the global region. - * - * @param plugin The plugin - * @param task The task to run - * @param delayTicks Initial delay in ticks - * @param periodTicks Period between executions in ticks - * @return A cancellable task wrapper - */ - public static CancellableTask runSyncTimer(Plugin plugin, Runnable task, long delayTicks, long periodTicks) { - if (IS_FOLIA) { - var scheduled = Bukkit.getGlobalRegionScheduler().runAtFixedRate( - plugin, scheduledTask -> task.run(), delayTicks, periodTicks - ); - return scheduled::cancel; - } else { - var bukkitTask = Bukkit.getScheduler().runTaskTimer(plugin, task, delayTicks, periodTicks); - return bukkitTask::cancel; - } - } - - /** - * Interface for cancellable tasks to abstract between Bukkit and Folia - */ - @FunctionalInterface - public interface CancellableTask { - - /** - * Cancel the task - */ - void cancel(); - } -} diff --git a/paper/src/main/resources/paper-plugin.yml b/paper/src/main/resources/paper-plugin.yml deleted file mode 100644 index d270ab8..0000000 --- a/paper/src/main/resources/paper-plugin.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: ServerStats -version: ${version} -main: com.serverstats.paper.ServerStatsPlugin -api-version: "1.21" -folia-supported: true -description: ServerStats tracking plugin -author: VertCode - -permissions: - serverstats.command: - description: Base permission for serverstats commands - default: op - serverstats.command.reload: - description: Permission to reload the plugin - default: op - serverstats.command.debug: - description: Permission to toggle debug mode - default: op - serverstats.command.event: - description: Permission to send custom events - default: op diff --git a/release.sh b/release.sh index 461c335..3f67b23 100755 --- a/release.sh +++ b/release.sh @@ -7,14 +7,15 @@ if [ -z "$VERSION" ]; then exit 1 fi -echo "Building serverstats v${VERSION}..." +echo "Building analyse v${VERSION}..." ./gradlew build --no-daemon -q -OUTPUT="serverstats-${VERSION}.zip" +OUTPUT="analyse-${VERSION}.zip" JARS=( - "paper/build/libs/serverstats-paper-${VERSION}.jar" - "bungeecord/build/libs/serverstats-bungeecord-${VERSION}.jar" - "velocity/build/libs/serverstats-velocity-${VERSION}.jar" + "modules/spigot/build/libs/analyse-spigot-${VERSION}.jar" + "modules/bungeecord/build/libs/analyse-bungeecord-${VERSION}.jar" + "modules/velocity/build/libs/analyse-velocity-${VERSION}.jar" + "modules/hytale/build/libs/analyse-hytale-${VERSION}.jar" ) FOUND=() diff --git a/sdk/src/main/java/com/serverstats/sdk/config/ServerStatsConfig.java b/sdk/src/main/java/com/serverstats/sdk/config/ServerStatsConfig.java deleted file mode 100644 index 6ee378f..0000000 --- a/sdk/src/main/java/com/serverstats/sdk/config/ServerStatsConfig.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.serverstats.sdk.config; - -import lombok.Getter; - -/** - * Configuration for the ServerStats SDK - */ -@Getter -public class ServerStatsConfig { - - private static final String API_URL = "https://api.serverstats.com"; - - private final String apiUrl; - private final String apiKey; - - /** - * Create a new configuration - * - * @param apiKey The API key for authentication - */ - public ServerStatsConfig(String apiKey) { - if (apiKey == null || apiKey.isBlank()) { - throw new IllegalArgumentException("API key cannot be null or blank"); - } - - this.apiUrl = API_URL; - this.apiKey = apiKey; - } -} diff --git a/settings.gradle b/settings.gradle index fe5e214..55329d3 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,10 +1,8 @@ -rootProject.name = 'serverstats' +rootProject.name = 'analyse' -include 'sdk' -include 'api' -include 'paper' -include 'velocity' -include 'bungeecord' -include 'hytale' - - \ No newline at end of file +include 'modules:sdk' +include 'modules:api' +include 'modules:spigot' +include 'modules:velocity' +include 'modules:bungeecord' +include 'modules:hytale'