mirror of
https://github.com/WiIIiam278/HuskSync.git
synced 2025-12-21 15:49:20 +00:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4288742052 | ||
|
|
8205b9c169 | ||
|
|
1d7f6a8d8b | ||
|
|
3425c97245 | ||
|
|
2d1d8f1ab6 | ||
|
|
f322d31b03 | ||
|
|
368e665ac3 | ||
|
|
922eb2f19a | ||
|
|
23e0123004 | ||
|
|
e98bac844a | ||
|
|
d6d9a55f72 |
7
.github/dependabot.yml
vendored
Normal file
7
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
# Dependabot configuration file for GitHub
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "gradle" # See documentation for possible values
|
||||
directory: "/" # Location of package manifests
|
||||
schedule:
|
||||
interval: "daily"
|
||||
3
.github/funding.yml
vendored
Normal file
3
.github/funding.yml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# Funding metadata for GitHub
|
||||
github: WiIIiam278
|
||||
custom: https://buymeacoff.ee/william278
|
||||
88
README.md
88
README.md
@@ -1,36 +1,59 @@
|
||||
# [](https://github.com/WiIIiam278/HuskSync)
|
||||
[](https://github.com/WiIIiam278/HuskSync/actions/workflows/java_ci.yml)
|
||||
[](https://jitpack.io/#net.william278/HuskSync)
|
||||
[](https://discord.gg/tVYhJfyDWG)
|
||||
|
||||
[Documentation, Guides & API](https://william278.net/docs/husksync) · [Resource Page](https://www.spigotmc.org/resources/husksync.97144/) · [Bug Reports](https://github.com/WiIIiam278/HuskSync/issues)
|
||||
<p align="center">
|
||||
<img src="images/banner.png" alt="HuskSync" />
|
||||
<a href="https://github.com/WiIIiam278/HuskSync/actions/workflows/java_ci.yml">
|
||||
<img src="https://img.shields.io/github/actions/workflow/status/WiIIiam278/HuskSync/java_ci.yml?branch=master&logo=github"/>
|
||||
</a>
|
||||
<a href="https://jitpack.io/#net.william278/HuskSync">
|
||||
<img src="https://img.shields.io/jitpack/version/net.william278/HuskSync?color=%2300fb9a&label=api&logo=gradle" />
|
||||
</a>
|
||||
<a href="https://discord.gg/tVYhJfyDWG">
|
||||
<img src="https://img.shields.io/discord/818135932103557162.svg?label=&logo=discord&logoColor=fff&color=7389D8&labelColor=6A7EC2" />
|
||||
</a>
|
||||
<br/>
|
||||
<b>
|
||||
<a href="https://www.spigotmc.org/resources/husksync.97144/">Spigot</a>
|
||||
</b> —
|
||||
<b>
|
||||
<a href="https://william278.net/docs/husksync/setup">Setup</a>
|
||||
</b> —
|
||||
<b>
|
||||
<a href="https://william278.net/docs/husksync/">Docs</a>
|
||||
</b> —
|
||||
<b>
|
||||
<a href="https://github.com/WiIIiam278/HuskSync/issues">Issues</a>
|
||||
</b>
|
||||
</p>
|
||||
<br/>
|
||||
|
||||
**HuskSync** is a modern, cross-server player data synchronisation system that enables the comprehensive synchronisation of your user's data across multiple proxied servers. It does this by making use of Redis and MySQL to optimally cache data while players change servers.
|
||||
|
||||
## Features
|
||||

|
||||
**⭐ Seamless synchronisation** — Utilises optimised Redis caching when players change server to sync player data super quickly for a seamless experience.
|
||||
|
||||
- Synchronise inventories, ender chests, advancements, statistics, experience points, health, max health, hunger, saturation, potion effects, persistent data container tags, game mode, location and more across multiple proxied servers.
|
||||
- Create and manage "snapshot" backups of user data and roll back users to previous states on-the-fly. (`/userdata`)
|
||||
- Preview, list, delete, restore & pin user data snapshots in-game with an intuitive menu.
|
||||
- Examine the contents of player's inventories and ender chests on-the-fly. (`/inventory`, `/enderchest`)
|
||||
- Hooks with your [Player Analytics](https://github.com/plan-player-analytics/Plan) web panel to provide an overview of user data.
|
||||
- Supports segregating synchronisation across multiple distinct clusters on one network.
|
||||
**⭐ Complete player synchronisation** — Sync inventories, Ender Chests, health, hunger, effects, advancements, statistics, locked maps & [more](https://william278.net/docs/husksync/sync-features)—no data left behind!
|
||||
|
||||
## Requirements
|
||||
* A MySQL Database (v8.0+).
|
||||
* A Redis Database (v5.0+)
|
||||
* Any number of proxied Spigot servers (Minecraft v1.16.5+, Java 16+)
|
||||
**⭐ Backup, restore & rotate** — Something gone wrong? Restore players back to a previous data state. Rotate and manage data snapshots in-game!
|
||||
|
||||
**⭐ Import existing data** — Import your MySQLPlayerDataBridge data—or from your existing world data! No server reset needed!
|
||||
|
||||
**⭐ Works great with Plan** — Stay in touch with your community through HuskSync analytics on your Plan web panel.
|
||||
|
||||
**⭐ Extensible API & open-source** — Need more? Extend the plugin with the Developer API. Or, submit a pull request through our code bounty system!
|
||||
|
||||
**Ready?** [Let's head down town!](https://william278.net/docs/husksync/setup)
|
||||
|
||||
## Setup
|
||||
1. Place the plugin jar file in the `/plugins/` directory of each Spigot server. You do not need to install HuskSync as a proxy plugin.
|
||||
Requires a MySQL (v8.0+) database, a Redis (v5.0+) server and any number of Spigot-based 1.16.5+ Minecraft servers, running Java 16+.
|
||||
|
||||
1. Place the plugin jar file in the /plugins/ directory of each Spigot server. You do not need to install HuskSync as a proxy plugin.
|
||||
2. Start, then stop every server to let HuskSync generate the config file.
|
||||
3. Navigate to the HuskSync config file on each server (`~/plugins/HuskSync/config.yml`) and fill in both the MySQL and Redis database credentials.
|
||||
3. Navigate to the HuskSync config file on each server (~/plugins/HuskSync/config.yml) and fill in both the MySQL and Redis database credentials.
|
||||
4. Start every server again and synchronization will begin.
|
||||
|
||||
## Building
|
||||
To build HuskSync, simply run the following in the root of the repository:
|
||||
```
|
||||
|
||||
```bash
|
||||
./gradlew clean build
|
||||
```
|
||||
|
||||
@@ -40,25 +63,20 @@ HuskSync is a premium resource. This source code is provided as reference only f
|
||||
- [License](https://github.com/WiIIiam278/HuskSync/blob/master/LICENSE)
|
||||
|
||||
## Contributing
|
||||
A code bounty program is in place for HuskSync, where developers making significant code contributions to HuskSync may be entitled to a license at my discretion to use HuskSync in commercial contexts without having to purchase the resource. Please read the information for contributors in the LICENSE file before submitting a pull request.
|
||||
A code bounty program is in place for HuskSync, where developers making significant code contributions to HuskSync may be entitled to a license at my discretion to use HuskSync in commercial contexts without having to purchase the resource. Please read the information for contributors in the LICENSE file before submitting a pull request.
|
||||
|
||||
## Translation
|
||||
## Translations
|
||||
Translations of the plugin locales are welcome to help make the plugin more accessible. Please submit a pull request with your translations as a `.yml` file.
|
||||
|
||||
- [Locales Directory](https://github.com/WiIIiam278/HuskSync/tree/master/common/src/main/resources/locales)
|
||||
- [English Locales](https://github.com/WiIIiam278/HuskSync/tree/master/common/src/main/resources/locales/en-gb.yml)
|
||||
|
||||
## bStats
|
||||
This plugin uses bStats to provide me with metrics about its usage:
|
||||
- [bStats Metrics](https://bstats.org/plugin/bukkit/HuskSync%20-%20Bukkit/13140)
|
||||
|
||||
You can turn metric collection off by navigating to `~/plugins/bStats/config.yml` and editing the config to disable plugin metrics.
|
||||
- [Locales Directory](https://github.com/WiIIiam278/HuskSync/tree/master/common/src/main/resources/languages)
|
||||
- [English Locales](https://github.com/WiIIiam278/HuskSync/tree/master/common/src/main/resources/languages/en-gb.yml)
|
||||
|
||||
## Links
|
||||
- [Documentation, Guides & API](https://william278.net/docs/husksync)
|
||||
- [Resource Page](https://www.spigotmc.org/resources/husksync.97144/)
|
||||
- [Bug Reports](https://github.com/WiIIiam278/HuskSync/issues)
|
||||
- [Discord Support](https://discord.gg/tVYhJfyDWG) (Proof of purchase required)
|
||||
- [Docs](https://william278.net/docs/husksync/) — Read the plugin documentation!
|
||||
- [Spigot](https://www.spigotmc.org/resources/husksync.97144/) — View the Spigot resource page (Also: [Polymart](https://polymart.org/resource/husksync.1634), [Songoda](https://marketplace.songoda.com/marketplace/product/husksync-a-modern-cross-server-player-data-synchronization-system.758))
|
||||
- [Issues](https://github.com/WiIIiam278/HuskSync/issues) — File a bug report or feature request
|
||||
- [Discord](https://discord.gg/tVYhJfyDWG) — Get help, ask questions (Proof of purchase required)
|
||||
- [bStats](https://bstats.org/plugin/bukkit/HuskSync%20-%20Bukkit/13140) — View plugin metrics
|
||||
|
||||
---
|
||||
© [William278](https://william278.net/), 2022. All rights reserved.
|
||||
© [William278](https://william278.net/), 2023. All rights reserved.
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
dependencies {
|
||||
implementation project(path: ':common')
|
||||
implementation 'org.bstats:bstats-bukkit:3.0.0'
|
||||
implementation 'org.bstats:bstats-bukkit:3.0.1'
|
||||
implementation 'net.william278:mpdbdataconverter:1.0.1'
|
||||
implementation 'net.william278:hsldataconverter:1.0'
|
||||
implementation 'net.william278:MapDataAPI:1.0.2'
|
||||
implementation 'net.william278:AndJam:1.0.2'
|
||||
implementation 'me.lucko:commodore:2.2'
|
||||
implementation 'net.kyori:adventure-platform-bukkit:4.1.2'
|
||||
implementation 'net.kyori:adventure-platform-bukkit:4.2.0'
|
||||
implementation 'dev.triumphteam:triumph-gui:3.1.3'
|
||||
|
||||
compileOnly 'org.spigotmc:spigot-api:1.16.5-R0.1-SNAPSHOT'
|
||||
@@ -16,7 +16,7 @@ dependencies {
|
||||
compileOnly 'com.zaxxer:HikariCP:5.0.1'
|
||||
compileOnly 'redis.clients:jedis:' + jedis_version
|
||||
compileOnly 'net.william278:DesertWell:1.1'
|
||||
compileOnly 'net.william278:Annotaml:2.0'
|
||||
compileOnly 'net.william278:Annotaml:2.0.1'
|
||||
compileOnly 'net.william278:AdvancementAPI:97a9583413'
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
package net.william278.husksync.data;
|
||||
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.persistence.PersistentDataContainer;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
public record BukkitPersistentTypeMapping<T, Z>(PersistentDataTagType type, PersistentDataType<T, Z> bukkitType) {
|
||||
|
||||
public static final BukkitPersistentTypeMapping<?, ?>[] PRIMITIVE_TYPE_MAPPINGS = new BukkitPersistentTypeMapping<?, ?>[]{
|
||||
new BukkitPersistentTypeMapping<>(PersistentDataTagType.BYTE, PersistentDataType.BYTE),
|
||||
new BukkitPersistentTypeMapping<>(PersistentDataTagType.SHORT, PersistentDataType.SHORT),
|
||||
new BukkitPersistentTypeMapping<>(PersistentDataTagType.INTEGER, PersistentDataType.INTEGER),
|
||||
new BukkitPersistentTypeMapping<>(PersistentDataTagType.LONG, PersistentDataType.LONG),
|
||||
new BukkitPersistentTypeMapping<>(PersistentDataTagType.FLOAT, PersistentDataType.FLOAT),
|
||||
new BukkitPersistentTypeMapping<>(PersistentDataTagType.DOUBLE, PersistentDataType.DOUBLE),
|
||||
new BukkitPersistentTypeMapping<>(PersistentDataTagType.STRING, PersistentDataType.STRING),
|
||||
new BukkitPersistentTypeMapping<>(PersistentDataTagType.BYTE_ARRAY, PersistentDataType.BYTE_ARRAY),
|
||||
new BukkitPersistentTypeMapping<>(PersistentDataTagType.INTEGER_ARRAY, PersistentDataType.INTEGER_ARRAY),
|
||||
new BukkitPersistentTypeMapping<>(PersistentDataTagType.LONG_ARRAY, PersistentDataType.LONG_ARRAY),
|
||||
new BukkitPersistentTypeMapping<>(PersistentDataTagType.TAG_CONTAINER_ARRAY, PersistentDataType.TAG_CONTAINER_ARRAY),
|
||||
new BukkitPersistentTypeMapping<>(PersistentDataTagType.TAG_CONTAINER, PersistentDataType.TAG_CONTAINER)
|
||||
};
|
||||
|
||||
public BukkitPersistentTypeMapping(@NotNull PersistentDataTagType type, @NotNull PersistentDataType<T, Z> bukkitType) {
|
||||
this.type = type;
|
||||
this.bukkitType = bukkitType;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PersistentDataTag<Z> getContainerValue(@NotNull PersistentDataContainer container, @NotNull NamespacedKey key) throws NullPointerException {
|
||||
return new PersistentDataTag<>(type, Objects.requireNonNull(container.get(key, bukkitType)));
|
||||
}
|
||||
|
||||
public void setContainerValue(@NotNull PersistentDataContainerData container, @NotNull Player player, @NotNull NamespacedKey key) throws NullPointerException {
|
||||
container.getTagValue(key.toString(), bukkitType.getPrimitiveType())
|
||||
.ifPresent(value -> player.getPersistentDataContainer().set(key, bukkitType, (Z) value));
|
||||
}
|
||||
|
||||
public static Optional<BukkitPersistentTypeMapping<?, ?>> getMapping(@NotNull PersistentDataTagType type) {
|
||||
for (BukkitPersistentTypeMapping<?, ?> mapping : PRIMITIVE_TYPE_MAPPINGS) {
|
||||
if (mapping.type().equals(type)) {
|
||||
return Optional.of(mapping);
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import net.william278.husksync.player.OnlineUser;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.Projectile;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
@@ -21,20 +22,25 @@ import org.bukkit.event.entity.PlayerDeathEvent;
|
||||
import org.bukkit.event.entity.ProjectileLaunchEvent;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.event.inventory.InventoryOpenEvent;
|
||||
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
|
||||
import org.bukkit.event.player.PlayerDropItemEvent;
|
||||
import org.bukkit.event.player.PlayerInteractEntityEvent;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.event.world.WorldSaveEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class BukkitEventListener extends EventListener implements BukkitJoinEventListener, BukkitQuitEventListener,
|
||||
BukkitDeathEventListener, Listener {
|
||||
protected final List<String> blacklistedCommands;
|
||||
|
||||
public BukkitEventListener(@NotNull BukkitHuskSync huskSync) {
|
||||
super(huskSync);
|
||||
this.blacklistedCommands = huskSync.getSettings().blacklistedCommandsWhileLocked;
|
||||
Bukkit.getServer().getPluginManager().registerEvents(this, huskSync);
|
||||
}
|
||||
|
||||
@@ -97,11 +103,9 @@ public class BukkitEventListener extends EventListener implements BukkitJoinEven
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onProjectileLaunch(@NotNull ProjectileLaunchEvent event) {
|
||||
if (event.getEntity().getType() == EntityType.TRIDENT) {
|
||||
var player = (Player) event.getEntity().getShooter();
|
||||
if (player != null) {
|
||||
event.setCancelled(cancelPlayerEvent(player.getUniqueId()));
|
||||
}
|
||||
final Projectile projectile = event.getEntity();
|
||||
if (projectile.getShooter() instanceof Player player && projectile.getType() == EntityType.TRIDENT) {
|
||||
event.setCancelled(cancelPlayerEvent(player.getUniqueId()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,6 +126,11 @@ public class BukkitEventListener extends EventListener implements BukkitJoinEven
|
||||
event.setCancelled(cancelPlayerEvent(event.getPlayer().getUniqueId()));
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onPlayerInteractEntity(@NotNull PlayerInteractEntityEvent event) {
|
||||
event.setCancelled(cancelPlayerEvent(event.getPlayer().getUniqueId()));
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onBlockPlace(@NotNull BlockPlaceEvent event) {
|
||||
event.setCancelled(cancelPlayerEvent(event.getPlayer().getUniqueId()));
|
||||
@@ -151,4 +160,14 @@ public class BukkitEventListener extends EventListener implements BukkitJoinEven
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
|
||||
public void onPermissionCommand(@NotNull PlayerCommandPreprocessEvent event) {
|
||||
String[] commandArgs = event.getMessage().substring(1).split(" ");
|
||||
String commandLabel = commandArgs[0].toLowerCase();
|
||||
|
||||
if (blacklistedCommands.contains(commandLabel)) {
|
||||
event.setCancelled(cancelPlayerEvent(event.getPlayer().getUniqueId()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.player.PlayerTeleportEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.persistence.PersistentDataContainer;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -37,19 +36,6 @@ import java.util.logging.Level;
|
||||
*/
|
||||
public class BukkitPlayer extends OnlineUser {
|
||||
|
||||
private static final PersistentDataType<?, ?>[] PRIMITIVE_PERSISTENT_DATA_TYPES = new PersistentDataType<?, ?>[]{
|
||||
PersistentDataType.BYTE,
|
||||
PersistentDataType.SHORT,
|
||||
PersistentDataType.INTEGER,
|
||||
PersistentDataType.LONG,
|
||||
PersistentDataType.FLOAT,
|
||||
PersistentDataType.DOUBLE,
|
||||
PersistentDataType.STRING,
|
||||
PersistentDataType.BYTE_ARRAY,
|
||||
PersistentDataType.INTEGER_ARRAY,
|
||||
PersistentDataType.LONG_ARRAY,
|
||||
PersistentDataType.TAG_CONTAINER_ARRAY,
|
||||
PersistentDataType.TAG_CONTAINER};
|
||||
|
||||
private final Player player;
|
||||
private final Audience audience;
|
||||
@@ -450,64 +436,27 @@ public class BukkitPlayer extends OnlineUser {
|
||||
|
||||
@Override
|
||||
public CompletableFuture<PersistentDataContainerData> getPersistentDataContainer() {
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
final CompletableFuture<PersistentDataContainerData> future = new CompletableFuture<>();
|
||||
final Map<String, PersistentDataTag<?>> persistentDataMap = new HashMap<>();
|
||||
|
||||
Bukkit.getScheduler().runTask(BukkitHuskSync.getInstance(), () -> {
|
||||
final PersistentDataContainer container = player.getPersistentDataContainer();
|
||||
if (container.isEmpty()) {
|
||||
return new PersistentDataContainerData(new HashMap<>());
|
||||
}
|
||||
final HashMap<String, PersistentDataTag<?>> persistentDataMap = new HashMap<>();
|
||||
for (final NamespacedKey key : container.getKeys()) {
|
||||
PersistentDataType<?, ?> type = null;
|
||||
for (PersistentDataType<?, ?> dataType : PRIMITIVE_PERSISTENT_DATA_TYPES) {
|
||||
if (container.has(key, dataType)) {
|
||||
container.getKeys().forEach(key -> {
|
||||
BukkitPersistentTypeMapping<?, ?> type = null;
|
||||
for (BukkitPersistentTypeMapping<?, ?> dataType : BukkitPersistentTypeMapping.PRIMITIVE_TYPE_MAPPINGS) {
|
||||
if (container.has(key, dataType.bukkitType())) {
|
||||
type = dataType;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (type != null) {
|
||||
// This is absolutely disgusting code and needs to be swiftly put out of its misery with a refactor
|
||||
final Class<?> primitiveType = type.getPrimitiveType();
|
||||
if (String.class.equals(primitiveType)) {
|
||||
persistentDataMap.put(key.toString(), new PersistentDataTag<>(BukkitPersistentDataTagType.STRING,
|
||||
Objects.requireNonNull(container.get(key, PersistentDataType.STRING))));
|
||||
} else if (int.class.equals(primitiveType)) {
|
||||
persistentDataMap.put(key.toString(), new PersistentDataTag<>(BukkitPersistentDataTagType.INTEGER,
|
||||
Objects.requireNonNull(container.get(key, PersistentDataType.INTEGER))));
|
||||
} else if (double.class.equals(primitiveType)) {
|
||||
persistentDataMap.put(key.toString(), new PersistentDataTag<>(BukkitPersistentDataTagType.DOUBLE,
|
||||
Objects.requireNonNull(container.get(key, PersistentDataType.DOUBLE))));
|
||||
} else if (float.class.equals(primitiveType)) {
|
||||
persistentDataMap.put(key.toString(), new PersistentDataTag<>(BukkitPersistentDataTagType.FLOAT,
|
||||
Objects.requireNonNull(container.get(key, PersistentDataType.FLOAT))));
|
||||
} else if (long.class.equals(primitiveType)) {
|
||||
persistentDataMap.put(key.toString(), new PersistentDataTag<>(BukkitPersistentDataTagType.LONG,
|
||||
Objects.requireNonNull(container.get(key, PersistentDataType.LONG))));
|
||||
} else if (short.class.equals(primitiveType)) {
|
||||
persistentDataMap.put(key.toString(), new PersistentDataTag<>(BukkitPersistentDataTagType.SHORT,
|
||||
Objects.requireNonNull(container.get(key, PersistentDataType.SHORT))));
|
||||
} else if (byte.class.equals(primitiveType)) {
|
||||
persistentDataMap.put(key.toString(), new PersistentDataTag<>(BukkitPersistentDataTagType.BYTE,
|
||||
Objects.requireNonNull(container.get(key, PersistentDataType.BYTE))));
|
||||
} else if (byte[].class.equals(primitiveType)) {
|
||||
persistentDataMap.put(key.toString(), new PersistentDataTag<>(BukkitPersistentDataTagType.BYTE_ARRAY,
|
||||
Objects.requireNonNull(container.get(key, PersistentDataType.BYTE_ARRAY))));
|
||||
} else if (int[].class.equals(primitiveType)) {
|
||||
persistentDataMap.put(key.toString(), new PersistentDataTag<>(BukkitPersistentDataTagType.INTEGER_ARRAY,
|
||||
Objects.requireNonNull(container.get(key, PersistentDataType.INTEGER_ARRAY))));
|
||||
} else if (long[].class.equals(primitiveType)) {
|
||||
persistentDataMap.put(key.toString(), new PersistentDataTag<>(BukkitPersistentDataTagType.LONG_ARRAY,
|
||||
Objects.requireNonNull(container.get(key, PersistentDataType.LONG_ARRAY))));
|
||||
} else if (PersistentDataContainer.class.equals(primitiveType)) {
|
||||
persistentDataMap.put(key.toString(), new PersistentDataTag<>(BukkitPersistentDataTagType.TAG_CONTAINER,
|
||||
Objects.requireNonNull(container.get(key, PersistentDataType.TAG_CONTAINER))));
|
||||
} else if (PersistentDataContainer[].class.equals(primitiveType)) {
|
||||
persistentDataMap.put(key.toString(), new PersistentDataTag<>(BukkitPersistentDataTagType.TAG_CONTAINER_ARRAY,
|
||||
Objects.requireNonNull(container.get(key, PersistentDataType.TAG_CONTAINER_ARRAY))));
|
||||
}
|
||||
persistentDataMap.put(key.toString(), type.getContainerValue(container, key));
|
||||
}
|
||||
}
|
||||
return new PersistentDataContainerData(persistentDataMap);
|
||||
}).exceptionally(throwable -> {
|
||||
});
|
||||
future.complete(new PersistentDataContainerData(persistentDataMap));
|
||||
});
|
||||
|
||||
return future.exceptionally(throwable -> {
|
||||
BukkitHuskSync.getInstance().log(Level.WARNING,
|
||||
"Could not read " + player.getName() + "'s persistent data map, skipping!");
|
||||
throwable.printStackTrace();
|
||||
@@ -523,51 +472,12 @@ public class BukkitPlayer extends OnlineUser {
|
||||
container.getTags().forEach(keyString -> {
|
||||
final NamespacedKey key = NamespacedKey.fromString(keyString);
|
||||
if (key != null) {
|
||||
// Set a tag with the given key and value. This is crying out for a refactor.
|
||||
container.getTagType(keyString).ifPresentOrElse(dataType -> {
|
||||
switch (dataType) {
|
||||
case BYTE -> container.getTagValue(keyString, byte.class).ifPresent(
|
||||
value -> player.getPersistentDataContainer().set(key,
|
||||
PersistentDataType.BYTE, value));
|
||||
case SHORT -> container.getTagValue(keyString, short.class).ifPresent(
|
||||
value -> player.getPersistentDataContainer().set(key,
|
||||
PersistentDataType.SHORT, value));
|
||||
case INTEGER -> container.getTagValue(keyString, int.class).ifPresent(
|
||||
value -> player.getPersistentDataContainer().set(key,
|
||||
PersistentDataType.INTEGER, value));
|
||||
case LONG -> container.getTagValue(keyString, long.class).ifPresent(
|
||||
value -> player.getPersistentDataContainer().set(key,
|
||||
PersistentDataType.LONG, value));
|
||||
case FLOAT -> container.getTagValue(keyString, float.class).ifPresent(
|
||||
value -> player.getPersistentDataContainer().set(key,
|
||||
PersistentDataType.FLOAT, value));
|
||||
case DOUBLE -> container.getTagValue(keyString, double.class).ifPresent(
|
||||
value -> player.getPersistentDataContainer().set(key,
|
||||
PersistentDataType.DOUBLE, value));
|
||||
case STRING -> container.getTagValue(keyString, String.class).ifPresent(
|
||||
value -> player.getPersistentDataContainer().set(key,
|
||||
PersistentDataType.STRING, value));
|
||||
case BYTE_ARRAY -> container.getTagValue(keyString, byte[].class).ifPresent(
|
||||
value -> player.getPersistentDataContainer().set(key,
|
||||
PersistentDataType.BYTE_ARRAY, value));
|
||||
case INTEGER_ARRAY -> container.getTagValue(keyString, int[].class).ifPresent(
|
||||
value -> player.getPersistentDataContainer().set(key,
|
||||
PersistentDataType.INTEGER_ARRAY, value));
|
||||
case LONG_ARRAY -> container.getTagValue(keyString, long[].class).ifPresent(
|
||||
value -> player.getPersistentDataContainer().set(key,
|
||||
PersistentDataType.LONG_ARRAY, value));
|
||||
case TAG_CONTAINER ->
|
||||
container.getTagValue(keyString, PersistentDataContainer.class).ifPresent(
|
||||
value -> player.getPersistentDataContainer().set(key,
|
||||
PersistentDataType.TAG_CONTAINER, value));
|
||||
case TAG_CONTAINER_ARRAY ->
|
||||
container.getTagValue(keyString, PersistentDataContainer[].class).ifPresent(
|
||||
value -> player.getPersistentDataContainer().set(key,
|
||||
PersistentDataType.TAG_CONTAINER_ARRAY, value));
|
||||
}
|
||||
}, () -> BukkitHuskSync.getInstance().log(Level.WARNING,
|
||||
"Could not set " + player.getName() + "'s persistent data key " + keyString +
|
||||
" as it has an invalid type. Skipping!"));
|
||||
container.getTagType(keyString)
|
||||
.flatMap(BukkitPersistentTypeMapping::getMapping)
|
||||
.ifPresentOrElse(mapping -> mapping.setContainerValue(container, player, key),
|
||||
() -> BukkitHuskSync.getInstance().log(Level.WARNING,
|
||||
"Could not set " + player.getName() + "'s persistent data key " + keyString +
|
||||
" as it has an invalid type. Skipping!"));
|
||||
}
|
||||
});
|
||||
}).exceptionally(throwable -> {
|
||||
|
||||
@@ -2,16 +2,16 @@ dependencies {
|
||||
implementation 'commons-io:commons-io:2.11.0'
|
||||
implementation 'de.themoep:minedown-adventure:1.7.1-SNAPSHOT'
|
||||
implementation 'net.kyori:adventure-api:4.11.0'
|
||||
implementation 'com.google.code.gson:gson:2.10'
|
||||
implementation 'com.google.code.gson:gson:2.10.1'
|
||||
implementation 'dev.dejvokep:boosted-yaml:1.3'
|
||||
implementation 'net.william278:Annotaml:2.0'
|
||||
implementation 'net.william278:Annotaml:2.0.1'
|
||||
implementation 'net.william278:DesertWell:1.1'
|
||||
implementation 'net.william278:PagineDown:1.1'
|
||||
implementation('com.zaxxer:HikariCP:5.0.1') {
|
||||
exclude module: 'slf4j-api'
|
||||
}
|
||||
|
||||
compileOnly 'org.jetbrains:annotations:23.0.0'
|
||||
compileOnly 'org.jetbrains:annotations:24.0.0'
|
||||
compileOnly 'com.github.plan-player-analytics:Plan:5.4.1690'
|
||||
compileOnly 'redis.clients:jedis:' + jedis_version
|
||||
compileOnly 'org.xerial.snappy:snappy-java:' + snappy_version
|
||||
@@ -23,7 +23,7 @@ dependencies {
|
||||
testImplementation 'org.xerial.snappy:snappy-java:' + snappy_version
|
||||
testImplementation 'org.apache.commons:commons-text:' + commons_text_version
|
||||
testCompileOnly 'dev.dejvokep:boosted-yaml:1.3'
|
||||
testCompileOnly 'org.jetbrains:annotations:23.0.0'
|
||||
testCompileOnly 'org.jetbrains:annotations:24.0.0'
|
||||
}
|
||||
|
||||
shadowJar {
|
||||
|
||||
@@ -5,7 +5,9 @@ import net.william278.annotaml.YamlFile;
|
||||
import net.william278.annotaml.YamlKey;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@@ -120,6 +122,9 @@ public class Settings {
|
||||
@YamlKey("synchronization.features")
|
||||
public Map<String, Boolean> synchronizationFeatures = SynchronizationFeature.getDefaults();
|
||||
|
||||
@YamlKey("synchronization.blacklisted_commands_while_locked")
|
||||
public List<String> blacklistedCommandsWhileLocked = new ArrayList<>();
|
||||
|
||||
public boolean getSynchronizationFeature(@NotNull SynchronizationFeature feature) {
|
||||
return synchronizationFeatures.getOrDefault(feature.name().toLowerCase(), feature.enabledByDefault);
|
||||
}
|
||||
|
||||
@@ -34,9 +34,9 @@ public class PersistentDataContainerData {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public Optional<BukkitPersistentDataTagType> getTagType(@NotNull final String tagType) {
|
||||
public Optional<PersistentDataTagType> getTagType(@NotNull final String tagType) {
|
||||
if (persistentDataMap.containsKey(tagType)) {
|
||||
return BukkitPersistentDataTagType.getDataType(persistentDataMap.get(tagType).type);
|
||||
return PersistentDataTagType.getDataType(persistentDataMap.get(tagType).type);
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@@ -19,16 +19,17 @@ public class PersistentDataTag<T> {
|
||||
*/
|
||||
public T value;
|
||||
|
||||
public PersistentDataTag(@NotNull BukkitPersistentDataTagType type, @NotNull T value) {
|
||||
public PersistentDataTag(@NotNull PersistentDataTagType type, @NotNull T value) {
|
||||
this.type = type.name();
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private PersistentDataTag() {
|
||||
}
|
||||
|
||||
public Optional<BukkitPersistentDataTagType> getType() {
|
||||
return BukkitPersistentDataTagType.getDataType(type);
|
||||
public Optional<PersistentDataTagType> getType() {
|
||||
return PersistentDataTagType.getDataType(type);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import java.util.Optional;
|
||||
/**
|
||||
* Represents the type of a {@link PersistentDataTag}
|
||||
*/
|
||||
public enum BukkitPersistentDataTagType {
|
||||
public enum PersistentDataTagType {
|
||||
|
||||
BYTE,
|
||||
SHORT,
|
||||
@@ -23,8 +23,8 @@ public enum BukkitPersistentDataTagType {
|
||||
TAG_CONTAINER;
|
||||
|
||||
|
||||
public static Optional<BukkitPersistentDataTagType> getDataType(@NotNull String typeName) {
|
||||
for (BukkitPersistentDataTagType type : values()) {
|
||||
public static Optional<PersistentDataTagType> getDataType(@NotNull String typeName) {
|
||||
for (PersistentDataTagType type : values()) {
|
||||
if (type.name().equalsIgnoreCase(typeName)) {
|
||||
return Optional.of(type);
|
||||
}
|
||||
@@ -62,13 +62,13 @@ public class DataAdaptionTests {
|
||||
|
||||
private String getTestSerializedPersistentDataContainer() {
|
||||
final HashMap<String, PersistentDataTag<?>> persistentDataTest = new HashMap<>();
|
||||
persistentDataTest.put("husksync:byte_test", new PersistentDataTag<>(BukkitPersistentDataTagType.BYTE, 0x01));
|
||||
persistentDataTest.put("husksync:double_test", new PersistentDataTag<>(BukkitPersistentDataTagType.DOUBLE, 2d));
|
||||
persistentDataTest.put("husksync:string_test", new PersistentDataTag<>(BukkitPersistentDataTagType.STRING, "test"));
|
||||
persistentDataTest.put("husksync:int_test", new PersistentDataTag<>(BukkitPersistentDataTagType.INTEGER, 3));
|
||||
persistentDataTest.put("husksync:long_test", new PersistentDataTag<>(BukkitPersistentDataTagType.LONG, 4L));
|
||||
persistentDataTest.put("husksync:float_test", new PersistentDataTag<>(BukkitPersistentDataTagType.FLOAT, 5f));
|
||||
persistentDataTest.put("husksync:short_test", new PersistentDataTag<>(BukkitPersistentDataTagType.SHORT, 6));
|
||||
persistentDataTest.put("husksync:byte_test", new PersistentDataTag<>(PersistentDataTagType.BYTE, 0x01));
|
||||
persistentDataTest.put("husksync:double_test", new PersistentDataTag<>(PersistentDataTagType.DOUBLE, 2d));
|
||||
persistentDataTest.put("husksync:string_test", new PersistentDataTag<>(PersistentDataTagType.STRING, "test"));
|
||||
persistentDataTest.put("husksync:int_test", new PersistentDataTag<>(PersistentDataTagType.INTEGER, 3));
|
||||
persistentDataTest.put("husksync:long_test", new PersistentDataTag<>(PersistentDataTagType.LONG, 4L));
|
||||
persistentDataTest.put("husksync:float_test", new PersistentDataTag<>(PersistentDataTagType.FLOAT, 5f));
|
||||
persistentDataTest.put("husksync:short_test", new PersistentDataTag<>(PersistentDataTagType.SHORT, 6));
|
||||
final PersistentDataContainerData persistentDataContainerData = new PersistentDataContainerData(persistentDataTest);
|
||||
|
||||
final DataAdapter dataAdapter = new JsonDataAdapter();
|
||||
|
||||
@@ -3,7 +3,7 @@ org.gradle.jvmargs='-Dfile.encoding=UTF-8'
|
||||
org.gradle.daemon=true
|
||||
javaVersion=16
|
||||
|
||||
plugin_version=2.2.1
|
||||
plugin_version=2.2.3
|
||||
plugin_archive=husksync
|
||||
|
||||
jedis_version=4.3.1
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 52 KiB |
BIN
images/banner.png
Normal file
BIN
images/banner.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 94 KiB |
Reference in New Issue
Block a user