A unified storage system that standardizes all databases under a JSON document-based API (add / set / get).
| Type | Category | Notes |
|---|---|---|
| JSON | Local | .json file-based |
| SQLITE | Local | HikariCP-based .db file |
| MYSQL | RDBMS | mysql-connector |
| MARIADB | RDBMS | mariadb-java-client |
| POSTGRESQL | RDBMS | PostgreSQL driver |
| MONGODB | NoSQL | Async document cluster |
Tip
Regardless of the StorageType selected, you use the same Storage API.
Just change the type in the config file and the driver switches automatically.
public interface Storage {
CompletableFuture<Result> add(JSON data); // Insert
CompletableFuture<Result> set(JSON find, JSON data); // Update
CompletableFuture<List<JsonObject>> get(JSON find); // Query
void close();
}| Status | success |
changed |
Meaning |
|---|---|---|---|
UPDATED |
✅ | ✅ | Successfully changed |
UNCHANGED |
✅ | ❌ | Succeeded but no changes |
FAILED |
❌ | ❌ | Failed |
import kr.rtustudio.storage.JSON;
JSON player = JSON.of("uuid", uuid.toString())
.append("name", "IPECTER")
.append("coins", 1000)
.append("level", 5);
JsonObject json = player.get(); // Convert to JsonObject@Override
protected void enable() {
registerStorage("PlayerData", StorageType.MARIADB);
registerStorage("Settings", StorageType.SQLITE);
registerStorage("Cache"); // Default JSON
}A config file Config/Storage/PlayerData.yml is auto-generated on registration:
Host: '127.0.0.1'
Port: 3306
Username: 'root'
Password: 'password123'
Database: 'minecraft_server'String dbType = getConfig().getString("database-type", "sqlite");
registerStorage("PlayerData", StorageType.fromString(dbType));Storage storage = getStorage("PlayerData");public class PlayerStorage {
private final Storage storage;
public PlayerStorage(RSPlugin plugin) {
this.storage = plugin.getStorage("PlayerData");
}
// CREATE
public void createPlayer(UUID uuid, String name) {
storage.add(JSON.of("uuid", uuid.toString())
.append("name", name)
.append("coins", 0)
.append("level", 1)
).thenAccept(result -> {
if (result.isSuccess()) System.out.println("Player created");
});
}
// READ
public void getPlayer(UUID uuid) {
storage.get(JSON.of("uuid", uuid.toString())).thenAccept(results -> {
if (!results.isEmpty()) {
int coins = results.get(0).get("coins").getAsInt();
System.out.println("Coins: " + coins);
}
});
}
// UPDATE
public void setCoins(UUID uuid, int newCoins) {
JSON find = JSON.of("uuid", uuid.toString());
JSON data = JSON.of("uuid", uuid.toString()).append("coins", newCoins);
storage.set(find, data).thenAccept(result -> {
if (result.isChanged()) System.out.println("Coins updated");
});
}
}public void showBalance(Player player) {
storage.get(JSON.of("uuid", player.getUniqueId().toString())).thenAccept(results -> {
// ⚠️ Running on async thread — thread switch required for Bukkit API
CraftScheduler.sync(plugin, task -> {
if (results.isEmpty()) {
player.sendMessage("No data found.");
return;
}
int coins = results.get(0).get("coins").getAsInt();
player.sendMessage("Coins: " + coins);
});
});
}Important
- Async returns —
add(),set(),get()all returnCompletableFuture. UseCraftScheduler.sync()for Bukkit API calls. - No main thread blocking — Calling
.join()or.get()on the main thread can freeze the server. - DB-independent — The same code works with any backend: JSON, SQLite, MySQL, MongoDB, etc.
- Built-in HikariCP — Connection pools are automatically created for relational DB registrations.
- Hot reload —
/rsf reloaddetects changed storage and reconnects only what's needed.
| Method | Returns | Description |
|---|---|---|
add(JSON data) |
CompletableFuture<Result> |
Insert a document |
set(JSON find, JSON data) |
CompletableFuture<Result> |
Search and update |
get(JSON find) |
CompletableFuture<List<JsonObject>> |
Search and query |
close() |
void |
Close storage |
| Method | Returns | Description |
|---|---|---|
JSON.of() |
JSON |
Empty builder |
JSON.of(key, value) |
JSON |
Builder with initial field |
append(key, value) |
JSON |
Add field (chaining) |
get() |
JsonObject |
Convert |
| Method | Description |
|---|---|
registerStorage(name, type) |
Register storage |
registerStorage(name) |
Register with JSON type |
getStorage(name) |
Get registered instance |