Skip to content

SyperCraft-mc/ObsiCore

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ObsiCore

ObsiCore is a Spigot 1.8.8 plugin development framework, It provides a complete infrastructure: dependency injection, SQL migrations, cache, commands, listeners, GUI and seeders — all auto-discovered via package scanning.


Table of Contents


Installation

Requirements: Java 8, Maven, Spigot 1.8.8

Add ObsiCore as a Maven dependency in your plugin:

<dependency>
    <groupId>fr.kainovaii</groupId>
    <artifactId>ObsiCore</artifactId>
    <version>latest</version>
    <scope>provided</scope>
</dependency>

Quick Start

In your plugin's onEnable():

@Override
public void onEnable() {
    DB.initMySQL("localhost", 3306, "mydb", "user", "password", getLogger());

    new CoreBootstrap(getLogger(), "fr.kainovaii.myplugin", this)
        .dbDriver(new MyDatabaseDriver())
        .withMigration("my_migrations")
        .boot();
}

boot() automatically runs in order:

  1. Cache initialization
  2. SQL migrations
  3. DI component scan (@Service, @Repository)
  4. Listener scan (@EventListener)
  5. Command scan (@Command)
  6. Seeder scan (@SeederInfo)
  7. GUI initialization (@GUI)

Class Reference


Bootstrap

CoreBootstrap

Package: fr.kainovaii.core

Main entry point for the framework. Orchestrates the startup of all subsystems via a fluent builder.

Method Description
CoreBootstrap(Logger, String, Plugin) Constructor. Takes the logger, the base package to scan, and the plugin instance.
dbDriver(DatabaseDriver) Sets the database driver to use.
withMigration(String) Enables migrations with a custom table name.
withMigration() Enables migrations with the default table "migrations".
cacheDriver(CacheDriver) Sets the cache driver (default: InMemoryCacheDriver).
boot() Launches all startup phases in order.

Example:

public class MyDatabaseDriver implements DatabaseDriver {
    @Override
    public <T> T withConnection(Callable<T> task) { return DB.getInstance().executeWithConnection(task); }
    @Override
    public <T> T withTransaction(Callable<T> task) { return DB.getInstance().executeWithTransaction(task); }
}

new CoreBootstrap(getLogger(), "fr.kainovaii.myplugin", this)
    .dbDriver(new MyDatabaseDriver())
    .withMigration("plugin_migrations")
    .cacheDriver(new RedisCacheDriver(jedisPool))
    .boot();

Cache

Cache

Package: fr.kainovaii.core.cache

Static facade for accessing the cache system. The driver is automatically injected by CoreBootstrap.

Method Description
put(String key, Object value, int ttlSeconds) Stores a value with a TTL.
putAll(Map<String,Object> entries, int ttlSeconds) Stores multiple values with a shared TTL.
get(String key) Retrieves a value (returns null if absent/expired).
getAll(List<String> keys) Retrieves multiple values in key order.
has(String key) Checks if a key exists and has not expired.
forget(String key) Removes an entry from the cache.
remember(String key, int ttl, Supplier<T> supplier) Returns the cached value, or computes, stores and returns it.
setDriver(CacheDriver) (internal) Sets the active driver.

Example:

Player player = Cache.remember("player:" + uuid, 300, () -> loadFromDB(uuid));

CacheDriver (interface)

Package: fr.kainovaii.core.cache

Contract to implement for providing a custom cache backend. Methods: put, putAll, get, getAll, has, forget.


CacheConfig

Package: fr.kainovaii.core.cache

Cache driver configuration.

Constructor Description
CacheConfig() In-Memory configuration (default).
CacheConfig(String driver, String host, int port, String password) Redis configuration. Pass "redis" as driver to enable Redis.
Method Description
isRedis() Returns true if the configured driver is Redis.
getRedisHost() Returns the Redis host.
getRedisPort() Returns the Redis port.
getRedisPassword() Returns the Redis password (or null).

InMemoryCacheDriver

Package: fr.kainovaii.core.cache.drivers

In-Memory implementation based on ConcurrentHashMap with TTL expiration. Default driver if none is configured.


RedisCacheDriver

Package: fr.kainovaii.core.cache.drivers

Redis implementation via JedisPool. Batch operations use pipelining for performance.

Constructor Description
RedisCacheDriver(JedisPool pool) Creates the driver with an existing Jedis connection pool.

Database

DB

Package: fr.kainovaii.core.database

MySQL connection manager with HikariCP pool. Thread-safe singleton.

Method Description
DB.initMySQL(host, port, database, user, password, logger) (static) Initializes the singleton. Call only once.
DB.getInstance() (static) Returns the singleton instance.
DB.withConnection(Callable<T>) (static) Shortcut to getInstance().executeWithConnection().
DB.withTransaction(Callable<T>) (static) Shortcut to getInstance().executeWithTransaction().
executeWithConnection(Callable<T>) (instance) Opens a connection if needed, executes the task, closes.
executeWithTransaction(Callable<T>) (instance) Opens a transaction, commits on success, rolls back on error.
close() Closes the connection pool. Call in onDisable().
getDatabase() Returns the configured database name.

Example:

DB.initMySQL("localhost", 3306, "mydb", "root", "password", getLogger());

DB.withConnection(() -> {
    return null;
});

DatabaseDriver (interface)

Package: fr.kainovaii.core.database

Interface the plugin must implement to provide DB access to the framework. Methods: withConnection(Callable<T>), withTransaction(Callable<T>).


Migration

Package: fr.kainovaii.core.database

Base class for migrations. Provides a fluent Laravel-style API for schema definition.

Method Description
up() (abstract) Migration logic (schema creation/modification).
createTable(String name, TableBuilder) Creates a table with columns defined in the builder.
dropTable(String name) Drops a table if it exists.
addColumn(String table, String column, String definition) Adds a column to an existing table.
dropColumn(String table, String column) Drops a column.
tableExists(String name) Checks if a table exists.

Migration.Blueprint — Fluent column builder:

Method Generated SQL
id() / id(name) INT AUTO_INCREMENT PRIMARY KEY
string(name) / string(name, length) VARCHAR(255) or VARCHAR(n)
text(name) TEXT
integer(name) INT
bigInteger(name) BIGINT
decimal(name, precision, scale) DECIMAL(p,s)
bool(name) BOOLEAN
date(name) DATE
dateTime(name) DATETIME
timestamp(name) TIMESTAMP
timestamps() Automatic created_at + updated_at
notNull() Adds NOT NULL to the last column
unique() Adds UNIQUE
defaultValue(String) Adds DEFAULT value
nullable() No-op (nullable by default)
index() Adds an INDEX on the last column

Example:

@MigrationInfo(version = 1, name = "create_players_table")
public class CreatePlayersTable extends Migration {
    @Override
    public void up() {
        createTable("players", t -> t
            .id()
            .string("uuid", 36).notNull().unique()
            .string("name").notNull()
            .integer("kills").defaultValue("0")
            .timestamps()
        );
    }
}

MigrationRunner

Package: fr.kainovaii.core.database

Discovers and runs all pending migrations. Idempotent: an already-applied migration is skipped.

Constructor Description
MigrationRunner(Logger, String packageName, DatabaseDriver) With default tracking table ("migrations").
MigrationRunner(Logger, String packageName, DatabaseDriver, String table) With custom tracking table.
run() Launches the scan and execution of pending migrations.

@MigrationInfo

Package: fr.kainovaii.core.database.annotations

Class annotation to mark a migration.

Attribute Description
version Version number. Migrations are executed in ascending order.
name Descriptive name (e.g., "create_users_table").

Seeder

Package: fr.kainovaii.core.database.seeder

Base class for database seeders.

Method Description
run() (abstract) Data insertion logic.
setLogger(Logger) Injects the logger (called by SeederScanner).

SeederScanner

Package: fr.kainovaii.core.database.seeder

Scans and runs seeders annotated with @SeederInfo, in the order defined by order. Each seeder runs only once per session.

Method Description
scan() Launches the scan and execution.
reset() Resets tracking to allow re-execution.

@SeederInfo

Package: fr.kainovaii.core.database.seeder.annotations

Class annotation to mark a seeder.

Attribute Description
name Unique identifier for the seeder.
order Execution order (default: 100, lower = first).

Dependency Injection

Container

Package: fr.kainovaii.core.di

Singleton IoC container. Manages automatic dependency resolution via constructor injection and field injection.

Method Description
Container.singleton(Class<T>, T instance) Manually registers a singleton instance.
Container.bind(Class<T>, Class<? extends T>) Binds an interface to its implementation.
Container.resolve(Class<T>) Resolves and returns an instance with auto-injected dependencies.
Container.injectFields(Object) Injects the @Inject fields of an existing instance.
Container.clear() Clears all singletons and bindings (useful for tests).

Resolution rules:

  • First checks if a singleton is already registered.
  • Classes must be annotated with @Service or @Repository (or bound via bind()).
  • Detects circular dependencies and throws an explicit exception.
  • If multiple constructors exist, one must be annotated with @Inject.

ComponentScanner

Package: fr.kainovaii.core.di

Scans the base package for classes annotated with @Service or @Repository and registers them in the Container via Container.resolve().


@Service

Package: fr.kainovaii.core.di.annotations

Marks a class as an injectable service. Will be auto-discovered and instantiated as a singleton by ComponentScanner.


@Repository

Package: fr.kainovaii.core.di.annotations

Marks a class as an injectable repository (data access layer). Identical behavior to @Service.


@Inject

Package: fr.kainovaii.core.di.annotations

Marks a constructor or field as an injection point. The Container will automatically inject the corresponding dependency.

Example:

@Service
public class PlayerService {
    @Inject
    private PlayerRepository playerRepository;

    public void save(PlayerData data) {
        DB.withTransaction(() -> {
            return null;
        });
    }
}

Commands

BaseCommand

Package: fr.kainovaii.core.command

Base class for all command handlers. Provides automatic routing to @Default and @Subcommand methods.

On instantiation, automatically injects @Inject fields via the Container and scans annotated methods.

Parameter injection in methods: Parameters of type CommandSender, Player, String[], or String are automatically injected at invocation.

Example:

@Command(name = "stats", aliases = {"s"}, description = "View stats")
public class StatsCommand extends BaseCommand {

    @Inject
    private PlayerService playerService;

    @Default
    public void onDefault(Player player) {
        player.sendMessage("Your stats: ...");
    }

    @Subcommand("top")
    public void onTop(CommandSender sender) {
        sender.sendMessage("Top players: ...");
    }
}

BukkitCommandWrapper

Package: fr.kainovaii.core.command

Bridge between BaseCommand and Bukkit's Command system. Created and registered automatically by CommandScanner. No direct usage.


CommandScanner

Package: fr.kainovaii.core.command

Scans classes annotated with @Command, instantiates each handler, and dynamically registers them in Bukkit's CommandMap via reflection.


@Command

Package: fr.kainovaii.core.command.annotations

Class annotation to mark a command handler.

Attribute Description
name Command name (e.g., "stats").
aliases Aliases (e.g., {"s", "stat"}). Default: {}.
description Description. Default: "".
usage Usage message. Default: "".
permission Required permission. Default: "".

@Subcommand

Package: fr.kainovaii.core.command.annotations

Method annotation to define a sub-handler.

Attribute Description
value Subcommand name (e.g., "create").
aliases Subcommand aliases.
permission Permission required for this subcommand.

@Default

Package: fr.kainovaii.core.command.annotations

Method annotation. The annotated method is called when no subcommand matches.


Events

ListenerScanner

Package: fr.kainovaii.core.events

Scans classes annotated with @EventListener that implement Bukkit Listener, instantiates them, injects their @Inject fields, and registers them with Bukkit.


@EventListener

Package: fr.kainovaii.core.events.annotations

Marks a class as a Bukkit event listener. The class must implement org.bukkit.event.Listener.

Example:

@EventListener
public class PlayerJoinListener implements Listener {

    @Inject
    private PlayerService playerService;

    @EventHandler
    public void onJoin(PlayerJoinEvent e) {
        playerService.onPlayerJoin(e.getPlayer());
    }
}

Inventory / GUI

Inventory

Package: fr.kainovaii.core.inventory

Abstract base class for custom GUI inventories. Implements InventoryHolder. Subclasses define content in init(), which is called automatically after @Inject field injection.

Constructors:

Constructor Description
Inventory(int size) CHEST inventory with the given number of slots and Bukkit's default title.
Inventory(int size, String title) CHEST inventory with custom size and title.
Inventory(InventoryType type) Inventory of the given Bukkit type with its default title.
Inventory(InventoryType type, String title) Inventory of the given Bukkit type with a custom title.

Main methods:

Method Description
init() (abstract) Inventory population and handler definition. Called once after DI injection.
open(Player) Opens the GUI. If the player already has an inventory of the same type/size open, updates the content in place (avoids visual flicker), otherwise opens normally.
addItem(ItemStack) Adds an item to the first empty slot.
addItem(ItemStack, Consumer<InventoryClickEvent>) Adds an item to the first empty slot with a click handler.
setItem(int slot, ItemStack) Places an item on a slot without a handler.
setItem(int slot, ItemStack, Consumer<InventoryClickEvent>) Places an item on a slot with a click handler.
setItems(int from, int to, ItemStack) Places the same item on a contiguous range of slots.
setItems(int from, int to, ItemStack, Consumer<InventoryClickEvent>) Same with shared handler.
setItems(int[] slots, ItemStack) Places the same item on the given slots.
setItems(int[] slots, ItemStack, Consumer<InventoryClickEvent>) Same with shared handler.
removeItem(int slot) Removes the item and its handler from the given slot.
removeItems(int... slots) Removes items and handlers from the given slots.
setCloseFilter(Predicate<Player>) Prevents closing if the predicate returns true (automatically reopens on the next tick).
addOpenHandler(Consumer<InventoryOpenEvent>) Adds an open handler.
addCloseHandler(Consumer<InventoryCloseEvent>) Adds a close handler.
addClickHandler(Consumer<InventoryClickEvent>) Adds a global click handler (all slots).
getBorders() Returns the slot indices of the border.
getCorners() Returns the corner indices.
onOpen(InventoryOpenEvent) (protected) Hook to override for custom open logic.
onClick(InventoryClickEvent) (protected) Hook to override for custom click logic.
onClose(InventoryCloseEvent) (protected) Hook to override for custom close logic.

Example:

@GUI
public class ShopGUI extends Inventory {
    public ShopGUI() {
        super(54, "§6Shop");
    }

    @Override
    public void init() {
        fillBorder(new ItemBuilder(Material.STAINED_GLASS_PANE).data(7).name("§r").build());
        setItem(13, new ItemBuilder(Material.DIAMOND).name("§bDiamond §7- 100 coins").build(),
            e -> ((Player) e.getWhoClicked()).sendMessage("Purchase complete!"));
    }
}

new ShopGUI().open(player);

InventoryManager

Package: fr.kainovaii.core.inventory

Static utility that registers the central Bukkit listener routing all inventory events to Inventory instances. Called automatically by CoreBootstrap.

Method Description
register(Plugin) Registers the listener. Can only be called once.
closeAll() Closes all GUI inventories open by connected players.

InventoryManager.InventoryListener — Internal listener that routes InventoryClickEvent, InventoryOpenEvent, InventoryCloseEvent to the correct handlers, and manages PluginDisableEvent.


GUIScanner

Package: fr.kainovaii.core.inventory

Scans classes annotated with @GUI extending Inventory. Does not instantiate them — GUIs are created on demand. Validates and logs discovered GUIs at startup.


@GUI

Package: fr.kainovaii.core.inventory.annotations

Marks a class as a GUI inventory. The class must extend Inventory. Will be discovered by GUIScanner at startup.


ItemBuilder

Package: fr.kainovaii.core.inventory

Fluent builder for constructing ItemStacks cleanly.

Method Description
ItemBuilder(Material) Creates a builder for an item of a given material.
ItemBuilder(ItemStack) Creates a builder from an existing item.
type(Material) Changes the material.
data(int) Sets the data value (sub-type).
durability(short) Sets the durability.
amount(int) Sets the quantity (1–64).
enchant(Enchantment) Adds an enchantment at level 1.
enchant(Enchantment, int) Adds an enchantment at a given level.
removeEnchant(Enchantment) Removes an enchantment.
removeEnchants() Removes all enchantments.
meta(Consumer<ItemMeta>) Direct meta modification.
meta(Class<T>, Consumer<T>) Typed meta modification (e.g., LeatherArmorMeta).
name(String) Sets the display name (supports § color codes).
lore(String...) Replaces the lore with the given lines.
lore(List<String>) Replaces the lore with a list.
addLore(String) / addLore(String...) Appends lines to the existing lore.
flags(ItemFlag...) Adds flags (e.g., HIDE_ENCHANTS).
flags() Adds all available flags.
removeFlags(ItemFlag...) Removes flags.
armorColor(Color) Sets the color of leather armor.
build() Returns the final ItemStack.

Scoreboard

BaseScoreboard

Package: fr.kainovaii.core.scoreboard

Abstract base class for custom scoreboards. Subclasses define sidebar lines and tablist content. Auto-refreshed by ScoreboardManager at a configurable interval.

The Bukkit Scoreboard and Objective are created once and reused across refreshes — only changed lines are updated in-place.

Method Description
getLines(Player) (abstract) Returns the sidebar lines for the given player. Max 15 lines, color codes (§) supported.
getTitleFrames(String baseTitle) Returns animation frames for the title. Override to customize. Only called when animated = true.
getTabHeader(Player) Tab list header. Return null or "" to skip. Default: null.
getTabFooter(Player) Tab list footer. Return null or "" to skip. Default: null.
remove(Player) Removes the scoreboard from the player and resets them to the main server scoreboard.

Example:

@Scoreboard(title = "§6§lMy Server", interval = 20)
public class MyScoreboard extends BaseScoreboard {

    @Inject
    private PlayerService playerService;

    @Override
    public List<String> getLines(Player player) {
        return Arrays.asList(
            "§8§m                  ",
            "§7➤ §fPlayer",
            "§8 • §7Name : §f" + player.getName(),
            "§8§m                  "
        );
    }

    @Override
    public String getTabHeader(Player player) {
        return "§6§lMy Server";
    }

    @Override
    public String getTabFooter(Player player) {
        return "§7Online: §a" + Bukkit.getOnlinePlayers().size();
    }
}

ScoreboardManager

Package: fr.kainovaii.core.scoreboard

Manages scoreboard assignment per player. Runs two separate schedulers per player:

  • Data task — refreshes lines at @Scoreboard#interval() ticks (default: 20)
  • Title task — advances the animation frame every 3 ticks when animated = true

This separation ensures DB queries never run on animation frames.

Method Description
ScoreboardManager.init(Plugin, Logger) (static) Initializes the singleton. Called automatically by CoreBootstrap.
ScoreboardManager.assign(Player, BaseScoreboard) (static) Assigns a scoreboard to a player and starts refresh tasks.
ScoreboardManager.remove(Player) (static) Removes the scoreboard from a player and cancels all tasks.
ScoreboardManager.refresh(Player) (static) Manually triggers a data refresh for a player.
ScoreboardManager.shutdown() (static) Removes all scoreboards and cancels all tasks. Call in onDisable().

Example:

// In PlayerJoinListener
@EventHandler
public void onJoin(PlayerJoinEvent e) {
    MyScoreboard board = new MyScoreboard();
    Container.injectFields(board); // inject @Inject fields
    ScoreboardManager.assign(e.getPlayer(), board);
}

// In PlayerQuitListener
@EventHandler
public void onQuit(PlayerQuitEvent e) {
    ScoreboardManager.remove(e.getPlayer());
}

// In onDisable()
ScoreboardManager.shutdown();

ScoreboardScanner

Package: fr.kainovaii.core.scoreboard

Scans the base package for classes annotated with @Scoreboard that extend BaseScoreboard. Does not instantiate them — scoreboards are created on demand via ScoreboardManager.assign(). Validates and logs discovered scoreboard classes at startup. Called automatically by CoreBootstrap.


@Scoreboard

Package: fr.kainovaii.core.scoreboard.annotations

Class annotation to mark a scoreboard definition. The class must extend BaseScoreboard.

Attribute Description
title Sidebar title displayed above the lines. Supports color codes (§). Default: "§fScoreboard".
interval Auto-refresh interval in ticks (20 ticks = 1 second). Set to 0 to disable automatic refresh. Default: 20.
animated Enables title animation by cycling through getTitleFrames() every 3 ticks. Default: false.

Scanner

BaseScanner<T, A>

Package: fr.kainovaii.core.scanner

Generic abstract class for annotation-based class discovery via reflection. Base of all framework scanners.

Method Description
scan() Starts the discovery, filtering, and processing of classes.
discoverClasses() Discovers all classes matching the scan criteria.
processClass(Class<? extends T>) (abstract) Processing of a discovered class.
getBaseClass() (abstract) Base type to scan (e.g., Listener.class).
getAnnotationClass() (abstract) Primary filter annotation.
getAnnotationClasses() List of filter annotations (default: delegates to getAnnotationClass()).
getScannerName() (abstract) Scanner name for logs.
shouldProcess(Class<? extends T>) Determines if a class should be processed: must be concrete, non-interface, and carry at least one of the annotations defined in getAnnotationClasses().
getComparator() Sort comparator for classes (default: alphabetical).
onScanComplete() Hook called after all processing.

Utils

ChatBox

Package: fr.kainovaii.core.utils

Chat message formatting utility with aligned header/footer and tree structure support.

Created via ChatBox.Builder (builder pattern).

ChatBox.Builder:

Method Description
title(String) Title displayed in the header (supports color codes).
line(String) Adds a line.
lines(String...) Adds multiple lines.
treeLine(String content, boolean isLast) Adds a line with a tree prefix (, , ).
width(int) Target chat box width (default: 32).
build() Builds the ChatBox instance.
Instance method Description
send(Player) Sends the formatted chat box to the player.

Example:

ChatBox.builder()
    .title("§bStats")
    .treeLine("§7Kills: §a" + kills, false)
    .treeLine("§7Deaths: §c" + deaths, false)
    .treeLine("§7K/D: §e" + kd, true)
    .build()
    .send(player);

ItemSerializer

Package: fr.kainovaii.core.utils

Serialization/deserialization of ItemStack lists to Base64 for storage in databases or files.

Method Description
serializeItems(List<ItemStack>) Serializes a list of items to a Base64 string.
deserializeItems(String) Deserializes a Base64 string to a list of ItemStacks.

Example:

String encoded = ItemSerializer.serializeItems(Arrays.asList(player.getInventory().getContents()));
DB.withConnection(() -> { return null; });

List<ItemStack> items = ItemSerializer.deserializeItems(encoded);

Dependencies

Dependency Version Scope
Spigot API 1.8.8-R0.1-SNAPSHOT provided
ActiveJDBC 2.3.1-j8 provided
HikariCP 2.7.9 provided
Jedis (Redis) 5.1.0 provided
Reflections 0.10.2 compile

provided dependencies must be present on the server or shaded into the final jar by the consuming plugin.


Developed by KainoVaii — ObsiCore v1.0

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Contributors