mirror of
https://github.com/WiIIiam278/HuskSync.git
synced 2026-01-03 14:12:17 +00:00
v3.0: New modular, more compatible data format, new API, better UX (#160)
* Start work on v3 * More work on task scheduling * Add comment to notification display slot * Synchronise branches * Use new HuskHomes-style task system * Bump to 2.3 * Remove HuskSyncInitializationException.java * Optimise database for MariaDB * Update libraries, move some around * Tweak command registration * Remove dummyhusksync * Fixup core synchronisation logic to use new task system * Implement new event dispatch subsystem * Remove last remaining future calls * Remove `Event#fire()` * Refactor startup process * New command subsystem, more initialization improvements, locale fixes * Update docs, tweak command perms * Reduce task number during data setting * add todo * Start work on data format / serialization refactor * More work on Bukkit impl * More serialization work * Fixes to serialization, data preview system * Start legacy conversion skeleton * Handle setting empty inventories * Start on-the-fly legacy conversion work * Add advancement conversion * Rewrite advancement get / apply logic * Start work on locked map persistence * More map persistence work * More work on map serialization * Move around persistence logic * Add testing suite * Fix item synchronisation * Finalize more reliable locked map persistence * Remove deprecated method call * remove sync feature enum * Fix held item slot syncing * Make data types modular and API-extensible * Remove some excessive debugging, minor refactor * Fixup date formatting, improve menu UIs * Finish up legacy data converting * Null safety in item stack serializaiton * Fix relocation of nbtapi, update dumping docs * Add v1/MPDB Migrators back in * Fix pinning/unpinning data not working * Consumer instead of Function for editing data * Show file size in DataSnapshotOverview * Fix getIdentifier always returning empty * Re-add items and inventory GUI commands * Improve config file, fixup data restoration * Add min time between backups (more useful backups!) * More work on backups * Fixup backup rotation frequency * Remove stdout debug print in `#getEventPriority` * Improve sync complete locale logic, fix synchronization spelling * Remove `static` on exception * Use dedicated thread for Redis, properly unsubscribe * Refactor `player` package -> `user` * `PlayerDataHolder` -> `UserDataHolder` * Make `StatisticsMap` public, but `@ApiStatus.Internal` * Suppress unused warnings on `Data` * Add option to disable Plan hook * Decompress legacy data before converting * Decompress bytes in fromBytes * Check permission node before serving TAB suggestions * Actually convert legacy item stack data * Fix syntax errors * Minor method refactor in items command * Fixup case-sensitive parsing in HuskSync command * Start API work * More work on API, fix potion effects * Fix cross-server, config formatting for auto-pinned issue * Fix confusion with UserData command, update docs images * Update commands docs * More docs updating * Fix sync feature enabled/disabled checking logic * Fix `#isCustom()` * Enable persistent_data syncing by default * docs: update Sync-Features config snippet * docs: correct typo in Sync Features * More API work * bukkit: slightly optimized schedulers * More API work, various refactorings * docs: Start new API docs * bump dependencies * Add some basic unit tests * docs: Correct typos * More docs work, annotate DB methods as `@Blocking` * Encapsulate `RedisMessage`, minor optimisations * api: Simplify `#getCurrentData` * api: Simplify `editCurrentData`, using `ThrowingConsumers` for better error handling * docs: More Data Snapshot API documenting * docs: add TOC to Data Snapshot API page * bukkit: Make data types extend BukkitData * Move where custom data is stored, finish up Custom Data API docs * Optimise imports * Fix `data_manager_advancements_preview_remaining` locale * Fix advancement and playtime previews * Fix potion effect deserialization * Make snapshot_backup_frequency default to 4, more error handling/logging * docs: Add ToC to Custom Data API * docs: Minor legacy API tweaks * Remove some unneeded catch logic * Suppress a few warnings * Fix Effect constructor being supplied in wrong order
This commit is contained in:
@@ -1,157 +0,0 @@
|
||||
/*
|
||||
* This file is part of HuskSync, licensed under the Apache License 2.0.
|
||||
*
|
||||
* Copyright (c) William278 <will27528@gmail.com>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.william278.husksync.api;
|
||||
|
||||
import net.william278.husksync.HuskSync;
|
||||
import net.william278.husksync.data.DataSaveCause;
|
||||
import net.william278.husksync.data.UserData;
|
||||
import net.william278.husksync.data.UserDataSnapshot;
|
||||
import net.william278.husksync.player.OnlineUser;
|
||||
import net.william278.husksync.player.User;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/**
|
||||
* The base implementation of the HuskSync API, containing cross-platform API calls.
|
||||
* </p>
|
||||
* This class should not be used directly, but rather through platform-specific extending API classes.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public abstract class BaseHuskSyncAPI {
|
||||
|
||||
/**
|
||||
* <b>(Internal use only)</b> - Instance of the implementing plugin.
|
||||
*/
|
||||
protected final HuskSync plugin;
|
||||
|
||||
protected BaseHuskSyncAPI(@NotNull HuskSync plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link User} by the given player's account {@link UUID}, if they exist.
|
||||
*
|
||||
* @param uuid the unique id of the player to get the {@link User} instance for
|
||||
* @return future returning the {@link User} instance for the given player's unique id if they exist, otherwise an empty {@link Optional}
|
||||
* @apiNote The player does not have to be online
|
||||
* @since 2.0
|
||||
*/
|
||||
public final CompletableFuture<Optional<User>> getUser(@NotNull UUID uuid) {
|
||||
return plugin.getDatabase().getUser(uuid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link User} by the given player's username (case-insensitive), if they exist.
|
||||
*
|
||||
* @param username the username of the {@link User} instance for
|
||||
* @return future returning the {@link User} instance for the given player's username if they exist,
|
||||
* otherwise an empty {@link Optional}
|
||||
* @apiNote The player does not have to be online, though their username has to be the username
|
||||
* they had when they last joined the server.
|
||||
* @since 2.0
|
||||
*/
|
||||
public final CompletableFuture<Optional<User>> getUser(@NotNull String username) {
|
||||
return plugin.getDatabase().getUserByName(username);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link User}'s current {@link UserData}
|
||||
*
|
||||
* @param user the {@link User} to get the {@link UserData} for
|
||||
* @return future returning the {@link UserData} for the given {@link User} if they exist, otherwise an empty {@link Optional}
|
||||
* @apiNote If the user is not online on the implementing bukkit server,
|
||||
* the {@link UserData} returned will be their last database-saved UserData.
|
||||
* </p>
|
||||
* Because of this, if the user is online on another server on the network,
|
||||
* then the {@link UserData} returned by this method will <i>not necessarily reflective of
|
||||
* their current state</i>
|
||||
* @since 2.0
|
||||
*/
|
||||
public final CompletableFuture<Optional<UserData>> getUserData(@NotNull User user) {
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
if (user instanceof OnlineUser) {
|
||||
return ((OnlineUser) user).getUserData(plugin).join();
|
||||
} else {
|
||||
return plugin.getDatabase().getCurrentUserData(user).join().map(UserDataSnapshot::userData);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link UserData} to the database for the given {@link User}.
|
||||
* </p>
|
||||
* If the user is online and on the same cluster, their data will be updated in game.
|
||||
*
|
||||
* @param user the {@link User} to set the {@link UserData} for
|
||||
* @param userData the {@link UserData} to set for the given {@link User}
|
||||
* @return future returning void when complete
|
||||
* @since 2.0
|
||||
*/
|
||||
public final CompletableFuture<Void> setUserData(@NotNull User user, @NotNull UserData userData) {
|
||||
return CompletableFuture.runAsync(() ->
|
||||
plugin.getDatabase().setUserData(user, userData, DataSaveCause.API)
|
||||
.thenRun(() -> plugin.getRedisManager().sendUserDataUpdate(user, userData).join()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the {@link UserData} of an {@link OnlineUser} to the database
|
||||
*
|
||||
* @param user the {@link OnlineUser} to save the {@link UserData} of
|
||||
* @return future returning void when complete
|
||||
* @since 2.0
|
||||
*/
|
||||
public final CompletableFuture<Void> saveUserData(@NotNull OnlineUser user) {
|
||||
return CompletableFuture.runAsync(() -> user.getUserData(plugin)
|
||||
.thenAccept(optionalUserData -> optionalUserData.ifPresent(
|
||||
userData -> plugin.getDatabase().setUserData(user, userData, DataSaveCause.API).join())));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the saved {@link UserDataSnapshot} records for the given {@link User}
|
||||
*
|
||||
* @param user the {@link User} to get the {@link UserDataSnapshot} for
|
||||
* @return future returning a list {@link UserDataSnapshot} for the given {@link User} if they exist,
|
||||
* otherwise an empty {@link Optional}
|
||||
* @apiNote The length of the list of VersionedUserData will correspond to the configured
|
||||
* {@code max_user_data_records} config option
|
||||
* @since 2.0
|
||||
*/
|
||||
public final CompletableFuture<List<UserDataSnapshot>> getSavedUserData(@NotNull User user) {
|
||||
return CompletableFuture.supplyAsync(() -> plugin.getDatabase().getUserData(user).join());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the JSON string representation of the given {@link UserData}
|
||||
*
|
||||
* @param userData the {@link UserData} to get the JSON string representation of
|
||||
* @param prettyPrint whether to pretty print the JSON string
|
||||
* @return the JSON string representation of the given {@link UserData}
|
||||
* @since 2.0
|
||||
*/
|
||||
@NotNull
|
||||
public final String getUserDataJson(@NotNull UserData userData, boolean prettyPrint) {
|
||||
return plugin.getDataAdapter().toJson(userData, prettyPrint);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,458 @@
|
||||
/*
|
||||
* This file is part of HuskSync, licensed under the Apache License 2.0.
|
||||
*
|
||||
* Copyright (c) William278 <will27528@gmail.com>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.william278.husksync.api;
|
||||
|
||||
import net.william278.desertwell.util.ThrowingConsumer;
|
||||
import net.william278.husksync.HuskSync;
|
||||
import net.william278.husksync.adapter.Adaptable;
|
||||
import net.william278.husksync.data.Data;
|
||||
import net.william278.husksync.data.DataSnapshot;
|
||||
import net.william278.husksync.data.Identifier;
|
||||
import net.william278.husksync.data.Serializer;
|
||||
import net.william278.husksync.user.OnlineUser;
|
||||
import net.william278.husksync.user.User;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/**
|
||||
* The base implementation of the HuskSync API, containing cross-platform API calls.
|
||||
* </p>
|
||||
* This class should not be used directly, but rather through platform-specific extending API classes.
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public abstract class HuskSyncAPI {
|
||||
|
||||
/**
|
||||
* <b>(Internal use only)</b> - Instance of the implementing plugin.
|
||||
*/
|
||||
protected final HuskSync plugin;
|
||||
|
||||
/**
|
||||
* <b>(Internal use only)</b> - Constructor, instantiating the base API class.
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
protected HuskSyncAPI(@NotNull HuskSync plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a {@link User} by their UUID
|
||||
*
|
||||
* @param uuid The UUID of the user to get
|
||||
* @return A future containing the user, or an empty optional if the user doesn't exist
|
||||
* @since 3.0
|
||||
*/
|
||||
@NotNull
|
||||
public CompletableFuture<Optional<User>> getUser(@NotNull UUID uuid) {
|
||||
return plugin.supplyAsync(() -> plugin.getDatabase().getUser(uuid));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a {@link User} by their username
|
||||
*
|
||||
* @param username The username of the user to get
|
||||
* @return A future containing the user, or an empty optional if the user doesn't exist
|
||||
* @since 3.0
|
||||
*/
|
||||
@NotNull
|
||||
public CompletableFuture<Optional<User>> getUser(@NotNull String username) {
|
||||
return plugin.supplyAsync(() -> plugin.getDatabase().getUserByName(username));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new data snapshot of an {@link OnlineUser}'s data.
|
||||
*
|
||||
* @param user The user to create the snapshot of
|
||||
* @return The snapshot of the user's data
|
||||
* @since 3.0
|
||||
*/
|
||||
@NotNull
|
||||
public DataSnapshot.Packed createSnapshot(@NotNull OnlineUser user) {
|
||||
return snapshotBuilder().saveCause(DataSnapshot.SaveCause.API).buildAndPack();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a {@link User}'s current data, as a {@link DataSnapshot.Unpacked}
|
||||
* <p>
|
||||
* If the user is online, this will create a new snapshot of their data with the {@code API} data save cause.
|
||||
* </p>
|
||||
* If the user is offline, this will return the latest snapshot of their data if that exists
|
||||
* (an empty optional will be returned otherwise).
|
||||
*
|
||||
* @param user The user to get the data of
|
||||
* @return A future containing the user's current data, or an empty optional if the user has no data
|
||||
* @since 3.0
|
||||
*/
|
||||
public CompletableFuture<Optional<DataSnapshot.Unpacked>> getCurrentData(@NotNull User user) {
|
||||
return plugin.getRedisManager()
|
||||
.getUserData(UUID.randomUUID(), user)
|
||||
.thenApply(data -> data.or(() -> plugin.getDatabase().getLatestSnapshot(user)))
|
||||
.thenApply(data -> data.map(snapshot -> snapshot.unpack(plugin)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a user's current data.
|
||||
* <p>
|
||||
* This will update the user's data in the database (creating a new snapshot) and send a data update,
|
||||
* updating the user if they are online.
|
||||
*
|
||||
* @param user The user to set the data of
|
||||
* @param data The data to set
|
||||
* @since 3.0
|
||||
*/
|
||||
public void setCurrentData(@NotNull User user, @NotNull DataSnapshot data) {
|
||||
plugin.runAsync(() -> {
|
||||
final DataSnapshot.Packed packed = data instanceof DataSnapshot.Unpacked unpacked
|
||||
? unpacked.pack(plugin) : (DataSnapshot.Packed) data;
|
||||
addSnapshot(user, packed);
|
||||
plugin.getRedisManager().sendUserDataUpdate(user, packed);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit a user's current data.
|
||||
* <p>
|
||||
* This will update the user's data in the database (creating a new snapshot) and send a data update,
|
||||
* updating the user if they are online.
|
||||
*
|
||||
* @param user The user to edit the data of
|
||||
* @param editor The editor function
|
||||
* @since 3.0
|
||||
*/
|
||||
public void editCurrentData(@NotNull User user, @NotNull ThrowingConsumer<DataSnapshot.Unpacked> editor) {
|
||||
getCurrentData(user).thenAccept(optional -> optional.ifPresent(data -> {
|
||||
editor.accept(data);
|
||||
setCurrentData(user, data);
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all saved data snapshots for a user
|
||||
*
|
||||
* @param user The user to get the data snapshots of
|
||||
* @return The user's data snapshots
|
||||
* @since 3.0
|
||||
*/
|
||||
public CompletableFuture<List<DataSnapshot.Unpacked>> getSnapshots(@NotNull User user) {
|
||||
return plugin.supplyAsync(
|
||||
() -> plugin.getDatabase().getAllSnapshots(user).stream()
|
||||
.map(snapshot -> snapshot.unpack(plugin))
|
||||
.toList()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a specific data snapshot for a user
|
||||
*
|
||||
* @param user The user to get the data snapshot of
|
||||
* @param versionId The version ID of the snapshot to get
|
||||
* @return The user's data snapshot, or an empty optional if the user has no data
|
||||
* @see #getSnapshots(User)
|
||||
* @since 3.0
|
||||
*/
|
||||
public CompletableFuture<List<DataSnapshot.Unpacked>> getSnapshot(@NotNull User user, @NotNull UUID versionId) {
|
||||
return plugin.supplyAsync(
|
||||
() -> plugin.getDatabase().getSnapshot(user, versionId).stream()
|
||||
.map(snapshot -> snapshot.unpack(plugin))
|
||||
.toList()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit a data snapshot for a user
|
||||
*
|
||||
* @param user The user to edit the snapshot of
|
||||
* @param versionId The version ID of the snapshot to edit
|
||||
* @param editor The editor function
|
||||
* @since 3.0
|
||||
*/
|
||||
public void editSnapshot(@NotNull User user, @NotNull UUID versionId,
|
||||
@NotNull ThrowingConsumer<DataSnapshot.Unpacked> editor) {
|
||||
plugin.runAsync(() -> plugin.getDatabase().getSnapshot(user, versionId).ifPresent(snapshot -> {
|
||||
final DataSnapshot.Unpacked unpacked = snapshot.unpack(plugin);
|
||||
editor.accept(unpacked);
|
||||
plugin.getDatabase().updateSnapshot(user, unpacked.pack(plugin));
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the latest data snapshot for a user that has been saved in the database.
|
||||
* <p>
|
||||
* Not to be confused with {@link #getCurrentData(User)}, which will return the current data of a user
|
||||
* if they are online (this method will only return their latest <i>saved</i> snapshot).
|
||||
* </p>
|
||||
*
|
||||
* @param user The user to get the latest data snapshot of
|
||||
* @return The user's latest data snapshot, or an empty optional if the user has no data
|
||||
* @since 3.0
|
||||
*/
|
||||
public CompletableFuture<Optional<DataSnapshot.Unpacked>> getLatestSnapshot(@NotNull User user) {
|
||||
return plugin.supplyAsync(
|
||||
() -> plugin.getDatabase().getLatestSnapshot(user).map(snapshot -> snapshot.unpack(plugin))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit the latest data snapshot for a user
|
||||
*
|
||||
* @param user The user to edit the latest snapshot of
|
||||
* @param editor The editor function
|
||||
* @since 3.0
|
||||
*/
|
||||
public void editLatestSnapshot(@NotNull User user, @NotNull ThrowingConsumer<DataSnapshot.Unpacked> editor) {
|
||||
plugin.runAsync(() -> plugin.getDatabase().getLatestSnapshot(user).ifPresent(snapshot -> {
|
||||
final DataSnapshot.Unpacked unpacked = snapshot.unpack(plugin);
|
||||
editor.accept(unpacked);
|
||||
plugin.getDatabase().updateSnapshot(user, unpacked.pack(plugin));
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a data snapshot to the database
|
||||
*
|
||||
* @param user The user to save the data for
|
||||
* @param snapshot The snapshot to save
|
||||
* @since 3.0
|
||||
*/
|
||||
public void addSnapshot(@NotNull User user, @NotNull DataSnapshot snapshot) {
|
||||
plugin.runAsync(() -> plugin.getDatabase().addSnapshot(
|
||||
user, snapshot instanceof DataSnapshot.Unpacked unpacked
|
||||
? unpacked.pack(plugin) : (DataSnapshot.Packed) snapshot
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an <i>existing</i> data snapshot in the database.
|
||||
* Not to be confused with {@link #addSnapshot(User, DataSnapshot)}, which will add a new snapshot if one
|
||||
* snapshot doesn't exist.
|
||||
*
|
||||
* @param user The user to update the snapshot of
|
||||
* @param snapshot The snapshot to update
|
||||
* @since 3.0
|
||||
*/
|
||||
public void updateSnapshot(@NotNull User user, @NotNull DataSnapshot snapshot) {
|
||||
plugin.runAsync(() -> plugin.getDatabase().updateSnapshot(
|
||||
user, snapshot instanceof DataSnapshot.Unpacked unpacked
|
||||
? unpacked.pack(plugin) : (DataSnapshot.Packed) snapshot
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Pin a data snapshot, preventing it from being rotated
|
||||
*
|
||||
* @param user The user to pin the snapshot of
|
||||
* @param snapshotVersion The version ID of the snapshot to pin
|
||||
* @since 3.0
|
||||
*/
|
||||
public void pinSnapshot(@NotNull User user, @NotNull UUID snapshotVersion) {
|
||||
plugin.runAsync(() -> plugin.getDatabase().pinSnapshot(user, snapshotVersion));
|
||||
}
|
||||
|
||||
/**
|
||||
* Unpin a data snapshot, allowing it to be rotated
|
||||
*
|
||||
* @param user The user to unpin the snapshot of
|
||||
* @param snapshotVersion The version ID of the snapshot to unpin
|
||||
* @since 3.0
|
||||
*/
|
||||
public void unpinSnapshot(@NotNull User user, @NotNull UUID snapshotVersion) {
|
||||
plugin.runAsync(() -> plugin.getDatabase().unpinSnapshot(user, snapshotVersion));
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a data snapshot from the database
|
||||
*
|
||||
* @param user The user to delete the snapshot of
|
||||
* @param versionId The version ID of the snapshot to delete
|
||||
* @return A future which will complete with true if the snapshot was deleted, or false if it wasn't
|
||||
* (e.g., if the snapshot didn't exist)
|
||||
* @since 3.0
|
||||
*/
|
||||
public CompletableFuture<Boolean> deleteSnapshot(@NotNull User user, @NotNull UUID versionId) {
|
||||
return plugin.supplyAsync(() -> plugin.getDatabase().deleteSnapshot(user, versionId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a data snapshot from the database
|
||||
*
|
||||
* @param user The user to delete the snapshot of
|
||||
* @param snapshot The snapshot to delete
|
||||
* @return A future which will complete with true if the snapshot was deleted, or false if it wasn't
|
||||
* (e.g., if the snapshot hasn't been saved to the database yet)
|
||||
* @since 3.0
|
||||
*/
|
||||
public CompletableFuture<Boolean> deleteSnapshot(@NotNull User user, @NotNull DataSnapshot snapshot) {
|
||||
return deleteSnapshot(user, snapshot.getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a new custom data type serializer.
|
||||
* <p>
|
||||
* This allows for custom {@link Data} types to be persisted in {@link DataSnapshot}s. To register
|
||||
* a new data type, you must provide a {@link Serializer} for serializing and deserializing the data type
|
||||
* and invoke this method.
|
||||
* </p>
|
||||
* You'll need to do this on every server you wish to sync data between. On servers where the registered
|
||||
* data type is not present, the data will be ignored and snapshots created on that server will not
|
||||
* contain the data.
|
||||
*
|
||||
* @param identifier The identifier of the data type to register.
|
||||
* Create one using {@code Identifier.from(Key.of("your_plugin_name", "key"))}
|
||||
* @param serializer An implementation of {@link Serializer} for serializing and deserializing the {@link Data}
|
||||
* @param <T> A type extending {@link Data}; this will represent the data being held.
|
||||
*/
|
||||
public <T extends Data> void registerDataSerializer(@NotNull Identifier identifier,
|
||||
@NotNull Serializer<T> serializer) {
|
||||
plugin.registerSerializer(identifier, serializer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a {@link DataSnapshot.Unpacked} from a {@link DataSnapshot.Packed}
|
||||
*
|
||||
* @param unpacked The unpacked snapshot
|
||||
* @return The packed snapshot
|
||||
* @since 3.0
|
||||
*/
|
||||
@NotNull
|
||||
public DataSnapshot.Packed packSnapshot(@NotNull DataSnapshot.Unpacked unpacked) {
|
||||
return unpacked.pack(plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a {@link DataSnapshot.Unpacked} from a {@link DataSnapshot.Packed}
|
||||
*
|
||||
* @param packed The packed snapshot
|
||||
* @return The unpacked snapshot
|
||||
* @since 3.0
|
||||
*/
|
||||
@NotNull
|
||||
public DataSnapshot.Unpacked unpackSnapshot(@NotNull DataSnapshot.Packed packed) {
|
||||
return packed.unpack(plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unpack, edit, and repack a data snapshot.
|
||||
* </p>
|
||||
* This won't save the snapshot to the database; it'll just edit the data snapshot in place.
|
||||
*
|
||||
* @param packed The packed snapshot
|
||||
* @param editor An editor function for editing the unpacked snapshot
|
||||
* @return The edited packed snapshot
|
||||
* @since 3.0
|
||||
*/
|
||||
@NotNull
|
||||
public DataSnapshot.Packed editPackedSnapshot(@NotNull DataSnapshot.Packed packed,
|
||||
@NotNull ThrowingConsumer<DataSnapshot.Unpacked> editor) {
|
||||
final DataSnapshot.Unpacked unpacked = packed.unpack(plugin);
|
||||
editor.accept(unpacked);
|
||||
return unpacked.pack(plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the estimated size of a {@link DataSnapshot} in bytes
|
||||
*
|
||||
* @param snapshot The snapshot to get the size of
|
||||
* @return The size of the snapshot in bytes
|
||||
* @since 3.0
|
||||
*/
|
||||
public int getSnapshotFileSize(@NotNull DataSnapshot snapshot) {
|
||||
return (snapshot instanceof DataSnapshot.Packed packed)
|
||||
? packed.getFileSize(plugin)
|
||||
: ((DataSnapshot.Unpacked) snapshot).pack(plugin).getFileSize(plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a builder for creating a new data snapshot
|
||||
*
|
||||
* @return The builder
|
||||
* @since 3.0
|
||||
*/
|
||||
@NotNull
|
||||
public DataSnapshot.Builder snapshotBuilder() {
|
||||
return DataSnapshot.builder(plugin).saveCause(DataSnapshot.SaveCause.API);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserialize a JSON string to an {@link Adaptable}
|
||||
*
|
||||
* @param serialized The serialized JSON string
|
||||
* @param type The type of the element
|
||||
* @param <T> The type of the element
|
||||
* @return The deserialized element
|
||||
* @throws Serializer.DeserializationException If the element could not be deserialized
|
||||
*/
|
||||
@NotNull
|
||||
public <T extends Adaptable> T deserializeData(@NotNull String serialized, Class<T> type)
|
||||
throws Serializer.DeserializationException {
|
||||
return plugin.getDataAdapter().fromJson(serialized, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize an {@link Adaptable} to a JSON string
|
||||
*
|
||||
* @param element The element to serialize
|
||||
* @param <T> The type of the element
|
||||
* @return The serialized JSON string
|
||||
* @throws Serializer.SerializationException If the element could not be serialized
|
||||
*/
|
||||
@NotNull
|
||||
public <T extends Adaptable> String serializeData(@NotNull T element)
|
||||
throws Serializer.SerializationException {
|
||||
return plugin.getDataAdapter().toJson(element);
|
||||
}
|
||||
|
||||
/**
|
||||
* <b>(Internal use only)</b> - Get the plugin instance
|
||||
*
|
||||
* @return The plugin instance
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
public HuskSync getPlugin() {
|
||||
return plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
* An exception indicating the plugin has been accessed before it has been registered.
|
||||
*/
|
||||
static final class NotRegisteredException extends IllegalStateException {
|
||||
|
||||
private static final String MESSAGE = """
|
||||
Could not access the HuskSync API as it has not yet been registered. This could be because:
|
||||
1) HuskSync has failed to enable successfully
|
||||
2) Your plugin isn't set to load after HuskSync has
|
||||
(Check if it set as a (soft)depend in plugin.yml or to load: BEFORE in paper-plugin.yml?)
|
||||
3) You are attempting to access HuskSync on plugin construction/before your plugin has enabled.
|
||||
4) You have shaded HuskSync into your plugin jar and need to fix your maven/gradle/build script
|
||||
to only include HuskSync as a dependency and not as a shaded dependency.""";
|
||||
|
||||
NotRegisteredException() {
|
||||
super(MESSAGE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user