Replay Manager
This is the documentation for the Replay Manager. It is used to manage replays in the Mint Client. Either playing or stopping a replay.
The ReplayManager is a class that is used to manage replays in the Mint Client.
It is located in the com.originmint.managers.ReplayManager class.
The ReplayManager has the following methods:
startPlaying: Starts the replay with the ID provided.stopPlaying: Stops the current replay.pausePlaying: Pauses the current replay.resumePlaying: Resumes the current replay.outOfSync: Called when the replay goes out of sync. You can use this to simulate the replay going out of sync.isPlaying: Returns if the replay is currently playing.queueReplay: Plays that replay next instead of repeating the current one. Returnsfalseif the ID is not one of your replays, or if that replay is not loaded.queuedReplay: Returns the queued replay’s ID, or""when nothing is queued.clearQueuedReplay: Forgets the queued replay, so the current one keeps looping.isLoaded: Whether that replay’s payload is in memory, which is what playing and queueing need.load: Downloads the payload and waits for it.unload: Frees the payload again.importReplay: Claims a replay that is not on your account yet.ensureLoaded: Imports what is missing, loads what is not loaded, and answers whether the replay can be played now.ensureLoadedAsync: The same, off the client thread, answering through a callback.getInstance: Returns the instance of theReplayManager.
This can be useful to start, stop, pause, or resume the replay.
ReplayManager.getInstance().startPlaying("replay-id");
ReplayManager.getInstance().stopPlaying();
ReplayManager.getInstance().pausePlaying();
ReplayManager.getInstance().resumePlaying();
ReplayManager.getInstance().outOfSync();
if (ReplayManager.getInstance().isPlaying()) {
// Do something
}
Queueing the next replay
startPlaying stops whatever is running and starts something else. queueReplay does not: it says
which replay should play instead of the next repeat of the current one, and can be called at any
time, including while a replay is playing.
The switch happens at the moment the loop would have started the same clip again — after the current run has finished and before the next one begins. That is the only point where changing clips is free, so the queued replay starts as an ordinary play: position and camera locks, drift syncs, the entity, area and inventory checks and the smooth camera pan onto its first look all arm against the new clip, exactly as they would if you had played it yourself. Stopping and starting to change clips skips all of that in between.
The current run is never interrupted, and looping continues afterwards with the new clip in place — so a chain of replays is a queue call per clip, not a stop-and-start each time.
The loop count carries across the switch. LOOP_AMOUNT is a budget for the loop rather than for a
clip, so a queued replay continues the count instead of starting a fresh one: ask for three runs,
queue another clip during the first, and you get one run of the first clip and two of the queued one.
Use a LOOP_AMOUNT of 0 for a chain that keeps going.
// While "warmup" is playing, line up the run that follows it.
ReplayManager.getInstance().queueReplay("main-run-id");
// The queued clip takes over at the next loop, then loops in its place.
String next = ReplayManager.getInstance().queuedReplay(); // "main-run-id" until it is consumed
ReplayManager.getInstance().clearQueuedReplay(); // changed your mind
Only a loaded replay can be queued. queueReplay does not download: it refuses a replay whose
payload is not in memory, exactly as starting one does, so a queue is always something that can
actually play. Load it first — with ensureLoaded below, from the Replays tab, or by having played
it. Queueing the replay that is already playing does nothing, and an ID that is not on your account
is refused.
A queue outlives a stop: it is consumed by the next play, whether that play comes from the loop, the
Play key, or startPlaying. Call clearQueuedReplay if you want the current clip back.
Making sure a replay is there
Playing and queueing both need the replay’s payload in memory, and the payload only arrives when something asks for it. These five calls are that “something”, so a plugin no longer has to tell the user to go and open the Replays tab first.
ReplayManager replay = ReplayManager.getInstance();
if (!replay.isLoaded("replay-id")) {
replay.load("replay-id"); // downloads it, waits, true when it is loaded
}
replay.importReplay("someone-elses-id"); // claims it for this account, does not load it
replay.unload("replay-id"); // frees the payload again
// The one that does all of it: import if this account does not have it, load if it is not
// loaded, and answer whether it can play now.
if (replay.ensureLoaded("replay-id")) {
replay.startPlaying("replay-id");
}
isLoaded is instant and free to call as often as you like. The other four block the calling
thread while they talk to the API — one request for a load, up to three for an ensureLoaded that
has to import first. A replay that is already loaded makes ensureLoaded return true without a
request, so guarding with isLoaded first buys nothing.
Without the wait
ensureLoadedAsync does the same work on a worker thread and answers through a callback, so the
game keeps running while the replay is fetched. The callback runs on the client thread, at the
start of a tick, which means it can start the replay, draw, or touch Minecraft directly.
@Override
public void onEnable() {
PluginManager.getInstance().PLUGIN_EVENT_BUS.register(this);
ReplayManager.getInstance().ensureLoadedAsync("replay-id", loaded -> {
if (!loaded) {
LoggingManager.getInstance().log("that replay is unavailable", LoggingManager.LOG_LEVEL.WARNING);
return;
}
ReplayManager.getInstance().startPlaying("replay-id");
});
}
The callback is ReplayManager.LoadCallback, a single void onResult(boolean loaded) — a lambda
does. Pass null to fetch without being told.
It fires exactly once, and always later — never inside the call itself, even for a replay that was already loaded, so there is only one ordering to write against. Asking again for the same replay while the first request is still out joins that request instead of starting a second, so calling it from a tick handler costs you callbacks rather than downloads. It does not retry a failed fetch by itself.
unload refuses the selected replay while something is playing or about to. importReplay is
refused for free accounts, and adds the replay to the list without loading it — ensureLoaded is
the one that does both halves.