Build Extensions for TitanLogin
Create powerful addons that extend TitanLogin's functionality. No complicated setup β just Java, a JAR, and your creativity.
π Overview
TitanLogin extensions are simple Java JAR files that get dropped into the
plugins/TitanLogin/extensions/ folder. They can add new features, commands, GUIs, listeners
β anything you can do with the Bukkit API.
It's like making a Bukkit plugin, but simpler. Just like how Bukkit plugins have a
plugin.yml inside the JAR, your extension has an extension.yml inside the
JAR. You write the code, build one .jar file, and that single file is everything.
How Extensions Work
- You create a Java project and extend
TitanExtension - You add an
extension.ymlfile in your source code (atsrc/main/resources/) - You build it β Maven/Gradle automatically packages everything into one
.jarfile - Server admins drop that single JAR into
plugins/TitanLogin/extensions/ - TitanLogin reads
extension.ymlfrom inside the JAR and loads it automatically!
Server admins only need the .jar file! The extension.yml is NOT a
separate file β it lives inside your JAR. When you build with Maven, everything in
src/main/resources/ is automatically included in the JAR.
π§ Requirements
- Java 17+ (same as Minecraft 1.17+)
- An IDE β IntelliJ IDEA (recommended), Eclipse, or VS Code
- TitanLogin.jar β as a dependency (for compiling against the API)
- Spigot/Paper API β for Bukkit classes
- Maven or Gradle β for building (or manual compilation)
π Quick Start (5 Minutes)
Create Your Project
Create a new Java project in your IDE. Name it something like my-titanlogin-extension.
Add TitanLogin as a Dependency
Add the TitanLogin JAR and Spigot API as dependencies to your project:
<!-- pom.xml (Maven) -->
<dependencies>
<!-- TitanLogin API - add as local JAR -->
<dependency>
<groupId>com.titanlogin</groupId>
<artifactId>TitanLogin</artifactId>
<version>1.5</version>
<scope>provided</scope>
</dependency>
<!-- Spigot API -->
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.20.4-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
</dependencies>
Set scope to provided β TitanLogin and Spigot are already on the server, you don't want to include them in your JAR.
Create Your Main Class
package com.example.myextension; import com.titanlogin.extensions.TitanExtension; public class MyExtension extends TitanExtension { @Override public void onEnable() { getLogger().info("My Extension is now active! π"); } @Override public void onDisable() { getLogger().info("My Extension disabled."); } }
Create extension.yml (in your source code)
Create a file called extension.yml in your project's src/main/resources/
folder. This file gets automatically packaged inside your JAR when you build β you
don't need to distribute it separately:
name: "My Extension" version: "1.0" author: "YourName" main: "com.example.myextension.MyExtension" description: "A cool extension that does something awesome!" api-version: 1 category: "Utility"
Think of it like plugin.yml in Bukkit plugins β it's part of your project, and Maven
puts it inside the JAR automatically. Server admins never see or touch this
file.
Build & Install
Build your project (mvn package) β this creates one single JAR file
containing your code + extension.yml. Drop that JAR into plugins/TitanLogin/extensions/
and run /tl extensions reload. That's it!
What goes where:
β’ MyExtension.jar β plugins/TitanLogin/extensions/ (the ONLY file
needed!)
β’ Your code + extension.yml are INSIDE the JAR β nothing else to copy!
π Project Structure
A typical extension project looks like this:
βββ pom.xml (or build.gradle)
βββ src/main/
βββ java/com/example/myextension/
β βββ MyExtension.java
βββ resources/
βββ extension.yml β Required!
π extension.yml Reference
This file tells TitanLogin about your extension. Place it at
src/main/resources/extension.yml in your project β Maven/Gradle will automatically include
it in the root of your JAR when you build.
# Required fields name: "Login Rewards" # Unique name version: "1.0" # Your version author: "YourName" # Your name main: "com.example.Rewards" # Full class path # Recommended fields description: "Daily login rewards!" api-version: 1 # TitanLogin API version category: "Gameplay" # Authentication, Security, # Visual, Gameplay, Utility # Optional icon: "DIAMOND" # Minecraft material name dependencies: # Other extensions needed - "Some Other Extension"
ποΈ Main Class β TitanExtension
Your main class must extend TitanExtension. Here's what you get access to:
public class MyExtension extends TitanExtension { @Override public void onEnable() { // Called when your extension is enabled // Register listeners, commands, etc. here // Access the main TitanLogin plugin getTitanLogin().getServer().broadcastMessage("Extension loaded!"); // Your extension's data folder // plugins/TitanLogin/extensions/MyExtension/ getDataFolder().mkdirs(); // Load/save config getConfig().set("enabled", true); saveConfig(); // Logging getLogger().info("Hello from my extension!"); } @Override public void onDisable() { // Cleanup when extension is disabled } }
π API Reference
Methods Available in TitanExtension
| Method | Returns | Description |
|---|---|---|
getTitanLogin() |
TitanLogin | Main plugin instance β access everything |
getDataFolder() |
File | Your extension's private data folder |
getConfig() |
FileConfiguration | Your extension's config.yml |
saveConfig() |
void | Save config to disk |
reloadConfig() |
void | Reload config from disk |
getLogger() |
Logger | Logger with your extension's name prefix |
getName() |
String | Extension name from extension.yml |
getVersion() |
String | Extension version |
isEnabled() |
boolean | Whether extension is currently enabled |
π¦ Example: Login Rewards
Give players items when they log in daily:
package com.example.rewards; import com.titanlogin.extensions.TitanExtension; import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.event.*; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.inventory.ItemStack; public class LoginRewards extends TitanExtension implements Listener { @Override public void onEnable() { // Register this class as an event listener getTitanLogin().getServer().getPluginManager() .registerEvents(this, getTitanLogin()); getLogger().info("Login Rewards enabled!"); } @Override public void onDisable() { HandlerList.unregisterAll(this); } @EventHandler public void onJoin(PlayerJoinEvent event) { Player player = event.getPlayer(); // Give a diamond on login player.getInventory().addItem( new ItemStack(Material.DIAMOND, 1) ); player.sendMessage("Β§aβ‘ Daily reward: Β§b1 Diamond!"); } }
And the extension.yml:
name: "Login Rewards" version: "1.0" author: "YourName" main: "com.example.rewards.LoginRewards" description: "Give players daily rewards when they log in!" category: "Gameplay" api-version: 1
β¨οΈ Example: Custom Commands
Register a command that players can use:
package com.example.welcome; import com.titanlogin.extensions.TitanExtension; import org.bukkit.command.*; import org.bukkit.entity.Player; import org.bukkit.event.*; import org.bukkit.event.player.PlayerCommandPreprocessEvent; public class WelcomeExtension extends TitanExtension implements Listener { @Override public void onEnable() { getTitanLogin().getServer().getPluginManager() .registerEvents(this, getTitanLogin()); // Load welcome message from config if (!getConfig().contains("message")) { getConfig().set("message", "&bβ‘ Welcome to the server!"); saveConfig(); } } @Override public void onDisable() { HandlerList.unregisterAll(this); } @EventHandler public void onCommand(PlayerCommandPreprocessEvent e) { if (e.getMessage().equalsIgnoreCase("/welcome")) { e.setCancelled(true); String msg = getConfig().getString("message"); e.getPlayer().sendMessage( org.bukkit.ChatColor.translateAlternateColorCodes('&', msg) ); } } }
π₯οΈ Example: Custom GUI
Create an inventory GUI:
package com.example.infogui; import com.titanlogin.extensions.TitanExtension; import org.bukkit.*; import org.bukkit.entity.Player; import org.bukkit.event.*; import org.bukkit.event.player.PlayerCommandPreprocessEvent; import org.bukkit.inventory.*; import org.bukkit.inventory.meta.ItemMeta; import java.util.Arrays; public class InfoGUI extends TitanExtension implements Listener { @Override public void onEnable() { getTitanLogin().getServer().getPluginManager() .registerEvents(this, getTitanLogin()); } @Override public void onDisable() { HandlerList.unregisterAll(this); } @EventHandler public void onCmd(PlayerCommandPreprocessEvent e) { if (e.getMessage().equalsIgnoreCase("/serverinfo")) { e.setCancelled(true); openInfoGUI(e.getPlayer()); } } private void openInfoGUI(Player player) { Inventory gui = Bukkit.createInventory(null, 27, ChatColor.translateAlternateColorCodes('&', "&bβ‘ Server Info")); // Add items with info ItemStack info = new ItemStack(Material.BOOK); ItemMeta meta = info.getItemMeta(); meta.setDisplayName("Β§bΒ§lServer Rules"); meta.setLore(Arrays.asList( "Β§71. Be respectful", "Β§72. No griefing", "Β§73. Have fun!" )); info.setItemMeta(meta); gui.setItem(13, info); player.openInventory(gui); } }
π¨ Building Your JAR
With Maven
Run mvn package β your JAR will be in the target/ folder.
With Gradle
Run gradle build β your JAR will be in build/libs/.
Without Build Tools
If you just want to compile manually:
# Compile javac -cp TitanLogin.jar;spigot-api.jar -d out src/com/example/*.java # Package (include extension.yml in JAR root) jar cf MyExtension.jar -C out . -C resources .
Important: Make sure extension.yml is in the root of
your JAR file, not inside a subfolder. TitanLogin looks for it at the top level.
π€ Submitting to the Store
- Open the TitanLogin Extension Store
- Click "π€ Submit Extension"
- Fill in the details:
- Name β your extension's display name
- Version β current version number
- Author β your name or team name
- Description β what your extension does
- Download URL β link to your
.jarfile (use GitHub Releases, Dropbox, Google Drive, etc.) - Category β best fitting category
- Submit! PRINCExd will review your extension
- Once approved, it appears in the store for everyone to download
To get the Verified badge, your extension must be well-tested, have good documentation, and follow the guidelines below.
π Extension Guidelines
β Do
- Keep your extension focused on one feature
- Handle errors gracefully β don't crash the server
- Unregister listeners in
onDisable() - Use your extension's data folder for files
- Test on the latest Minecraft version
- Include a clear description of what it does
β Don't
- Access files outside your data folder
- Run blocking operations on the main thread
- Include malicious code, backdoors, or hidden features
- Modify TitanLogin's core files or database
- Depend on specific server implementations (use Bukkit API)
Extensions that violate these guidelines will be rejected from the store. Repeated violations may result in a ban from submitting.