mirror of
https://github.com/WiIIiam278/HuskSync.git
synced 2025-12-23 16:49:19 +00:00
Compare commits
50 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
633847a254 | ||
|
|
3cd144088d | ||
|
|
e312e8dd01 | ||
|
|
2b6e2a1ddc | ||
|
|
aed68b3045 | ||
|
|
6ee5141c8f | ||
|
|
3ff3c1207c | ||
|
|
5947bac82c | ||
|
|
baab59d17a | ||
|
|
e98f272dfd | ||
|
|
f4b680bee7 | ||
|
|
73fe184e70 | ||
|
|
bdc07f064d | ||
|
|
01aa28f28c | ||
|
|
5de81f06d6 | ||
|
|
d5da516f17 | ||
|
|
5e0e3fd27d | ||
|
|
5cee7cca84 | ||
|
|
330627553e | ||
|
|
359f0d6f18 | ||
|
|
b531196d8a | ||
|
|
951fc27a67 | ||
|
|
a5f7b37fac | ||
|
|
da7a85dde9 | ||
|
|
0f215c80ea | ||
|
|
a76aecdd23 | ||
|
|
2f3b0f37e8 | ||
|
|
330476ee23 | ||
|
|
6bf36bcbb1 | ||
|
|
a25b7a2c89 | ||
|
|
ab3271c0ec | ||
|
|
0fd5e4eb36 | ||
|
|
996b9bc63d | ||
|
|
bedb903215 | ||
|
|
d8b80388fd | ||
|
|
3f77b8b5f6 | ||
|
|
bd599081e5 | ||
|
|
4d5902132c | ||
|
|
bd3c080b4f | ||
|
|
dd46a6cdd5 | ||
|
|
7d453b7438 | ||
|
|
c5e0640f83 | ||
|
|
fb3b2bd66e | ||
|
|
cfe3879010 | ||
|
|
aedb517662 | ||
|
|
b7e6861f03 | ||
|
|
61072bfa51 | ||
|
|
ae439595ea | ||
|
|
e1f6e40624 | ||
|
|
ff17b58473 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -106,7 +106,7 @@ build/
|
|||||||
# Ignore Gradle GUI config
|
# Ignore Gradle GUI config
|
||||||
gradle-app.setting
|
gradle-app.setting
|
||||||
|
|
||||||
# me.william278.crossserversync.bungeecord.data.DataManager.PlayerDataCache of project
|
# net.william278.crossserversync.bungeecord.data.DataManager.PlayerDataCache of project
|
||||||
.gradletasknamecache
|
.gradletasknamecache
|
||||||
|
|
||||||
**/build/
|
**/build/
|
||||||
|
|||||||
5
.jitpack/install-mpdb-converter
Normal file
5
.jitpack/install-mpdb-converter
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo "mvn-installing mpdbdataconverter..."
|
||||||
|
curl "-L" "-O" "https://github.com/WiIIiam278/MPDBDataConverter/releases/download/1.0/mpdbdataconverter-1.0.jar"
|
||||||
|
mvn "install:install-file" "-Dfile=mpdbdataconverter-1.0.jar" "-DgroupId=net.william278" "-DartifactId=mpdbdataconverter" "-Dversion=1.0" "-Dpackaging=jar" "-DgeneratePom=true" "-e"
|
||||||
4
LICENSE
4
LICENSE
@@ -1,4 +1,4 @@
|
|||||||
Copyright © William278 2021. All rights reserved
|
Copyright © William278 2022. All rights reserved
|
||||||
|
|
||||||
LICENSE
|
LICENSE
|
||||||
This source code is provided as reference to licensed individuals that have purchased the HuskSync
|
This source code is provided as reference to licensed individuals that have purchased the HuskSync
|
||||||
@@ -8,7 +8,7 @@ not grant you the rights to modify, re-distribute, compile or redistribute this
|
|||||||
parties that are utilised in the plugin.
|
parties that are utilised in the plugin.
|
||||||
|
|
||||||
CONTRIBUTOR AGREEMENT
|
CONTRIBUTOR AGREEMENT
|
||||||
By contributing code to this repository, contributors agree that they forefeit their contributions
|
By contributing code to this repository, contributors agree that they forfeit their contributions
|
||||||
to the copyright holder and only the copyright holder.
|
to the copyright holder and only the copyright holder.
|
||||||
In exchange for contributing, the copyright holder may give, at their discretion, permission to use
|
In exchange for contributing, the copyright holder may give, at their discretion, permission to use
|
||||||
the plugin in commercial contexts
|
the plugin in commercial contexts
|
||||||
|
|||||||
44
README.md
44
README.md
@@ -37,10 +37,15 @@ To migrate from MySQLPLayerDataBridge, you need a Proxy server with HuskSync ins
|
|||||||
#### Commands do not function
|
#### Commands do not function
|
||||||
Please check that the plugin is installed and enabled on both the proxy and bukkit server you are trying to execute the command from and that both plugins connected to Redis. (A connection handshake confirmation message is logged to console when communications are successfully established.)
|
Please check that the plugin is installed and enabled on both the proxy and bukkit server you are trying to execute the command from and that both plugins connected to Redis. (A connection handshake confirmation message is logged to console when communications are successfully established.)
|
||||||
|
|
||||||
#### SQL errors in proxy console / data not synchronising
|
#### Data not being synced on player join and SQL errors in proxy console
|
||||||
This issue frequently occurs in users running Cracked (illegal) servers. I do not support piracy and so will be limited in my ability to help you.
|
This issue frequently occurs in users running Cracked (illegal) servers. I do not support piracy and so will be limited in my ability to help you.
|
||||||
If you are running an offline server for a legitimate reason, however, make sure that in the `paper.yml` of your Bukkit servers `bungee-online-mode` is set to the correct value - and that both your Proxy (BungeeCord, Waterfall, etc.) server and Bukkit (Spigot, paper, etc.) servers are set up correctly to work with offline mode.
|
If you are running an offline server for a legitimate reason, however, make sure that in the `paper.yml` of your Bukkit servers `bungee-online-mode` is set to the correct value - and that both your Proxy (BungeeCord, Waterfall, etc.) server and Bukkit (Spigot, paper, etc.) servers are set up correctly to work with offline mode.
|
||||||
|
|
||||||
|
#### Data sometimes not syncing between servers
|
||||||
|
There are two primary reasons this may happen:
|
||||||
|
* On your proxy server, you are running _FlameCord_ or a similar fork of Waterfall. Due to the nature of these forks changing security parameters, they can block or interfere with Redis packets being sent to and from your server. FlameCord, XCord and other forks are not compatible with HuskSync. For security-conscious users, I recommend Velocity.
|
||||||
|
* Your backend servers/proxy and Redis server have noticeably different amounts of latency between each other. This is particularly relevant for users running across multiple machines, where some backend servers / the proxy are installed with Redis and other backend servers are on a different machine. The solution to this is to have your BungeeCord and Redis alone on one machine, and your backend servers across the others - or have a separate machine with equal latency to the others that has Redis on. In the future, I may have a look at automatically correcting and accounting for differences in latency.
|
||||||
|
|
||||||
## How it works
|
## How it works
|
||||||

|

|
||||||
HuskSync saves a player's data when they log out to a cache on your proxy server, and redistributes that data to players when they join another HuskSync-enabled server. Player data in the cache is then saved to a database (be it SQLite or MySQL) and this is loaded from when a player joins your network.
|
HuskSync saves a player's data when they log out to a cache on your proxy server, and redistributes that data to players when they join another HuskSync-enabled server. Player data in the cache is then saved to a database (be it SQLite or MySQL) and this is loaded from when a player joins your network.
|
||||||
@@ -69,15 +74,15 @@ Everything except player locations are synchronised by default. You can enable o
|
|||||||
### Commands
|
### Commands
|
||||||
Commands are handled by the proxy server, rather than each spigot server. Some will only work on Spigot servers with HuskSync installed. Please remember that you will need a Proxy permission plugin (e.g. LuckPermsBungee) to set permissions for proxy commands.
|
Commands are handled by the proxy server, rather than each spigot server. Some will only work on Spigot servers with HuskSync installed. Please remember that you will need a Proxy permission plugin (e.g. LuckPermsBungee) to set permissions for proxy commands.
|
||||||
|
|
||||||
| Command | Description | Permission |
|
| Command | Description | Permission |
|
||||||
|---------------------|--------------------------------------|--------------------------------|
|
|---------------------------------------|--------------------------------------|--------------------------------|
|
||||||
| `/husksync about` | View plugin information | _None_ |
|
| `/husksync about` | View plugin information | _None_ |
|
||||||
| `/husksync update` | Check if an update is available | `husksync.command.admin` |
|
| `/husksync update` | Check if an update is available | `husksync.command.admin` |
|
||||||
| `/husksync status` | View system status information | `husksync.command.admin` |
|
| `/husksync status` | View system status information | `husksync.command.admin` |
|
||||||
| `/husksync reload` | Reload config & message files | `husksync.command.admin` |
|
| `/husksync reload` | Reload config & message files | `husksync.command.admin` |
|
||||||
| `/husksync invsee` | View an offline player's inventory | `husksync.command.inventory` |
|
| `/husksync invsee <player> [cluster]` | View an offline player's inventory | `husksync.command.inventory` |
|
||||||
| `/husksync echest` | View an offline player's ender chest | `husksync.command.ender_chest` |
|
| `/husksync echest <player> [cluster]` | View an offline player's ender chest | `husksync.command.ender_chest` |
|
||||||
| `/husksync migrate` | Migrate data from MPDB | _Console-only_ |
|
| `/husksync migrate [args] ` | Migrate data from MPDB | _Console-only_ |
|
||||||
|
|
||||||
### Frequently Asked Questions (FAQs)
|
### Frequently Asked Questions (FAQs)
|
||||||
#### Is Redis required?
|
#### Is Redis required?
|
||||||
@@ -131,7 +136,7 @@ With Maven, add the repository to your pom.xml:
|
|||||||
Then, add the dependency. Replace `version` with the latest version of HuskSync: [](https://jitpack.io/#WiIIiam278/HuskSync)
|
Then, add the dependency. Replace `version` with the latest version of HuskSync: [](https://jitpack.io/#WiIIiam278/HuskSync)
|
||||||
```xml
|
```xml
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.WiIIiam278</groupId>
|
<groupId>net.william278</groupId>
|
||||||
<artifactId>HuskSync</artifactId>
|
<artifactId>HuskSync</artifactId>
|
||||||
<version>version</version>
|
<version>version</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
@@ -147,10 +152,10 @@ Or, with Gradle, add the dependency like so to your build.gradle:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
Then add the dependency as follows. Replace `version` with the latest version of HuskSync: [](https://jitpack.io/#WiIIiam278/HuskSync)
|
Then add the dependency as follows. Replace `version` with the latest version of HuskSync: [](https://jitpack.io/#net.william278/HuskSync)
|
||||||
```
|
```
|
||||||
dependencies {
|
dependencies {
|
||||||
compileOnly 'com.github.WiIIiam278:HuskSync:version'
|
compileOnly 'net.william278:HuskSync:version'
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -174,7 +179,7 @@ try {
|
|||||||
```
|
```
|
||||||
|
|
||||||
#### Getting ItemStacks and usable data from PlayerData
|
#### Getting ItemStacks and usable data from PlayerData
|
||||||
Use the static methods provided in the [DataSerializer class](https://javadoc.jitpack.io/com/github/WiIIiam278/HuskSync/latest/javadoc/me/william278/husksync/bukkit/data/DataSerializer.html). For instance, to get a player's inventory as an `ItemStack[]` from a `PlayerData` object.
|
Use the static methods provided in the [DataSerializer class](https://javadoc.jitpack.io/net.william278/HuskSync/latest/javadoc/net/william278/husksync/bukkit/data/DataSerializer.html). For instance, to get a player's inventory as an `ItemStack[]` from a `PlayerData` object.
|
||||||
```java
|
```java
|
||||||
ItemStack[] inventoryItems = DataSerializer.serializeInventory(playerData.getSerializedInventory());
|
ItemStack[] inventoryItems = DataSerializer.serializeInventory(playerData.getSerializedInventory());
|
||||||
ItemStack[] enderChestItems = DataSerializer.serializeInventory(playerData.getSerializedEnderChest());
|
ItemStack[] enderChestItems = DataSerializer.serializeInventory(playerData.getSerializedEnderChest());
|
||||||
@@ -201,10 +206,9 @@ A code bounty program is in place for HuskSync, where developers making signific
|
|||||||
While the code bounty program is not available for translation contributors, they are still strongly appreciated in making the plugin more accessible. If you'd like to contribute translated message strings for your language, you can submit a Pull Request that creates a .yml file in `bungeecord/src/main/resources/languages` with the correct translations.
|
While the code bounty program is not available for translation contributors, they are still strongly appreciated in making the plugin more accessible. If you'd like to contribute translated message strings for your language, you can submit a Pull Request that creates a .yml file in `bungeecord/src/main/resources/languages` with the correct translations.
|
||||||
|
|
||||||
### Building
|
### Building
|
||||||
To build HuskSync you will first need to download MySqlPlayerDataBridge and `mvn install:install-file` the jar file to your local maven repository.
|
You can build HuskSync yourself, though please read the license and buy yourself a copy as HuskSync is indeed a premium resource.
|
||||||
```
|
|
||||||
mvn install:install-file -Dfile=MysqlPlayerDataBridge-v4.0.1.jar -DgroupId=net.craftersland.data -DartifactId=bridge -Dversion=4.0.1 -Dpackaging=jar
|
To build HuskSync, you'll need to get the [MPDBConverter](https://github.com/WiIIiam278/MPDBDataConverter) library, either by authenticating through GitHub packages or by downloading and running `mvn install-file` to publish it to your local maven repository.
|
||||||
```
|
|
||||||
|
|
||||||
Then, to build the plugin, run the following in the root of the repository:
|
Then, to build the plugin, run the following in the root of the repository:
|
||||||
```
|
```
|
||||||
@@ -217,7 +221,7 @@ This plugin uses bStats to provide me with metrics about its usage:
|
|||||||
* [View BungeeCord metrics](https://bstats.org/plugin/bungeecord/HuskSync%20-%20BungeeCord/13141)
|
* [View BungeeCord metrics](https://bstats.org/plugin/bungeecord/HuskSync%20-%20BungeeCord/13141)
|
||||||
* [View Velocity metrics](https://bstats.org/plugin/velocity/HuskSync%20-%20Velocity/13489)
|
* [View Velocity metrics](https://bstats.org/plugin/velocity/HuskSync%20-%20Velocity/13489)
|
||||||
|
|
||||||
You can turn metric collection off by navigating to `plugins/bStats/config.yml` and editing the config to disable plugin metrics.
|
You can turn metric collection off by navigating to `~/plugins/bStats/config.yml` and editing the config to disable plugin metrics.
|
||||||
|
|
||||||
## Support
|
## Support
|
||||||
* Report bugs: [Click here](https://github.com/WiIIiam278/HuskSync/issues)
|
* Report bugs: [Click here](https://github.com/WiIIiam278/HuskSync/issues)
|
||||||
|
|||||||
@@ -1,49 +1,20 @@
|
|||||||
//file:noinspection GroovyAssignabilityCheck
|
|
||||||
plugins {
|
|
||||||
id 'java-library'
|
|
||||||
id 'maven-publish'
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compileOnly project(path: ':common', configuration: 'shadow')
|
compileOnly project(path: ':common')
|
||||||
|
implementation project(path: ':bukkit')
|
||||||
|
|
||||||
compileOnly 'org.spigotmc:spigot-api:1.16.5-R0.1-SNAPSHOT'
|
compileOnly 'org.spigotmc:spigot-api:1.16.5-R0.1-SNAPSHOT'
|
||||||
compileOnly 'org.jetbrains:annotations:22.0.0'
|
compileOnly 'org.jetbrains:annotations:23.0.0'
|
||||||
}
|
}
|
||||||
|
|
||||||
repositories {
|
shadowJar {
|
||||||
mavenCentral()
|
relocate 'de.themoep', 'net.william278.husksync.libraries'
|
||||||
maven { url 'https://hub.spigotmc.org/nexus/content/repositories/snapshots/' }
|
relocate 'org.bstats', 'net.william278.husksync.libraries.bstats'
|
||||||
|
relocate 'redis.clients', 'net.william278.husksync.libraries'
|
||||||
|
relocate 'org.apache', 'net.william278.husksync.libraries'
|
||||||
|
relocate 'net.william278.mpdbconverter', 'net.william278.husksync.libraries.mpdbconverter'
|
||||||
}
|
}
|
||||||
|
|
||||||
afterEvaluate {
|
java {
|
||||||
publishing {
|
withSourcesJar()
|
||||||
publications {
|
withJavadocJar()
|
||||||
maven(MavenPublication) {
|
|
||||||
groupId = "${rootProject.group}.${rootProject.name.toLowerCase()}"
|
|
||||||
artifactId = project.name
|
|
||||||
|
|
||||||
from components.java
|
|
||||||
artifact javadocsJar
|
|
||||||
}
|
|
||||||
}
|
|
||||||
repositories {
|
|
||||||
mavenLocal()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
task javadocs(type: Javadoc) {
|
|
||||||
options.encoding = 'UTF-8'
|
|
||||||
options.addStringOption('Xdoclint:none', '-quiet')
|
|
||||||
source = project(':common').sourceSets.main.allJava
|
|
||||||
source += project(':api').sourceSets.main.allJava
|
|
||||||
classpath = files(project(':common').sourceSets.main.compileClasspath)
|
|
||||||
classpath += files(project(':api').sourceSets.main.compileClasspath)
|
|
||||||
destinationDir = file("${buildDir}/docs/javadoc")
|
|
||||||
}
|
|
||||||
|
|
||||||
task javadocsJar(type: Jar, dependsOn: javadocs) {
|
|
||||||
archiveClassifier.set 'javadoc'
|
|
||||||
from javadocs.destinationDir
|
|
||||||
}
|
}
|
||||||
@@ -1,16 +1,18 @@
|
|||||||
package me.william278.husksync.bukkit.api;
|
package net.william278.husksync.bukkit.api;
|
||||||
|
|
||||||
import me.william278.husksync.PlayerData;
|
import net.william278.husksync.PlayerData;
|
||||||
import me.william278.husksync.Settings;
|
import net.william278.husksync.Settings;
|
||||||
import me.william278.husksync.redis.RedisMessage;
|
import net.william278.husksync.bukkit.listener.BukkitRedisListener;
|
||||||
|
import net.william278.husksync.redis.RedisMessage;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* API method class for HuskSync. To access methods, use the {@link #getInstance()} entrypoint.
|
* HuskSync's API. To access methods, use the {@link #getInstance()} entrypoint.
|
||||||
|
*
|
||||||
|
* @author William
|
||||||
*/
|
*/
|
||||||
public class HuskSyncAPI {
|
public class HuskSyncAPI {
|
||||||
|
|
||||||
@@ -20,7 +22,7 @@ public class HuskSyncAPI {
|
|||||||
private static HuskSyncAPI instance;
|
private static HuskSyncAPI instance;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* API entry point. Returns an instance of the {@link HuskSyncAPI}
|
* The API entry point. Returns an instance of the {@link HuskSyncAPI}
|
||||||
*
|
*
|
||||||
* @return instance of the {@link HuskSyncAPI}
|
* @return instance of the {@link HuskSyncAPI}
|
||||||
*/
|
*/
|
||||||
@@ -32,35 +34,38 @@ public class HuskSyncAPI {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* (INTERNAL) Map of API requests that are processed by the bukkit plugin that implements the API.
|
* Returns a {@link CompletableFuture} that will fetch the {@link PlayerData} for a user given their {@link UUID},
|
||||||
*/
|
* which contains serialized synchronised data.
|
||||||
public static HashMap<UUID, CompletableFuture<PlayerData>> apiRequests = new HashMap<>();
|
* <p>
|
||||||
|
* This can then be deserialized into ItemStacks and other usable values using the {@code DataSerializer} class.
|
||||||
/**
|
* <p>
|
||||||
* Returns a {@link CompletableFuture} that will fetch the {@link PlayerData} for a user given their {@link UUID}, which contains synchronised data that can then be deserialized into ItemStacks and other usable values using the {@link me.william278.husksync.bukkit.data.DataSerializer} class. If no data could be returned, such as if an invalid UUID is specified, the CompletableFuture will be cancelled. Note that this only returns the last cached data of the user; not necessarily the current state of their inventory if they are online.
|
* If no data could be returned, such as if an invalid UUID is specified, the CompletableFuture will be cancelled.
|
||||||
*
|
*
|
||||||
* @param playerUUID The {@link UUID} of the player to get data for
|
* @param playerUUID The {@link UUID} of the player to get data for
|
||||||
* @return a {@link CompletableFuture} with the user's {@link PlayerData} accessible on completion
|
* @return a {@link CompletableFuture} with the user's {@link PlayerData} accessible on completion
|
||||||
* @throws IOException If an exception occurs with serializing during processing of the request
|
* @throws IOException If an exception occurs with serializing during processing of the request
|
||||||
|
* @apiNote This only returns the latest saved and cached data of the user. This is <b>not</b> necessarily the current state of their inventory if they are online.
|
||||||
*/
|
*/
|
||||||
public CompletableFuture<PlayerData> getPlayerData(UUID playerUUID) throws IOException {
|
public CompletableFuture<PlayerData> getPlayerData(UUID playerUUID) throws IOException {
|
||||||
// Create the request to be completed
|
// Create the request to be completed
|
||||||
final UUID requestUUID = UUID.randomUUID();
|
final UUID requestUUID = UUID.randomUUID();
|
||||||
apiRequests.put(requestUUID, new CompletableFuture<>());
|
BukkitRedisListener.apiRequests.put(requestUUID, new CompletableFuture<>());
|
||||||
|
|
||||||
// Remove the request from the map on completion
|
// Remove the request from the map on completion
|
||||||
apiRequests.get(requestUUID).whenComplete((playerData, throwable) -> apiRequests.remove(requestUUID));
|
BukkitRedisListener.apiRequests.get(requestUUID).whenComplete((playerData, throwable) -> BukkitRedisListener.apiRequests.remove(requestUUID));
|
||||||
|
|
||||||
// Request the data via the proxy
|
// Request the data via the proxy
|
||||||
new RedisMessage(RedisMessage.MessageType.API_DATA_REQUEST,
|
new RedisMessage(RedisMessage.MessageType.API_DATA_REQUEST,
|
||||||
new RedisMessage.MessageTarget(Settings.ServerType.PROXY, null, Settings.cluster),
|
new RedisMessage.MessageTarget(Settings.ServerType.PROXY, null, Settings.cluster),
|
||||||
playerUUID.toString(), requestUUID.toString()).send();
|
playerUUID.toString(), requestUUID.toString()).send();
|
||||||
|
|
||||||
return apiRequests.get(requestUUID);
|
return BukkitRedisListener.apiRequests.get(requestUUID);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates a player's {@link PlayerData} to the central cache and database. If the player is online on the Proxy network, they will be updated and overwritten with this data.
|
* Updates a player's {@link PlayerData} to the proxy cache and database.
|
||||||
|
* <p>
|
||||||
|
* If the player is online on the Proxy network, they will be updated and overwritten with this data.
|
||||||
*
|
*
|
||||||
* @param playerData The {@link PlayerData} (which contains the {@link UUID}) of the player data to update to the central cache and database
|
* @param playerData The {@link PlayerData} (which contains the {@link UUID}) of the player data to update to the central cache and database
|
||||||
* @throws IOException If an exception occurs with serializing during processing of the update
|
* @throws IOException If an exception occurs with serializing during processing of the update
|
||||||
@@ -70,7 +75,7 @@ public class HuskSyncAPI {
|
|||||||
final String serializedPlayerData = RedisMessage.serialize(playerData);
|
final String serializedPlayerData = RedisMessage.serialize(playerData);
|
||||||
new RedisMessage(RedisMessage.MessageType.PLAYER_DATA_UPDATE,
|
new RedisMessage(RedisMessage.MessageType.PLAYER_DATA_UPDATE,
|
||||||
new RedisMessage.MessageTarget(Settings.ServerType.PROXY, null, Settings.cluster),
|
new RedisMessage.MessageTarget(Settings.ServerType.PROXY, null, Settings.cluster),
|
||||||
serializedPlayerData).send();
|
serializedPlayerData, Boolean.toString(true)).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -4,7 +4,7 @@ plugins {
|
|||||||
id 'java'
|
id 'java'
|
||||||
}
|
}
|
||||||
|
|
||||||
group 'me.william278'
|
group 'net.william278'
|
||||||
version "$ext.plugin_version+${versionMetadata()}"
|
version "$ext.plugin_version+${versionMetadata()}"
|
||||||
|
|
||||||
ext {
|
ext {
|
||||||
@@ -19,6 +19,7 @@ allprojects {
|
|||||||
|
|
||||||
compileJava.options.encoding = 'UTF-8'
|
compileJava.options.encoding = 'UTF-8'
|
||||||
javadoc.options.encoding = 'UTF-8'
|
javadoc.options.encoding = 'UTF-8'
|
||||||
|
javadoc.options.addStringOption('Xdoclint:none', '-quiet')
|
||||||
|
|
||||||
compileJava.options.release.set 16
|
compileJava.options.release.set 16
|
||||||
|
|
||||||
@@ -34,7 +35,7 @@ allprojects {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation('redis.clients:jedis:4.1.1') {
|
implementation('redis.clients:jedis:4.2.3') {
|
||||||
//noinspection GroovyAssignabilityCheck
|
//noinspection GroovyAssignabilityCheck
|
||||||
exclude module: 'slf4j-api'
|
exclude module: 'slf4j-api'
|
||||||
}
|
}
|
||||||
@@ -50,7 +51,7 @@ subprojects {
|
|||||||
version rootProject.version
|
version rootProject.version
|
||||||
archivesBaseName = "${rootProject.name}-${project.name.capitalize()}"
|
archivesBaseName = "${rootProject.name}-${project.name.capitalize()}"
|
||||||
|
|
||||||
if (['bukkit', 'bungeecord', 'velocity', 'plugin'].contains(project.name)) {
|
if (['bukkit', 'api', 'bungeecord', 'velocity', 'plugin'].contains(project.name)) {
|
||||||
shadowJar {
|
shadowJar {
|
||||||
destinationDirectory.set(file("$rootDir/target"))
|
destinationDirectory.set(file("$rootDir/target"))
|
||||||
archiveClassifier.set('')
|
archiveClassifier.set('')
|
||||||
|
|||||||
@@ -1,19 +1,18 @@
|
|||||||
dependencies {
|
dependencies {
|
||||||
implementation project(':api')
|
implementation project(path: ':common')
|
||||||
implementation project(path: ':common', configuration: 'shadow')
|
|
||||||
|
|
||||||
implementation 'org.bstats:bstats-bukkit:3.0.0'
|
implementation 'org.bstats:bstats-bukkit:3.0.0'
|
||||||
implementation 'de.themoep:minedown:1.7.1-SNAPSHOT'
|
implementation 'de.themoep:minedown:1.7.1-SNAPSHOT'
|
||||||
|
implementation 'net.william278:mpdbdataconverter:1.0'
|
||||||
|
|
||||||
compileOnly 'net.craftersland.data:bridge:4.0.1'
|
|
||||||
compileOnly 'org.spigotmc:spigot-api:1.16.5-R0.1-SNAPSHOT'
|
compileOnly 'org.spigotmc:spigot-api:1.16.5-R0.1-SNAPSHOT'
|
||||||
compileOnly 'org.jetbrains:annotations:22.0.0'
|
compileOnly 'org.jetbrains:annotations:23.0.0'
|
||||||
}
|
}
|
||||||
|
|
||||||
shadowJar {
|
shadowJar {
|
||||||
relocate 'de.themoep', 'me.william278.husksync.libraries'
|
relocate 'de.themoep', 'net.william278.husksync.libraries'
|
||||||
relocate 'org.bstats', 'me.william278.husksync.libraries.bstats'
|
relocate 'org.bstats', 'net.william278.husksync.libraries.bstats'
|
||||||
|
relocate 'redis.clients', 'net.william278.husksync.libraries'
|
||||||
relocate 'redis.clients', 'me.william278.husksync.libraries'
|
relocate 'org.apache', 'net.william278.husksync.libraries'
|
||||||
relocate 'org.apache', 'me.william278.husksync.libraries'
|
relocate 'net.william278.mpdbconverter', 'net.william278.husksync.libraries.mpdbconverter'
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
package me.william278.husksync.bukkit.data;
|
||||||
|
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.Statistic;
|
||||||
|
import org.bukkit.World;
|
||||||
|
import org.bukkit.entity.EntityType;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds legacy data store methods for data storage
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
@SuppressWarnings("DeprecatedIsStillUsed")
|
||||||
|
public class DataSerializer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A record used to store data for advancement synchronisation
|
||||||
|
*
|
||||||
|
* @deprecated Old format - Use {@link AdvancementRecordDate} instead
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
@SuppressWarnings("DeprecatedIsStillUsed")
|
||||||
|
// Suppress deprecation warnings here (still used for backwards compatibility)
|
||||||
|
public record AdvancementRecord(String advancementKey,
|
||||||
|
ArrayList<String> awardedAdvancementCriteria) implements Serializable {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A record used to store data for a player's statistics
|
||||||
|
*/
|
||||||
|
public record StatisticData(HashMap<Statistic, Integer> untypedStatisticValues,
|
||||||
|
HashMap<Statistic, HashMap<Material, Integer>> blockStatisticValues,
|
||||||
|
HashMap<Statistic, HashMap<Material, Integer>> itemStatisticValues,
|
||||||
|
HashMap<Statistic, HashMap<EntityType, Integer>> entityStatisticValues) implements Serializable {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A record used to store data for native advancement synchronisation, tracking advancement date progress
|
||||||
|
*/
|
||||||
|
public record AdvancementRecordDate(String key, Map<String, Date> criteriaMap) implements Serializable {
|
||||||
|
public AdvancementRecordDate(String key, List<String> criteriaList) {
|
||||||
|
this(key, new HashMap<>() {{
|
||||||
|
criteriaList.forEach(s -> put(s, Date.from(Instant.EPOCH)));
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A record used to store data for a player's location
|
||||||
|
*/
|
||||||
|
public record PlayerLocation(double x, double y, double z, float yaw, float pitch,
|
||||||
|
String worldName, World.Environment environment) implements Serializable {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +1,14 @@
|
|||||||
package me.william278.husksync;
|
package net.william278.husksync;
|
||||||
|
|
||||||
import me.william278.husksync.bukkit.util.BukkitUpdateChecker;
|
import net.william278.husksync.Settings;
|
||||||
import me.william278.husksync.bukkit.util.PlayerSetter;
|
import net.william278.husksync.bukkit.util.BukkitUpdateChecker;
|
||||||
import me.william278.husksync.bukkit.config.ConfigLoader;
|
import net.william278.husksync.bukkit.util.PlayerSetter;
|
||||||
import me.william278.husksync.bukkit.data.BukkitDataCache;
|
import net.william278.husksync.bukkit.config.ConfigLoader;
|
||||||
import me.william278.husksync.bukkit.listener.BukkitRedisListener;
|
import net.william278.husksync.bukkit.data.BukkitDataCache;
|
||||||
import me.william278.husksync.bukkit.listener.BukkitEventListener;
|
import net.william278.husksync.bukkit.listener.BukkitRedisListener;
|
||||||
import me.william278.husksync.bukkit.migrator.MPDBDeserializer;
|
import net.william278.husksync.bukkit.listener.BukkitEventListener;
|
||||||
import me.william278.husksync.redis.RedisMessage;
|
import net.william278.husksync.bukkit.migrator.MPDBDeserializer;
|
||||||
|
import net.william278.husksync.redis.RedisMessage;
|
||||||
import org.bstats.bukkit.Metrics;
|
import org.bstats.bukkit.Metrics;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
@@ -143,7 +144,11 @@ public final class HuskSyncBukkit extends JavaPlugin {
|
|||||||
if (HuskSyncBukkit.handshakeCompleted && !HuskSyncBukkit.isMySqlPlayerDataBridgeInstalled && Bukkit.getOnlinePlayers().size() > 0) {
|
if (HuskSyncBukkit.handshakeCompleted && !HuskSyncBukkit.isMySqlPlayerDataBridgeInstalled && Bukkit.getOnlinePlayers().size() > 0) {
|
||||||
getLogger().info("Saving data for remaining online players...");
|
getLogger().info("Saving data for remaining online players...");
|
||||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||||
PlayerSetter.updatePlayerData(player);
|
PlayerSetter.updatePlayerData(player, false);
|
||||||
|
|
||||||
|
// Clear player inventory and ender chest
|
||||||
|
player.getInventory().clear();
|
||||||
|
player.getEnderChest().clear();
|
||||||
}
|
}
|
||||||
getLogger().info("Data save complete!");
|
getLogger().info("Data save complete!");
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package me.william278.husksync.bukkit.config;
|
package net.william278.husksync.bukkit.config;
|
||||||
|
|
||||||
import me.william278.husksync.Settings;
|
import net.william278.husksync.Settings;
|
||||||
import org.bukkit.configuration.file.FileConfiguration;
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
|
|
||||||
public class ConfigLoader {
|
public class ConfigLoader {
|
||||||
@@ -27,6 +27,8 @@ public class ConfigLoader {
|
|||||||
Settings.syncFlight = config.getBoolean("synchronisation_settings.flight", false);
|
Settings.syncFlight = config.getBoolean("synchronisation_settings.flight", false);
|
||||||
|
|
||||||
Settings.useNativeImplementation = config.getBoolean("native_advancement_synchronization", false);
|
Settings.useNativeImplementation = config.getBoolean("native_advancement_synchronization", false);
|
||||||
|
Settings.saveOnWorldSave = config.getBoolean("save_on_world_save", true);
|
||||||
|
Settings.synchronizationTimeoutRetryDelay = config.getLong("synchronization_timeout_retry_delay", 15L);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package me.william278.husksync.bukkit.data;
|
package net.william278.husksync.bukkit.data;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package me.william278.husksync.bukkit.data;
|
package net.william278.husksync.bukkit.data;
|
||||||
|
|
||||||
import me.william278.husksync.redis.RedisMessage;
|
import net.william278.husksync.redis.RedisMessage;
|
||||||
import org.bukkit.*;
|
import org.bukkit.*;
|
||||||
import org.bukkit.advancement.Advancement;
|
import org.bukkit.advancement.Advancement;
|
||||||
import org.bukkit.advancement.AdvancementProgress;
|
import org.bukkit.advancement.AdvancementProgress;
|
||||||
@@ -15,12 +15,10 @@ import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder;
|
|||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.Serializable;
|
|
||||||
import java.time.Instant;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class that contains static methods for serializing and deserializing data from {@link me.william278.husksync.PlayerData}
|
* Class that contains static methods for serializing and deserializing data from {@link net.william278.husksync.PlayerData}
|
||||||
*/
|
*/
|
||||||
public class DataSerializer {
|
public class DataSerializer {
|
||||||
|
|
||||||
@@ -194,12 +192,12 @@ public class DataSerializer {
|
|||||||
return serializedPotionEffect != null ? new PotionEffect((Map<String, Object>) serializedPotionEffect) : null;
|
return serializedPotionEffect != null ? new PotionEffect((Map<String, Object>) serializedPotionEffect) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DataSerializer.PlayerLocation deserializePlayerLocationData(String serializedLocationData) throws IOException {
|
public static me.william278.husksync.bukkit.data.DataSerializer.PlayerLocation deserializePlayerLocationData(String serializedLocationData) throws IOException {
|
||||||
if (serializedLocationData.isEmpty()) {
|
if (serializedLocationData.isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return (DataSerializer.PlayerLocation) RedisMessage.deserialize(serializedLocationData);
|
return (me.william278.husksync.bukkit.data.DataSerializer.PlayerLocation) RedisMessage.deserialize(serializedLocationData);
|
||||||
} catch (ClassNotFoundException e) {
|
} catch (ClassNotFoundException e) {
|
||||||
throw new IOException("Unable to decode class type.", e);
|
throw new IOException("Unable to decode class type.", e);
|
||||||
}
|
}
|
||||||
@@ -207,19 +205,19 @@ public class DataSerializer {
|
|||||||
|
|
||||||
public static String getSerializedLocation(Player player) throws IOException {
|
public static String getSerializedLocation(Player player) throws IOException {
|
||||||
final Location playerLocation = player.getLocation();
|
final Location playerLocation = player.getLocation();
|
||||||
return RedisMessage.serialize(new DataSerializer.PlayerLocation(playerLocation.getX(), playerLocation.getY(), playerLocation.getZ(),
|
return RedisMessage.serialize(new me.william278.husksync.bukkit.data.DataSerializer.PlayerLocation(playerLocation.getX(), playerLocation.getY(), playerLocation.getZ(),
|
||||||
playerLocation.getYaw(), playerLocation.getPitch(), player.getWorld().getName(), player.getWorld().getEnvironment()));
|
playerLocation.getYaw(), playerLocation.getPitch(), player.getWorld().getName(), player.getWorld().getEnvironment()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deserializes a player's advancement data as serialized with {@link #getSerializedAdvancements(Player)} into {@link AdvancementRecordDate} data.
|
* Deserializes a player's advancement data as serialized with {@link #getSerializedAdvancements(Player)} into {@link me.william278.husksync.bukkit.data.DataSerializer.AdvancementRecordDate} data.
|
||||||
*
|
*
|
||||||
* @param serializedAdvancementData The serialized advancement data {@link String}
|
* @param serializedAdvancementData The serialized advancement data {@link String}
|
||||||
* @return The deserialized {@link AdvancementRecordDate} for the player
|
* @return The deserialized {@link me.william278.husksync.bukkit.data.DataSerializer.AdvancementRecordDate} for the player
|
||||||
* @throws IOException If the deserialization fails
|
* @throws IOException If the deserialization fails
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked") // Ignore the unchecked cast here
|
@SuppressWarnings("unchecked") // Ignore the unchecked cast here
|
||||||
public static List<DataSerializer.AdvancementRecordDate> deserializeAdvancementData(String serializedAdvancementData) throws IOException {
|
public static List<me.william278.husksync.bukkit.data.DataSerializer.AdvancementRecordDate> deserializeAdvancementData(String serializedAdvancementData) throws IOException {
|
||||||
if (serializedAdvancementData.isEmpty()) {
|
if (serializedAdvancementData.isEmpty()) {
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
@@ -227,15 +225,15 @@ public class DataSerializer {
|
|||||||
List<?> deserialize = (List<?>) RedisMessage.deserialize(serializedAdvancementData);
|
List<?> deserialize = (List<?>) RedisMessage.deserialize(serializedAdvancementData);
|
||||||
|
|
||||||
// Migrate old AdvancementRecord into date format
|
// Migrate old AdvancementRecord into date format
|
||||||
if (!deserialize.isEmpty() && deserialize.get(0) instanceof AdvancementRecord) {
|
if (!deserialize.isEmpty() && deserialize.get(0) instanceof me.william278.husksync.bukkit.data.DataSerializer.AdvancementRecord) {
|
||||||
deserialize = ((List<AdvancementRecord>) deserialize).stream()
|
deserialize = ((List<me.william278.husksync.bukkit.data.DataSerializer.AdvancementRecord>) deserialize).stream()
|
||||||
.map(o -> new AdvancementRecordDate(
|
.map(o -> new me.william278.husksync.bukkit.data.DataSerializer.AdvancementRecordDate(
|
||||||
o.advancementKey,
|
o.advancementKey(),
|
||||||
o.awardedAdvancementCriteria
|
o.awardedAdvancementCriteria()
|
||||||
)).toList();
|
)).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
return (List<AdvancementRecordDate>) deserialize;
|
return (List<me.william278.husksync.bukkit.data.DataSerializer.AdvancementRecordDate>) deserialize;
|
||||||
} catch (ClassNotFoundException e) {
|
} catch (ClassNotFoundException e) {
|
||||||
throw new IOException("Unable to decode class type.", e);
|
throw new IOException("Unable to decode class type.", e);
|
||||||
}
|
}
|
||||||
@@ -250,7 +248,7 @@ public class DataSerializer {
|
|||||||
*/
|
*/
|
||||||
public static String getSerializedAdvancements(Player player) throws IOException {
|
public static String getSerializedAdvancements(Player player) throws IOException {
|
||||||
Iterator<Advancement> serverAdvancements = Bukkit.getServer().advancementIterator();
|
Iterator<Advancement> serverAdvancements = Bukkit.getServer().advancementIterator();
|
||||||
ArrayList<DataSerializer.AdvancementRecordDate> advancementData = new ArrayList<>();
|
ArrayList<me.william278.husksync.bukkit.data.DataSerializer.AdvancementRecordDate> advancementData = new ArrayList<>();
|
||||||
|
|
||||||
while (serverAdvancements.hasNext()) {
|
while (serverAdvancements.hasNext()) {
|
||||||
final AdvancementProgress progress = player.getAdvancementProgress(serverAdvancements.next());
|
final AdvancementProgress progress = player.getAdvancementProgress(serverAdvancements.next());
|
||||||
@@ -259,25 +257,25 @@ public class DataSerializer {
|
|||||||
final Map<String, Date> awardedCriteria = new HashMap<>();
|
final Map<String, Date> awardedCriteria = new HashMap<>();
|
||||||
progress.getAwardedCriteria().forEach(s -> awardedCriteria.put(s, progress.getDateAwarded(s)));
|
progress.getAwardedCriteria().forEach(s -> awardedCriteria.put(s, progress.getDateAwarded(s)));
|
||||||
|
|
||||||
advancementData.add(new DataSerializer.AdvancementRecordDate(advancementKey.getNamespace() + ":" + advancementKey.getKey(), awardedCriteria));
|
advancementData.add(new me.william278.husksync.bukkit.data.DataSerializer.AdvancementRecordDate(advancementKey.getNamespace() + ":" + advancementKey.getKey(), awardedCriteria));
|
||||||
}
|
}
|
||||||
|
|
||||||
return RedisMessage.serialize(advancementData);
|
return RedisMessage.serialize(advancementData);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deserializes a player's statistic data as serialized with {@link #getSerializedStatisticData(Player)} into {@link StatisticData}.
|
* Deserializes a player's statistic data as serialized with {@link #getSerializedStatisticData(Player)} into {@link me.william278.husksync.bukkit.data.DataSerializer.StatisticData}.
|
||||||
*
|
*
|
||||||
* @param serializedStatisticData The serialized statistic data {@link String}
|
* @param serializedStatisticData The serialized statistic data {@link String}
|
||||||
* @return The deserialized {@link StatisticData} for the player
|
* @return The deserialized {@link me.william278.husksync.bukkit.data.DataSerializer.StatisticData} for the player
|
||||||
* @throws IOException If the deserialization fails
|
* @throws IOException If the deserialization fails
|
||||||
*/
|
*/
|
||||||
public static DataSerializer.StatisticData deserializeStatisticData(String serializedStatisticData) throws IOException {
|
public static me.william278.husksync.bukkit.data.DataSerializer.StatisticData deserializeStatisticData(String serializedStatisticData) throws IOException {
|
||||||
if (serializedStatisticData.isEmpty()) {
|
if (serializedStatisticData.isEmpty()) {
|
||||||
return new DataSerializer.StatisticData(new HashMap<>(), new HashMap<>(), new HashMap<>(), new HashMap<>());
|
return new me.william278.husksync.bukkit.data.DataSerializer.StatisticData(new HashMap<>(), new HashMap<>(), new HashMap<>(), new HashMap<>());
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return (DataSerializer.StatisticData) RedisMessage.deserialize(serializedStatisticData);
|
return (me.william278.husksync.bukkit.data.DataSerializer.StatisticData) RedisMessage.deserialize(serializedStatisticData);
|
||||||
} catch (ClassNotFoundException e) {
|
} catch (ClassNotFoundException e) {
|
||||||
throw new IOException("Unable to decode class type.", e);
|
throw new IOException("Unable to decode class type.", e);
|
||||||
}
|
}
|
||||||
@@ -322,46 +320,8 @@ public class DataSerializer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DataSerializer.StatisticData statisticData = new DataSerializer.StatisticData(untypedStatisticValues, blockStatisticValues, itemStatisticValues, entityStatisticValues);
|
me.william278.husksync.bukkit.data.DataSerializer.StatisticData statisticData = new me.william278.husksync.bukkit.data.DataSerializer.StatisticData(untypedStatisticValues, blockStatisticValues, itemStatisticValues, entityStatisticValues);
|
||||||
return RedisMessage.serialize(statisticData);
|
return RedisMessage.serialize(statisticData);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* A record used to store data for a player's location
|
|
||||||
*/
|
|
||||||
public record PlayerLocation(double x, double y, double z, float yaw, float pitch,
|
|
||||||
String worldName, World.Environment environment) implements Serializable {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A record used to store data for advancement synchronisation
|
|
||||||
*
|
|
||||||
* @deprecated Old format - Use {@link AdvancementRecordDate} instead
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
@SuppressWarnings("DeprecatedIsStillUsed") // Suppress deprecation warnings here (still used for backwards compatibility)
|
|
||||||
public record AdvancementRecord(String advancementKey,
|
|
||||||
ArrayList<String> awardedAdvancementCriteria) implements Serializable {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A record used to store data for native advancement synchronisation, tracking advancement date progress
|
|
||||||
*/
|
|
||||||
public record AdvancementRecordDate(String key, Map<String, Date> criteriaMap) implements Serializable {
|
|
||||||
AdvancementRecordDate(String key, List<String> criteriaList) {
|
|
||||||
this(key, new HashMap<>() {{
|
|
||||||
criteriaList.forEach(s -> put(s, Date.from(Instant.EPOCH)));
|
|
||||||
}});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A record used to store data for a player's statistics
|
|
||||||
*/
|
|
||||||
public record StatisticData(HashMap<Statistic, Integer> untypedStatisticValues,
|
|
||||||
HashMap<Statistic, HashMap<Material, Integer>> blockStatisticValues,
|
|
||||||
HashMap<Statistic, HashMap<Material, Integer>> itemStatisticValues,
|
|
||||||
HashMap<Statistic, HashMap<EntityType, Integer>> entityStatisticValues) implements Serializable {
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
package me.william278.husksync.bukkit.data;
|
package net.william278.husksync.bukkit.data;
|
||||||
|
|
||||||
import me.william278.husksync.HuskSyncBukkit;
|
import net.william278.husksync.HuskSyncBukkit;
|
||||||
import me.william278.husksync.PlayerData;
|
import net.william278.husksync.PlayerData;
|
||||||
import me.william278.husksync.Settings;
|
import net.william278.husksync.Settings;
|
||||||
import me.william278.husksync.bukkit.util.PlayerSetter;
|
import net.william278.husksync.bukkit.util.PlayerSetter;
|
||||||
import me.william278.husksync.redis.RedisMessage;
|
import net.william278.husksync.redis.RedisMessage;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.inventory.Inventory;
|
import org.bukkit.inventory.Inventory;
|
||||||
@@ -58,7 +58,7 @@ public class DataViewer {
|
|||||||
// Send a redis message with the updated data after the viewing
|
// Send a redis message with the updated data after the viewing
|
||||||
new RedisMessage(RedisMessage.MessageType.PLAYER_DATA_UPDATE,
|
new RedisMessage(RedisMessage.MessageType.PLAYER_DATA_UPDATE,
|
||||||
new RedisMessage.MessageTarget(Settings.ServerType.PROXY, null, Settings.cluster),
|
new RedisMessage.MessageTarget(Settings.ServerType.PROXY, null, Settings.cluster),
|
||||||
RedisMessage.serialize(playerData))
|
RedisMessage.serialize(playerData), Boolean.toString(true))
|
||||||
.send();
|
.send();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package me.william278.husksync.bukkit.api.events;
|
package net.william278.husksync.bukkit.events;
|
||||||
|
|
||||||
import me.william278.husksync.PlayerData;
|
import net.william278.husksync.PlayerData;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.HandlerList;
|
import org.bukkit.event.HandlerList;
|
||||||
import org.bukkit.event.player.PlayerEvent;
|
import org.bukkit.event.player.PlayerEvent;
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package me.william278.husksync.bukkit.api.events;
|
package net.william278.husksync.bukkit.events;
|
||||||
|
|
||||||
import me.william278.husksync.PlayerData;
|
import net.william278.husksync.PlayerData;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.Cancellable;
|
import org.bukkit.event.Cancellable;
|
||||||
import org.bukkit.event.HandlerList;
|
import org.bukkit.event.HandlerList;
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
package me.william278.husksync.bukkit.listener;
|
package net.william278.husksync.bukkit.listener;
|
||||||
|
|
||||||
import me.william278.husksync.HuskSyncBukkit;
|
import net.william278.husksync.HuskSyncBukkit;
|
||||||
import me.william278.husksync.bukkit.data.DataViewer;
|
import net.william278.husksync.Settings;
|
||||||
import me.william278.husksync.bukkit.util.PlayerSetter;
|
import net.william278.husksync.bukkit.data.DataViewer;
|
||||||
|
import net.william278.husksync.bukkit.util.PlayerSetter;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
@@ -14,6 +15,7 @@ import org.bukkit.event.entity.EntityPickupItemEvent;
|
|||||||
import org.bukkit.event.inventory.InventoryCloseEvent;
|
import org.bukkit.event.inventory.InventoryCloseEvent;
|
||||||
import org.bukkit.event.inventory.InventoryOpenEvent;
|
import org.bukkit.event.inventory.InventoryOpenEvent;
|
||||||
import org.bukkit.event.player.*;
|
import org.bukkit.event.player.*;
|
||||||
|
import org.bukkit.event.world.WorldSaveEvent;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
@@ -37,7 +39,14 @@ public class BukkitEventListener implements Listener {
|
|||||||
return; // If the plugin has not been initialized correctly
|
return; // If the plugin has not been initialized correctly
|
||||||
|
|
||||||
// Update the player's data
|
// Update the player's data
|
||||||
PlayerSetter.updatePlayerData(player);
|
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
|
||||||
|
// Update data to proxy
|
||||||
|
PlayerSetter.updatePlayerData(player, true);
|
||||||
|
|
||||||
|
// Clear player inventory and ender chest
|
||||||
|
player.getInventory().clear();
|
||||||
|
player.getEnderChest().clear();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.LOWEST)
|
@EventHandler(priority = EventPriority.LOWEST)
|
||||||
@@ -50,19 +59,22 @@ public class BukkitEventListener implements Listener {
|
|||||||
// Mark the player as awaiting data fetch
|
// Mark the player as awaiting data fetch
|
||||||
HuskSyncBukkit.bukkitCache.setAwaitingDataFetch(player.getUniqueId());
|
HuskSyncBukkit.bukkitCache.setAwaitingDataFetch(player.getUniqueId());
|
||||||
|
|
||||||
if (!HuskSyncBukkit.handshakeCompleted || HuskSyncBukkit.isMySqlPlayerDataBridgeInstalled)
|
if (!HuskSyncBukkit.handshakeCompleted || HuskSyncBukkit.isMySqlPlayerDataBridgeInstalled) {
|
||||||
return; // If the data handshake has not been completed yet (or MySqlPlayerDataBridge is installed)
|
return; // If the data handshake has not been completed yet (or MySqlPlayerDataBridge is installed)
|
||||||
|
}
|
||||||
|
|
||||||
// Send a redis message requesting the player data (if they need to)
|
// Send a redis message requesting the player data (if they need to)
|
||||||
if (HuskSyncBukkit.bukkitCache.isPlayerRequestingOnJoin(player.getUniqueId())) {
|
if (HuskSyncBukkit.bukkitCache.isPlayerRequestingOnJoin(player.getUniqueId())) {
|
||||||
try {
|
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
|
||||||
PlayerSetter.requestPlayerData(player.getUniqueId());
|
try {
|
||||||
} catch (IOException e) {
|
PlayerSetter.requestPlayerData(player.getUniqueId());
|
||||||
plugin.getLogger().log(Level.SEVERE, "Failed to send a PlayerData fetch request", e);
|
} catch (IOException e) {
|
||||||
}
|
plugin.getLogger().log(Level.SEVERE, "Failed to send a PlayerData fetch request", e);
|
||||||
|
}
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
// If the player's data wasn't set after 10 ticks, ensure it will be
|
// If the player's data wasn't set after the synchronization timeout retry delay ticks, ensure it will be
|
||||||
Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, () -> {
|
Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, () -> {
|
||||||
if (player.isOnline()) {
|
if (player.isOnline()) {
|
||||||
try {
|
try {
|
||||||
if (HuskSyncBukkit.bukkitCache.isAwaitingDataFetch(player.getUniqueId())) {
|
if (HuskSyncBukkit.bukkitCache.isAwaitingDataFetch(player.getUniqueId())) {
|
||||||
@@ -72,7 +84,7 @@ public class BukkitEventListener implements Listener {
|
|||||||
plugin.getLogger().log(Level.SEVERE, "Failed to send a PlayerData fetch request", e);
|
plugin.getLogger().log(Level.SEVERE, "Failed to send a PlayerData fetch request", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, 5);
|
}, Settings.synchronizationTimeoutRetryDelay);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,4 +153,14 @@ public class BukkitEventListener implements Listener {
|
|||||||
event.setCancelled(true); // If the plugin / player has not been set
|
event.setCancelled(true); // If the plugin / player has not been set
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.NORMAL)
|
||||||
|
public void onWorldSave(WorldSaveEvent event) {
|
||||||
|
if (!plugin.isEnabled() || !HuskSyncBukkit.handshakeCompleted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (Player playerInWorld : event.getWorld().getPlayers()) {
|
||||||
|
PlayerSetter.updatePlayerData(playerInWorld, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,29 +1,32 @@
|
|||||||
package me.william278.husksync.bukkit.listener;
|
package net.william278.husksync.bukkit.listener;
|
||||||
|
|
||||||
import de.themoep.minedown.MineDown;
|
import de.themoep.minedown.MineDown;
|
||||||
import me.william278.husksync.HuskSyncBukkit;
|
import net.william278.husksync.HuskSyncBukkit;
|
||||||
import me.william278.husksync.PlayerData;
|
import net.william278.husksync.PlayerData;
|
||||||
import me.william278.husksync.Settings;
|
import net.william278.husksync.Settings;
|
||||||
import me.william278.husksync.bukkit.api.HuskSyncAPI;
|
import net.william278.husksync.bukkit.config.ConfigLoader;
|
||||||
import me.william278.husksync.bukkit.config.ConfigLoader;
|
import net.william278.husksync.bukkit.data.DataViewer;
|
||||||
import me.william278.husksync.bukkit.data.DataViewer;
|
import net.william278.husksync.bukkit.migrator.MPDBDeserializer;
|
||||||
import me.william278.husksync.bukkit.migrator.MPDBDeserializer;
|
import net.william278.husksync.bukkit.util.PlayerSetter;
|
||||||
import me.william278.husksync.bukkit.util.PlayerSetter;
|
import net.william278.husksync.migrator.MPDBPlayerData;
|
||||||
import me.william278.husksync.migrator.MPDBPlayerData;
|
import net.william278.husksync.redis.RedisListener;
|
||||||
import me.william278.husksync.redis.RedisListener;
|
import net.william278.husksync.redis.RedisMessage;
|
||||||
import me.william278.husksync.redis.RedisMessage;
|
import net.william278.husksync.util.MessageManager;
|
||||||
import me.william278.husksync.util.MessageManager;
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
public class BukkitRedisListener extends RedisListener {
|
public class BukkitRedisListener extends RedisListener {
|
||||||
|
|
||||||
private static final HuskSyncBukkit plugin = HuskSyncBukkit.getInstance();
|
private static final HuskSyncBukkit plugin = HuskSyncBukkit.getInstance();
|
||||||
|
|
||||||
|
public static HashMap<UUID, CompletableFuture<PlayerData>> apiRequests = new HashMap<>();
|
||||||
|
|
||||||
// Initialize the listener on the bukkit server
|
// Initialize the listener on the bukkit server
|
||||||
public BukkitRedisListener() {
|
public BukkitRedisListener() {
|
||||||
super();
|
super();
|
||||||
@@ -111,10 +114,10 @@ public class BukkitRedisListener extends RedisListener {
|
|||||||
}
|
}
|
||||||
case API_DATA_RETURN -> {
|
case API_DATA_RETURN -> {
|
||||||
final UUID requestUUID = UUID.fromString(message.getMessageDataElements()[0]);
|
final UUID requestUUID = UUID.fromString(message.getMessageDataElements()[0]);
|
||||||
if (HuskSyncAPI.apiRequests.containsKey(requestUUID)) {
|
if (apiRequests.containsKey(requestUUID)) {
|
||||||
try {
|
try {
|
||||||
final PlayerData data = (PlayerData) RedisMessage.deserialize(message.getMessageDataElements()[1]);
|
final PlayerData data = (PlayerData) RedisMessage.deserialize(message.getMessageDataElements()[1]);
|
||||||
HuskSyncAPI.apiRequests.get(requestUUID).complete(data);
|
apiRequests.get(requestUUID).complete(data);
|
||||||
} catch (IOException | ClassNotFoundException e) {
|
} catch (IOException | ClassNotFoundException e) {
|
||||||
log(Level.SEVERE, "Failed to serialize returned API-requested player data");
|
log(Level.SEVERE, "Failed to serialize returned API-requested player data");
|
||||||
}
|
}
|
||||||
@@ -124,8 +127,8 @@ public class BukkitRedisListener extends RedisListener {
|
|||||||
case API_DATA_CANCEL -> {
|
case API_DATA_CANCEL -> {
|
||||||
final UUID requestUUID = UUID.fromString(message.getMessageDataElements()[0]);
|
final UUID requestUUID = UUID.fromString(message.getMessageDataElements()[0]);
|
||||||
// Cancel requests if no data could be found on the proxy
|
// Cancel requests if no data could be found on the proxy
|
||||||
if (HuskSyncAPI.apiRequests.containsKey(requestUUID)) {
|
if (apiRequests.containsKey(requestUUID)) {
|
||||||
HuskSyncAPI.apiRequests.get(requestUUID).cancel(true);
|
apiRequests.get(requestUUID).cancel(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case RELOAD_CONFIG -> {
|
case RELOAD_CONFIG -> {
|
||||||
@@ -1,17 +1,17 @@
|
|||||||
package me.william278.husksync.bukkit.migrator;
|
package net.william278.husksync.bukkit.migrator;
|
||||||
|
|
||||||
import me.william278.husksync.HuskSyncBukkit;
|
import net.william278.husksync.HuskSyncBukkit;
|
||||||
import me.william278.husksync.PlayerData;
|
import net.william278.husksync.PlayerData;
|
||||||
import me.william278.husksync.bukkit.util.PlayerSetter;
|
import net.william278.husksync.bukkit.data.DataSerializer;
|
||||||
import me.william278.husksync.bukkit.data.DataSerializer;
|
import net.william278.husksync.bukkit.util.PlayerSetter;
|
||||||
import me.william278.husksync.migrator.MPDBPlayerData;
|
import net.william278.husksync.migrator.MPDBPlayerData;
|
||||||
import net.craftersland.data.bridge.PD;
|
import net.william278.mpdbconverter.MPDBConverter;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.event.inventory.InventoryType;
|
import org.bukkit.event.inventory.InventoryType;
|
||||||
import org.bukkit.inventory.Inventory;
|
import org.bukkit.inventory.Inventory;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.plugin.Plugin;
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
public class MPDBDeserializer {
|
public class MPDBDeserializer {
|
||||||
@@ -19,10 +19,12 @@ public class MPDBDeserializer {
|
|||||||
private static final HuskSyncBukkit plugin = HuskSyncBukkit.getInstance();
|
private static final HuskSyncBukkit plugin = HuskSyncBukkit.getInstance();
|
||||||
|
|
||||||
// Instance of MySqlPlayerDataBridge
|
// Instance of MySqlPlayerDataBridge
|
||||||
private static PD mySqlPlayerDataBridge;
|
private static MPDBConverter mpdbConverter;
|
||||||
|
|
||||||
public static void setMySqlPlayerDataBridge() {
|
public static void setMySqlPlayerDataBridge() {
|
||||||
mySqlPlayerDataBridge = (PD) Bukkit.getPluginManager().getPlugin("MySqlPlayerDataBridge");
|
Plugin mpdbPlugin = Bukkit.getPluginManager().getPlugin("MySqlPlayerDataBridge");
|
||||||
|
assert mpdbPlugin != null;
|
||||||
|
mpdbConverter = MPDBConverter.getInstance(mpdbPlugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -44,13 +46,13 @@ public class MPDBDeserializer {
|
|||||||
// Set inventory contents
|
// Set inventory contents
|
||||||
Inventory inventory = Bukkit.createInventory(null, InventoryType.PLAYER);
|
Inventory inventory = Bukkit.createInventory(null, InventoryType.PLAYER);
|
||||||
if (!mpdbPlayerData.inventoryData.isEmpty() && !mpdbPlayerData.inventoryData.equalsIgnoreCase("none")) {
|
if (!mpdbPlayerData.inventoryData.isEmpty() && !mpdbPlayerData.inventoryData.equalsIgnoreCase("none")) {
|
||||||
PlayerSetter.setInventory(inventory, getItemStackArrayFromMPDBBase64String(mpdbPlayerData.inventoryData));
|
PlayerSetter.setInventory(inventory, mpdbConverter.getItemStackFromSerializedData(mpdbPlayerData.inventoryData));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set armor (if there is data; MPDB stores empty data with literally the word "none". Obviously.)
|
// Set armor (if there is data; MPDB stores empty data with literally the word "none". Obviously.)
|
||||||
int armorSlot = 36;
|
int armorSlot = 36;
|
||||||
if (!mpdbPlayerData.armorData.isEmpty() && !mpdbPlayerData.armorData.equalsIgnoreCase("none")) {
|
if (!mpdbPlayerData.armorData.isEmpty() && !mpdbPlayerData.armorData.equalsIgnoreCase("none")) {
|
||||||
ItemStack[] armorItems = getItemStackArrayFromMPDBBase64String(mpdbPlayerData.armorData);
|
ItemStack[] armorItems = mpdbConverter.getItemStackFromSerializedData(mpdbPlayerData.armorData);
|
||||||
for (ItemStack armorPiece : armorItems) {
|
for (ItemStack armorPiece : armorItems) {
|
||||||
if (armorPiece != null) {
|
if (armorPiece != null) {
|
||||||
inventory.setItem(armorSlot, armorPiece);
|
inventory.setItem(armorSlot, armorPiece);
|
||||||
@@ -66,7 +68,7 @@ public class MPDBDeserializer {
|
|||||||
// Set ender chest (again, if there is data)
|
// Set ender chest (again, if there is data)
|
||||||
ItemStack[] enderChestData;
|
ItemStack[] enderChestData;
|
||||||
if (!mpdbPlayerData.enderChestData.isEmpty() && !mpdbPlayerData.enderChestData.equalsIgnoreCase("none")) {
|
if (!mpdbPlayerData.enderChestData.isEmpty() && !mpdbPlayerData.enderChestData.equalsIgnoreCase("none")) {
|
||||||
enderChestData = getItemStackArrayFromMPDBBase64String(mpdbPlayerData.enderChestData);
|
enderChestData = mpdbConverter.getItemStackFromSerializedData(mpdbPlayerData.enderChestData);
|
||||||
} else {
|
} else {
|
||||||
enderChestData = new ItemStack[0];
|
enderChestData = new ItemStack[0];
|
||||||
}
|
}
|
||||||
@@ -82,19 +84,4 @@ public class MPDBDeserializer {
|
|||||||
}
|
}
|
||||||
return playerData;
|
return playerData;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an ItemStack array from a decoded base 64 string in MySQLPlayerDataBridge's format
|
|
||||||
*
|
|
||||||
* @param data The encoded ItemStack[] string from MySQLPlayerDataBridge
|
|
||||||
* @return The {@link ItemStack[]} array
|
|
||||||
* @throws InvocationTargetException If an error occurs during decoding
|
|
||||||
* @throws IllegalAccessException If an error occurs during decoding
|
|
||||||
*/
|
|
||||||
public static ItemStack[] getItemStackArrayFromMPDBBase64String(String data) throws InvocationTargetException, IllegalAccessException {
|
|
||||||
if (data.isEmpty()) {
|
|
||||||
return new ItemStack[0];
|
|
||||||
}
|
|
||||||
return mySqlPlayerDataBridge.getItemStackSerializer().fromBase64(data);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package me.william278.husksync.bukkit.util;
|
package net.william278.husksync.bukkit.util;
|
||||||
|
|
||||||
import me.william278.husksync.HuskSyncBukkit;
|
import net.william278.husksync.HuskSyncBukkit;
|
||||||
import me.william278.husksync.util.UpdateChecker;
|
import net.william278.husksync.util.UpdateChecker;
|
||||||
|
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
package me.william278.husksync.bukkit.util;
|
package net.william278.husksync.bukkit.util;
|
||||||
|
|
||||||
import me.william278.husksync.HuskSyncBukkit;
|
import net.william278.husksync.HuskSyncBukkit;
|
||||||
import me.william278.husksync.PlayerData;
|
import net.william278.husksync.PlayerData;
|
||||||
import me.william278.husksync.Settings;
|
import net.william278.husksync.Settings;
|
||||||
import me.william278.husksync.bukkit.api.events.SyncCompleteEvent;
|
import net.william278.husksync.bukkit.events.SyncCompleteEvent;
|
||||||
import me.william278.husksync.bukkit.api.events.SyncEvent;
|
import net.william278.husksync.bukkit.events.SyncEvent;
|
||||||
import me.william278.husksync.bukkit.data.DataSerializer;
|
import net.william278.husksync.bukkit.data.DataSerializer;
|
||||||
import me.william278.husksync.bukkit.util.nms.AdvancementUtils;
|
import net.william278.husksync.bukkit.util.nms.AdvancementUtils;
|
||||||
import me.william278.husksync.redis.RedisMessage;
|
import net.william278.husksync.redis.RedisMessage;
|
||||||
import org.bukkit.*;
|
import org.bukkit.*;
|
||||||
import org.bukkit.advancement.Advancement;
|
import org.bukkit.advancement.Advancement;
|
||||||
import org.bukkit.advancement.AdvancementProgress;
|
import org.bukkit.advancement.AdvancementProgress;
|
||||||
@@ -95,22 +95,19 @@ public class PlayerSetter {
|
|||||||
/**
|
/**
|
||||||
* Update a {@link Player}'s data, sending it to the proxy
|
* Update a {@link Player}'s data, sending it to the proxy
|
||||||
*
|
*
|
||||||
* @param player {@link Player} to send data to proxy
|
* @param player {@link Player} to send data to proxy
|
||||||
|
* @param bounceBack whether the plugin should bounce-back the updated data to the player (used for server switching)
|
||||||
*/
|
*/
|
||||||
public static void updatePlayerData(Player player) {
|
public static void updatePlayerData(Player player, boolean bounceBack) {
|
||||||
// Send a redis message with the player's last updated PlayerData version UUID and their new PlayerData
|
// Send a redis message with the player's last updated PlayerData version UUID and their new PlayerData
|
||||||
try {
|
try {
|
||||||
final String serializedPlayerData = getNewSerializedPlayerData(player);
|
final String serializedPlayerData = getNewSerializedPlayerData(player);
|
||||||
new RedisMessage(RedisMessage.MessageType.PLAYER_DATA_UPDATE,
|
new RedisMessage(RedisMessage.MessageType.PLAYER_DATA_UPDATE,
|
||||||
new RedisMessage.MessageTarget(Settings.ServerType.PROXY, null, Settings.cluster),
|
new RedisMessage.MessageTarget(Settings.ServerType.PROXY, null, Settings.cluster),
|
||||||
serializedPlayerData).send();
|
serializedPlayerData, Boolean.toString(bounceBack)).send();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
plugin.getLogger().log(Level.SEVERE, "Failed to send a PlayerData update to the proxy", e);
|
plugin.getLogger().log(Level.SEVERE, "Failed to send a PlayerData update to the proxy", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear player inventory and ender chest
|
|
||||||
player.getInventory().clear();
|
|
||||||
player.getEnderChest().clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -158,7 +155,7 @@ public class PlayerSetter {
|
|||||||
// Set the player's data from the PlayerData
|
// Set the player's data from the PlayerData
|
||||||
try {
|
try {
|
||||||
if (Settings.syncAdvancements) {
|
if (Settings.syncAdvancements) {
|
||||||
List<DataSerializer.AdvancementRecordDate> advancementRecords
|
List<me.william278.husksync.bukkit.data.DataSerializer.AdvancementRecordDate> advancementRecords
|
||||||
= DataSerializer.deserializeAdvancementData(data.getSerializedAdvancements());
|
= DataSerializer.deserializeAdvancementData(data.getSerializedAdvancements());
|
||||||
|
|
||||||
if (Settings.useNativeImplementation) {
|
if (Settings.useNativeImplementation) {
|
||||||
@@ -276,11 +273,11 @@ public class PlayerSetter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void nativeSyncPlayerAdvancements(final Player player, final List<DataSerializer.AdvancementRecordDate> advancementRecords) {
|
private static void nativeSyncPlayerAdvancements(final Player player, final List<me.william278.husksync.bukkit.data.DataSerializer.AdvancementRecordDate> advancementRecords) {
|
||||||
final Object playerAdvancements = AdvancementUtils.getPlayerAdvancements(player);
|
final Object playerAdvancements = AdvancementUtils.getPlayerAdvancements(player);
|
||||||
|
|
||||||
// Clear
|
// Clear
|
||||||
AdvancementUtils.clearPlayerAdvancements(playerAdvancements);
|
AdvancementUtils.clearPlayerAdvancements(playerAdvancements);
|
||||||
AdvancementUtils.clearVisibleAdvancements(playerAdvancements);
|
AdvancementUtils.clearVisibleAdvancements(playerAdvancements);
|
||||||
|
|
||||||
advancementRecords.forEach(advancementRecord -> {
|
advancementRecords.forEach(advancementRecord -> {
|
||||||
@@ -315,9 +312,9 @@ public class PlayerSetter {
|
|||||||
* Update a player's advancements and progress to match the advancementData
|
* Update a player's advancements and progress to match the advancementData
|
||||||
*
|
*
|
||||||
* @param player The player to set the advancements of
|
* @param player The player to set the advancements of
|
||||||
* @param advancementData The ArrayList of {@link DataSerializer.AdvancementRecordDate}s to set
|
* @param advancementData The ArrayList of {@link me.william278.husksync.bukkit.data.DataSerializer.AdvancementRecordDate}s to set
|
||||||
*/
|
*/
|
||||||
private static void setPlayerAdvancements(Player player, List<DataSerializer.AdvancementRecordDate> advancementData, PlayerData data) {
|
private static void setPlayerAdvancements(Player player, List<me.william278.husksync.bukkit.data.DataSerializer.AdvancementRecordDate> advancementData, PlayerData data) {
|
||||||
// Temporarily disable advancement announcing if needed
|
// Temporarily disable advancement announcing if needed
|
||||||
boolean announceAdvancementUpdate = false;
|
boolean announceAdvancementUpdate = false;
|
||||||
if (Boolean.TRUE.equals(player.getWorld().getGameRuleValue(GameRule.ANNOUNCE_ADVANCEMENTS))) {
|
if (Boolean.TRUE.equals(player.getWorld().getGameRuleValue(GameRule.ANNOUNCE_ADVANCEMENTS))) {
|
||||||
@@ -330,12 +327,12 @@ public class PlayerSetter {
|
|||||||
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
|
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
|
||||||
|
|
||||||
// Apply the advancements to the player
|
// Apply the advancements to the player
|
||||||
Iterator<Advancement> serverAdvancements = Bukkit.getServer().advancementIterator();
|
final Iterator<Advancement> serverAdvancements = Bukkit.getServer().advancementIterator();
|
||||||
while (serverAdvancements.hasNext()) { // Iterate through all advancements
|
while (serverAdvancements.hasNext()) { // Iterate through all advancements
|
||||||
boolean correctExperienceCheck = false; // Determines whether the experience might have changed warranting an update
|
boolean correctExperienceCheck = false; // Determines whether the experience might have changed warranting an update
|
||||||
Advancement advancement = serverAdvancements.next();
|
Advancement advancement = serverAdvancements.next();
|
||||||
AdvancementProgress playerProgress = player.getAdvancementProgress(advancement);
|
AdvancementProgress playerProgress = player.getAdvancementProgress(advancement);
|
||||||
for (DataSerializer.AdvancementRecordDate record : advancementData) {
|
for (me.william278.husksync.bukkit.data.DataSerializer.AdvancementRecordDate record : advancementData) {
|
||||||
// If the advancement is one on the data
|
// If the advancement is one on the data
|
||||||
if (record.key().equals(advancement.getKey().getNamespace() + ":" + advancement.getKey().getKey())) {
|
if (record.key().equals(advancement.getKey().getNamespace() + ":" + advancement.getKey().getKey())) {
|
||||||
|
|
||||||
@@ -378,9 +375,9 @@ public class PlayerSetter {
|
|||||||
* Set a player's statistics (in the Statistic menu)
|
* Set a player's statistics (in the Statistic menu)
|
||||||
*
|
*
|
||||||
* @param player The player to set the statistics of
|
* @param player The player to set the statistics of
|
||||||
* @param statisticData The {@link DataSerializer.StatisticData} to set
|
* @param statisticData The {@link me.william278.husksync.bukkit.data.DataSerializer.StatisticData} to set
|
||||||
*/
|
*/
|
||||||
private static void setPlayerStatistics(Player player, DataSerializer.StatisticData statisticData) {
|
private static void setPlayerStatistics(Player player, me.william278.husksync.bukkit.data.DataSerializer.StatisticData statisticData) {
|
||||||
// Set untyped statistics
|
// Set untyped statistics
|
||||||
for (Statistic statistic : statisticData.untypedStatisticValues().keySet()) {
|
for (Statistic statistic : statisticData.untypedStatisticValues().keySet()) {
|
||||||
player.setStatistic(statistic, statisticData.untypedStatisticValues().get(statistic));
|
player.setStatistic(statistic, statisticData.untypedStatisticValues().get(statistic));
|
||||||
@@ -421,12 +418,12 @@ public class PlayerSetter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set a player's location from {@link DataSerializer.PlayerLocation} data
|
* Set a player's location from {@link me.william278.husksync.bukkit.data.DataSerializer.PlayerLocation} data
|
||||||
*
|
*
|
||||||
* @param player The {@link Player} to teleport
|
* @param player The {@link Player} to teleport
|
||||||
* @param location The {@link DataSerializer.PlayerLocation}
|
* @param location The {@link me.william278.husksync.bukkit.data.DataSerializer.PlayerLocation}
|
||||||
*/
|
*/
|
||||||
private static void setPlayerLocation(Player player, DataSerializer.PlayerLocation location) {
|
private static void setPlayerLocation(Player player, me.william278.husksync.bukkit.data.DataSerializer.PlayerLocation location) {
|
||||||
// Don't teleport if the location is invalid
|
// Don't teleport if the location is invalid
|
||||||
if (location == null) {
|
if (location == null) {
|
||||||
return;
|
return;
|
||||||
@@ -463,12 +460,13 @@ public class PlayerSetter {
|
|||||||
*/
|
*/
|
||||||
private static void setPlayerHealth(Player player, double health, double maxHealth, double healthScale) {
|
private static void setPlayerHealth(Player player, double health, double maxHealth, double healthScale) {
|
||||||
// Set max health
|
// Set max health
|
||||||
if (maxHealth != 0.0D) {
|
if (maxHealth != 0D) {
|
||||||
Objects.requireNonNull(player.getAttribute(Attribute.GENERIC_MAX_HEALTH)).setBaseValue(maxHealth);
|
Objects.requireNonNull(player.getAttribute(Attribute.GENERIC_MAX_HEALTH)).setBaseValue(maxHealth);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set health
|
// Set health
|
||||||
player.setHealth(player.getHealth() > maxHealth ? maxHealth : health);
|
double currentHealth = player.getHealth();
|
||||||
|
if (health != currentHealth) player.setHealth(currentHealth > maxHealth ? maxHealth : health);
|
||||||
|
|
||||||
// Set health scaling if needed
|
// Set health scaling if needed
|
||||||
if (healthScale != 0D) {
|
if (healthScale != 0D) {
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package me.william278.husksync.bukkit.util.nms;
|
package net.william278.husksync.bukkit.util.nms;
|
||||||
|
|
||||||
import me.william278.husksync.util.ThrowSupplier;
|
import net.william278.husksync.util.ThrowSupplier;
|
||||||
import org.bukkit.advancement.Advancement;
|
import org.bukkit.advancement.Advancement;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package me.william278.husksync.bukkit.util.nms;
|
package net.william278.husksync.bukkit.util.nms;
|
||||||
|
|
||||||
import me.william278.husksync.util.ThrowSupplier;
|
import net.william278.husksync.util.ThrowSupplier;
|
||||||
import org.bukkit.entity.LivingEntity;
|
import org.bukkit.entity.LivingEntity;
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package me.william278.husksync.bukkit.util.nms;
|
package net.william278.husksync.bukkit.util.nms;
|
||||||
|
|
||||||
import me.william278.husksync.util.ThrowSupplier;
|
import net.william278.husksync.util.ThrowSupplier;
|
||||||
import me.william278.husksync.util.VersionUtils;
|
import net.william278.husksync.util.VersionUtils;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
|
|
||||||
public class MinecraftVersionUtils {
|
public class MinecraftVersionUtils {
|
||||||
@@ -17,4 +17,6 @@ synchronisation_settings:
|
|||||||
flight: false
|
flight: false
|
||||||
cluster_id: 'main'
|
cluster_id: 'main'
|
||||||
check_for_updates: true
|
check_for_updates: true
|
||||||
native_advancement_synchronization: true
|
synchronization_timeout_retry_delay: 15
|
||||||
|
save_on_world_save: true
|
||||||
|
native_advancement_synchronization: false
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
name: HuskSync
|
name: HuskSync
|
||||||
version: ${version}
|
version: ${version}
|
||||||
main: me.william278.husksync.HuskSyncBukkit
|
main: net.william278.husksync.HuskSyncBukkit
|
||||||
api-version: 1.16
|
api-version: 1.16
|
||||||
author: William278
|
author: William278
|
||||||
description: 'A modern, cross-server player data synchronization system'
|
description: 'A modern, cross-server player data synchronization system'
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
dependencies {
|
dependencies {
|
||||||
implementation project(path: ':common', configuration: 'shadow')
|
implementation project(path: ':common')
|
||||||
|
|
||||||
implementation 'com.zaxxer:HikariCP:5.0.1'
|
implementation 'com.zaxxer:HikariCP:5.0.1'
|
||||||
implementation 'org.bstats:bstats-bungeecord:3.0.0'
|
implementation 'org.bstats:bstats-bungeecord:3.0.0'
|
||||||
@@ -10,14 +10,11 @@ dependencies {
|
|||||||
}
|
}
|
||||||
|
|
||||||
shadowJar {
|
shadowJar {
|
||||||
relocate 'de.themoep', 'me.william278.husksync.libraries'
|
relocate 'de.themoep', 'net.william278.husksync.libraries'
|
||||||
relocate 'net.byteflux', 'me.william278.husksync.libraries'
|
relocate 'net.byteflux', 'net.william278.husksync.libraries'
|
||||||
relocate 'org.bstats', 'me.william278.husksync.libraries.bstats'
|
relocate 'org.bstats', 'net.william278.husksync.libraries.bstats'
|
||||||
|
relocate 'redis.clients', 'net.william278.husksync.libraries'
|
||||||
relocate 'redis.clients', 'me.william278.husksync.libraries'
|
relocate 'org.apache', 'net.william278.husksync.libraries'
|
||||||
relocate 'org.apache', 'me.william278.husksync.libraries'
|
|
||||||
|
|
||||||
relocate 'com.zaxxer', 'me.william278.husksync.libraries'
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
//noinspection GroovyAssignabilityCheck
|
//noinspection GroovyAssignabilityCheck
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
package me.william278.husksync;
|
package net.william278.husksync;
|
||||||
|
|
||||||
import me.william278.husksync.bungeecord.command.BungeeCommand;
|
|
||||||
import me.william278.husksync.bungeecord.config.ConfigLoader;
|
|
||||||
import me.william278.husksync.bungeecord.config.ConfigManager;
|
|
||||||
import me.william278.husksync.bungeecord.listener.BungeeEventListener;
|
|
||||||
import me.william278.husksync.bungeecord.listener.BungeeRedisListener;
|
|
||||||
import me.william278.husksync.bungeecord.util.BungeeLogger;
|
|
||||||
import me.william278.husksync.bungeecord.util.BungeeUpdateChecker;
|
|
||||||
import me.william278.husksync.migrator.MPDBMigrator;
|
|
||||||
import me.william278.husksync.proxy.data.DataManager;
|
|
||||||
import me.william278.husksync.redis.RedisMessage;
|
|
||||||
import me.william278.husksync.util.Logger;
|
|
||||||
import net.byteflux.libby.BungeeLibraryManager;
|
import net.byteflux.libby.BungeeLibraryManager;
|
||||||
import net.byteflux.libby.Library;
|
import net.byteflux.libby.Library;
|
||||||
import net.md_5.bungee.api.ProxyServer;
|
import net.md_5.bungee.api.ProxyServer;
|
||||||
import net.md_5.bungee.api.plugin.Plugin;
|
import net.md_5.bungee.api.plugin.Plugin;
|
||||||
|
import net.william278.husksync.bungeecord.command.BungeeCommand;
|
||||||
|
import net.william278.husksync.bungeecord.config.ConfigLoader;
|
||||||
|
import net.william278.husksync.bungeecord.config.ConfigManager;
|
||||||
|
import net.william278.husksync.bungeecord.listener.BungeeEventListener;
|
||||||
|
import net.william278.husksync.bungeecord.listener.BungeeRedisListener;
|
||||||
|
import net.william278.husksync.bungeecord.util.BungeeLogger;
|
||||||
|
import net.william278.husksync.bungeecord.util.BungeeUpdateChecker;
|
||||||
|
import net.william278.husksync.migrator.MPDBMigrator;
|
||||||
|
import net.william278.husksync.proxy.data.DataManager;
|
||||||
|
import net.william278.husksync.redis.RedisMessage;
|
||||||
|
import net.william278.husksync.util.Logger;
|
||||||
import org.bstats.bungeecord.Metrics;
|
import org.bstats.bungeecord.Metrics;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -155,7 +155,7 @@ public final class HuskSyncBungeeCord extends Plugin {
|
|||||||
Library mySqlLib = Library.builder()
|
Library mySqlLib = Library.builder()
|
||||||
.groupId("mysql")
|
.groupId("mysql")
|
||||||
.artifactId("mysql-connector-java")
|
.artifactId("mysql-connector-java")
|
||||||
.version("8.0.27")
|
.version("8.0.29")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
Library sqLiteLib = Library.builder()
|
Library sqLiteLib = Library.builder()
|
||||||
@@ -1,17 +1,17 @@
|
|||||||
package me.william278.husksync.bungeecord.command;
|
package net.william278.husksync.bungeecord.command;
|
||||||
|
|
||||||
import de.themoep.minedown.MineDown;
|
import de.themoep.minedown.MineDown;
|
||||||
import me.william278.husksync.HuskSyncBungeeCord;
|
import net.william278.husksync.HuskSyncBungeeCord;
|
||||||
import me.william278.husksync.PlayerData;
|
import net.william278.husksync.PlayerData;
|
||||||
import me.william278.husksync.Server;
|
import net.william278.husksync.Server;
|
||||||
import me.william278.husksync.Settings;
|
import net.william278.husksync.Settings;
|
||||||
import me.william278.husksync.bungeecord.config.ConfigLoader;
|
import net.william278.husksync.bungeecord.config.ConfigLoader;
|
||||||
import me.william278.husksync.bungeecord.config.ConfigManager;
|
import net.william278.husksync.bungeecord.config.ConfigManager;
|
||||||
import me.william278.husksync.bungeecord.util.BungeeUpdateChecker;
|
import net.william278.husksync.bungeecord.util.BungeeUpdateChecker;
|
||||||
import me.william278.husksync.migrator.MPDBMigrator;
|
import net.william278.husksync.migrator.MPDBMigrator;
|
||||||
import me.william278.husksync.proxy.command.HuskSyncCommand;
|
import net.william278.husksync.proxy.command.HuskSyncCommand;
|
||||||
import me.william278.husksync.redis.RedisMessage;
|
import net.william278.husksync.redis.RedisMessage;
|
||||||
import me.william278.husksync.util.MessageManager;
|
import net.william278.husksync.util.MessageManager;
|
||||||
import net.md_5.bungee.api.CommandSender;
|
import net.md_5.bungee.api.CommandSender;
|
||||||
import net.md_5.bungee.api.ProxyServer;
|
import net.md_5.bungee.api.ProxyServer;
|
||||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||||
@@ -317,7 +317,7 @@ public class BungeeCommand extends Command implements TabExecutor, HuskSyncComma
|
|||||||
// View the inventory of a player specified by their name
|
// View the inventory of a player specified by their name
|
||||||
private void openInventory(ProxiedPlayer viewer, String targetPlayerName, String clusterId) {
|
private void openInventory(ProxiedPlayer viewer, String targetPlayerName, String clusterId) {
|
||||||
if (viewer.getName().equalsIgnoreCase(targetPlayerName)) {
|
if (viewer.getName().equalsIgnoreCase(targetPlayerName)) {
|
||||||
viewer.sendMessage(new MineDown(MessageManager.getMessage("error_cannot_view_own_ender_chest")).toComponent());
|
viewer.sendMessage(new MineDown(MessageManager.getMessage("error_cannot_view_own_inventory")).toComponent());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (ProxyServer.getInstance().getPlayer(targetPlayerName) != null) {
|
if (ProxyServer.getInstance().getPlayer(targetPlayerName) != null) {
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package me.william278.husksync.bungeecord.config;
|
package net.william278.husksync.bungeecord.config;
|
||||||
|
|
||||||
import me.william278.husksync.HuskSyncBungeeCord;
|
import net.william278.husksync.HuskSyncBungeeCord;
|
||||||
import me.william278.husksync.Settings;
|
import net.william278.husksync.Settings;
|
||||||
import me.william278.husksync.util.MessageManager;
|
import net.william278.husksync.util.MessageManager;
|
||||||
import net.md_5.bungee.config.Configuration;
|
import net.md_5.bungee.config.Configuration;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -60,6 +60,8 @@ public class ConfigLoader {
|
|||||||
Settings.hikariKeepAliveTime = config.getLong("data_storage_settings.hikari_pool_settings.keepalive_time", 0);
|
Settings.hikariKeepAliveTime = config.getLong("data_storage_settings.hikari_pool_settings.keepalive_time", 0);
|
||||||
Settings.hikariConnectionTimeOut = config.getLong("data_storage_settings.hikari_pool_settings.connection_timeout", 5000);
|
Settings.hikariConnectionTimeOut = config.getLong("data_storage_settings.hikari_pool_settings.connection_timeout", 5000);
|
||||||
|
|
||||||
|
Settings.bounceBackSynchronisation = config.getBoolean("bounce_back_synchronization", true);
|
||||||
|
|
||||||
// Read cluster data
|
// Read cluster data
|
||||||
Configuration section = config.getSection("clusters");
|
Configuration section = config.getSection("clusters");
|
||||||
final String settingDatabaseName = Settings.mySQLDatabase != null ? Settings.mySQLDatabase : "HuskSync";
|
final String settingDatabaseName = Settings.mySQLDatabase != null ? Settings.mySQLDatabase : "HuskSync";
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package me.william278.husksync.bungeecord.config;
|
package net.william278.husksync.bungeecord.config;
|
||||||
|
|
||||||
import me.william278.husksync.HuskSyncBungeeCord;
|
import net.william278.husksync.HuskSyncBungeeCord;
|
||||||
import me.william278.husksync.Settings;
|
import net.william278.husksync.Settings;
|
||||||
import net.md_5.bungee.config.Configuration;
|
import net.md_5.bungee.config.Configuration;
|
||||||
import net.md_5.bungee.config.ConfigurationProvider;
|
import net.md_5.bungee.config.ConfigurationProvider;
|
||||||
import net.md_5.bungee.config.YamlConfiguration;
|
import net.md_5.bungee.config.YamlConfiguration;
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
package me.william278.husksync.bungeecord.listener;
|
package net.william278.husksync.bungeecord.listener;
|
||||||
|
|
||||||
import me.william278.husksync.HuskSyncBungeeCord;
|
import net.william278.husksync.HuskSyncBungeeCord;
|
||||||
import me.william278.husksync.PlayerData;
|
import net.william278.husksync.PlayerData;
|
||||||
import me.william278.husksync.Settings;
|
import net.william278.husksync.Settings;
|
||||||
import me.william278.husksync.redis.RedisMessage;
|
import net.william278.husksync.redis.RedisMessage;
|
||||||
import net.md_5.bungee.api.ProxyServer;
|
import net.md_5.bungee.api.ProxyServer;
|
||||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||||
import net.md_5.bungee.api.event.PostLoginEvent;
|
import net.md_5.bungee.api.event.PostLoginEvent;
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
package me.william278.husksync.bungeecord.listener;
|
package net.william278.husksync.bungeecord.listener;
|
||||||
|
|
||||||
import de.themoep.minedown.MineDown;
|
import de.themoep.minedown.MineDown;
|
||||||
import me.william278.husksync.HuskSyncBungeeCord;
|
import net.william278.husksync.HuskSyncBungeeCord;
|
||||||
import me.william278.husksync.Server;
|
import net.william278.husksync.Server;
|
||||||
import me.william278.husksync.util.MessageManager;
|
import net.william278.husksync.util.MessageManager;
|
||||||
import me.william278.husksync.PlayerData;
|
import net.william278.husksync.PlayerData;
|
||||||
import me.william278.husksync.Settings;
|
import net.william278.husksync.Settings;
|
||||||
import me.william278.husksync.migrator.MPDBMigrator;
|
import net.william278.husksync.migrator.MPDBMigrator;
|
||||||
import me.william278.husksync.redis.RedisListener;
|
import net.william278.husksync.redis.RedisListener;
|
||||||
import me.william278.husksync.redis.RedisMessage;
|
import net.william278.husksync.redis.RedisMessage;
|
||||||
import net.md_5.bungee.api.ChatMessageType;
|
import net.md_5.bungee.api.ChatMessageType;
|
||||||
import net.md_5.bungee.api.ProxyServer;
|
import net.md_5.bungee.api.ProxyServer;
|
||||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||||
@@ -63,40 +63,37 @@ public class BungeeRedisListener extends RedisListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (message.getMessageType()) {
|
switch (message.getMessageType()) {
|
||||||
case PLAYER_DATA_REQUEST -> {
|
case PLAYER_DATA_REQUEST -> ProxyServer.getInstance().getScheduler().runAsync(plugin, () -> {
|
||||||
// Get the UUID of the requesting player
|
// Get the UUID of the requesting player
|
||||||
final UUID requestingPlayerUUID = UUID.fromString(message.getMessageData());
|
final UUID requestingPlayerUUID = UUID.fromString(message.getMessageData());
|
||||||
ProxyServer.getInstance().getScheduler().runAsync(plugin, () -> {
|
try {
|
||||||
try {
|
// Send the reply, serializing the message data
|
||||||
// Send the reply, serializing the message data
|
new RedisMessage(RedisMessage.MessageType.PLAYER_DATA_SET,
|
||||||
new RedisMessage(RedisMessage.MessageType.PLAYER_DATA_SET,
|
new RedisMessage.MessageTarget(Settings.ServerType.BUKKIT, requestingPlayerUUID, message.getMessageTarget().targetClusterId()),
|
||||||
new RedisMessage.MessageTarget(Settings.ServerType.BUKKIT, requestingPlayerUUID, message.getMessageTarget().targetClusterId()),
|
RedisMessage.serialize(getPlayerCachedData(requestingPlayerUUID, message.getMessageTarget().targetClusterId())))
|
||||||
RedisMessage.serialize(getPlayerCachedData(requestingPlayerUUID, message.getMessageTarget().targetClusterId())))
|
.send();
|
||||||
.send();
|
|
||||||
|
|
||||||
// Send an update to all bukkit servers removing the player from the requester cache
|
// Send an update to all bukkit servers removing the player from the requester cache
|
||||||
new RedisMessage(RedisMessage.MessageType.REQUEST_DATA_ON_JOIN,
|
new RedisMessage(RedisMessage.MessageType.REQUEST_DATA_ON_JOIN,
|
||||||
new RedisMessage.MessageTarget(Settings.ServerType.BUKKIT, null, message.getMessageTarget().targetClusterId()),
|
new RedisMessage.MessageTarget(Settings.ServerType.BUKKIT, null, message.getMessageTarget().targetClusterId()),
|
||||||
RedisMessage.RequestOnJoinUpdateType.REMOVE_REQUESTER.toString(), requestingPlayerUUID.toString())
|
RedisMessage.RequestOnJoinUpdateType.REMOVE_REQUESTER.toString(), requestingPlayerUUID.toString())
|
||||||
.send();
|
.send();
|
||||||
|
|
||||||
// Send synchronisation complete message
|
// Send synchronisation complete message
|
||||||
ProxiedPlayer player = ProxyServer.getInstance().getPlayer(requestingPlayerUUID);
|
ProxiedPlayer player = ProxyServer.getInstance().getPlayer(requestingPlayerUUID);
|
||||||
if (player != null) {
|
if (player != null) {
|
||||||
if (player.isConnected()) {
|
player.sendMessage(ChatMessageType.ACTION_BAR, new MineDown(MessageManager.getMessage("synchronisation_complete")).toComponent());
|
||||||
player.sendMessage(ChatMessageType.ACTION_BAR, new MineDown(MessageManager.getMessage("synchronisation_complete")).toComponent());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
log(Level.SEVERE, "Failed to serialize data when replying to a data request");
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
});
|
} catch (IOException e) {
|
||||||
}
|
log(Level.SEVERE, "Failed to serialize data when replying to a data request");
|
||||||
case PLAYER_DATA_UPDATE -> {
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
case PLAYER_DATA_UPDATE -> ProxyServer.getInstance().getScheduler().runAsync(plugin, () -> {
|
||||||
// Deserialize the PlayerData received
|
// Deserialize the PlayerData received
|
||||||
PlayerData playerData;
|
PlayerData playerData;
|
||||||
final String serializedPlayerData = message.getMessageData();
|
final String serializedPlayerData = message.getMessageDataElements()[0];
|
||||||
|
final boolean bounceBack = Boolean.parseBoolean(message.getMessageDataElements()[1]);
|
||||||
try {
|
try {
|
||||||
playerData = (PlayerData) RedisMessage.deserialize(serializedPlayerData);
|
playerData = (PlayerData) RedisMessage.deserialize(serializedPlayerData);
|
||||||
} catch (IOException | ClassNotFoundException e) {
|
} catch (IOException | ClassNotFoundException e) {
|
||||||
@@ -114,10 +111,10 @@ public class BungeeRedisListener extends RedisListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Reply with the player data if they are still online (switching server)
|
// Reply with the player data if they are still online (switching server)
|
||||||
try {
|
if (Settings.bounceBackSynchronisation && bounceBack) {
|
||||||
ProxiedPlayer player = ProxyServer.getInstance().getPlayer(playerData.getPlayerUUID());
|
try {
|
||||||
if (player != null) {
|
ProxiedPlayer player = ProxyServer.getInstance().getPlayer(playerData.getPlayerUUID());
|
||||||
if (player.isConnected()) {
|
if (player != null) {
|
||||||
new RedisMessage(RedisMessage.MessageType.PLAYER_DATA_SET,
|
new RedisMessage(RedisMessage.MessageType.PLAYER_DATA_SET,
|
||||||
new RedisMessage.MessageTarget(Settings.ServerType.BUKKIT, playerData.getPlayerUUID(), message.getMessageTarget().targetClusterId()),
|
new RedisMessage.MessageTarget(Settings.ServerType.BUKKIT, playerData.getPlayerUUID(), message.getMessageTarget().targetClusterId()),
|
||||||
serializedPlayerData)
|
serializedPlayerData)
|
||||||
@@ -126,12 +123,12 @@ public class BungeeRedisListener extends RedisListener {
|
|||||||
// Send synchronisation complete message
|
// Send synchronisation complete message
|
||||||
player.sendMessage(ChatMessageType.ACTION_BAR, new MineDown(MessageManager.getMessage("synchronisation_complete")).toComponent());
|
player.sendMessage(ChatMessageType.ACTION_BAR, new MineDown(MessageManager.getMessage("synchronisation_complete")).toComponent());
|
||||||
}
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
log(Level.SEVERE, "Failed to re-serialize PlayerData when handling a player update request");
|
||||||
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
|
||||||
log(Level.SEVERE, "Failed to re-serialize PlayerData when handling a player update request");
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
case CONNECTION_HANDSHAKE -> {
|
case CONNECTION_HANDSHAKE -> {
|
||||||
// Reply to a Bukkit server's connection handshake to complete the process
|
// Reply to a Bukkit server's connection handshake to complete the process
|
||||||
if (HuskSyncBungeeCord.isDisabling) return; // Return if the Proxy is disabling
|
if (HuskSyncBungeeCord.isDisabling) return; // Return if the Proxy is disabling
|
||||||
@@ -198,10 +195,9 @@ public class BungeeRedisListener extends RedisListener {
|
|||||||
HuskSyncBungeeCord.dataManager));
|
HuskSyncBungeeCord.dataManager));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case API_DATA_REQUEST -> {
|
case API_DATA_REQUEST -> ProxyServer.getInstance().getScheduler().runAsync(plugin, () -> {
|
||||||
final UUID playerUUID = UUID.fromString(message.getMessageDataElements()[0]);
|
final UUID playerUUID = UUID.fromString(message.getMessageDataElements()[0]);
|
||||||
final UUID requestUUID = UUID.fromString(message.getMessageDataElements()[1]);
|
final UUID requestUUID = UUID.fromString(message.getMessageDataElements()[1]);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final PlayerData data = getPlayerCachedData(playerUUID, message.getMessageTarget().targetClusterId());
|
final PlayerData data = getPlayerCachedData(playerUUID, message.getMessageTarget().targetClusterId());
|
||||||
|
|
||||||
@@ -221,7 +217,7 @@ public class BungeeRedisListener extends RedisListener {
|
|||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
plugin.getBungeeLogger().log(Level.SEVERE, "Failed to serialize PlayerData requested via the API");
|
plugin.getBungeeLogger().log(Level.SEVERE, "Failed to serialize PlayerData requested via the API");
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package me.william278.husksync.bungeecord.util;
|
package net.william278.husksync.bungeecord.util;
|
||||||
|
|
||||||
import me.william278.husksync.util.Logger;
|
import net.william278.husksync.util.Logger;
|
||||||
|
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package me.william278.husksync.bungeecord.util;
|
package net.william278.husksync.bungeecord.util;
|
||||||
|
|
||||||
import me.william278.husksync.HuskSyncBungeeCord;
|
import net.william278.husksync.HuskSyncBungeeCord;
|
||||||
import me.william278.husksync.util.UpdateChecker;
|
import net.william278.husksync.util.UpdateChecker;
|
||||||
|
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
name: HuskSync
|
name: HuskSync
|
||||||
version: ${version}
|
version: ${version}
|
||||||
main: me.william278.husksync.HuskSyncBungeeCord
|
main: net.william278.husksync.HuskSyncBungeeCord
|
||||||
author: William278
|
author: William278
|
||||||
description: 'A modern, cross-server player data synchronization system'
|
description: 'A modern, cross-server player data synchronization system'
|
||||||
@@ -1,7 +1,11 @@
|
|||||||
|
plugins {
|
||||||
|
id 'java'
|
||||||
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compileOnly 'com.zaxxer:HikariCP:5.0.1'
|
compileOnly 'com.zaxxer:HikariCP:5.0.1'
|
||||||
}
|
}
|
||||||
|
|
||||||
shadowJar {
|
shadowJar {
|
||||||
relocate 'com.zaxxer', 'me.william278.husksync.libraries'
|
relocate 'com.zaxxer', 'net.william278.husksync.libraries'
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package me.william278.husksync;
|
package net.william278.husksync;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
import java.time.Instant;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -18,6 +19,11 @@ public class PlayerData implements Serializable {
|
|||||||
*/
|
*/
|
||||||
private final UUID dataVersionUUID;
|
private final UUID dataVersionUUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Epoch time identifying when the data was last updated or created
|
||||||
|
*/
|
||||||
|
private long timestamp;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A special flag that will be {@code true} if the player is new to the network and should not have their data set when joining the Bukkit
|
* A special flag that will be {@code true} if the player is new to the network and should not have their data set when joining the Bukkit
|
||||||
*/
|
*/
|
||||||
@@ -70,6 +76,7 @@ public class PlayerData implements Serializable {
|
|||||||
String serializedStatusEffects, int totalExperience, int expLevel, float expProgress, String gameMode,
|
String serializedStatusEffects, int totalExperience, int expLevel, float expProgress, String gameMode,
|
||||||
String serializedStatistics, boolean isFlying, String serializedAdvancements, String serializedLocation) {
|
String serializedStatistics, boolean isFlying, String serializedAdvancements, String serializedLocation) {
|
||||||
this.dataVersionUUID = UUID.randomUUID();
|
this.dataVersionUUID = UUID.randomUUID();
|
||||||
|
this.timestamp = Instant.now().getEpochSecond();
|
||||||
this.playerUUID = playerUUID;
|
this.playerUUID = playerUUID;
|
||||||
this.serializedInventory = serializedInventory;
|
this.serializedInventory = serializedInventory;
|
||||||
this.serializedEnderChest = serializedEnderChest;
|
this.serializedEnderChest = serializedEnderChest;
|
||||||
@@ -109,16 +116,17 @@ public class PlayerData implements Serializable {
|
|||||||
* @param totalExperience Their total experience points ("Score")
|
* @param totalExperience Their total experience points ("Score")
|
||||||
* @param expLevel Their exp level
|
* @param expLevel Their exp level
|
||||||
* @param expProgress Their exp progress to the next level
|
* @param expProgress Their exp progress to the next level
|
||||||
* @param gameMode Their game mode ({@code SURVIVAL}, {@code CREATIVE}, etc)
|
* @param gameMode Their game mode ({@code SURVIVAL}, {@code CREATIVE}, etc.)
|
||||||
* @param serializedStatistics Their serialized statistics data (Displayed in Statistics menu in ESC menu)
|
* @param serializedStatistics Their serialized statistics data (Displayed in Statistics menu in ESC menu)
|
||||||
*/
|
*/
|
||||||
public PlayerData(UUID playerUUID, UUID dataVersionUUID, String serializedInventory, String serializedEnderChest,
|
public PlayerData(UUID playerUUID, UUID dataVersionUUID, long timestamp, String serializedInventory, String serializedEnderChest,
|
||||||
double health, double maxHealth, double healthScale, int hunger, float saturation, float saturationExhaustion,
|
double health, double maxHealth, double healthScale, int hunger, float saturation, float saturationExhaustion,
|
||||||
int selectedSlot, String serializedStatusEffects, int totalExperience, int expLevel, float expProgress,
|
int selectedSlot, String serializedStatusEffects, int totalExperience, int expLevel, float expProgress,
|
||||||
String gameMode, String serializedStatistics, boolean isFlying, String serializedAdvancements,
|
String gameMode, String serializedStatistics, boolean isFlying, String serializedAdvancements,
|
||||||
String serializedLocation) {
|
String serializedLocation) {
|
||||||
this.playerUUID = playerUUID;
|
this.playerUUID = playerUUID;
|
||||||
this.dataVersionUUID = dataVersionUUID;
|
this.dataVersionUUID = dataVersionUUID;
|
||||||
|
this.timestamp = timestamp;
|
||||||
this.serializedInventory = serializedInventory;
|
this.serializedInventory = serializedInventory;
|
||||||
this.serializedEnderChest = serializedEnderChest;
|
this.serializedEnderChest = serializedEnderChest;
|
||||||
this.health = health;
|
this.health = health;
|
||||||
@@ -172,6 +180,15 @@ public class PlayerData implements Serializable {
|
|||||||
return dataVersionUUID;
|
return dataVersionUUID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the timestamp when this data was created or last updated
|
||||||
|
*
|
||||||
|
* @return time since epoch of last data update or creation
|
||||||
|
*/
|
||||||
|
public long getDataTimestamp() {
|
||||||
|
return timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the serialized player {@code ItemStack[]} inventory
|
* Returns the serialized player {@code ItemStack[]} inventory
|
||||||
*
|
*
|
||||||
@@ -341,6 +358,7 @@ public class PlayerData implements Serializable {
|
|||||||
*/
|
*/
|
||||||
public void setSerializedInventory(String serializedInventory) {
|
public void setSerializedInventory(String serializedInventory) {
|
||||||
this.serializedInventory = serializedInventory;
|
this.serializedInventory = serializedInventory;
|
||||||
|
this.timestamp = Instant.now().getEpochSecond();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -350,6 +368,7 @@ public class PlayerData implements Serializable {
|
|||||||
*/
|
*/
|
||||||
public void setSerializedEnderChest(String serializedEnderChest) {
|
public void setSerializedEnderChest(String serializedEnderChest) {
|
||||||
this.serializedEnderChest = serializedEnderChest;
|
this.serializedEnderChest = serializedEnderChest;
|
||||||
|
this.timestamp = Instant.now().getEpochSecond();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -359,6 +378,7 @@ public class PlayerData implements Serializable {
|
|||||||
*/
|
*/
|
||||||
public void setHealth(double health) {
|
public void setHealth(double health) {
|
||||||
this.health = health;
|
this.health = health;
|
||||||
|
this.timestamp = Instant.now().getEpochSecond();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -368,6 +388,7 @@ public class PlayerData implements Serializable {
|
|||||||
*/
|
*/
|
||||||
public void setMaxHealth(double maxHealth) {
|
public void setMaxHealth(double maxHealth) {
|
||||||
this.maxHealth = maxHealth;
|
this.maxHealth = maxHealth;
|
||||||
|
this.timestamp = Instant.now().getEpochSecond();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -377,6 +398,7 @@ public class PlayerData implements Serializable {
|
|||||||
*/
|
*/
|
||||||
public void setHealthScale(double healthScale) {
|
public void setHealthScale(double healthScale) {
|
||||||
this.healthScale = healthScale;
|
this.healthScale = healthScale;
|
||||||
|
this.timestamp = Instant.now().getEpochSecond();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -386,6 +408,7 @@ public class PlayerData implements Serializable {
|
|||||||
*/
|
*/
|
||||||
public void setHunger(int hunger) {
|
public void setHunger(int hunger) {
|
||||||
this.hunger = hunger;
|
this.hunger = hunger;
|
||||||
|
this.timestamp = Instant.now().getEpochSecond();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -395,6 +418,7 @@ public class PlayerData implements Serializable {
|
|||||||
*/
|
*/
|
||||||
public void setSaturation(float saturation) {
|
public void setSaturation(float saturation) {
|
||||||
this.saturation = saturation;
|
this.saturation = saturation;
|
||||||
|
this.timestamp = Instant.now().getEpochSecond();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -404,6 +428,7 @@ public class PlayerData implements Serializable {
|
|||||||
*/
|
*/
|
||||||
public void setSaturationExhaustion(float saturationExhaustion) {
|
public void setSaturationExhaustion(float saturationExhaustion) {
|
||||||
this.saturationExhaustion = saturationExhaustion;
|
this.saturationExhaustion = saturationExhaustion;
|
||||||
|
this.timestamp = Instant.now().getEpochSecond();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -413,6 +438,7 @@ public class PlayerData implements Serializable {
|
|||||||
*/
|
*/
|
||||||
public void setSelectedSlot(int selectedSlot) {
|
public void setSelectedSlot(int selectedSlot) {
|
||||||
this.selectedSlot = selectedSlot;
|
this.selectedSlot = selectedSlot;
|
||||||
|
this.timestamp = Instant.now().getEpochSecond();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -422,6 +448,7 @@ public class PlayerData implements Serializable {
|
|||||||
*/
|
*/
|
||||||
public void setSerializedEffectData(String serializedEffectData) {
|
public void setSerializedEffectData(String serializedEffectData) {
|
||||||
this.serializedEffectData = serializedEffectData;
|
this.serializedEffectData = serializedEffectData;
|
||||||
|
this.timestamp = Instant.now().getEpochSecond();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -431,6 +458,7 @@ public class PlayerData implements Serializable {
|
|||||||
*/
|
*/
|
||||||
public void setTotalExperience(int totalExperience) {
|
public void setTotalExperience(int totalExperience) {
|
||||||
this.totalExperience = totalExperience;
|
this.totalExperience = totalExperience;
|
||||||
|
this.timestamp = Instant.now().getEpochSecond();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -440,6 +468,7 @@ public class PlayerData implements Serializable {
|
|||||||
*/
|
*/
|
||||||
public void setExpLevel(int expLevel) {
|
public void setExpLevel(int expLevel) {
|
||||||
this.expLevel = expLevel;
|
this.expLevel = expLevel;
|
||||||
|
this.timestamp = Instant.now().getEpochSecond();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -449,6 +478,7 @@ public class PlayerData implements Serializable {
|
|||||||
*/
|
*/
|
||||||
public void setExpProgress(float expProgress) {
|
public void setExpProgress(float expProgress) {
|
||||||
this.expProgress = expProgress;
|
this.expProgress = expProgress;
|
||||||
|
this.timestamp = Instant.now().getEpochSecond();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -458,6 +488,7 @@ public class PlayerData implements Serializable {
|
|||||||
*/
|
*/
|
||||||
public void setGameMode(String gameMode) {
|
public void setGameMode(String gameMode) {
|
||||||
this.gameMode = gameMode;
|
this.gameMode = gameMode;
|
||||||
|
this.timestamp = Instant.now().getEpochSecond();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -467,6 +498,7 @@ public class PlayerData implements Serializable {
|
|||||||
*/
|
*/
|
||||||
public void setSerializedStatistics(String serializedStatistics) {
|
public void setSerializedStatistics(String serializedStatistics) {
|
||||||
this.serializedStatistics = serializedStatistics;
|
this.serializedStatistics = serializedStatistics;
|
||||||
|
this.timestamp = Instant.now().getEpochSecond();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -476,6 +508,7 @@ public class PlayerData implements Serializable {
|
|||||||
*/
|
*/
|
||||||
public void setFlying(boolean flying) {
|
public void setFlying(boolean flying) {
|
||||||
isFlying = flying;
|
isFlying = flying;
|
||||||
|
this.timestamp = Instant.now().getEpochSecond();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -485,6 +518,7 @@ public class PlayerData implements Serializable {
|
|||||||
*/
|
*/
|
||||||
public void setSerializedAdvancements(String serializedAdvancements) {
|
public void setSerializedAdvancements(String serializedAdvancements) {
|
||||||
this.serializedAdvancements = serializedAdvancements;
|
this.serializedAdvancements = serializedAdvancements;
|
||||||
|
this.timestamp = Instant.now().getEpochSecond();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -494,5 +528,6 @@ public class PlayerData implements Serializable {
|
|||||||
*/
|
*/
|
||||||
public void setSerializedLocation(String serializedLocation) {
|
public void setSerializedLocation(String serializedLocation) {
|
||||||
this.serializedLocation = serializedLocation;
|
this.serializedLocation = serializedLocation;
|
||||||
|
this.timestamp = Instant.now().getEpochSecond();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package me.william278.husksync;
|
package net.william278.husksync;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package me.william278.husksync;
|
package net.william278.husksync;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
@@ -36,6 +36,9 @@ public class Settings {
|
|||||||
// SQL settings
|
// SQL settings
|
||||||
public static DataStorageType dataStorageType;
|
public static DataStorageType dataStorageType;
|
||||||
|
|
||||||
|
// Bounce-back synchronisation (default)
|
||||||
|
public static boolean bounceBackSynchronisation;
|
||||||
|
|
||||||
// MySQL specific settings
|
// MySQL specific settings
|
||||||
public static String mySQLHost;
|
public static String mySQLHost;
|
||||||
public static String mySQLDatabase;
|
public static String mySQLDatabase;
|
||||||
@@ -67,8 +70,8 @@ public class Settings {
|
|||||||
public static boolean syncAdvancements;
|
public static boolean syncAdvancements;
|
||||||
public static boolean syncLocation;
|
public static boolean syncLocation;
|
||||||
public static boolean syncFlight;
|
public static boolean syncFlight;
|
||||||
|
public static long synchronizationTimeoutRetryDelay;
|
||||||
// Future
|
public static boolean saveOnWorldSave;
|
||||||
public static boolean useNativeImplementation;
|
public static boolean useNativeImplementation;
|
||||||
|
|
||||||
// This Cluster ID
|
// This Cluster ID
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
package me.william278.husksync.migrator;
|
package net.william278.husksync.migrator;
|
||||||
|
|
||||||
import me.william278.husksync.PlayerData;
|
import net.william278.husksync.PlayerData;
|
||||||
import me.william278.husksync.Server;
|
import net.william278.husksync.Server;
|
||||||
import me.william278.husksync.Settings;
|
import net.william278.husksync.Settings;
|
||||||
import me.william278.husksync.proxy.data.DataManager;
|
import net.william278.husksync.proxy.data.DataManager;
|
||||||
import me.william278.husksync.proxy.data.sql.Database;
|
import net.william278.husksync.proxy.data.sql.Database;
|
||||||
import me.william278.husksync.proxy.data.sql.MySQL;
|
import net.william278.husksync.proxy.data.sql.MySQL;
|
||||||
import me.william278.husksync.redis.RedisListener;
|
import net.william278.husksync.redis.RedisListener;
|
||||||
import me.william278.husksync.redis.RedisMessage;
|
import net.william278.husksync.redis.RedisMessage;
|
||||||
import me.william278.husksync.util.Logger;
|
import net.william278.husksync.util.Logger;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package me.william278.husksync.migrator;
|
package net.william278.husksync.migrator;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package me.william278.husksync.proxy.command;
|
package net.william278.husksync.proxy.command;
|
||||||
|
|
||||||
public interface HuskSyncCommand {
|
public interface HuskSyncCommand {
|
||||||
|
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
package me.william278.husksync.proxy.data;
|
package net.william278.husksync.proxy.data;
|
||||||
|
|
||||||
import me.william278.husksync.PlayerData;
|
import net.william278.husksync.PlayerData;
|
||||||
import me.william278.husksync.Settings;
|
import net.william278.husksync.Settings;
|
||||||
import me.william278.husksync.proxy.data.sql.Database;
|
import net.william278.husksync.proxy.data.sql.Database;
|
||||||
import me.william278.husksync.proxy.data.sql.MySQL;
|
import net.william278.husksync.proxy.data.sql.MySQL;
|
||||||
import me.william278.husksync.proxy.data.sql.SQLite;
|
import net.william278.husksync.proxy.data.sql.SQLite;
|
||||||
import me.william278.husksync.util.Logger;
|
import net.william278.husksync.util.Logger;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.sql.*;
|
import java.sql.*;
|
||||||
@@ -184,7 +184,7 @@ public class DataManager {
|
|||||||
ResultSet resultSet = statement.executeQuery();
|
ResultSet resultSet = statement.executeQuery();
|
||||||
if (resultSet.next()) {
|
if (resultSet.next()) {
|
||||||
final UUID dataVersionUUID = UUID.fromString(resultSet.getString("version_uuid"));
|
final UUID dataVersionUUID = UUID.fromString(resultSet.getString("version_uuid"));
|
||||||
//final Timestamp dataSaveTimestamp = resultSet.getTimestamp("timestamp");
|
final Timestamp dataSaveTimestamp = resultSet.getTimestamp("timestamp");
|
||||||
final String serializedInventory = resultSet.getString("inventory");
|
final String serializedInventory = resultSet.getString("inventory");
|
||||||
final String serializedEnderChest = resultSet.getString("ender_chest");
|
final String serializedEnderChest = resultSet.getString("ender_chest");
|
||||||
final double health = resultSet.getDouble("health");
|
final double health = resultSet.getDouble("health");
|
||||||
@@ -204,10 +204,10 @@ public class DataManager {
|
|||||||
final String serializedLocationData = resultSet.getString("location");
|
final String serializedLocationData = resultSet.getString("location");
|
||||||
final String serializedStatisticData = resultSet.getString("statistics");
|
final String serializedStatisticData = resultSet.getString("statistics");
|
||||||
|
|
||||||
data.put(cluster, new PlayerData(playerUUID, dataVersionUUID, serializedInventory, serializedEnderChest,
|
data.put(cluster, new PlayerData(playerUUID, dataVersionUUID, dataSaveTimestamp.toInstant().getEpochSecond(),
|
||||||
health, maxHealth, healthScale, hunger, saturation, saturationExhaustion, selectedSlot, serializedStatusEffects,
|
serializedInventory, serializedEnderChest, health, maxHealth, healthScale, hunger, saturation,
|
||||||
totalExperience, expLevel, expProgress, gameMode, serializedStatisticData, isFlying,
|
saturationExhaustion, selectedSlot, serializedStatusEffects, totalExperience, expLevel, expProgress,
|
||||||
serializedAdvancementData, serializedLocationData));
|
gameMode, serializedStatisticData, isFlying, serializedAdvancementData, serializedLocationData));
|
||||||
} else {
|
} else {
|
||||||
data.put(cluster, PlayerData.DEFAULT_PLAYER_DATA(playerUUID));
|
data.put(cluster, PlayerData.DEFAULT_PLAYER_DATA(playerUUID));
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package me.william278.husksync.proxy.data.sql;
|
package net.william278.husksync.proxy.data.sql;
|
||||||
|
|
||||||
import me.william278.husksync.Settings;
|
import net.william278.husksync.Settings;
|
||||||
import me.william278.husksync.util.Logger;
|
import net.william278.husksync.util.Logger;
|
||||||
|
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package me.william278.husksync.proxy.data.sql;
|
package net.william278.husksync.proxy.data.sql;
|
||||||
|
|
||||||
import com.zaxxer.hikari.HikariDataSource;
|
import com.zaxxer.hikari.HikariDataSource;
|
||||||
import me.william278.husksync.Settings;
|
import net.william278.husksync.Settings;
|
||||||
import me.william278.husksync.util.Logger;
|
import net.william278.husksync.util.Logger;
|
||||||
|
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package me.william278.husksync.proxy.data.sql;
|
package net.william278.husksync.proxy.data.sql;
|
||||||
|
|
||||||
import com.zaxxer.hikari.HikariDataSource;
|
import com.zaxxer.hikari.HikariDataSource;
|
||||||
import me.william278.husksync.Settings;
|
import net.william278.husksync.Settings;
|
||||||
import me.william278.husksync.util.Logger;
|
import net.william278.husksync.util.Logger;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package me.william278.husksync.redis;
|
package net.william278.husksync.redis;
|
||||||
|
|
||||||
import me.william278.husksync.Settings;
|
import net.william278.husksync.Settings;
|
||||||
import redis.clients.jedis.*;
|
import redis.clients.jedis.*;
|
||||||
import redis.clients.jedis.exceptions.JedisConnectionException;
|
import redis.clients.jedis.exceptions.JedisConnectionException;
|
||||||
import redis.clients.jedis.exceptions.JedisException;
|
import redis.clients.jedis.exceptions.JedisException;
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package me.william278.husksync.redis;
|
package net.william278.husksync.redis;
|
||||||
|
|
||||||
import me.william278.husksync.PlayerData;
|
import net.william278.husksync.PlayerData;
|
||||||
import me.william278.husksync.Settings;
|
import net.william278.husksync.Settings;
|
||||||
import redis.clients.jedis.Jedis;
|
import redis.clients.jedis.Jedis;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package me.william278.husksync.util;
|
package net.william278.husksync.util;
|
||||||
|
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package me.william278.husksync.util;
|
package net.william278.husksync.util;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ public class MessageManager {
|
|||||||
.append("[%plugin_description%](gray)\n")
|
.append("[%plugin_description%](gray)\n")
|
||||||
.append("[• Author:](white) [William278](gray show_text=&7Click to visit website open_url=https://william278.net)\n")
|
.append("[• Author:](white) [William278](gray show_text=&7Click to visit website open_url=https://william278.net)\n")
|
||||||
.append("[• Contributors:](white) [HarvelsX](gray show_text=&7Code)\n")
|
.append("[• Contributors:](white) [HarvelsX](gray show_text=&7Code)\n")
|
||||||
.append("[• Translators:](white) [Namiu/うにたろう](gray show_text=&7Japanese, ja-jp), [anchelthe](gray show_text=&7Spanish, es-es)\n")
|
.append("[• Translators:](white) [Namiu/うにたろう](gray show_text=&7Japanese, ja-jp), [anchelthe](gray show_text=&7Spanish, es-es), [Ceddix](gray show_text=&7German, de-de), [小蔡](gray show_text=&7Traditional Chinese, zh-tw), [Ghost-chu](gray show_text=&7Simplified Chinese, zh-cn), [Thourgard](gray show_text=&7Ukrainian, uk-ua)\n")
|
||||||
.append("[• Plugin Info:](white) [[Link]](#00fb9a show_text=&7Click to open link open_url=https://github.com/WiIIiam278/HuskSync/)\n")
|
.append("[• Plugin Info:](white) [[Link]](#00fb9a show_text=&7Click to open link open_url=https://github.com/WiIIiam278/HuskSync/)\n")
|
||||||
.append("[• Report Issues:](white) [[Link]](#00fb9a show_text=&7Click to open link open_url=https://github.com/WiIIiam278/HuskSync/issues)\n")
|
.append("[• Report Issues:](white) [[Link]](#00fb9a show_text=&7Click to open link open_url=https://github.com/WiIIiam278/HuskSync/issues)\n")
|
||||||
.append("[• Support Discord:](white) [[Link]](#00fb9a show_text=&7Click to join open_url=https://discord.gg/tVYhJfyDWG)");
|
.append("[• Support Discord:](white) [[Link]](#00fb9a show_text=&7Click to join open_url=https://discord.gg/tVYhJfyDWG)");
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package me.william278.husksync.util;
|
package net.william278.husksync.util;
|
||||||
|
|
||||||
public interface ThrowSupplier<T> {
|
public interface ThrowSupplier<T> {
|
||||||
T get() throws Exception;
|
T get() throws Exception;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package me.william278.husksync.util;
|
package net.william278.husksync.util;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package me.william278.husksync.util;
|
package net.william278.husksync.util;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
14
common/src/main/resources/languages/de-de.yml
Normal file
14
common/src/main/resources/languages/de-de.yml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
synchronisation_complete: '[Daten synchronisiert!](#00fb9a)'
|
||||||
|
viewing_inventory_of: '[Einsicht in das Inventar von](#00fb9a) [%1%](#00fb9a bold)'
|
||||||
|
viewing_ender_chest_of: '[Einsicht in die Endertruhe von](#00fb9a) [%1%](#00fb9a bold)'
|
||||||
|
reload_complete: '[HuskSync](#00fb9a bold) [| Die Konfigurations- und Meldungsdateien wurden aktualisiert.](#00fb9a)'
|
||||||
|
error_invalid_syntax: '[Fehler:](#ff3300) [Falsche Syntax. Nutze: %1%](#ff7e5e)'
|
||||||
|
error_invalid_player: '[Fehler:](#ff3300) [Dieser Spieler konnte nicht gefunden werden](#ff7e5e)'
|
||||||
|
error_no_permission: '[Fehler:](#ff3300) [Du hast nicht die benötigten Berechtigungen um diesen Befehl auszuführen](#ff7e5e)'
|
||||||
|
error_cannot_view_inventory_online: '[Fehler:](#ff3300) [Du kannst nicht über HuskSync auf das Inventar eines Online-Spielers zugreifen](#ff7e5e)'
|
||||||
|
error_cannot_view_ender_chest_online: '[Fehler:](#ff3300) [Du kannst nicht über HuskSync auf die Endertruhe eines Online-Spielers zugreifen](#ff7e5e)'
|
||||||
|
error_cannot_view_own_inventory: '[Fehler:](#ff3300) [Du kannst nicht auf dein eigenes Inventar zugreifen!](#ff7e5e)'
|
||||||
|
error_cannot_view_own_ender_chest: '[Fehler:](#ff3300) [Du kannst nicht auf deine eigene Endertruhe zugreifen!](#ff7e5e)'
|
||||||
|
error_console_command_only: '[Fehler:](#ff3300) [Dieser Befehl kann nur über die %1% Konsole ausgeführt werden](#ff7e5e)'
|
||||||
|
error_no_servers_proxied: '[Fehler:](#ff3300) [Vorgang konnte nicht verarbeitet werden; Es sind keine Server online, auf denen HuskSync installiert ist. Bitte stelle sicher, dass HuskSync sowohl auf dem Proxy-Server als auch auf allen Servern installiert ist, zwischen denen du Daten synchronisieren möchtest.](#ff7e5e)'
|
||||||
|
error_invalid_cluster: '[Fehler:](#ff3300) [Bitte gib die ID eines gültigen Clusters an.](#ff7e5e)'
|
||||||
14
common/src/main/resources/languages/uk-ua.yml
Normal file
14
common/src/main/resources/languages/uk-ua.yml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
synchronisation_complete: '[Дані синхронізовано!](#00fb9a)'
|
||||||
|
viewing_inventory_of: '[Переглядання інвентару](#00fb9a) [%1%](#00fb9a bold)'
|
||||||
|
viewing_ender_chest_of: '[Переглядання скрині енду](#00fb9a) [%1%](#00fb9a bold)'
|
||||||
|
reload_complete: '[HuskSync](#00fb9a bold) [| Перезавантажено конфіґ та файли повідомлень.](#00fb9a)'
|
||||||
|
error_invalid_syntax: '[Помилка:](#ff3300) [Неправильний синтакс. Використання: %1%](#ff7e5e)'
|
||||||
|
error_invalid_player: '[Помилка:](#ff3300) [Гравця не знайдено](#ff7e5e)'
|
||||||
|
error_no_permission: '[Помилка:](#ff3300) [Ввас немає дозволу на використання цієї команди](#ff7e5e)'
|
||||||
|
error_cannot_view_inventory_online: '[Помилка:](#ff3300) [Ви не можете переглядати інвентар гравців, що знаходяться онлайн, з допомогую HuskSync](#ff7e5e)'
|
||||||
|
error_cannot_view_ender_chest_online: '[Помилка:](#ff3300) [Ви не можете переглядати скриню енду гравців, що знаходяться онлайн, з допомогую HuskSync](#ff7e5e)'
|
||||||
|
error_cannot_view_own_inventory: '[Помилка:](#ff3300) [Ви не можете переглядати власний інвентар!](#ff7e5e)'
|
||||||
|
error_cannot_view_own_ender_chest: '[Помилка:](#ff3300) [Ви не можете переглядати власну скриню енду!](#ff7e5e)'
|
||||||
|
error_console_command_only: '[Помилка:](#ff3300) [Ця команда може бути використана лише з допомогою %1% консолі](#ff7e5e)'
|
||||||
|
error_no_servers_proxied: '[Помилка:](#ff3300) [Не вдалося опрацювати операцію; не знайдено жодного сервера із встановленим HuskSync. Запевніться, будьласка, що HuskSync встановлено на Проксі та усіх серверах між якими ви хочете синхроніхувати дані.](#ff7e5e)'
|
||||||
|
error_invalid_cluster: '[Помилка:](#ff3300) [Зазнчте будь ласка ID слушного кластеру.](#ff7e5e)'
|
||||||
14
common/src/main/resources/languages/zh-cn.yml
Normal file
14
common/src/main/resources/languages/zh-cn.yml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
synchronisation_complete: '[数据同步完成](#00fb9a)'
|
||||||
|
viewing_inventory_of: '[查看玩家背包:](#00fb9a) [%1%](#00fb9a bold)'
|
||||||
|
viewing_ender_chest_of: '[查看玩家末影箱:](#00fb9a) [%1%](#00fb9a bold)'
|
||||||
|
reload_complete: '[HuskSync](#00fb9a bold) [| 配置与语言文件重载完成.](#00fb9a)'
|
||||||
|
error_invalid_syntax: '[错误:](#ff3300) [格式错误. 使用方法: %1%](#ff7e5e)'
|
||||||
|
error_invalid_player: '[错误:](#ff3300) [未找到目标玩家](#ff7e5e)'
|
||||||
|
error_no_permission: '[错误:](#ff3300) [你没有权限执行此命令](#ff7e5e)'
|
||||||
|
error_cannot_view_inventory_online: '[错误:](#ff3300) [你不能在玩家在线时通过 HuskSync 查看与编辑玩家物品栏](#ff7e5e)'
|
||||||
|
error_cannot_view_ender_chest_online: '[错误:](#ff3300) [你不能在玩家在线时通过 HuskSync 查看与编辑玩家末影箱](#ff7e5e)'
|
||||||
|
error_cannot_view_own_inventory: '[错误:](#ff3300) [你不能查看和编辑自己的物品栏!](#ff7e5e)'
|
||||||
|
error_cannot_view_own_ender_chest: '[错误:](#ff3300) [你不能查看和编辑自己的末影箱!](#ff7e5e)'
|
||||||
|
error_console_command_only: '[错误:](#ff3300) [该命令只能由 %1% 控制台执行](#ff7e5e)'
|
||||||
|
error_no_servers_proxied: '[错误:](#ff3300) [操作处理失败; 没有任何安装了 HuskSync 的后端服务器在线. 请确认 HuskSync 已在 BungeeCord/Velocity 等代理服务器和所有你希望互相同步数据的后端服务器间安装.](#ff7e5e)'
|
||||||
|
error_invalid_cluster: '[错误:](#ff3300) [请指定一个有效的集群(cluster) ID.](#ff7e5e)'
|
||||||
14
common/src/main/resources/languages/zh-tw.yml
Normal file
14
common/src/main/resources/languages/zh-tw.yml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
synchronisation_complete: '[資料已同步!!](#00fb9a)'
|
||||||
|
viewing_inventory_of: '[查看](#00fb9a) [%1%](#00fb9a bold) [的背包](#00fb9a)'
|
||||||
|
viewing_ender_chest_of: '[查看](#00fb9a) [%1%](#00fb9a bold) [的終界箱](#00fb9a)'
|
||||||
|
reload_complete: '[HuskSync](#00fb9a bold) [| 已重新載入配置和訊息文件](#00fb9a)'
|
||||||
|
error_invalid_syntax: '[錯誤:](#ff3300) [語法不正確,用法: %1%](#ff7e5e)'
|
||||||
|
error_invalid_player: '[錯誤:](#ff3300) [找不到這位玩家](#ff7e5e)'
|
||||||
|
error_no_permission: '[錯誤:](#ff3300) [您沒有權限執行這個指令](#ff7e5e)'
|
||||||
|
error_cannot_view_inventory_online: '[錯誤:](#ff3300) [您無法通過 HuskSync 查看在線玩家的背包](#ff7e5e)'
|
||||||
|
error_cannot_view_ender_chest_online: '[錯誤:](#ff3300) [您無法通過 HuskSync 查看在線玩家的終界箱](#ff7e5e)'
|
||||||
|
error_cannot_view_own_inventory: '[錯誤:](#ff3300) [您無法查看自己的背包!](#ff7e5e)'
|
||||||
|
error_cannot_view_own_ender_chest: '[錯誤:](#ff3300) [你無法查看自己的終界箱!](#ff7e5e)'
|
||||||
|
error_console_command_only: '[錯誤:](#ff3300) [該指令只能通過 %1% 控制台運行](#ff7e5e)'
|
||||||
|
error_no_servers_proxied: '[錯誤:](#ff3300) [處理操作失敗: 沒有安裝 HuskSync 的伺服器在線。 請確保在 Proxy 伺服器和您希望在其他同步數據的所有伺服器上都安裝了 HuskSync。](#ff7e5e)'
|
||||||
|
error_invalid_cluster: '[錯誤:](#ff3300) [請提供有效的 Cluster ID](#ff7e5e)'
|
||||||
@@ -19,6 +19,7 @@ data_storage_settings:
|
|||||||
maximum_lifetime: 1800000
|
maximum_lifetime: 1800000
|
||||||
keepalive_time: 0
|
keepalive_time: 0
|
||||||
connection_timeout: 5000
|
connection_timeout: 5000
|
||||||
|
bounce_back_synchronization: true
|
||||||
clusters:
|
clusters:
|
||||||
main:
|
main:
|
||||||
player_table: 'husksync_players'
|
player_table: 'husksync_players'
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
org.gradle.parallel=true
|
|
||||||
javaVersion=16
|
javaVersion=16
|
||||||
|
plugin_version=1.4
|
||||||
plugin_version=1.3.2
|
|
||||||
plugin_archive=husksync
|
plugin_archive=husksync
|
||||||
@@ -6,7 +6,8 @@ before_install:
|
|||||||
- 'chmod +x gradlew'
|
- 'chmod +x gradlew'
|
||||||
- 'chmod +x ./.jitpack/ensure-java-16'
|
- 'chmod +x ./.jitpack/ensure-java-16'
|
||||||
- 'bash ./.jitpack/ensure-java-16 install'
|
- 'bash ./.jitpack/ensure-java-16 install'
|
||||||
|
- 'bash ./.jitpack/install-mpdb-converter'
|
||||||
install:
|
install:
|
||||||
- 'if ! ./.jitpack/ensure-java-16 use; then source ~/.sdkman/bin/sdkman-init.sh; fi'
|
- 'if ! ./.jitpack/ensure-java-16 use; then source ~/.sdkman/bin/sdkman-init.sh; fi'
|
||||||
- 'java -version'
|
- 'java -version'
|
||||||
- './gradlew api:clean api:publishToMavenLocal'
|
- './gradlew clean publishToMavenLocal'
|
||||||
@@ -5,6 +5,7 @@ plugins {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(path: ':bukkit', configuration: 'shadow')
|
implementation project(path: ':bukkit', configuration: 'shadow')
|
||||||
|
implementation project(path: ':api', configuration: 'shadow')
|
||||||
implementation project(path: ':bungeecord', configuration: 'shadow')
|
implementation project(path: ':bungeecord', configuration: 'shadow')
|
||||||
implementation project(path: ':velocity', configuration: 'shadow')
|
implementation project(path: ':velocity', configuration: 'shadow')
|
||||||
}
|
}
|
||||||
@@ -19,7 +20,7 @@ shadowJar {
|
|||||||
publishing {
|
publishing {
|
||||||
publications {
|
publications {
|
||||||
mavenJava(MavenPublication) {
|
mavenJava(MavenPublication) {
|
||||||
groupId = 'me.william278'
|
groupId = 'net.william278'
|
||||||
artifactId = 'husksync-plugin'
|
artifactId = 'husksync-plugin'
|
||||||
version = "$rootProject.version"
|
version = "$rootProject.version"
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
dependencies {
|
dependencies {
|
||||||
implementation project(path: ':common', configuration: 'shadow')
|
implementation project(path: ':common')
|
||||||
|
|
||||||
implementation 'com.zaxxer:HikariCP:5.0.1'
|
implementation 'com.zaxxer:HikariCP:5.0.1'
|
||||||
implementation 'org.bstats:bstats-velocity:3.0.0'
|
implementation 'org.bstats:bstats-velocity:3.0.0'
|
||||||
@@ -10,14 +10,11 @@ dependencies {
|
|||||||
}
|
}
|
||||||
|
|
||||||
shadowJar {
|
shadowJar {
|
||||||
relocate 'de.themoep', 'me.william278.husksync.libraries'
|
relocate 'de.themoep', 'net.william278.husksync.libraries'
|
||||||
relocate 'net.byteflux', 'me.william278.husksync.libraries'
|
relocate 'net.byteflux', 'net.william278.husksync.libraries'
|
||||||
relocate 'org.bstats', 'me.william278.husksync.libraries.bstats'
|
relocate 'org.bstats', 'net.william278.husksync.libraries.bstats'
|
||||||
|
relocate 'redis.clients', 'net.william278.husksync.libraries'
|
||||||
relocate 'redis.clients', 'me.william278.husksync.libraries'
|
relocate 'org.apache', 'net.william278.husksync.libraries'
|
||||||
relocate 'org.apache', 'me.william278.husksync.libraries'
|
|
||||||
|
|
||||||
relocate 'com.zaxxer', 'me.william278.husksync.libraries'
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
//noinspection GroovyAssignabilityCheck
|
//noinspection GroovyAssignabilityCheck
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package me.william278.husksync;
|
package net.william278.husksync;
|
||||||
|
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import com.velocitypowered.api.command.CommandManager;
|
import com.velocitypowered.api.command.CommandManager;
|
||||||
@@ -10,16 +10,18 @@ import com.velocitypowered.api.plugin.Plugin;
|
|||||||
import com.velocitypowered.api.plugin.PluginContainer;
|
import com.velocitypowered.api.plugin.PluginContainer;
|
||||||
import com.velocitypowered.api.plugin.annotation.DataDirectory;
|
import com.velocitypowered.api.plugin.annotation.DataDirectory;
|
||||||
import com.velocitypowered.api.proxy.ProxyServer;
|
import com.velocitypowered.api.proxy.ProxyServer;
|
||||||
import me.william278.husksync.migrator.MPDBMigrator;
|
import net.william278.husksync.Server;
|
||||||
import me.william278.husksync.proxy.data.DataManager;
|
import net.william278.husksync.Settings;
|
||||||
import me.william278.husksync.redis.RedisMessage;
|
import net.william278.husksync.migrator.MPDBMigrator;
|
||||||
import me.william278.husksync.velocity.command.VelocityCommand;
|
import net.william278.husksync.proxy.data.DataManager;
|
||||||
import me.william278.husksync.velocity.config.ConfigLoader;
|
import net.william278.husksync.redis.RedisMessage;
|
||||||
import me.william278.husksync.velocity.config.ConfigManager;
|
import net.william278.husksync.velocity.command.VelocityCommand;
|
||||||
import me.william278.husksync.velocity.listener.VelocityEventListener;
|
import net.william278.husksync.velocity.config.ConfigLoader;
|
||||||
import me.william278.husksync.velocity.listener.VelocityRedisListener;
|
import net.william278.husksync.velocity.config.ConfigManager;
|
||||||
import me.william278.husksync.velocity.util.VelocityLogger;
|
import net.william278.husksync.velocity.listener.VelocityEventListener;
|
||||||
import me.william278.husksync.velocity.util.VelocityUpdateChecker;
|
import net.william278.husksync.velocity.listener.VelocityRedisListener;
|
||||||
|
import net.william278.husksync.velocity.util.VelocityLogger;
|
||||||
|
import net.william278.husksync.velocity.util.VelocityUpdateChecker;
|
||||||
import net.byteflux.libby.Library;
|
import net.byteflux.libby.Library;
|
||||||
import net.byteflux.libby.VelocityLibraryManager;
|
import net.byteflux.libby.VelocityLibraryManager;
|
||||||
import org.bstats.velocity.Metrics;
|
import org.bstats.velocity.Metrics;
|
||||||
@@ -202,7 +204,7 @@ public class HuskSyncVelocity {
|
|||||||
Library mySqlLib = Library.builder()
|
Library mySqlLib = Library.builder()
|
||||||
.groupId("mysql")
|
.groupId("mysql")
|
||||||
.artifactId("mysql-connector-java")
|
.artifactId("mysql-connector-java")
|
||||||
.version("8.0.27")
|
.version("8.0.29")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
Library sqLiteLib = Library.builder()
|
Library sqLiteLib = Library.builder()
|
||||||
@@ -1,20 +1,20 @@
|
|||||||
package me.william278.husksync.velocity.command;
|
package net.william278.husksync.velocity.command;
|
||||||
|
|
||||||
import com.velocitypowered.api.command.CommandSource;
|
import com.velocitypowered.api.command.CommandSource;
|
||||||
import com.velocitypowered.api.command.SimpleCommand;
|
import com.velocitypowered.api.command.SimpleCommand;
|
||||||
import com.velocitypowered.api.proxy.Player;
|
import com.velocitypowered.api.proxy.Player;
|
||||||
import de.themoep.minedown.adventure.MineDown;
|
import de.themoep.minedown.adventure.MineDown;
|
||||||
import me.william278.husksync.HuskSyncVelocity;
|
import net.william278.husksync.HuskSyncVelocity;
|
||||||
import me.william278.husksync.PlayerData;
|
import net.william278.husksync.PlayerData;
|
||||||
import me.william278.husksync.Server;
|
import net.william278.husksync.Server;
|
||||||
import me.william278.husksync.Settings;
|
import net.william278.husksync.Settings;
|
||||||
import me.william278.husksync.migrator.MPDBMigrator;
|
import net.william278.husksync.migrator.MPDBMigrator;
|
||||||
import me.william278.husksync.proxy.command.HuskSyncCommand;
|
import net.william278.husksync.proxy.command.HuskSyncCommand;
|
||||||
import me.william278.husksync.redis.RedisMessage;
|
import net.william278.husksync.redis.RedisMessage;
|
||||||
import me.william278.husksync.util.MessageManager;
|
import net.william278.husksync.util.MessageManager;
|
||||||
import me.william278.husksync.velocity.util.VelocityUpdateChecker;
|
import net.william278.husksync.velocity.util.VelocityUpdateChecker;
|
||||||
import me.william278.husksync.velocity.config.ConfigLoader;
|
import net.william278.husksync.velocity.config.ConfigLoader;
|
||||||
import me.william278.husksync.velocity.config.ConfigManager;
|
import net.william278.husksync.velocity.config.ConfigManager;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@@ -310,7 +310,7 @@ public class VelocityCommand implements SimpleCommand, HuskSyncCommand {
|
|||||||
// View the inventory of a player specified by their name
|
// View the inventory of a player specified by their name
|
||||||
private void openInventory(Player viewer, String targetPlayerName, String clusterId) {
|
private void openInventory(Player viewer, String targetPlayerName, String clusterId) {
|
||||||
if (viewer.getUsername().equalsIgnoreCase(targetPlayerName)) {
|
if (viewer.getUsername().equalsIgnoreCase(targetPlayerName)) {
|
||||||
viewer.sendMessage(new MineDown(MessageManager.getMessage("error_cannot_view_own_ender_chest")).toComponent());
|
viewer.sendMessage(new MineDown(MessageManager.getMessage("error_cannot_view_own_inventory")).toComponent());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (plugin.getProxyServer().getPlayer(targetPlayerName).isPresent()) {
|
if (plugin.getProxyServer().getPlayer(targetPlayerName).isPresent()) {
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package me.william278.husksync.velocity.config;
|
package net.william278.husksync.velocity.config;
|
||||||
|
|
||||||
import me.william278.husksync.HuskSyncVelocity;
|
import net.william278.husksync.HuskSyncVelocity;
|
||||||
import me.william278.husksync.Settings;
|
import net.william278.husksync.Settings;
|
||||||
import me.william278.husksync.util.MessageManager;
|
import net.william278.husksync.util.MessageManager;
|
||||||
import ninja.leaping.configurate.ConfigurationNode;
|
import ninja.leaping.configurate.ConfigurationNode;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -75,6 +75,8 @@ public class ConfigLoader {
|
|||||||
Settings.hikariKeepAliveTime = getConfigLong(config, 0, "data_storage_settings", "hikari_pool_settings", "keepalive_time");
|
Settings.hikariKeepAliveTime = getConfigLong(config, 0, "data_storage_settings", "hikari_pool_settings", "keepalive_time");
|
||||||
Settings.hikariConnectionTimeOut = getConfigLong(config, 5000, "data_storage_settings", "hikari_pool_settings", "connection_timeout");
|
Settings.hikariConnectionTimeOut = getConfigLong(config, 5000, "data_storage_settings", "hikari_pool_settings", "connection_timeout");
|
||||||
|
|
||||||
|
Settings.bounceBackSynchronisation = getConfigBoolean(config, true,"bounce_back_synchronization");
|
||||||
|
|
||||||
// Read cluster data
|
// Read cluster data
|
||||||
ConfigurationNode clusterSection = config.getNode("clusters");
|
ConfigurationNode clusterSection = config.getNode("clusters");
|
||||||
final String settingDatabaseName = Settings.mySQLDatabase != null ? Settings.mySQLDatabase : "HuskSync";
|
final String settingDatabaseName = Settings.mySQLDatabase != null ? Settings.mySQLDatabase : "HuskSync";
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package me.william278.husksync.velocity.config;
|
package net.william278.husksync.velocity.config;
|
||||||
|
|
||||||
import me.william278.husksync.HuskSyncVelocity;
|
import net.william278.husksync.HuskSyncVelocity;
|
||||||
import me.william278.husksync.Settings;
|
import net.william278.husksync.Settings;
|
||||||
import ninja.leaping.configurate.ConfigurationNode;
|
import ninja.leaping.configurate.ConfigurationNode;
|
||||||
import ninja.leaping.configurate.yaml.YAMLConfigurationLoader;
|
import ninja.leaping.configurate.yaml.YAMLConfigurationLoader;
|
||||||
import org.yaml.snakeyaml.DumperOptions;
|
import org.yaml.snakeyaml.DumperOptions;
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
package me.william278.husksync.velocity.listener;
|
package net.william278.husksync.velocity.listener;
|
||||||
|
|
||||||
|
import com.velocitypowered.api.event.PostOrder;
|
||||||
import com.velocitypowered.api.event.Subscribe;
|
import com.velocitypowered.api.event.Subscribe;
|
||||||
import com.velocitypowered.api.event.connection.PostLoginEvent;
|
import com.velocitypowered.api.event.connection.PostLoginEvent;
|
||||||
import com.velocitypowered.api.proxy.Player;
|
import com.velocitypowered.api.proxy.Player;
|
||||||
import me.william278.husksync.HuskSyncVelocity;
|
import net.william278.husksync.HuskSyncVelocity;
|
||||||
import me.william278.husksync.PlayerData;
|
import net.william278.husksync.PlayerData;
|
||||||
import me.william278.husksync.Settings;
|
import net.william278.husksync.Settings;
|
||||||
import me.william278.husksync.redis.RedisMessage;
|
import net.william278.husksync.redis.RedisMessage;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -16,7 +17,7 @@ public class VelocityEventListener {
|
|||||||
|
|
||||||
private static final HuskSyncVelocity plugin = HuskSyncVelocity.getInstance();
|
private static final HuskSyncVelocity plugin = HuskSyncVelocity.getInstance();
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe(order = PostOrder.FIRST)
|
||||||
public void onPostLogin(PostLoginEvent event) {
|
public void onPostLogin(PostLoginEvent event) {
|
||||||
final Player player = event.getPlayer();
|
final Player player = event.getPlayer();
|
||||||
plugin.getProxyServer().getScheduler().buildTask(plugin, () -> {
|
plugin.getProxyServer().getScheduler().buildTask(plugin, () -> {
|
||||||
@@ -1,15 +1,15 @@
|
|||||||
package me.william278.husksync.velocity.listener;
|
package net.william278.husksync.velocity.listener;
|
||||||
|
|
||||||
import com.velocitypowered.api.proxy.Player;
|
import com.velocitypowered.api.proxy.Player;
|
||||||
import de.themoep.minedown.adventure.MineDown;
|
import de.themoep.minedown.adventure.MineDown;
|
||||||
import me.william278.husksync.HuskSyncVelocity;
|
import net.william278.husksync.HuskSyncVelocity;
|
||||||
import me.william278.husksync.PlayerData;
|
import net.william278.husksync.PlayerData;
|
||||||
import me.william278.husksync.Server;
|
import net.william278.husksync.Server;
|
||||||
import me.william278.husksync.Settings;
|
import net.william278.husksync.Settings;
|
||||||
import me.william278.husksync.migrator.MPDBMigrator;
|
import net.william278.husksync.migrator.MPDBMigrator;
|
||||||
import me.william278.husksync.redis.RedisListener;
|
import net.william278.husksync.redis.RedisListener;
|
||||||
import me.william278.husksync.redis.RedisMessage;
|
import net.william278.husksync.redis.RedisMessage;
|
||||||
import me.william278.husksync.util.MessageManager;
|
import net.william278.husksync.util.MessageManager;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@@ -62,36 +62,35 @@ public class VelocityRedisListener extends RedisListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (message.getMessageType()) {
|
switch (message.getMessageType()) {
|
||||||
case PLAYER_DATA_REQUEST -> {
|
case PLAYER_DATA_REQUEST -> plugin.getProxyServer().getScheduler().buildTask(plugin, () -> {
|
||||||
// Get the UUID of the requesting player
|
// Get the UUID of the requesting player
|
||||||
final UUID requestingPlayerUUID = UUID.fromString(message.getMessageData());
|
final UUID requestingPlayerUUID = UUID.fromString(message.getMessageData());
|
||||||
plugin.getProxyServer().getScheduler().buildTask(plugin, () -> {
|
try {
|
||||||
try {
|
// Send the reply, serializing the message data
|
||||||
// Send the reply, serializing the message data
|
new RedisMessage(RedisMessage.MessageType.PLAYER_DATA_SET,
|
||||||
new RedisMessage(RedisMessage.MessageType.PLAYER_DATA_SET,
|
new RedisMessage.MessageTarget(Settings.ServerType.BUKKIT, requestingPlayerUUID, message.getMessageTarget().targetClusterId()),
|
||||||
new RedisMessage.MessageTarget(Settings.ServerType.BUKKIT, requestingPlayerUUID, message.getMessageTarget().targetClusterId()),
|
RedisMessage.serialize(getPlayerCachedData(requestingPlayerUUID, message.getMessageTarget().targetClusterId())))
|
||||||
RedisMessage.serialize(getPlayerCachedData(requestingPlayerUUID, message.getMessageTarget().targetClusterId())))
|
.send();
|
||||||
.send();
|
|
||||||
|
|
||||||
// Send an update to all bukkit servers removing the player from the requester cache
|
// Send an update to all bukkit servers removing the player from the requester cache
|
||||||
new RedisMessage(RedisMessage.MessageType.REQUEST_DATA_ON_JOIN,
|
new RedisMessage(RedisMessage.MessageType.REQUEST_DATA_ON_JOIN,
|
||||||
new RedisMessage.MessageTarget(Settings.ServerType.BUKKIT, null, message.getMessageTarget().targetClusterId()),
|
new RedisMessage.MessageTarget(Settings.ServerType.BUKKIT, null, message.getMessageTarget().targetClusterId()),
|
||||||
RedisMessage.RequestOnJoinUpdateType.REMOVE_REQUESTER.toString(), requestingPlayerUUID.toString())
|
RedisMessage.RequestOnJoinUpdateType.REMOVE_REQUESTER.toString(), requestingPlayerUUID.toString())
|
||||||
.send();
|
.send();
|
||||||
|
|
||||||
// Send synchronisation complete message
|
// Send synchronisation complete message
|
||||||
Optional<Player> player = plugin.getProxyServer().getPlayer(requestingPlayerUUID);
|
Optional<Player> player = plugin.getProxyServer().getPlayer(requestingPlayerUUID);
|
||||||
player.ifPresent(value -> value.sendActionBar(new MineDown(MessageManager.getMessage("synchronisation_complete")).toComponent()));
|
player.ifPresent(value -> value.sendActionBar(new MineDown(MessageManager.getMessage("synchronisation_complete")).toComponent()));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log(Level.SEVERE, "Failed to serialize data when replying to a data request");
|
log(Level.SEVERE, "Failed to serialize data when replying to a data request");
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}).schedule();
|
}).schedule();
|
||||||
}
|
case PLAYER_DATA_UPDATE -> plugin.getProxyServer().getScheduler().buildTask(plugin, () -> {
|
||||||
case PLAYER_DATA_UPDATE -> {
|
|
||||||
// Deserialize the PlayerData received
|
// Deserialize the PlayerData received
|
||||||
PlayerData playerData;
|
PlayerData playerData;
|
||||||
final String serializedPlayerData = message.getMessageData();
|
final String serializedPlayerData = message.getMessageDataElements()[0];
|
||||||
|
final boolean bounceBack = Boolean.parseBoolean(message.getMessageDataElements()[1]);
|
||||||
try {
|
try {
|
||||||
playerData = (PlayerData) RedisMessage.deserialize(serializedPlayerData);
|
playerData = (PlayerData) RedisMessage.deserialize(serializedPlayerData);
|
||||||
} catch (IOException | ClassNotFoundException e) {
|
} catch (IOException | ClassNotFoundException e) {
|
||||||
@@ -109,23 +108,24 @@ public class VelocityRedisListener extends RedisListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Reply with the player data if they are still online (switching server)
|
// Reply with the player data if they are still online (switching server)
|
||||||
Optional<Player> updatingPlayer = plugin.getProxyServer().getPlayer(playerData.getPlayerUUID());
|
if (Settings.bounceBackSynchronisation && bounceBack) {
|
||||||
updatingPlayer.ifPresent(player -> {
|
Optional<Player> updatingPlayer = plugin.getProxyServer().getPlayer(playerData.getPlayerUUID());
|
||||||
try {
|
updatingPlayer.ifPresent(player -> {
|
||||||
new RedisMessage(RedisMessage.MessageType.PLAYER_DATA_SET,
|
try {
|
||||||
new RedisMessage.MessageTarget(Settings.ServerType.BUKKIT, playerData.getPlayerUUID(), message.getMessageTarget().targetClusterId()),
|
new RedisMessage(RedisMessage.MessageType.PLAYER_DATA_SET,
|
||||||
RedisMessage.serialize(playerData))
|
new RedisMessage.MessageTarget(Settings.ServerType.BUKKIT, playerData.getPlayerUUID(), message.getMessageTarget().targetClusterId()),
|
||||||
.send();
|
RedisMessage.serialize(playerData))
|
||||||
|
.send();
|
||||||
|
|
||||||
// Send synchronisation complete message
|
// Send synchronisation complete message
|
||||||
player.sendActionBar(new MineDown(MessageManager.getMessage("synchronisation_complete")).toComponent());
|
player.sendActionBar(new MineDown(MessageManager.getMessage("synchronisation_complete")).toComponent());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log(Level.SEVERE, "Failed to re-serialize PlayerData when handling a player update request");
|
log(Level.SEVERE, "Failed to re-serialize PlayerData when handling a player update request");
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
}
|
}).schedule();
|
||||||
case CONNECTION_HANDSHAKE -> {
|
case CONNECTION_HANDSHAKE -> {
|
||||||
// Reply to a Bukkit server's connection handshake to complete the process
|
// Reply to a Bukkit server's connection handshake to complete the process
|
||||||
if (HuskSyncVelocity.isDisabling) return; // Return if the Proxy is disabling
|
if (HuskSyncVelocity.isDisabling) return; // Return if the Proxy is disabling
|
||||||
@@ -191,7 +191,7 @@ public class VelocityRedisListener extends RedisListener {
|
|||||||
migrator.loadIncomingData(migrator.incomingPlayerData, HuskSyncVelocity.dataManager);
|
migrator.loadIncomingData(migrator.incomingPlayerData, HuskSyncVelocity.dataManager);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case API_DATA_REQUEST -> {
|
case API_DATA_REQUEST -> plugin.getProxyServer().getScheduler().buildTask(plugin, () -> {
|
||||||
final UUID playerUUID = UUID.fromString(message.getMessageDataElements()[0]);
|
final UUID playerUUID = UUID.fromString(message.getMessageDataElements()[0]);
|
||||||
final UUID requestUUID = UUID.fromString(message.getMessageDataElements()[1]);
|
final UUID requestUUID = UUID.fromString(message.getMessageDataElements()[1]);
|
||||||
|
|
||||||
@@ -214,7 +214,7 @@ public class VelocityRedisListener extends RedisListener {
|
|||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
plugin.getVelocityLogger().log(Level.SEVERE, "Failed to serialize PlayerData requested via the API");
|
plugin.getVelocityLogger().log(Level.SEVERE, "Failed to serialize PlayerData requested via the API");
|
||||||
}
|
}
|
||||||
}
|
}).schedule();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package me.william278.husksync.velocity.util;
|
package net.william278.husksync.velocity.util;
|
||||||
|
|
||||||
import me.william278.husksync.util.Logger;
|
import net.william278.husksync.util.Logger;
|
||||||
|
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package me.william278.husksync.velocity.util;
|
package net.william278.husksync.velocity.util;
|
||||||
|
|
||||||
import me.william278.husksync.HuskSyncVelocity;
|
import net.william278.husksync.HuskSyncVelocity;
|
||||||
import me.william278.husksync.util.UpdateChecker;
|
import net.william278.husksync.util.UpdateChecker;
|
||||||
|
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
@@ -8,5 +8,5 @@
|
|||||||
"William278"
|
"William278"
|
||||||
],
|
],
|
||||||
"dependencies": [],
|
"dependencies": [],
|
||||||
"main": "me.william278.husksync.HuskSyncVelocity"
|
"main": "net.william278.husksync.HuskSyncVelocity"
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user