promotional bannermobile promotional banner

MC Personas

Single Account, multiple characters

Personas

Extra inventories that keep their own loot. Step into a persona and you are holding what it carries; step out and your own inventory is back where you left it.

Carrying a second bag of items without a second body is awkward: ender chests need a block and hold one stack, shulker boxes are bulky, and a chest at home is a walk away. Personas gives you a full inventory per persona, stored on disk and remembered across restarts.

A persona is just an inventory. It has no body — no entity, no position, no health, no hunger, no advancements. Nothing about it is ever in the world, so nothing about it is ever drawn, and no part of it can make the game unplayable.

Requirements

Minecraft 1.21.1
Loaders Fabric (Loader + Fabric API) or NeoForge 21.1.235+
Java 21
Side Client or Server / Client & Server

Getting started

  1. Install (see Installation) and join.
  2. /persona create — you now have a persona. It starts empty.
  3. Open your inventory. The tab strip runs along the top edge of the panel: a narrow +, then one tab per persona in index order. There is no tab for your own inventory.
  4. Click any tab to step into that persona's inventory; click the one you are inside to step back out.

The strip is drawn only once the server has sent your list, and only when you have at least one persona — a lone create button is not worth the row, so /persona create is how the first one is made.

Installation

Every jar below is universal — the same file works on both Fabric and NeoForge (it holds the loader-specific builds inside and each loader loads only its own copy).

It is best to use the bundle. mcp-bundle-all-<version>-universal-<mc>.jar is everything in one file — drop it in mods/ and you are done. mcp-bundle-personas is the same idea under the gameplay mod's own name.

But if you want separate mods, here are the correct combinations:

You want Install these jars
The gameplay mod, split out mcp-api + mcp-personas
Everything mcp-bundle-all (or both jars)
  • The gameplay mod (personas) needs the API jar (mcp-api-<version>-universal-<mc>.jar). When installing the mods individually, install the API jar too.
  • Never mix a bundle with individual jars — the same mods would load twice.

Install Fabric Loader + Fabric API, or NeoForge 21.1.235+, for Minecraft 1.21.1 first.

The universal jars are on CurseForge/Modrinth. If you want a single-loader build (fabric-* / neoforge-*), grab it from GitHub Releases.

Each module is versioned on its own: a release only bumps the mod that changed, so the API and the gameplay mod can be updated independently. Every GitHub release lists all current jars together, so you can always grab a matching set from one place.

Commands

Command Default op What it does
/persona create [name] 2 Creates a persona with an empty inventory. Names are unique per player, ignoring case.
/persona list 0 Your personas, and which one you are inside.
/persona remove <index> 2 Deletes a persona and its file.
/persona enter [index|name] 0 Switches to that persona's inventory. With one persona you can leave the target off.
/persona rename <index|name> <new name> 2 Changes a persona's name. Its number and its file do not move.
/persona exit 0 Switches back to your own inventory.
/persona rollback <index|placeholder> 2 Puts a stored inventory back to its newest backup. Refused while you are inside the persona in question.
/persona selftest 2 Creates personas for a synthetic owner on disk and prints PASS/FAIL per check.

Op levels are configurable per command and clamped to 0–4, where 0 is everyone (see Configuration). Everything that acts only on the caller's own roster defaults to 0; selftest and rollback default to 2, because both are about the server's own state rather than the caller's.

Every command sends the caller a refreshed persona list afterwards, so the strip reflects the change rather than what was sent when you logged in. enter and exit do nothing quietly when there is nothing to do — no personas to step into, or not inside one — rather than reporting a state you did not ask about. Naming a persona that does not exist is still an error, because that one is a mistake worth reporting.

The confirmation a command produces goes to the player who ran it and to nobody else — never broadcast — and it is off by default. The server owner turns it on with showFeedback, and there is no client-side switch, so a player cannot opt out of what the server chose to say. A refusal is not a confirmation, so a command that cannot do what you asked still tells you why.

The tab strip

Open your inventory and the strip is along the top edge: a narrow +, then one tab per persona in index order. Clicking the persona you are inside steps you back out; clicking any other steps you out of the current one and into that one.

Right-clicking a tab asks before deleting — unless the server would refuse the delete, which it does for the persona you are inside and, under the default deleteBehaviour, for one that still holds anything. Those two run straight away instead, so the refusal is what you see rather than a confirmation the delete would fail behind. Shift-clicking a tab opens a rename screen for it, without moving you.

Clicking a tab runs the matching command (/persona create, /persona enter <index|name>, /persona exit, /persona remove <index>, /persona rename <index|name> <new name>) — the same request, with the same permission check and the same parsing, as typing it. There is no second way into the server for the UI to fall out of step with, and the server refuses anything the player was not entitled to.

enter and rename take a number or a name: a bare number is an index, anything else is a name, and a name with a space in it has to be quoted.

The strip shares the panel's width and the tabs shrink as personas are added, so a tab shows its persona's name while that fits and its index when it does not — the full name is always in the tooltip.

Places and respawning

A persona remembers two things about where its player is, and they are separate settings because they are separate things.

With rememberLocation on, a persona keeps the spot you were last standing in it. Stepping into one puts you back on that spot and stepping out puts you where you came from, so a persona works like a place you can return to rather than a bag you carry. A persona that has never been left has no spot yet, so the first entry leaves you where you are. If a persona's spot is in a dimension the server no longer has, stepping in or out is logged and skipped rather than refused — being stranded inside a persona is worse than being in the wrong place.

With rememberRespawnPoint on, a bed or respawn anchor you use from inside a persona belongs to that persona. Dying there brings you back to it, and you are still holding the persona when you do. A persona with no spawn point of its own respawns at the world spawn, which is what vanilla does for a player who has set none. Your own bed and respawn anchors are never written to while you are inside a persona, and survive dying in one.

Items on death are vanilla in every case: the persona's own stacks drop where you died, unless the keep-inventory rule says otherwise. Your own inventory is not involved — it comes back when you step out, as it does for any other step out. Note that a command which hands you an item while you are inside a persona, /give included, gives it to the persona, because the persona's stacks are the ones you are holding.

Your health, hunger, experience and advancements are untouched by all of this. You are the same player throughout; only the inventory in your hands changes, and — while rememberLocation is on — where you are standing while you hold it.

Where persona data lives

<world>/playerdata/<ownerUuid>.dat                 you
<world>/playerdata/<ownerUuid>/personas.dat        the roster: which persona indices exist
<world>/playerdata/<ownerUuid>/<personaUuid>.dat   a persona: its inventory

A persona's UUID is derived from you and its index rather than generated, so it survives a restart with nothing to look up. The file is NBT holding one Inventory list tag — the same tag and the same slot layout Player#saveWithoutId writes — so a tool that already reads player data can read a persona's things out of it. It is not a vanilla player file: it carries nothing a player needs beyond that, and feeding one to a vanilla player-data reader would not produce a player.

Alongside the inventory, a persona that has been left records Pos, Rotation and Dimension (where it keeps its player), and one that has been given a bed or respawn anchor records the five Spawn* tags ServerPlayer writes for its own. Those are written only when there is something to record, so a persona that has never been left has neither.

personas.dat is written the first time you join, before you have made anything, so its presence means a roster exists rather than that it has content. An empty one is a legitimate state: the roster is the record of which indices exist, which is what keeps a new persona from being given an index whose file is still on disk.

Deleting a persona leaves its index empty and the next creation takes it; nothing is renumbered and no file is moved, because a persona's file is named after a UUID derived from its index, and the index stays with the persona for life. Nothing is stored in chunk data — a persona is affected by nothing that happens to the ground it was created on.

Configuration

config/personas.json on Fabric, config/personas-server.toml on NeoForge. Both are written on load, so a hand-added file gains any missing keys instead of staying incomplete.

Setting Default What it does
maxPersonas 5 Personas one player may hold. -1 is unlimited, 0 none. Lowering it never removes anything: it only refuses new personas, and a player over the cap can still use and delete the ones they have.
createPermissionLevel 0 Op level needed for /persona create.
listPermissionLevel 0 Op level needed for /persona list.
removePermissionLevel 0 Op level needed for /persona remove.
renamePermissionLevel 0 Op level needed for /persona rename.
enterPermissionLevel 0 Op level needed for /persona enter.
exitPermissionLevel 0 Op level needed for /persona exit.
selftestPermissionLevel 2 Op level needed for /persona selftest.
rollbackPermissionLevel 2 Op level needed for /persona rollback.
showFeedback off Whether a command's confirmation is sent to the player who caused it. Refusals are never gated.
backupCount 1 How many earlier copies are kept of every stored inventory, for /persona rollback. At least 1; each generation is a whole inventory file.
persistPersonaOnLogout off On: a player is put back inside the persona they were in when they logged out. Off: logging out steps them back out.
rememberLocation on A persona remembers where its player was left. Entering one puts you where you last stood in it and stepping out puts you back where you came from; a persona that has never been left has nowhere to send you yet, so the first entry still does not move you.
rememberRespawnPoint on A persona keeps the spawn point its player sets. A bed or respawn anchor used from inside a persona belongs to that persona, and dying in it brings you back there; a persona with no spawn point of its own respawns at the world spawn. Your own bed and anchors are never changed.
deleteBehaviour BLOCK What /persona remove does with a persona that still holds anything. BLOCK refuses the delete, so the contents have to be emptied by hand first; DROP_AT_PLAYER gives every slot back at your feet instead. Either way a player standing inside the persona has to step out before it can be deleted.
debugFeedback off Also copies every confirmation to the server log. Off by default; the engine already logs the state changes themselves, so this is for watching what each player is told. Only meaningful when showFeedback is on, because a message that is never sent is never shown.

Permission levels are clamped to 0–4, where 0 is everyone. maxPersonas is bounded on the low side at -1, so any negative value arrives as -1 and means "unlimited" — a typo'd -5 gets you an uncapped server rather than an error.

There is no client config. The only part of this mod a client can use is the tab strip, and whether a client has the mod at all is not something the server depends on: the mod can be installed on a server alone. A client without it plays with the /persona commands, has no strip, and sees no confirmations — the server asks whether a client can receive the list before sending it. Single-player is unaffected, because there the client is also the server.

For other mods

Depend on the API module and use the engine directly:

PersonaManager manager = PersonaManager.get(server);
List<Persona> personas = manager.personasOf(player.getUUID());

PersonaEvents.addEnterCheck((player, persona) -> true);   // veto stepping into a persona
PersonaEvents.addExited((player, persona) -> { ... });    // observe a switch back
PersonaEvents.post(server, "mymod:event", payload);       // your own channel

Persona is the handle: id(), owner(), index(), uuid(), name(), describe(), inventory(), save(), delete(). Listeners are registered the same way on both loaders and are called on the server thread; a listener that throws propagates rather than being swallowed.

There is no death event, because a persona has no body. There is no spawn event either: a persona comes into existence by being read off disk, which is not a moment worth listening to. addCreate fires when a player asks for a new one.

Seeding a persona from another mod

PersonaManager.create takes an optional seeder that fills the new inventory before it is saved:

PersonaManager manager = PersonaManager.get(server);
Persona persona = manager.create(player, "Quarry", inventory -> {
    inventory.setItem(0, new ItemStack(Items.DIAMOND_PICKAXE));
    inventory.setItem(9, new ItemStack(Items.STONE, 64));
});

Two details worth knowing:

  • The seeder runs before the file is read back, and the file wins where they overlap. The seeder fills an empty inventory, then the persona's file is layered on top without clearing it: a slot the file mentions wins, and a slot it does not keeps what the seeder put there. A persona created for the first time has no file, so what the seeder placed is exactly what it holds. That merging is why the seeder is a parameter of create — Inventory#load clears all three compartments before restoring, so seeding and then loading would throw the seed away.
  • Do not seed through PersonaEvents.addCreate instead. It fires after the inventory has been read, so a listener placing items there is overwriting whatever was loaded, and the result is not written anywhere until the next save.
  • The seeder gets a vanilla Inventory, so slots are contiguous: the main inventory is 0–35, armour 36–39 and the offhand 40. Those are Inventory#setItem indices. The 100-based numbering that appears in the saved file is the NBT tag layout, which the engine translates and you never need to touch.

create is refused when the player is at their cap. The cap lives in the engine, so a mod cannot route around it; a refused create throws IllegalStateException carrying the reason, so catch it if your own flow needs to tell the player.

Compatibility

  • Works on both loaders with no extra dependencies beyond Fabric API on Fabric.
  • Server-side installable: the mod works on a dedicated server on its own. The tab strip is client-side, so a client that also has the mod gets it and one that does not simply plays with the commands.
  • Tested on a NeoForge 1.21.1 pack of roughly 470 mods, including Accessories, Nameless Trinkets and Apotheosis. Entering, leaving, dying in and respawning from a persona all behave as documented there.

Known issue. If a player dies in a persona and then dies again as themselves, a mod that taxes the second death's drops — Death and Taxes was the one this was found with — is handed an empty drop list for it, while the items themselves appear on the ground as normal. Entering and leaving any persona clears the condition. The cause has not been established, so treat it as unverified rather than explained.

Structural note. Stepping into a persona used to replace the player's inventory menu with a fresh one, which left any extra slots another mod had added to the inventory screen absent while you were inside. That is no longer how it works: the player's own inventory and its menu are kept and only their contents change, so a mod's extra slots behave inside a persona exactly as they do outside one, and anything that reads the inventory's owner sees the player rather than a stand-in. Nothing is declared in neoforge.mods.toml either way, so the game loads any combination without warning.

License

This project's own source code is All Rights Reserved — see LICENSE.

Credits & third-party notices

  • Not an official Minecraft product. Not approved by or associated with Mojang or Microsoft. Built on Fabric Loader / Fabric API (Apache-2.0) and NeoForge (LGPL-2.1); the official Mojang mappings are used for development and are not redistributed.

Author

Retired Roca

MC Personas Team

profile avatar
  • 5
    Projects
  • 795
    Downloads

More from RetiredRocaView all