Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
c570d05
Add MariaDB database storage support
bedge117 Jan 28, 2026
8f96a97
Fix duplicate spawner entries when placing at existing location
bedge117 Jan 28, 2026
6be605b
Implement database storage and migration handling
bedge117 Feb 6, 2026
6020ddc
Implement cross-server selection in ListSubCommand
bedge117 Feb 6, 2026
dc5a9fb
Add spawner modification marking after stack size update
bedge117 Feb 6, 2026
d8c7253
Enhance world selection and spawner management logic
bedge117 Feb 6, 2026
1ef2130
Add targetServer field to SpawnerListHolder
bedge117 Feb 6, 2026
4de7359
Enhance SpawnerManagementGUI for remote server support
bedge117 Feb 6, 2026
85ac6e8
Refactor spawner management to use SpawnerStorage
bedge117 Feb 6, 2026
4efc698
Add targetServer field and isRemoteServer method
bedge117 Feb 6, 2026
8df0b06
Implement WorldSelectionHolder for server-specific viewing
bedge117 Feb 6, 2026
4176f66
Implement DatabaseManager for HikariCP connection pooling
bedge117 Feb 6, 2026
58e5a48
Add files via upload
bedge117 Feb 6, 2026
e239650
Integrate SpawnerManager for spawner modifications
bedge117 Feb 6, 2026
708320a
Update spawner deletion handling in SpawnerBreakListener
bedge117 Feb 6, 2026
7916584
Integrate SpawnerManager for spawner updates
bedge117 Feb 6, 2026
0c552da
Add database settings to config.yml
bedge117 Feb 6, 2026
5b6f9cf
Add ServerSelectionHandler for GUI interactions
bedge117 Feb 6, 2026
3d44ab1
Add files via upload
bedge117 Feb 6, 2026
f25041b
Fix database mode bugs and add cross-server spawner list feature
bedge117 Feb 6, 2026
7bad97f
Change spawner deletion method in SpawnerExplosionListener
bedge117 Feb 6, 2026
153608c
Add files via upload
bedge117 Feb 6, 2026
9875407
Add SpawnerStorage interface for data management
bedge117 Feb 6, 2026
135814a
Create StorageMode enum for storage options
bedge117 Feb 6, 2026
745dee9
Add shadow plugin to build.gradle
bedge117 Feb 6, 2026
ed824db
Add shadow plugin and configure shaded dependencies
bedge117 Feb 6, 2026
77c443c
Add SQLite storage support and rename config section
bedge117 Feb 6, 2026
dda661f
Merge remote-tracking branch 'origin/main' with SQLite support
bedge117 Feb 6, 2026
2f17905
Fix SQLite - remove relocation (JNI native libs cannot be relocated)
bedge117 Feb 6, 2026
881dad3
Fix SQLite upsert - use ON CONFLICT syntax instead of MySQL ON DUPLIC…
bedge117 Feb 6, 2026
a6bbde8
Add migration support for YAML->SQLite, YAML->MySQL, and SQLite->MySQL
bedge117 Feb 6, 2026
243023c
Add migrate_from_local config option for database migrations
bedge117 Feb 6, 2026
ef20587
Add config migration for renamed database.standalone to database.sql
bedge117 Feb 6, 2026
0c90a3c
Add cross-server filter/sort and remote spawner management
bedge117 Feb 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ plugins {
id 'java'
id 'java-library'
id 'maven-publish'
id 'com.gradleup.shadow' version '8.3.5' apply false
}

allprojects {
Expand Down
47 changes: 47 additions & 0 deletions core/build.gradle
Original file line number Diff line number Diff line change
@@ -1,10 +1,25 @@
plugins {
id 'com.gradleup.shadow'
}

// Create a custom configuration for database dependencies to shade
configurations {
shade
implementation.extendsFrom(shade)
}

dependencies {
// API
api project(':api')

// Paper API
compileOnly 'io.papermc.paper:paper-api:1.21.11-R0.1-SNAPSHOT'

// Database dependencies (shaded)
shade 'com.zaxxer:HikariCP:5.1.0'
shade 'org.mariadb.jdbc:mariadb-java-client:3.3.2'
shade 'org.xerial:sqlite-jdbc:3.45.1.0'

// Hook plugins
compileOnly 'org.geysermc.floodgate:api:2.2.5-SNAPSHOT'
compileOnly 'com.sk89q.worldguard:worldguard-bukkit:7.1.0-SNAPSHOT'
Expand Down Expand Up @@ -57,6 +72,38 @@ jar {
// destinationDirectory = file('C:\\Users\\notni\\OneDrive\\Desktop\\paper_1.21.8\\plugins')
}

shadowJar {
archiveBaseName.set("SmartSpawner")
archiveVersion.set("${version}")
archiveClassifier.set("")

from { project(':api').sourceSets.main.output }

// Only include shade configuration dependencies
configurations = [project.configurations.shade]

// Relocate shaded dependencies to avoid conflicts with other plugins
relocate 'com.zaxxer.hikari', 'github.nighter.smartspawner.libs.hikari'
relocate 'org.mariadb.jdbc', 'github.nighter.smartspawner.libs.mariadb'
// NOTE: SQLite JDBC cannot be relocated - it uses JNI native libraries

exclude 'META-INF/*.RSA', 'META-INF/*.SF', 'META-INF/*.DSA'
// Exclude unnecessary files from dependencies
exclude 'META-INF/maven/**'
exclude 'META-INF/MANIFEST.MF'
exclude 'META-INF/LICENSE*'
exclude 'META-INF/NOTICE*'

// Merge with main source output
from sourceSets.main.output

// Exclude slf4j as it's provided by Paper/Bukkit
exclude 'org/slf4j/**'
}

// Make shadowJar the default build artifact
build.dependsOn shadowJar

processResources {
def props = [version: version]
inputs.properties props
Expand Down
104 changes: 99 additions & 5 deletions core/src/main/java/github/nighter/smartspawner/SmartSpawner.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import github.nighter.smartspawner.commands.list.gui.management.SpawnerManagementHandler;
import github.nighter.smartspawner.commands.list.gui.management.SpawnerManagementGUI;
import github.nighter.smartspawner.commands.list.gui.adminstacker.AdminStackerHandler;
import github.nighter.smartspawner.commands.list.gui.serverselection.ServerSelectionHandler;
import github.nighter.smartspawner.commands.prices.PricesGUI;
import github.nighter.smartspawner.spawner.config.SpawnerSettingsConfig;
import github.nighter.smartspawner.spawner.config.ItemSpawnerSettingsConfig;
Expand Down Expand Up @@ -44,6 +45,12 @@
import github.nighter.smartspawner.spawner.data.SpawnerManager;
import github.nighter.smartspawner.spawner.sell.SpawnerSellManager;
import github.nighter.smartspawner.spawner.data.SpawnerFileHandler;
import github.nighter.smartspawner.spawner.data.storage.SpawnerStorage;
import github.nighter.smartspawner.spawner.data.storage.StorageMode;
import github.nighter.smartspawner.spawner.data.database.DatabaseManager;
import github.nighter.smartspawner.spawner.data.database.SpawnerDatabaseHandler;
import github.nighter.smartspawner.spawner.data.database.SqliteToMySqlMigration;
import github.nighter.smartspawner.spawner.data.database.YamlToDatabaseMigration;
import github.nighter.smartspawner.spawner.config.SpawnerMobHeadTexture;
import github.nighter.smartspawner.spawner.lootgen.SpawnerLootGenerator;
import github.nighter.smartspawner.spawner.data.WorldEventHandler;
Expand Down Expand Up @@ -107,6 +114,8 @@ public class SmartSpawner extends JavaPlugin implements SmartSpawnerPlugin {

// Core managers
private SpawnerFileHandler spawnerFileHandler;
private SpawnerStorage spawnerStorage;
private DatabaseManager databaseManager;
private SpawnerManager spawnerManager;
private HopperHandler hopperHandler;
private SpawnerLocationLockManager spawnerLocationLockManager;
Expand All @@ -128,6 +137,7 @@ public class SmartSpawner extends JavaPlugin implements SmartSpawnerPlugin {
private SpawnerListGUI spawnerListGUI;
private SpawnerManagementHandler spawnerManagementHandler;
private AdminStackerHandler adminStackerHandler;
private ServerSelectionHandler serverSelectionHandler;
private PricesGUI pricesGUI;

// Logging system
Expand Down Expand Up @@ -262,7 +272,9 @@ private void initializeEconomyComponents() {
}

private void initializeCoreComponents() {
this.spawnerFileHandler = new SpawnerFileHandler(this);
// Initialize storage based on configured mode
initializeStorage();

this.spawnerManager = new SpawnerManager(this);
this.spawnerLocationLockManager = new SpawnerLocationLockManager(this);
this.spawnerManager.reloadAllHolograms();
Expand All @@ -274,11 +286,85 @@ private void initializeCoreComponents() {
this.spawnerLootGenerator = new SpawnerLootGenerator(this);
this.spawnerSellManager = new SpawnerSellManager(this);
this.rangeChecker = new SpawnerRangeChecker(this);

// Initialize FormUI components only if Floodgate is available
initializeFormUIComponents();
}

private void initializeStorage() {
String modeStr = getConfig().getString("database.mode", "YAML").toUpperCase();
StorageMode mode;
try {
mode = StorageMode.valueOf(modeStr);
} catch (IllegalArgumentException e) {
getLogger().warning("Invalid storage mode '" + modeStr + "', defaulting to YAML");
mode = StorageMode.YAML;
}

if (mode == StorageMode.MYSQL || mode == StorageMode.SQLITE) {
String dbType = mode == StorageMode.MYSQL ? "MySQL/MariaDB" : "SQLite";
getLogger().info("Initializing " + dbType + " database storage mode...");
this.databaseManager = new DatabaseManager(this, mode);

if (databaseManager.initialize()) {
SpawnerDatabaseHandler dbHandler = new SpawnerDatabaseHandler(this, databaseManager);
if (dbHandler.initialize()) {
this.spawnerStorage = dbHandler;

// Check if migration is enabled in config
boolean migrateFromLocal = getConfig().getBoolean("database.migrate_from_local", true);

if (migrateFromLocal) {
// Check for YAML migration (YAML -> MySQL or YAML -> SQLite)
YamlToDatabaseMigration yamlMigration = new YamlToDatabaseMigration(this, databaseManager);
if (yamlMigration.needsMigration()) {
getLogger().info("YAML data detected, starting migration to " + dbType + "...");
if (yamlMigration.migrate()) {
getLogger().info("YAML migration completed successfully!");
} else {
getLogger().warning("YAML migration completed with some errors. Check logs for details.");
}
}

// Check for SQLite to MySQL migration (only when mode is MYSQL)
if (mode == StorageMode.MYSQL) {
SqliteToMySqlMigration sqliteMigration = new SqliteToMySqlMigration(this, databaseManager);
if (sqliteMigration.needsMigration()) {
getLogger().info("SQLite data detected, starting migration to MySQL...");
if (sqliteMigration.migrate()) {
getLogger().info("SQLite to MySQL migration completed successfully!");
} else {
getLogger().warning("SQLite migration completed with some errors. Check logs for details.");
}
}
}
} else {
debug("Local data migration is disabled in config.");
}

getLogger().info(dbType + " database storage initialized successfully.");
} else {
getLogger().severe("Failed to initialize database handler, falling back to YAML");
databaseManager.shutdown();
databaseManager = null;
initializeYamlStorage();
}
} else {
getLogger().severe("Failed to initialize database connection, falling back to YAML");
databaseManager = null;
initializeYamlStorage();
}
} else {
initializeYamlStorage();
}
}

private void initializeYamlStorage() {
this.spawnerFileHandler = new SpawnerFileHandler(this);
this.spawnerStorage = spawnerFileHandler;
getLogger().info("Using YAML file storage mode.");
}

private void initializeFormUIComponents() {
// Check if FormUI is enabled in config
boolean formUIEnabled = getConfig().getBoolean("bedrock_support.enable_formui", true);
Expand Down Expand Up @@ -353,6 +439,7 @@ private void registerListeners() {
pm.registerEvents(spawnerListGUI, this);
pm.registerEvents(spawnerManagementHandler, this);
pm.registerEvents(adminStackerHandler, this);
pm.registerEvents(serverSelectionHandler, this);
pm.registerEvents(pricesGUI, this);

// Register logging listener
Expand All @@ -369,6 +456,7 @@ private void setupCommand() {
this.spawnerListGUI = new SpawnerListGUI(this);
this.spawnerManagementHandler = new SpawnerManagementHandler(this, listSubCommand);
this.adminStackerHandler = new AdminStackerHandler(this, new SpawnerManagementGUI(this));
this.serverSelectionHandler = new ServerSelectionHandler(this, listSubCommand);
this.pricesGUI = new PricesGUI(this);
}

Expand Down Expand Up @@ -439,8 +527,14 @@ public void onDisable() {
private void saveAndCleanup() {
if (spawnerManager != null) {
try {
if (spawnerFileHandler != null) {
spawnerFileHandler.shutdown();
// Use the storage interface for shutdown
if (spawnerStorage != null) {
spawnerStorage.shutdown();
}

// Shutdown database manager if active
if (databaseManager != null) {
databaseManager.shutdown();
}

// Clean up the spawner manager
Expand All @@ -453,7 +547,7 @@ private void saveAndCleanup() {
if (itemPriceManager != null) {
itemPriceManager.cleanup();
}

// Shutdown logging system
if (spawnerActionLogger != null) {
spawnerActionLogger.shutdown();
Expand Down
Loading
Loading