Cassaforte
Overview
Cassaforte offers a clean abstraction layer for Hytale plugins, inspired by VaultAPI for Bukkit. It allows plugins to interact with economy, permission, and chat systems through a unified interface, regardless of the underlying implementation.
Plugins using Cassaforte
- Towny3D
- SimpleEconomy
- TheEconomy
- SimpleJobs
Features
- Service Registry: Centralized registration and retrieval of service implementations
- Economy API: Balance management, deposits, withdrawals, and bank support
- Permission API: Player and group permission management
- Chat API: Prefix/suffix formatting and player/group info nodes
- UUID-based identification: Full offline player support
- Thread-safe: Atomic operations for reliable concurrent access
- Zero dependencies: Pure Java with no runtime dependencies
- First-wins policy: Only first registration succeeds, preventing accidental overwrites
Installation
Add Cassaforte as a dependency in your Gradle project:
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
mavenCentral()
maven { url 'https://jitpack.io' }
}
}
dependencies {
compileOnly("it.cassaforte:api:v0.1.2")
}
Architecture
Cassaforte uses a service registry pattern where plugin implementations register themselves, and consumer plugins retrieve these implementations transparently.
┌─────────────────────────────────────────────────────────────┐
│ Cassaforte API │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Economy │ │ Permission │ │ Chat │ │
│ │ Interface │ │ Interface │ │ Interface │ │
│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │
│ │ │ │ │
│ └─────────────────┴─────────────────┘ │
│ │ │
│ ┌───────┴────────┐ │
│ │ Cassaforte │ │
│ │ Service Registry│ │
│ └────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
┌─────────────────┴─────────────────┐
│ │
┌─────────────────────┐ ┌─────────────────────┐
│ Economy Plugin │ │ Consumer Plugin │
│ (Registers impl) │ │ (Retrieves impl) │
└─────────────────────┘ └─────────────────────┘
Usage
For Service Implementers
If you're creating an economy, permission, or chat plugin, implement the interface and register it with Cassaforte:
import com.hypixel.hytale.server.core.plugin.JavaPlugin;
import com.hypixel.hytale.server.core.plugin.JavaPluginInit;
import it.cassaforte.api.Cassaforte;
import it.cassaforte.api.economy.AbstractEconomy;
import it.cassaforte.api.economy.EconomyResponse;
import javax.annotation.Nonnull;
import java.util.UUID;
public class MyEconomyPlugin extends AbstractEconomy {
private static MyEconomyPlugin instance;
public MyEconomyPlugin(@Nonnull JavaPluginInit init) {
super(init);
instance = this;
}
public static MyEconomyPlugin get() {
return instance;
}
@Override
protected void setup() {
// Register this economy implementation with Cassaforte
boolean registered = Cassaforte.registerEconomy(this);
if (!registered) {
getLogger().warning("Another economy is already registered!");
return;
}
getLogger().info("Economy registered successfully!");
}
@Override
protected void shutdown() {
// Clean up resources if needed
}
// Implement required economy methods
@Override
public EconomyResponse depositPlayer(UUID playerId, double amount) {
// Your implementation
return new EconomyResponse(amount, newBalance, EconomyResponse.ResponseType.SUCCESS);
}
@Override
public double getBalance(UUID playerId) {
// Your implementation
return 0.0;
}
// ... implement other required methods
}
For Service Consumers
If you're using an economy, permission, or chat service in your plugin, retrieve the registered implementation through Cassaforte:
import com.hypixel.hytale.server.core.plugin.JavaPlugin;
import com.hypixel.hytale.server.core.plugin.JavaPluginInit;
import it.cassaforte.api.Cassaforte;
import it.cassaforte.api.economy.Economy;
import it.cassaforte.api.permission.Permission;
import it.cassaforte.api.chat.Chat;
import javax.annotation.Nonnull;
public class MyPlugin extends JavaPlugin {
private Economy economy;
private Permission permission;
private Chat chat;
public MyPlugin(@Nonnull JavaPluginInit init) {
super(init);
}
@Override
protected void setup() {
// Retrieve registered services
economy = Cassaforte.getEconomy();
permission = Cassaforte.getPermission();
chat = Cassaforte.getChat();
// Check if services are available
if (economy != null && economy.isEnabled()) {
getLogger().info("Economy service available: " + economy.getName());
} else {
getLogger().warning("No economy service available");
}
if (permission != null && permission.isEnabled()) {
getLogger().info("Permission service available: " + permission.getName());
} else {
getLogger().warning("No permission service available");
}
if (chat != null) {
getLogger().info("Chat service available");
}
}
public void giveMoney(UUID playerId, double amount) {
if (economy != null && economy.isEnabled()) {
var response = economy.depositPlayer(playerId, amount);
if (response.transactionSuccess()) {
getLogger().info("Deposited " + amount + " to player");
}
} else {
getLogger().warning("Cannot deposit: Economy not available");
}
}
public boolean checkPermission(UUID playerId, String node) {
if (permission != null && permission.isEnabled()) {
return permission.playerHas(playerId, node);
}
return false;
}
public String formatPlayerName(UUID playerId, String playerName) {
if (chat != null) {
String prefix = chat.getPlayerPrefix(playerId, "");
String suffix = chat.getPlayerSuffix(playerId, "");
return prefix + playerName + suffix;
}
return playerName;
}
}
Using Hytale Plugin Manager
You can also retrieve Cassaforte directly through the Hytale Plugin Manager:
import com.hypixel.hytale.server.core.plugin.PluginManager;
import com.hypixel.hytale.common.plugin.PluginIdentifier;
import it.cassaforte.api.Cassaforte;
public class MyPlugin extends JavaPlugin {
@Override
protected void setup() {
// Method 1: Direct static access (recommended)
Economy economy = Cassaforte.getEconomy();
if (economy != null) {
getLogger().info("Economy: " + economy.getName());
}
// Method 2: Access via PluginManager to get the plugin instance
PluginManager pm = PluginManager.get();
PluginIdentifier cassaforteId = new PluginIdentifier("it.cassaforte", "Cassaforte");
if (pm.hasPlugin(cassaforteId)) {
getLogger().info("Cassaforte plugin is loaded");
// Services are accessed through Cassaforte static methods
Economy economy2 = Cassaforte.getEconomy();
Permission permission = Cassaforte.getPermission();
Chat chat = Cassaforte.getChat();
}
}
}
API Reference
Cassaforte Registry
The it.cassaforte.api.Cassaforte class provides static methods for service registration and retrieval.
Registration Methods
// Register an economy implementation (returns false if already registered)
boolean success = Cassaforte.registerEconomy(Economy economy);
// Register a permission implementation
boolean success = Cassaforte.registerPermission(Permission permission);
// Register a chat implementation
boolean success = Cassaforte.registerChat(Chat chat);
Retrieval Methods
// Get registered economy (null if none registered)
Economy economy = Cassaforte.getEconomy();
// Get registered permission (null if none registered)
Permission permission = Cassaforte.getPermission();
// Get registered chat (null if none registered)
Chat chat = Cassaforte.getChat();
Economy API
import it.cassaforte.api.economy.Economy;
import it.cassaforte.api.economy.EconomyResponse;
import java.util.UUID;
// Check if player has an account
boolean hasAccount = economy.hasAccount(playerId);
// Get player balance
double balance = economy.getBalance(playerId);
// Deposit money
EconomyResponse response = economy.depositPlayer(playerId, 100.0);
if (response.transactionSuccess()) {
// Success - new balance: response.balance
}
// Withdraw money
EconomyResponse response = economy.withdrawPlayer(playerId, 50.0);
// Check if player can afford
boolean canAfford = economy.has(playerId, 75.0);
// Bank operations (if supported)
if (economy.hasBankSupport()) {
economy.createBank("MyBank", playerId);
double bankBalance = economy.bankBalance("MyBank");
}
// Format currency
String formatted = economy.format(1000.50); // "$1,000.50"
Permission API
import it.cassaforte.api.permission.Permission;
import java.util.UUID;
// Player permissions
boolean hasPerm = permission.playerHas(playerId, "essentials.tp");
permission.playerAdd(playerId, "essentials.tp");
permission.playerRemove(playerId, "essentials.tp");
// Group permissions
boolean groupHas = permission.groupHas("admin", "essentials.*");
permission.groupAdd("admin", "essentials.*");
permission.groupRemove("admin", "essentials.*");
// Group membership
boolean inGroup = permission.playerInGroup(playerId, "vip");
permission.playerAddGroup(playerId, "vip");
permission.playerRemoveGroup(playerId, "vip");
// Get player's groups
List<String> groups = permission.getPlayerGroups(playerId);
String primaryGroup = permission.getPrimaryGroup(playerId);
Chat API
import it.cassaforte.api.chat.Chat;
import java.util.UUID;
// Player prefix/suffix
String prefix = chat.getPlayerPrefix(playerId, "");
String suffix = chat.getPlayerSuffix(playerId, "");
chat.setPlayerPrefix(playerId, "[Admin] ");
chat.setPlayerSuffix(playerId, " *");
// Group prefix/suffix
String groupPrefix = chat.getGroupPrefix("vip", "");
chat.setGroupPrefix("vip", "[VIP] ");
// Info nodes (metadata storage)
chat.setPlayerInfoString(playerId, "nickname", "Player1");
String nickname = chat.getPlayerInfoString(playerId, "nickname", "");
chat.setPlayerInfoInteger(playerId, "kills", 100);
int kills = chat.getPlayerInfoInteger(playerId, "kills", 0);
Project Structure
it.cassaforte.api/
├── Cassaforte.java # Central service registry
├── economy/
│ ├── Economy.java # Main economy interface
│ ├── AbstractEconomy.java # Base implementation with defaults
│ └── EconomyResponse.java # Operation response wrapper
├── permission/
│ └── Permission.java # Permission and group management
└── chat/
└── Chat.java # Chat formatting and metadata
Thread Safety
All Cassaforte registry methods are thread-safe. Registration uses atomic compare-and-set operations to ensure that only the first registration succeeds. Retrieval operations are lock-free and safe to call from any thread.
Best Practices
- Register Early: Always register your service in
setup()orstart()to ensure it's available before other plugins need it - Handle Null Returns: Always check for null when retrieving services - they may not be registered
- Check isEnabled(): Verify
isEnabled()before using economy or permission services - Use Static Accessors: Provide a static
getInstance()method in your plugin for easy access by other plugins - Graceful Degradation: Your plugin should work even when optional services are unavailable
Building
./gradlew build
The build produces:
jar- Standard JAR with dependenciesshadowJar- Fat JAR with shaded dependencies (Gson relocated)
Requirements
- Java 21+
- Gradle 9.0+
- Hytale Server API (compile-only)
License
MIT
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Inspired By
This project is inspired by VaultAPI for Bukkit/Minecraft, adapted for the Hytale platform.

