Astral Realms Documentation Help

Adapter Interfaces

An adapter is a self-contained handler for one type of player data. AstralSync calls all registered adapters in sequence during save and load operations. Each adapter is responsible for:

  1. Capturing current player state into a data object

  2. Serializing that object to a binary stream

  3. Deserializing it back from a binary stream

  4. Applying it to the player

SnapshotAdapter\<T\>

com.astralrealms.sync.adapter.SnapshotAdapter

The base interface all adapters must implement.

public interface SnapshotAdapter<T> { Key key(); T create(Player player); T update(Player player, T object); void apply(Player player, T object); T deserialize(DataHolder holder, BinaryMessage message); void serialize(DataHolder holder, T object, BinaryMessage message); }

Method Reference

key()

Key key()

Returns the unique namespaced key identifying this adapter. Must be unique across all registered adapters.

Use a namespace that matches your plugin name:

@Override public Key key() { return Key.key("myplugin", "stats"); }

create(Player)

T create(Player player)

Called when a player joins for the first time and no snapshot exists yet. Returns the default data instance. This is also used to initialize the holder entry if the adapter was not present in an older snapshot.

@Override public MyStats create(Player player) { return new MyStats(); // sensible defaults }

update(Player, T)

T update(Player player, T object)

Called just before serialization. Updates object to reflect the player's current state and returns it. You may mutate object in place and return it, or return a new instance.

@Override public MyStats update(Player player, MyStats stats) { stats.setLastSeen(System.currentTimeMillis()); return stats; }

apply(Player, T)

void apply(Player player, T object)

Called on the main server thread after deserialization. Applies the loaded data to the player.

@Override public void apply(Player player, MyStats stats) { player.setLevel(stats.getLevel()); }

deserialize(DataHolder, BinaryMessage)

T deserialize(DataHolder holder, BinaryMessage message)

Reads a data object from the binary stream. Called during the load operation. If deserialization fails, AstralSync calls create(player) instead and logs a warning — this ensures a corrupted chunk does not prevent the rest of the snapshot from loading.

@Override public MyStats deserialize(DataHolder holder, BinaryMessage message) { MyStats stats = new MyStats(); stats.setKills(message.readInt()); stats.setDeaths(message.readInt()); return stats; }

serialize(DataHolder, T, BinaryMessage)

void serialize(DataHolder holder, T object, BinaryMessage message)

Writes the data object to the binary stream. Called during the save operation. A serialization failure aborts the entire snapshot save.

@Override public void serialize(DataHolder holder, MyStats object, BinaryMessage message) { message.writeInt(object.getKills()); message.writeInt(object.getDeaths()); }

VersionedSnapshotAdapter\<T extends VersionedData\>

com.astralrealms.sync.adapter.VersionedSnapshotAdapter

Extends SnapshotAdapter<T> and VersionedData. Use this when your data format may change across plugin versions.

public interface VersionedSnapshotAdapter<T extends VersionedData> extends SnapshotAdapter<T>, VersionedData { // inherits int version() from VersionedData }

Your data class must implement VersionedData:

public interface VersionedData { int version(); }

How versioning works

AdapterContainer stores all registered versions of an adapter under the same key. When a snapshot is written, the current version number is stored alongside the data. When deserializing, the stored version is read first, and the matching adapter version is used to read the data.

This lets you add a v2 adapter while still being able to read old v1 snapshots from the database.

Example

public class MyStatsAdapterV2 implements VersionedSnapshotAdapter<MyStatsV2> { @Override public int version() { return 2; } @Override public Key key() { return Key.key("myplugin", "stats"); } // ... implement remaining SnapshotAdapter methods for MyStatsV2 }

Register both versions in onEnable():

SyncAPI.registerAdapter(new MyStatsAdapterV1()); // handles old snapshots SyncAPI.registerAdapter(new MyStatsAdapterV2()); // used for new snapshots

UnloadableSnapshotAdapter\<T\>

com.astralrealms.sync.adapter.UnloadableSnapshotAdapter

Extends SnapshotAdapter<T>. Use this when your adapter allocates resources that must be released when the player fully leaves.

public interface UnloadableSnapshotAdapter<T> extends SnapshotAdapter<T> { void unload(DataHolder holder, Player player, T object); }

unload(DataHolder, Player, T)

Called automatically by AstralSync after a successful save whose SnapshotCause.shouldUnload() returns true (DISCONNECT, SERVER_SHUTDOWN).

@Override public void unload(DataHolder holder, Player player, MyData data) { data.clearCache(); MyRegistry.remove(player.getUniqueId()); }

You do not need to check shouldUnload() yourself — AstralSync handles this internally.

AdapterContainer

com.astralrealms.sync.container.AdapterContainer

Singleton registry that manages all registered adapters.

Instance: AdapterContainer.INSTANCE

Methods

Method

Description

registerAdapter(SnapshotAdapter<?>)

Register an adapter (prefer SyncAPI.registerAdapter())

unregisterAdapter(Key)

Remove all versions of an adapter by key

findAdapter(Key)

Find the latest version of an adapter

findAdapter(Key, int version)

Find a specific version of an adapter

latestAdapters()

Map of key → latest adapter version

adapters()

Map of key → all versions map

24 April 2026