Description
Mikasa-tp-mod
Mikasa-tp-mod is a Fabric server teleport utility by Mikasa.
It adds player teleport, TPA requests with a short stand-still warmup, and multiple named homes. Permissions are controlled by configurable roles. Storage works out of the box with JSON, with optional PostgreSQL or MySQL.
Available Commands
/tphelp/tp <player>/tpa <player>/tpaccept/tpdeny/tpacancel/home list/home set <name>/home del <name>/home <name>
Philosophy
Full control over your data and roles.
Mikasa-tp-mod is built for those who want control — not "just another TP mod." There is no magic and no hidden decisions: your data is yours, your roles are yours, and everything lives exactly where you put it.
Your data, your rules
- PostgreSQL or MySQL — for high-load servers where data must be reliable.
- JSON — if no database is needed or not ready yet.
- Switching is a single config change. No external plugins, no dependencies.
Roles you define
Permissions are granted through roles: player, moderator, admin — or custom ones like vip. What each role can do is entirely up to you. No role — no access. Transparent and predictable.
The database sets itself up
If you have PostgreSQL or MySQL but don't want to deal with the schema — the mod does it for you. On first connection it automatically creates the minimum required tables:
roles— rolescommands— command keysrole_permissions— role permissionsplayers— player-to-role bindingssettings— settings such asmax_homeshomes— player homes
No SQL to write, no tables to create by hand. Just provide host, database, username, and password — the mod handles the rest.
Migrating config from JSON to DB
In config.json there is a key sync_to_database (default: false).
Set it to true — and on the next server start the entire JSON config is fully migrated into the database:
- roles and their permissions,
- the command list,
- settings (such as
max_homes).
The migration runs in a single transaction: all or nothing. Once it succeeds, the mod resets the key back to false — so the migration runs exactly once, and you don't have to remember it.
This means you can start on JSON and switch to a database with a single toggle — no manual SQL, no data loss.
Editing configs is safe
Player → role bindings are preserved as long as the role itself remains in config.json.
There's nothing to be afraid of when editing the config: while a role exists in the file, every player assigned to it stays on it after sync. If you delete a role, its players are not lost — they are automatically moved to player. Homes are never touched at all.
Edit your config freely: the sync logic is built so that nothing disappears.
Your data doesn't get lost
- Homes are never touched during role sync.
- Players on a deleted role are moved to
player, not lost. - Migration runs in a single transaction: all or nothing.
Why this matters
Previously, getting a lightweight teleport mod meant switching to Paper or Purpur — just for /tp, /tpa, and /home. That's no longer necessary.
Mikasa-tp-mod solves this on pure Fabric.
Commands Overview
| Command | Purpose |
|---|---|
/tphelp |
Shows the full command list (private message to the player) |
/tp <player> |
Teleport yourself to another online player (role-gated) |
/tpa <player> |
Send a teleport request to another player |
/tpaccept |
Accept an incoming TPA request |
/tpdeny |
Deny an incoming TPA request |
/tpacancel |
Cancel your outgoing TPA request or warmup |
/home set <name> |
Save a named home at your current position |
/home <name> |
Teleport to one of your saved homes |
/home del <name> |
Delete a saved home |
/home list |
List all of your homes |
TPA includes a short stand-still warmup with an on-screen countdown. Moving during warmup cancels the teleport.
All /home subcommands share the permission key home.
Dependencies
- Minecraft 26.3 — required
- IMPORTANT: Fabric Loader 0.19.5 or later — older loader versions (for example 0.19.3) are not supported
- Fabric API for Minecraft 26.3 — required
- Java 25+ — required
Optional (not required to run the mod):
- PostgreSQL or MySQL server — only if you enable database storage in the shared
configdatabase.json
Database JDBC drivers are already bundled in the mod jar. Without a database, the mod uses JSON storage automatically.
Configuration (created on first launch)
On the first server start, the mod automatically creates its config folders and files:
config/Mikasa-tp-mod/config.json— roles, command permissions, homes (JSON storage), settings such asmax_homes, andsync_to_databaseconfig/Mikasa-tp-mod/README.md— setup notes written next to the configsconfig/Mikasa-mods-general/database/configdatabase.json— optional shared database connection settings for Mikasa mods (disabled by default)
You can edit these files to configure permissions, home limits, and optional database sync. No manual file creation is needed before the first run.
Install
- Install Fabric Loader for Minecraft 26.3 on your server (IMPORTANT: use 0.19.5+).
- Put this mod and Fabric API into the server
modsfolder. - Start the server once so config files are generated.
- Edit configs if needed, then use
/tphelpin-game.
Note: This is a server-side mod. Players do not need it on the client.
Jar name: Mikasa-tp-mod-fabric-26.3-2.0.jar
License
MIT — Author: Mikasa
Storage modes
| Mode | When | Roles / settings / homes |
|---|---|---|
| JSON | DB disabled, misconfigured, or unreachable | config.json |
| Database | shared configdatabase.json usable and connect succeeds |
SQL tables |
Startup prefers the database when connected. If a DB query fails at runtime, many paths fall back to JSON.
Launch log examples:
launch config: database (postgres|mysql)launch config: file
config/Mikasa-mods-general/database/configdatabase.json
Shared across Mikasa mods. Created empty / disabled by default. Example:
{
"type": "postgres",
"enabled": true,
"host": "127.0.0.1",
"port": 5432,
"database": "minecraft",
"username": "minecraft",
"password": "secret"
}
MySQL / MariaDB:
{
"type": "mysql",
"enabled": true,
"host": "127.0.0.1",
"port": 3306,
"database": "minecraft",
"username": "minecraft",
"password": "secret"
}
| Field | Notes |
|---|---|
type |
postgres / postgresql / pg → PostgreSQL; mysql / mariadb / sql → MySQL |
enabled |
Must be true to connect |
host, database, username |
Required when enabled |
port |
Defaults: Postgres 5432, MySQL 3306 |
password |
Connection password |
JDBC drivers (PostgreSQL, MySQL) and HikariCP are bundled in the mod jar. You do not add extra jars for DB drivers.
On successful connect the mod runs CREATE TABLE IF NOT EXISTS ... and seeds defaults (player role, max_homes = 5).
Database structure
Tables are created automatically. Logical schema:
roles
| Column | Type (concept) | Description |
|---|---|---|
name |
text / varchar PK | Role id, e.g. player, moderator, admin |
Seeded: player.
commands
| Column | Type | Description |
|---|---|---|
name |
text / varchar PK | Permission / command key, e.g. tp, home |
role_permissions
| Column | Type | Description |
|---|---|---|
role_name |
FK → roles |
Role |
command_name |
FK → commands |
Command key |
allowed |
boolean | true = allowed, false = denied |
| PK | (role_name, command_name) |
If there is no row for a role+command, the mod treats it as denied.
players
| Column | Type | Description |
|---|---|---|
uuid |
UUID / CHAR(36) PK | Player UUID |
name |
text / varchar | Last known name (optional metadata) |
role_name |
FK → roles, default player |
Assigned role |
Important: this mod reads player roles for permission checks. It does not create or update player rows during normal gameplay (no auto-register on join). You assign roles yourself (SQL, admin tool, or JSON — see below).
settings
| Column | Type | Description |
|---|---|---|
key |
text / varchar PK | Setting name |
value |
text / varchar | String value |
Known setting used by the mod:
| Key | Default | Meaning |
|---|---|---|
max_homes |
5 |
Max homes per player for /home set (new homes only) |
homes
| Column | Type | Description |
|---|---|---|
player_uuid |
UUID / CHAR(36) | Owner |
home_name |
text / varchar | Home id |
world |
text / varchar | Dimension id (e.g. minecraft:overworld) |
x, y, z |
double | Position |
yaw, pitch |
float | Look direction |
| PK | (player_uuid, home_name) |
Homes are upserted on /home set and deleted on /home del.
PostgreSQL reference DDL
CREATE TABLE IF NOT EXISTS roles (
name TEXT PRIMARY KEY
);
CREATE TABLE IF NOT EXISTS commands (
name TEXT PRIMARY KEY
);
CREATE TABLE IF NOT EXISTS role_permissions (
role_name TEXT NOT NULL REFERENCES roles(name) ON DELETE CASCADE,
command_name TEXT NOT NULL REFERENCES commands(name) ON DELETE CASCADE,
allowed BOOLEAN NOT NULL DEFAULT FALSE,
PRIMARY KEY (role_name, command_name)
);
CREATE TABLE IF NOT EXISTS players (
uuid UUID PRIMARY KEY,
name TEXT,
role_name TEXT NOT NULL DEFAULT 'player' REFERENCES roles(name)
);
CREATE TABLE IF NOT EXISTS settings (
key TEXT PRIMARY KEY,
value TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS homes (
player_uuid UUID NOT NULL,
home_name TEXT NOT NULL,
world TEXT NOT NULL,
x DOUBLE PRECISION NOT NULL,
y DOUBLE PRECISION NOT NULL,
z DOUBLE PRECISION NOT NULL,
yaw REAL NOT NULL,
pitch REAL NOT NULL,
PRIMARY KEY (player_uuid, home_name)
);
INSERT INTO roles (name) VALUES ('player') ON CONFLICT DO NOTHING;
INSERT INTO settings (key, value) VALUES ('max_homes', '5') ON CONFLICT DO NOTHING;
MySQL uses compatible types (VARCHAR, CHAR(36), DOUBLE, FLOAT, etc.) with the same table/column names.
config.json structure
{
"sync_to_database": false,
"settings": {
"max_homes": 5
},
"roles": {
"player": {
"commands": {
"tphelp": true,
"tp": false,
"home": true,
"tpa": true,
"tpaccept": true,
"tpdeny": true,
"tpacancel": true
}
},
"moderator": {
"commands": {
"tphelp": true,
"tp": true,
"home": true,
"tpa": true,
"tpaccept": true,
"tpdeny": true,
"tpacancel": true
}
},
"admin": {
"commands": {
"tphelp": true,
"tp": true,
"home": true,
"tpa": true,
"tpaccept": true,
"tpdeny": true,
"tpacancel": true
}
}
},
"players": {},
"homes": {}
}
Default permission matrix
| Command | player |
moderator |
admin |
|---|---|---|---|
tphelp |
yes | yes | yes |
tp |
no | yes | yes |
home (set / <name> / del / list) |
yes | yes | yes |
tpa / tpaccept / tpdeny / tpacancel |
yes | yes | yes |
Players block (JSON mode)
"players": {
"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx": {
"name": "Steve",
"role": "moderator"
}
}
Missing player entry → treated as role player.
Homes block (JSON mode)
"homes": {
"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx": {
"spawn": {
"world": "minecraft:overworld",
"x": 0.0,
"y": 64.0,
"z": 0.0,
"yaw": 0.0,
"pitch": 0.0
}
}
}
How roles work
Resolution order
- Look up the player's role (
playerstable if DB connected, elseconfig.json→players). - If unknown / missing → role
player. - Check permission for that role + command key.
- Missing permission entry → denied.
Only players can use these commands (console is rejected by the permission gate).
Creating / adding a role (JSON)
- Open
config/Mikasa-tp-mod/config.json. - Under
roles, add a new object, for example:
"vip": {
"commands": {
"tphelp": true,
"tp": true,
"home": true,
"tpa": true,
"tpaccept": true,
"tpdeny": true,
"tpacancel": true
}
}
- Assign a player to that role in
players(JSON) or in theplayersSQL table (DB mode). - Restart is not always required for JSON edits depending on when the file is reloaded; safest is restart the server after role edits.
- If you use a database and want SQL tables to match this file, use
sync_to_database(next section).
Creating / adding a role (SQL, manual)
INSERT INTO roles (name) VALUES ('vip')
ON CONFLICT DO NOTHING;
INSERT INTO commands (name) VALUES
('tphelp'), ('tp'), ('home'),
('tpa'), ('tpaccept'), ('tpdeny'), ('tpacancel')
ON CONFLICT DO NOTHING;
INSERT INTO role_permissions (role_name, command_name, allowed) VALUES
('vip', 'tphelp', TRUE),
('vip', 'tp', TRUE),
('vip', 'home', TRUE),
('vip', 'tpa', TRUE),
('vip', 'tpaccept', TRUE),
('vip', 'tpdeny', TRUE),
('vip', 'tpacancel', TRUE)
ON CONFLICT (role_name, command_name) DO UPDATE SET allowed = EXCLUDED.allowed;
Assigning a role to a player
JSON:
"players": {
"uuid-here": { "name": "Steve", "role": "vip" }
}
SQL:
INSERT INTO players (uuid, name, role_name)
VALUES ('xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', 'Steve', 'vip')
ON CONFLICT (uuid) DO UPDATE
SET name = EXCLUDED.name, role_name = EXCLUDED.role_name;
Remember: the mod does not auto-create players rows on join.
sync_to_database — how overwrite / rewrite works
This is the built-in one-shot sync. You do not need an external Python script for normal use.
When it runs
At server startup, after a successful DB connection:
- If
sync_to_databaseisfalse→ nothing happens. - If
truebut DB is not connected → sync is skipped; the flag staystrue(retry next start). - If
trueand DB is connected → sync runs inside a transaction, then the mod setssync_to_databaseback tofalseand savesconfig.json.
How to use it
- Edit
rolesandsettingsinconfig.jsonthe way you want the database to look. - Ensure shared
config/Mikasa-mods-general/database/configdatabase.jsonis enabled and correct. - Set
"sync_to_database": true. - Restart the server.
- Check logs for sync success; flag should return to
false.
What gets written / overwritten
From config.json into the database:
| Data | Action |
|---|---|
Roles listed under roles |
Upserted into roles |
Role player |
Always ensured to exist |
| Command keys found in role maps | Upserted into commands |
Every role × command allowed flag |
Upserted into role_permissions |
settings (e.g. max_homes) |
Upserted into settings |
| Roles / commands / permissions not present in config | Pruned (deleted) from DB |
What is preserved
| Data | Behavior |
|---|---|
homes table |
Never touched by sync |
players assignments |
Not rewritten from JSON players during sync |
| Players on a deleted role | Moved to role player before that role is removed |
Role player |
Never deleted by prune |
Sync order (single transaction)
- Ensure
playerrole - Upsert desired roles
- Upsert desired commands
- Upsert permission rows
- Delete stale permissions
- Delete stale commands
- Delete stale roles (after moving affected players to
player) - Upsert settings
- Commit
- Set
sync_to_database = falseand save JSON
On failure: rollback, flag remains true, error is logged.
Warning
Sync replaces the database role/permission/settings picture with whatever is in config.json. Old roles that you removed from JSON are deleted from SQL (with players on those roles demoted to player). Homes stay intact.
Optional external sync (shared-db)
There is a separate folder mods/shared-db with Postgres helpers (schema.sql, roles.json, sync_roles.py). Behavior is similar (upsert + prune roles/permissions/settings; do not wipe homes).
For this mod, prefer sync_to_database in config.json. The Python tool is optional / shared tooling, not required to run Mikasa-tp-mod.
Homes details
- Limit:
settings.max_homes(JSON or DB). - Enforced when creating a new home name; updating an existing name does not consume another slot.
- World is stored as a dimension id string.
- With DB connected, homes live in the
homestable; otherwise inconfig.json→homes.
Dependencies (summary)
| Dependency | Required? |
|---|---|
| Minecraft 26.3 | Yes |
| Fabric Loader 0.19.5+ (IMPORTANT) | Yes |
| Fabric API | Yes |
| Java 25+ | Yes |
| PostgreSQL / MySQL server | No (optional storage) |


