9
0
mirror of https://github.com/WiIIiam278/HuskSync.git synced 2025-12-21 15:49:20 +00:00

Compare commits

..

11 Commits
2.2.1 ... 2.2.3

Author SHA1 Message Date
William
4288742052 Update dependencies, close #85, close #86, close #87, close #88, close #89 2023-02-13 13:29:52 +00:00
William
8205b9c169 Create dependabot.yml and funding.yml 2023-02-13 13:20:27 +00:00
William
1d7f6a8d8b refactor: Use mappings class for PDC tag type handling 2023-02-12 19:14:46 +00:00
William
3425c97245 Bump to v2.2.3 2023-02-12 18:18:29 +00:00
evlad
2d1d8f1ab6 Sync lock: Cancel item frame interaction, add command blacklist (#84)
Co-authored-by: William <will27528@gmail.com>
2023-02-12 18:08:46 +00:00
William
f322d31b03 [ci skip] Correct typos in README 2023-02-12 15:43:26 +00:00
William278
368e665ac3 [ci skip] Update README 2023-01-27 11:46:31 +00:00
William278
922eb2f19a Merge remote-tracking branch 'origin/master'
# Conflicts:
#	README.md
2023-01-27 11:45:50 +00:00
William278
23e0123004 Update README and banner 2023-01-27 11:45:04 +00:00
William
e98bac844a Hotfix bump to 2.2.2 - fix unchecked cast on trident lock check 2023-01-10 14:42:54 +00:00
William
d6d9a55f72 Fix unchecked cast on trident launch locking, fix #79 2023-01-10 14:42:28 +00:00
16 changed files with 190 additions and 173 deletions

7
.github/dependabot.yml vendored Normal file
View 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
View File

@@ -0,0 +1,3 @@
# Funding metadata for GitHub
github: WiIIiam278
custom: https://buymeacoff.ee/william278

View File

@@ -1,36 +1,59 @@
# [![HuskSync Banner](images/banner-graphic.png)](https://github.com/WiIIiam278/HuskSync)
[![GitHub CI](https://img.shields.io/github/actions/workflow/status/WiIIiam278/HuskSync/java_ci.yml?branch=master&logo=github)](https://github.com/WiIIiam278/HuskSync/actions/workflows/java_ci.yml)
[![JitPack API](https://img.shields.io/jitpack/version/net.william278/HuskSync?color=%2300fb9a&label=api&logo=gradle)](https://jitpack.io/#net.william278/HuskSync)
[![Support Discord](https://img.shields.io/discord/818135932103557162.svg?label=&logo=discord&logoColor=fff&color=7389D8&labelColor=6A7EC2)](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
![Data snapshot viewer](images/data-snapshot-viewer.png)
**⭐ Seamless synchronisation** &mdash; 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** &mdash; 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** &mdash; Something gone wrong? Restore players back to a previous data state. Rotate and manage data snapshots in-game!
**⭐ Import existing data** &mdash; Import your MySQLPlayerDataBridge data—or from your existing world data! No server reset needed!
**⭐ Works great with Plan** &mdash; Stay in touch with your community through HuskSync analytics on your Plan web panel.
**⭐ Extensible API & open-source** &mdash; 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/) &mdash; Read the plugin documentation!
- [Spigot](https://www.spigotmc.org/resources/husksync.97144/) &mdash; 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) &mdash; File a bug report or feature request
- [Discord](https://discord.gg/tVYhJfyDWG) &mdash; Get help, ask questions (Proof of purchase required)
- [bStats](https://bstats.org/plugin/bukkit/HuskSync%20-%20Bukkit/13140) &mdash; View plugin metrics
---
&copy; [William278](https://william278.net/), 2022. All rights reserved.
&copy; [William278](https://william278.net/), 2023. All rights reserved.

View File

@@ -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'
}

View File

@@ -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();
}
}

View File

@@ -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()));
}
}
}

View File

@@ -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 -> {

View File

@@ -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 {

View File

@@ -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);
}

View File

@@ -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();
}

View File

@@ -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);
}
}

View File

@@ -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);
}

View File

@@ -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();

View File

@@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB