mirror of
https://github.com/WiIIiam278/HuskSync.git
synced 2025-12-27 02:29:10 +00:00
Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3875447430 | ||
|
|
dce84f285d | ||
|
|
1314683eea | ||
|
|
6b1f89aab0 | ||
|
|
27e958a474 | ||
|
|
39ebd0dc4f | ||
|
|
2ada0497ec | ||
|
|
e9f2856040 | ||
|
|
6050c584c0 | ||
|
|
7ebf91bfae | ||
|
|
2d7799628a | ||
|
|
1627de732b | ||
|
|
fea882c642 | ||
|
|
8b749357f7 | ||
|
|
e4ff7e6d6c | ||
|
|
396630821f | ||
|
|
70f65d126b | ||
|
|
e8925a0d79 | ||
|
|
2a3cf9be7d | ||
|
|
971d3f5167 | ||
|
|
99da65a4d8 | ||
|
|
25744b4ef7 | ||
|
|
8f2d1c7298 |
8
.github/workflows/ci.yml
vendored
8
.github/workflows/ci.yml
vendored
@@ -55,15 +55,19 @@ jobs:
|
|||||||
paper-1.21.1
|
paper-1.21.1
|
||||||
paper-1.21.4
|
paper-1.21.4
|
||||||
paper-1.21.5
|
paper-1.21.5
|
||||||
|
paper-1.21.7
|
||||||
fabric-1.20.1
|
fabric-1.20.1
|
||||||
fabric-1.21.1
|
fabric-1.21.1
|
||||||
fabric-1.21.4
|
fabric-1.21.4
|
||||||
fabric-1.21.5
|
fabric-1.21.5
|
||||||
|
fabric-1.21.7
|
||||||
distro-groups: |
|
distro-groups: |
|
||||||
paper
|
paper
|
||||||
paper
|
paper
|
||||||
paper
|
paper
|
||||||
paper
|
paper
|
||||||
|
paper
|
||||||
|
fabric
|
||||||
fabric
|
fabric
|
||||||
fabric
|
fabric
|
||||||
fabric
|
fabric
|
||||||
@@ -73,16 +77,20 @@ jobs:
|
|||||||
Paper 1.21.1
|
Paper 1.21.1
|
||||||
Paper 1.21.4
|
Paper 1.21.4
|
||||||
Paper 1.21.5
|
Paper 1.21.5
|
||||||
|
Paper 1.21.7
|
||||||
Fabric 1.20.1
|
Fabric 1.20.1
|
||||||
Fabric 1.21.1
|
Fabric 1.21.1
|
||||||
Fabric 1.21.4
|
Fabric 1.21.4
|
||||||
Fabric 1.21.5
|
Fabric 1.21.5
|
||||||
|
Fabric 1.21.7
|
||||||
files: |
|
files: |
|
||||||
target/HuskSync-Bukkit-${{ env.version_name }}+mc.1.20.1.jar
|
target/HuskSync-Bukkit-${{ env.version_name }}+mc.1.20.1.jar
|
||||||
target/HuskSync-Bukkit-${{ env.version_name }}+mc.1.21.1.jar
|
target/HuskSync-Bukkit-${{ env.version_name }}+mc.1.21.1.jar
|
||||||
target/HuskSync-Bukkit-${{ env.version_name }}+mc.1.21.4.jar
|
target/HuskSync-Bukkit-${{ env.version_name }}+mc.1.21.4.jar
|
||||||
target/HuskSync-Bukkit-${{ env.version_name }}+mc.1.21.5.jar
|
target/HuskSync-Bukkit-${{ env.version_name }}+mc.1.21.5.jar
|
||||||
|
target/HuskSync-Bukkit-${{ env.version_name }}+mc.1.21.7.jar
|
||||||
target/HuskSync-Fabric-${{ env.version_name }}+mc.1.20.1.jar
|
target/HuskSync-Fabric-${{ env.version_name }}+mc.1.20.1.jar
|
||||||
target/HuskSync-Fabric-${{ env.version_name }}+mc.1.21.1.jar
|
target/HuskSync-Fabric-${{ env.version_name }}+mc.1.21.1.jar
|
||||||
target/HuskSync-Fabric-${{ env.version_name }}+mc.1.21.4.jar
|
target/HuskSync-Fabric-${{ env.version_name }}+mc.1.21.4.jar
|
||||||
target/HuskSync-Fabric-${{ env.version_name }}+mc.1.21.5.jar
|
target/HuskSync-Fabric-${{ env.version_name }}+mc.1.21.5.jar
|
||||||
|
target/HuskSync-Fabric-${{ env.version_name }}+mc.1.21.7.jar
|
||||||
8
.github/workflows/release.yml
vendored
8
.github/workflows/release.yml
vendored
@@ -44,15 +44,19 @@ jobs:
|
|||||||
paper-1.21.1
|
paper-1.21.1
|
||||||
paper-1.21.4
|
paper-1.21.4
|
||||||
paper-1.21.5
|
paper-1.21.5
|
||||||
|
paper-1.21.7
|
||||||
fabric-1.20.1
|
fabric-1.20.1
|
||||||
fabric-1.21.1
|
fabric-1.21.1
|
||||||
fabric-1.21.4
|
fabric-1.21.4
|
||||||
fabric-1.21.5
|
fabric-1.21.5
|
||||||
|
fabric-1.21.7
|
||||||
distro-groups: |
|
distro-groups: |
|
||||||
paper
|
paper
|
||||||
paper
|
paper
|
||||||
paper
|
paper
|
||||||
paper
|
paper
|
||||||
|
paper
|
||||||
|
fabric
|
||||||
fabric
|
fabric
|
||||||
fabric
|
fabric
|
||||||
fabric
|
fabric
|
||||||
@@ -62,16 +66,20 @@ jobs:
|
|||||||
Paper 1.21.1
|
Paper 1.21.1
|
||||||
Paper 1.21.4
|
Paper 1.21.4
|
||||||
Paper 1.21.5
|
Paper 1.21.5
|
||||||
|
Paper 1.21.7
|
||||||
Fabric 1.20.1
|
Fabric 1.20.1
|
||||||
Fabric 1.21.1
|
Fabric 1.21.1
|
||||||
Fabric 1.21.4
|
Fabric 1.21.4
|
||||||
Fabric 1.21.5
|
Fabric 1.21.5
|
||||||
|
Fabric 1.21.7
|
||||||
files: |
|
files: |
|
||||||
target/HuskSync-Bukkit-${{ github.event.release.tag_name }}+mc.1.20.1.jar
|
target/HuskSync-Bukkit-${{ github.event.release.tag_name }}+mc.1.20.1.jar
|
||||||
target/HuskSync-Bukkit-${{ github.event.release.tag_name }}+mc.1.21.1.jar
|
target/HuskSync-Bukkit-${{ github.event.release.tag_name }}+mc.1.21.1.jar
|
||||||
target/HuskSync-Bukkit-${{ github.event.release.tag_name }}+mc.1.21.4.jar
|
target/HuskSync-Bukkit-${{ github.event.release.tag_name }}+mc.1.21.4.jar
|
||||||
target/HuskSync-Bukkit-${{ github.event.release.tag_name }}+mc.1.21.5.jar
|
target/HuskSync-Bukkit-${{ github.event.release.tag_name }}+mc.1.21.5.jar
|
||||||
|
target/HuskSync-Bukkit-${{ github.event.release.tag_name }}+mc.1.21.7.jar
|
||||||
target/HuskSync-Fabric-${{ github.event.release.tag_name }}+mc.1.20.1.jar
|
target/HuskSync-Fabric-${{ github.event.release.tag_name }}+mc.1.20.1.jar
|
||||||
target/HuskSync-Fabric-${{ github.event.release.tag_name }}+mc.1.21.1.jar
|
target/HuskSync-Fabric-${{ github.event.release.tag_name }}+mc.1.21.1.jar
|
||||||
target/HuskSync-Fabric-${{ github.event.release.tag_name }}+mc.1.21.4.jar
|
target/HuskSync-Fabric-${{ github.event.release.tag_name }}+mc.1.21.4.jar
|
||||||
target/HuskSync-Fabric-${{ github.event.release.tag_name }}+mc.1.21.5.jar
|
target/HuskSync-Fabric-${{ github.event.release.tag_name }}+mc.1.21.5.jar
|
||||||
|
target/HuskSync-Fabric-${{ github.event.release.tag_name }}+mc.1.21.7.jar
|
||||||
@@ -48,7 +48,9 @@ HuskSync supports the following [compatible versions](https://william278.net/doc
|
|||||||
|
|
||||||
| Minecraft | Latest HuskSync | Java Version | Platforms | Support Status |
|
| Minecraft | Latest HuskSync | Java Version | Platforms | Support Status |
|
||||||
|:---------------:|:---------------:|:------------:|:--------------|:------------------------------|
|
|:---------------:|:---------------:|:------------:|:--------------|:------------------------------|
|
||||||
| 1.21.5 | _latest_ | 21 | Paper | ✅ **Active Release** |
|
| 1.21.7 | _latest_ | 21 | Paper | ✅ **Active Release** |
|
||||||
|
| 1.21.6 | 3.8.5 | 21 | Paper | 🗃️ Archived (July 2025) |
|
||||||
|
| 1.21.5 | _latest_ | 21 | Paper | ✅ **January 2026** (Non-LTS) |
|
||||||
| 1.21.4 | _latest_ | 21 | Paper, Fabric | ✅ **November 2025** (Non-LTS) |
|
| 1.21.4 | _latest_ | 21 | Paper, Fabric | ✅ **November 2025** (Non-LTS) |
|
||||||
| 1.21.3 | 3.7.1 | 21 | Paper, Fabric | 🗃️ Archived (December 2024) |
|
| 1.21.3 | 3.7.1 | 21 | Paper, Fabric | 🗃️ Archived (December 2024) |
|
||||||
| 1.21.1 | _latest_ | 21 | Paper, Fabric | ✅ **November 2025** (LTS) |
|
| 1.21.1 | _latest_ | 21 | Paper, Fabric | ✅ **November 2025** (LTS) |
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import org.apache.tools.ant.filters.ReplaceTokens
|
import org.apache.tools.ant.filters.ReplaceTokens
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id 'com.gradleup.shadow' version '8.3.6'
|
id 'com.gradleup.shadow' version '8.3.7'
|
||||||
id 'org.cadixdev.licenser' version '0.6.1' apply false
|
id 'org.cadixdev.licenser' version '0.6.1' apply false
|
||||||
id 'dev.architectury.loom' version '1.9-SNAPSHOT' apply false
|
id 'dev.architectury.loom' version '1.9-SNAPSHOT' apply false
|
||||||
id 'gg.essential.multi-version.root' apply false
|
id 'gg.essential.multi-version.root' apply false
|
||||||
id 'org.ajoberstar.grgit' version '5.3.0'
|
id 'org.ajoberstar.grgit' version '5.3.2'
|
||||||
id 'maven-publish'
|
id 'maven-publish'
|
||||||
id 'java'
|
id 'java'
|
||||||
}
|
}
|
||||||
@@ -89,7 +89,7 @@ allprojects {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
testImplementation(platform("org.junit:junit-bom:5.12.2"))
|
testImplementation(platform("org.junit:junit-bom:5.13.2"))
|
||||||
testImplementation 'org.junit.jupiter:junit-jupiter'
|
testImplementation 'org.junit.jupiter:junit-jupiter'
|
||||||
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
|
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
|
||||||
testCompileOnly 'org.jetbrains:annotations:26.0.2'
|
testCompileOnly 'org.jetbrains:annotations:26.0.2'
|
||||||
|
|||||||
3
bukkit/1.21.7/gradle.properties
Normal file
3
bukkit/1.21.7/gradle.properties
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
minecraft_version_numeric=12107
|
||||||
|
minecraft_api_version=1.21
|
||||||
|
paper_api_version=1.21.7-R0.1-SNAPSHOT
|
||||||
@@ -8,9 +8,9 @@ plugins {
|
|||||||
dependencies {
|
dependencies {
|
||||||
implementation project(path: ':common')
|
implementation project(path: ':common')
|
||||||
|
|
||||||
implementation 'net.william278.uniform:uniform-bukkit:1.3.4'
|
implementation 'net.william278.uniform:uniform-bukkit:1.3.8'
|
||||||
implementation 'net.william278.uniform:uniform-paper:1.3.4'
|
implementation 'net.william278.uniform:uniform-paper:1.3.8'
|
||||||
implementation 'net.william278.toilet:toilet-bukkit:1.0.13'
|
implementation 'net.william278.toilet:toilet-bukkit:1.0.15'
|
||||||
implementation 'net.william278:mpdbdataconverter:1.0.1'
|
implementation 'net.william278:mpdbdataconverter:1.0.1'
|
||||||
implementation 'net.william278:hsldataconverter:1.0'
|
implementation 'net.william278:hsldataconverter:1.0'
|
||||||
implementation 'net.william278:mapdataapi:2.0'
|
implementation 'net.william278:mapdataapi:2.0'
|
||||||
@@ -18,7 +18,7 @@ dependencies {
|
|||||||
implementation 'net.kyori:adventure-platform-bukkit:4.4.0'
|
implementation 'net.kyori:adventure-platform-bukkit:4.4.0'
|
||||||
implementation 'dev.triumphteam:triumph-gui:3.1.12'
|
implementation 'dev.triumphteam:triumph-gui:3.1.12'
|
||||||
implementation 'space.arim.morepaperlib:morepaperlib:0.4.4'
|
implementation 'space.arim.morepaperlib:morepaperlib:0.4.4'
|
||||||
implementation 'de.tr7zw:item-nbt-api:2.15.1-SNAPSHOT'
|
implementation 'de.tr7zw:item-nbt-api:2.15.1'
|
||||||
|
|
||||||
compileOnly "io.papermc.paper:paper-api:${paper_api_version}"
|
compileOnly "io.papermc.paper:paper-api:${paper_api_version}"
|
||||||
compileOnly 'com.github.retrooper:packetevents-spigot:2.8.0'
|
compileOnly 'com.github.retrooper:packetevents-spigot:2.8.0'
|
||||||
|
|||||||
@@ -354,9 +354,11 @@ public class BukkitHuskSync extends JavaPlugin implements HuskSync, BukkitTask.S
|
|||||||
case "1.20.3", "1.20.4" -> DataFixerUtil.VERSION1_20_4;
|
case "1.20.3", "1.20.4" -> DataFixerUtil.VERSION1_20_4;
|
||||||
case "1.20.5", "1.20.6" -> DataFixerUtil.VERSION1_20_5;
|
case "1.20.5", "1.20.6" -> DataFixerUtil.VERSION1_20_5;
|
||||||
case "1.21", "1.21.1" -> DataFixerUtil.VERSION1_21;
|
case "1.21", "1.21.1" -> DataFixerUtil.VERSION1_21;
|
||||||
case "1.21.2", "1.21.3" -> DataFixerUtil.VERSION1_21_2;
|
case "1.21.2" -> DataFixerUtil.VERSION1_21_2;
|
||||||
case "1.21.4" -> 4189;
|
case "1.21.3" -> DataFixerUtil.VERSION1_21_3;
|
||||||
|
case "1.21.4" -> DataFixerUtil.VERSION1_21_4;
|
||||||
case "1.21.5" -> DataFixerUtil.VERSION1_21_5;
|
case "1.21.5" -> DataFixerUtil.VERSION1_21_5;
|
||||||
|
case "1.21.6" -> 4435;
|
||||||
default -> DataFixerUtil.getCurrentVersion();
|
default -> DataFixerUtil.getCurrentVersion();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@SuppressWarnings("UnstableApiUsage")
|
@SuppressWarnings("UnstableApiUsage")
|
||||||
@@ -46,13 +47,20 @@ public class PaperHuskSyncLoader implements PluginLoader {
|
|||||||
resolveLibraries(classpathBuilder).stream()
|
resolveLibraries(classpathBuilder).stream()
|
||||||
.map(DefaultArtifact::new)
|
.map(DefaultArtifact::new)
|
||||||
.forEach(artifact -> resolver.addDependency(new Dependency(artifact, null)));
|
.forEach(artifact -> resolver.addDependency(new Dependency(artifact, null)));
|
||||||
resolver.addRepository(new RemoteRepository.Builder(
|
resolver.addRepository(new RemoteRepository.Builder("maven", "default", getMavenUrl()).build());
|
||||||
"maven", "default", "https://repo.maven.apache.org/maven2/"
|
|
||||||
).build());
|
|
||||||
|
|
||||||
classpathBuilder.addLibrary(resolver);
|
classpathBuilder.addLibrary(resolver);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private static String getMavenUrl() {
|
||||||
|
return Stream.of(
|
||||||
|
System.getenv("PAPER_DEFAULT_CENTRAL_REPOSITORY"),
|
||||||
|
System.getProperty("org.bukkit.plugin.java.LibraryLoader.centralURL"),
|
||||||
|
"https://maven-central.storage-download.googleapis.com/maven2"
|
||||||
|
).filter(Objects::nonNull).findFirst().orElseThrow(IllegalStateException::new);
|
||||||
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private static List<String> resolveLibraries(@NotNull PluginClasspathBuilder classpathBuilder) {
|
private static List<String> resolveLibraries(@NotNull PluginClasspathBuilder classpathBuilder) {
|
||||||
try (InputStream input = getLibraryListFile()) {
|
try (InputStream input = getLibraryListFile()) {
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ public class BukkitEventListener extends EventListener implements BukkitJoinEven
|
|||||||
@EventHandler(ignoreCancelled = true)
|
@EventHandler(ignoreCancelled = true)
|
||||||
public void onMapInitialize(@NotNull MapInitializeEvent event) {
|
public void onMapInitialize(@NotNull MapInitializeEvent event) {
|
||||||
if (plugin.getSettings().getSynchronization().isPersistLockedMaps() && event.getMap().isLocked()) {
|
if (plugin.getSettings().getSynchronization().isPersistLockedMaps() && event.getMap().isLocked()) {
|
||||||
getPlugin().runAsync(() -> ((BukkitHuskSync) plugin).renderPersistedMap(event.getMap()));
|
getPlugin().runAsync(() -> ((BukkitHuskSync) plugin).renderInitializingLockedMap(event.getMap()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -254,111 +254,139 @@ public interface BukkitMapHandler {
|
|||||||
if (!nbt.hasTag(MAP_DATA_KEY)) {
|
if (!nbt.hasTag(MAP_DATA_KEY)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final ReadableNBT mapData = nbt.getCompound(MAP_DATA_KEY);
|
final ReadableNBT mapData = nbt.getCompound(MAP_DATA_KEY);
|
||||||
if (mapData == null) {
|
if (mapData == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine map ID
|
// Server the map was originally created on, and the current server. If they match, isOrigin is true.
|
||||||
final String originServerName = mapData.getString(MAP_ORIGIN_KEY);
|
final String originServer = mapData.getString(MAP_ORIGIN_KEY);
|
||||||
final String currentServerName = getPlugin().getServerName();
|
final String currentServer = getPlugin().getServerName();
|
||||||
final int originalMapId = mapData.getInteger(MAP_ID_KEY);
|
final boolean isOrigin = currentServer.equals(originServer);
|
||||||
int newId = currentServerName.equals(originServerName)
|
|
||||||
? originalMapId : getBoundMapId(originServerName, originalMapId, currentServerName);
|
// Determine the map's ID on its origin server, and the new ID it should be bound to here.
|
||||||
|
// Then, update the map item / data accordingly (re-rendering and caching the map if needed)
|
||||||
|
final int originalId = mapData.getInteger(MAP_ID_KEY);
|
||||||
|
int newId = isOrigin ? originalId : getBoundMapId(originServer, originalId, currentServer);
|
||||||
if (newId != -1) {
|
if (newId != -1) {
|
||||||
final MapView view = Bukkit.getMap(newId);
|
handleBoundMap(meta, nbt, originServer, originalId, newId, isOrigin);
|
||||||
if (view != null) {
|
} else {
|
||||||
meta.setMapView(view);
|
handleUnboundMap(meta, nbt, originServer, originalId, currentServer);
|
||||||
meta.setMapId(newId);
|
|
||||||
map.setItemMeta(meta);
|
|
||||||
getPlugin().debug(String.format("Map ID set to #%s", newId));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
getPlugin().debug(String.format("Map ID #%s not saved on this server, creating...", newId));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the pixel data from the ItemStack and generate a map view otherwise
|
|
||||||
getPlugin().debug("Deserializing map data from NBT and generating view...");
|
|
||||||
@Nullable Map.Entry<MapData, Boolean> readMapData = readMapData(originServerName, originalMapId);
|
|
||||||
if (readMapData == null && nbt.hasTag(MAP_LEGACY_PIXEL_DATA_KEY)) {
|
|
||||||
readMapData = readLegacyMapItemData(nbt);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If map data was found, add a renderer to the MapView
|
|
||||||
if (readMapData == null) {
|
|
||||||
getPlugin().debug("Read pixel data was not found in database, skipping...");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final MapData canvasData = Objects.requireNonNull(readMapData, "Pixel data null!").getKey();
|
|
||||||
final MapView view = generateRenderedMap(canvasData);
|
|
||||||
meta.setMapView(view);
|
|
||||||
map.setItemMeta(meta);
|
map.setItemMeta(meta);
|
||||||
|
|
||||||
// Bind in the database & Redis
|
|
||||||
final int id = view.getId();
|
|
||||||
getRedisManager().bindMapIds(originServerName, originalMapId, currentServerName, id);
|
|
||||||
getPlugin().getDatabase().setMapBinding(originServerName, originalMapId, currentServerName, id);
|
|
||||||
meta.setMapId(id);
|
|
||||||
|
|
||||||
getPlugin().debug(String.format("Bound map to view (#%s) on server %s", id, currentServerName));
|
|
||||||
});
|
});
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
default void renderPersistedMap(@NotNull MapView view) {
|
private void handleBoundMap(@NotNull MapMeta meta, @NotNull ReadableItemNBT nbt, @NotNull String originServer,
|
||||||
if (getMapView(view.getId()).isPresent()) {
|
int originalId, int newId, boolean isOrigin) {
|
||||||
|
MapView view = Bukkit.getMap(newId);
|
||||||
|
if (isOrigin && view != null) {
|
||||||
|
meta.setMapView(view);
|
||||||
|
getPlugin().debug("Map ID set to original ID #%s".formatted(newId));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read map data, or
|
Optional<MapView> optionalView = getMapView(newId);
|
||||||
@Nullable Map.Entry<MapData, Boolean> data = readMapData(getPlugin().getServerName(), view.getId());
|
if (optionalView.isPresent()) {
|
||||||
|
meta.setMapView(optionalView.get());
|
||||||
|
getPlugin().debug("Map ID set to #%s".formatted(newId));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
getPlugin().debug("Deserializing map data from NBT and generating view...");
|
||||||
|
Map.Entry<MapData, Boolean> mapData = readMapData(originServer, originalId);
|
||||||
|
if (mapData == null && nbt.hasTag(MAP_LEGACY_PIXEL_DATA_KEY)) {
|
||||||
|
mapData = readLegacyMapItemData(nbt);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mapData == null) {
|
||||||
|
getPlugin().debug("Read pixel data was not found in database, skipping...");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MapView newView = view != null ? view : Bukkit.createMap(getDefaultMapWorld());
|
||||||
|
generateRenderedMap(Objects.requireNonNull(mapData).getKey(), newView);
|
||||||
|
meta.setMapView(newView);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleUnboundMap(@NotNull MapMeta meta, @NotNull ReadableItemNBT nbt, @NotNull String originServer,
|
||||||
|
int originalId, @NotNull String currentServer) {
|
||||||
|
getPlugin().debug("Deserializing map data from NBT and generating view...");
|
||||||
|
Map.Entry<MapData, Boolean> mapData = readMapData(originServer, originalId);
|
||||||
|
if (mapData == null && nbt.hasTag(MAP_LEGACY_PIXEL_DATA_KEY)) {
|
||||||
|
mapData = readLegacyMapItemData(nbt);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mapData == null) {
|
||||||
|
getPlugin().debug("Read pixel data was not found in database, skipping...");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final MapView view = generateRenderedMap(Objects.requireNonNull(mapData, "Pixel data null!").getKey());
|
||||||
|
meta.setMapView(view);
|
||||||
|
|
||||||
|
final int id = view.getId();
|
||||||
|
getRedisManager().bindMapIds(originServer, originalId, currentServer, id);
|
||||||
|
getPlugin().getDatabase().setMapBinding(originServer, originalId, currentServer, id);
|
||||||
|
|
||||||
|
getPlugin().debug("Bound map to view (#%s) on server %s".formatted(id, currentServer));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render a persisted locked map that is initializing (i.e. in an item frame)
|
||||||
|
default void renderInitializingLockedMap(@NotNull MapView view) {
|
||||||
|
if (view.isVirtual()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final Optional<MapView> optionalView = getMapView(view.getId());
|
||||||
|
if (optionalView.isPresent()) {
|
||||||
|
view.getRenderers().clear();
|
||||||
|
view.getRenderers().addAll(optionalView.get().getRenderers());
|
||||||
|
view.setLocked(true);
|
||||||
|
view.setScale(MapView.Scale.NORMAL);
|
||||||
|
view.setTrackingPosition(false);
|
||||||
|
view.setUnlimitedTracking(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map.Entry<MapData, Boolean> data = readMapData(getPlugin().getServerName(), view.getId());
|
||||||
if (data == null) {
|
if (data == null) {
|
||||||
data = readLegacyMapFileData(view.getId());
|
data = readLegacyMapFileData(view.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't render maps with no data
|
|
||||||
if (data == null) {
|
if (data == null) {
|
||||||
final World world = view.getWorld() == null ? getDefaultMapWorld() : view.getWorld();
|
World world = view.getWorld() == null ? getDefaultMapWorld() : view.getWorld();
|
||||||
getPlugin().debug("Not rendering map: no data in DB for world %s, map #%s."
|
getPlugin().debug("Not rendering map: no data in DB for world %s, map #%s."
|
||||||
.formatted(world.getName(), view.getId()));
|
.formatted(world.getName(), view.getId()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Don't render persisted maps on this server
|
|
||||||
if (data.getValue()) {
|
if (data.getValue()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
renderMapView(view, data.getKey());
|
||||||
final MapData canvasData = data.getKey();
|
|
||||||
|
|
||||||
// Create a new map view renderer with the map data color at each pixel
|
|
||||||
// use view.removeRenderer() to remove all this maps renderers
|
|
||||||
view.getRenderers().forEach(view::removeRenderer);
|
|
||||||
view.addRenderer(new PersistentMapRenderer(canvasData));
|
|
||||||
view.setLocked(true);
|
|
||||||
view.setScale(MapView.Scale.NORMAL);
|
|
||||||
view.setTrackingPosition(false);
|
|
||||||
view.setUnlimitedTracking(false);
|
|
||||||
|
|
||||||
// Set the view to the map
|
|
||||||
setMapView(view);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets the renderer of a map, and returns the generated MapView
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private MapView generateRenderedMap(@NotNull MapData canvasData) {
|
private MapView generateRenderedMap(@NotNull MapData canvasData) {
|
||||||
final MapView view = Bukkit.createMap(getDefaultMapWorld());
|
return generateRenderedMap(canvasData, Bukkit.createMap(getDefaultMapWorld()));
|
||||||
view.getRenderers().clear();
|
}
|
||||||
|
|
||||||
// Create a new map view renderer with the map data color at each pixel
|
@NotNull
|
||||||
|
private MapView generateRenderedMap(@NotNull MapData canvasData, @NotNull MapView view) {
|
||||||
|
renderMapView(view, canvasData);
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderMapView(@NotNull MapView view, @NotNull MapData canvasData) {
|
||||||
|
view.getRenderers().clear();
|
||||||
view.addRenderer(new PersistentMapRenderer(canvasData));
|
view.addRenderer(new PersistentMapRenderer(canvasData));
|
||||||
view.setLocked(true);
|
view.setLocked(true);
|
||||||
view.setScale(MapView.Scale.NORMAL);
|
view.setScale(MapView.Scale.NORMAL);
|
||||||
view.setTrackingPosition(false);
|
view.setTrackingPosition(false);
|
||||||
view.setUnlimitedTracking(false);
|
view.setUnlimitedTracking(false);
|
||||||
|
|
||||||
// Set the view to the map and return it
|
|
||||||
setMapView(view);
|
setMapView(view);
|
||||||
return view;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
|
|||||||
@@ -17,15 +17,15 @@ dependencies {
|
|||||||
exclude module: 'slf4j-api'
|
exclude module: 'slf4j-api'
|
||||||
}
|
}
|
||||||
|
|
||||||
compileOnlyApi 'net.william278.toilet:toilet-common:1.0.13'
|
compileOnlyApi 'net.william278.toilet:toilet-common:1.0.15'
|
||||||
|
|
||||||
compileOnly 'net.william278.uniform:uniform-common:1.3.4'
|
compileOnly 'net.william278.uniform:uniform-common:1.3.8'
|
||||||
compileOnly 'com.mojang:brigadier:1.1.8'
|
compileOnly 'com.mojang:brigadier:1.1.8'
|
||||||
compileOnly 'org.projectlombok:lombok:1.18.38'
|
compileOnly 'org.projectlombok:lombok:1.18.38'
|
||||||
compileOnly 'org.jetbrains:annotations:26.0.2'
|
compileOnly 'org.jetbrains:annotations:26.0.2'
|
||||||
compileOnly 'net.kyori:adventure-api:4.20.0'
|
compileOnly 'net.kyori:adventure-api:4.23.0'
|
||||||
compileOnly 'net.kyori:adventure-platform-api:4.4.0'
|
compileOnly 'net.kyori:adventure-platform-api:4.4.0'
|
||||||
compileOnly "net.kyori:adventure-text-serializer-plain:4.21.0"
|
compileOnly "net.kyori:adventure-text-serializer-plain:4.23.0"
|
||||||
compileOnly 'com.google.guava:guava:33.4.8-jre'
|
compileOnly 'com.google.guava:guava:33.4.8-jre'
|
||||||
compileOnly 'com.github.plan-player-analytics:Plan:5.6.2965'
|
compileOnly 'com.github.plan-player-analytics:Plan:5.6.2965'
|
||||||
compileOnly "redis.clients:jedis:$jedis_version"
|
compileOnly "redis.clients:jedis:$jedis_version"
|
||||||
|
|||||||
@@ -150,7 +150,7 @@ public class Settings {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 𝓡𝓮𝓭𝓲𝓼 settings
|
// Redis settings
|
||||||
@Comment("Redis settings")
|
@Comment("Redis settings")
|
||||||
private RedisSettings redis = new RedisSettings();
|
private RedisSettings redis = new RedisSettings();
|
||||||
|
|
||||||
@@ -326,6 +326,9 @@ public class Settings {
|
|||||||
@Getter(AccessLevel.NONE)
|
@Getter(AccessLevel.NONE)
|
||||||
private Map<String, String> eventPriorities = EventListener.ListenerType.getDefaults();
|
private Map<String, String> eventPriorities = EventListener.ListenerType.getDefaults();
|
||||||
|
|
||||||
|
@Comment("Enable check-in petitions for data syncing (don't change this unless you know what you're doing)")
|
||||||
|
private boolean checkinPetitions = true;
|
||||||
|
|
||||||
public boolean doAutoPin(@NotNull DataSnapshot.SaveCause cause) {
|
public boolean doAutoPin(@NotNull DataSnapshot.SaveCause cause) {
|
||||||
return autoPinnedSaveCauses.contains(cause.name());
|
return autoPinnedSaveCauses.contains(cause.name());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -190,7 +190,8 @@ public class RedisManager extends JedisPubSub {
|
|||||||
).dispatch(plugin, RedisMessage.Type.RETURN_USER_DATA)
|
).dispatch(plugin, RedisMessage.Type.RETURN_USER_DATA)
|
||||||
);
|
);
|
||||||
case CHECK_IN_PETITION -> {
|
case CHECK_IN_PETITION -> {
|
||||||
if (!redisMessage.isTargetServer(plugin)) {
|
if (!redisMessage.isTargetServer(plugin)
|
||||||
|
|| !plugin.getSettings().getSynchronization().isCheckinPetitions()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final String payload = new String(redisMessage.getPayload(), StandardCharsets.UTF_8);
|
final String payload = new String(redisMessage.getPayload(), StandardCharsets.UTF_8);
|
||||||
|
|||||||
@@ -54,7 +54,9 @@ public class LockstepDataSyncer extends DataSyncer {
|
|||||||
// If they are checked out, ask the server to check them back in and return false
|
// If they are checked out, ask the server to check them back in and return false
|
||||||
final Optional<String> server = getRedis().getUserCheckedOut(user);
|
final Optional<String> server = getRedis().getUserCheckedOut(user);
|
||||||
if (server.isPresent() && !server.get().equals(plugin.getServerName())) {
|
if (server.isPresent() && !server.get().equals(plugin.getServerName())) {
|
||||||
getRedis().petitionServerCheckin(server.get(), user);
|
if (plugin.getSettings().getSynchronization().isCheckinPetitions()) {
|
||||||
|
getRedis().petitionServerCheckin(server.get(), user);
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ locales:
|
|||||||
data_manager_timestamp: '[⌚ %1%](#ffc43b-#f5c962 show_text=&7バージョンタイムスタンプ:\n&8データの保存時期)'
|
data_manager_timestamp: '[⌚ %1%](#ffc43b-#f5c962 show_text=&7バージョンタイムスタンプ:\n&8データの保存時期)'
|
||||||
data_manager_pinned: '[※ ピン留めされたスナップショット](#d8ff2b show_text=&7ピン留め:\n&8このユーザーデータのスナップショットは自動的にローテーションされません。)'
|
data_manager_pinned: '[※ ピン留めされたスナップショット](#d8ff2b show_text=&7ピン留め:\n&8このユーザーデータのスナップショットは自動的にローテーションされません。)'
|
||||||
data_manager_cause: '[⚑ %1%](#23a825-#36f539 show_text=&7保存理由:\n&8データが保存された理由)'
|
data_manager_cause: '[⚑ %1%](#23a825-#36f539 show_text=&7保存理由:\n&8データが保存された理由)'
|
||||||
data_manager_server: '[☁ %1%](#ff87b3-#f5538e show_text=&7Server:\n&8Name of the server the data was saved on)'
|
data_manager_server: '[☁ %1%](#ff87b3-#f5538e show_text=&7サーバー:\n&8データが保存されたサーバー名)'
|
||||||
data_manager_size: '[⏏ %1%](color=#62a9f5-#7ab8fa show_text=&7スナップショットサイズ:\n&8スナップショットの推定ファイルサイズ(単位:KiB))\n'
|
data_manager_size: '[⏏ %1%](color=#62a9f5-#7ab8fa show_text=&7スナップショットサイズ:\n&8スナップショットの推定ファイルサイズ(単位:KiB))\n'
|
||||||
data_manger_status: '[%1%](red)[/](gray)[%2%](red)[×](gray)[❤](red show_text=&7体力) [%3%](yellow)[×](gray)[🍖](yellow show_text=&7空腹度) [ʟᴠ](green)[.](gray)[%4%](green show_text=&7経験値レベル) [🏹 %5%](dark_aqua show_text=&7ゲームモード)'
|
data_manger_status: '[%1%](red)[/](gray)[%2%](red)[×](gray)[❤](red show_text=&7体力) [%3%](yellow)[×](gray)[🍖](yellow show_text=&7空腹度) [ʟᴠ](green)[.](gray)[%4%](green show_text=&7経験値レベル) [🏹 %5%](dark_aqua show_text=&7ゲームモード)'
|
||||||
data_manager_advancements_statistics: '[⭐ 進捗: %1%](color=#ffc43b-#f5c962 show_text=&7達成した進捗:\n&8%2%) [⌛ プレイ時間: %3%ʜʀs](color=#62a9f5-#7ab8fa show_text=&7ゲーム内のプレイ時間\n&8⚠ ゲーム内の統計に基づく)\n'
|
data_manager_advancements_statistics: '[⭐ 進捗: %1%](color=#ffc43b-#f5c962 show_text=&7達成した進捗:\n&8%2%) [⌛ プレイ時間: %3%ʜʀs](color=#62a9f5-#7ab8fa show_text=&7ゲーム内のプレイ時間\n&8⚠ ゲーム内の統計に基づく)\n'
|
||||||
@@ -22,8 +22,8 @@ locales:
|
|||||||
data_manager_advancements_preview_remaining: 'さらに %1% 件…'
|
data_manager_advancements_preview_remaining: 'さらに %1% 件…'
|
||||||
data_list_title: '[%1% のユーザーデータスナップショット:](#00fb9a) [(%4%件中](#00fb9a bold) [%2%-%3%件](#00fb9a)[)](#00fb9a)\n'
|
data_list_title: '[%1% のユーザーデータスナップショット:](#00fb9a) [(%4%件中](#00fb9a bold) [%2%-%3%件](#00fb9a)[)](#00fb9a)\n'
|
||||||
data_list_item: '[%1%](gray show_text=&7%2% のユーザーデータスナップショット&8⚡ %4% run_command=/husksync:userdata view %2% %3%) [%5%](#d8ff2b show_text=&7ピン留め:\n&8ピン留めされたスナップショットは自動的にローテーションしません。 run_command=/husksync:userdata view %2% %3%) [%6%](color=#ffc43b-#f5c962 show_text=&7バージョンタイムスタンプ:&7\n&8データの保存時期\n&8%7% run_command=/userdata view %2% %3%) [⚑ %8%](#23a825-#36f539 show_text=&7保存理由:\n&8データが保存された理由 run_command=/userdata view %2% %3%) [⏏ %9%](color=#62a9f5-#7ab8fa show_text=&7スナップショットサイズ:&7\n&8スナップショットの推定ファイルサイズ (単位:KiB) run_command=/userdata view %2% %3%)'
|
data_list_item: '[%1%](gray show_text=&7%2% のユーザーデータスナップショット&8⚡ %4% run_command=/husksync:userdata view %2% %3%) [%5%](#d8ff2b show_text=&7ピン留め:\n&8ピン留めされたスナップショットは自動的にローテーションしません。 run_command=/husksync:userdata view %2% %3%) [%6%](color=#ffc43b-#f5c962 show_text=&7バージョンタイムスタンプ:&7\n&8データの保存時期\n&8%7% run_command=/userdata view %2% %3%) [⚑ %8%](#23a825-#36f539 show_text=&7保存理由:\n&8データが保存された理由 run_command=/userdata view %2% %3%) [⏏ %9%](color=#62a9f5-#7ab8fa show_text=&7スナップショットサイズ:&7\n&8スナップショットの推定ファイルサイズ (単位:KiB) run_command=/userdata view %2% %3%)'
|
||||||
data_list_item_invalid: '[%1%](dark_gray show_text=&7User Data Snapshot for %2%\n&8⚡ %4% suggest_command=/userdata delete %2% %3%) [%5%](dark_gray show_text=&7Pinned:\n&8Pinned snapshots won''t be automatically rotated. suggest_command=/userdata delete %2% %3%) [%6% ⚑ %8% ⏏ %9%](gray strikethrough show_text=&#ff3300&Invalid Data Snapshot\n&#ff7e5e&Click to delete\n\n&7⚠ %10% suggest_command=/userdata delete %2% %3%)'
|
data_list_item_invalid: '[%1%](dark_gray show_text=&7%2% のユーザーデータスナップショット\n&8⚡ %4% suggest_command=/userdata delete %2% %3%) [%5%](dark_gray show_text=&7ピン留め:\n&8ピン留めされたスナップショットは自動的にローテーションしません。 suggest_command=/userdata delete %2% %3%) [%6% ⚑ %8% ⏏ %9%](gray strikethrough show_text=&#ff3300&無効なデータのスナップショット\n&#ff7e5e&クリックで消去\n\n&7⚠ %10% suggest_command=/userdata delete %2% %3%)'
|
||||||
data_saved: '[Successfully saved a snapshot of %1%''s current user data.](#00fb9a)'
|
data_saved: '[%1% の現在のユーザーデータのスナップショットを正常に保存しました。](#00fb9a)'
|
||||||
data_deleted: '[❌](#00fb9a) [%3%](#00fb9a show_text=&7Player UUID:\n&8%4%) [のユーザーデータスナップショット](#00fb9a) [%1%](#00fb9a show_text=&7Version UUID:\n&8%2%) [の消去に成功しました。](#00fb9a)'
|
data_deleted: '[❌](#00fb9a) [%3%](#00fb9a show_text=&7Player UUID:\n&8%4%) [のユーザーデータスナップショット](#00fb9a) [%1%](#00fb9a show_text=&7Version UUID:\n&8%2%) [の消去に成功しました。](#00fb9a)'
|
||||||
data_restored: '[⏪](#00fb9a) [スナップショット](#00fb9a) [%3%](#00fb9a show_text=&7Version UUID:\n&8%4%) [から](#00fb9a) [%1%](#00fb9a show_text=&7Player UUID:\n&8%2%) [の現在のユーザーデータの復元に成功しました。](#00fb9a)'
|
data_restored: '[⏪](#00fb9a) [スナップショット](#00fb9a) [%3%](#00fb9a show_text=&7Version UUID:\n&8%4%) [から](#00fb9a) [%1%](#00fb9a show_text=&7Player UUID:\n&8%2%) [の現在のユーザーデータの復元に成功しました。](#00fb9a)'
|
||||||
data_pinned: '[※](#00fb9a) [%3%](#00fb9a show_text=&7Player UUID:\n&8%4%) [のユーザーデータスナップショット](#00fb9a) [%1%](#00fb9a show_text=&7Version UUID:\n&8%2%) [のピン留めに成功しました。](#00fb9a)'
|
data_pinned: '[※](#00fb9a) [%3%](#00fb9a show_text=&7Player UUID:\n&8%4%) [のユーザーデータスナップショット](#00fb9a) [%1%](#00fb9a show_text=&7Version UUID:\n&8%2%) [のピン留めに成功しました。](#00fb9a)'
|
||||||
@@ -37,35 +37,35 @@ locales:
|
|||||||
list_page_jumper_current_page: '[%1%](#00fb9a)'
|
list_page_jumper_current_page: '[%1%](#00fb9a)'
|
||||||
list_page_jumper_separator: ' '
|
list_page_jumper_separator: ' '
|
||||||
list_page_jumper_group_separator: '…'
|
list_page_jumper_group_separator: '…'
|
||||||
save_cause_disconnect: 'disconnect'
|
save_cause_disconnect: '切断'
|
||||||
save_cause_world_save: 'world save'
|
save_cause_world_save: 'ワールド保存'
|
||||||
save_cause_death: 'death'
|
save_cause_death: '死亡'
|
||||||
save_cause_server_shutdown: 'server shutdown'
|
save_cause_server_shutdown: 'サーバーシャットダウン'
|
||||||
save_cause_save_command: 'save command'
|
save_cause_save_command: 'セーブコマンド'
|
||||||
save_cause_dump_command: 'dump command'
|
save_cause_dump_command: 'ダンプコマンド'
|
||||||
save_cause_inventory_command: 'inventory command'
|
save_cause_inventory_command: 'インベントリコマンド'
|
||||||
save_cause_enderchest_command: 'enderchest command'
|
save_cause_enderchest_command: 'エンダーチェストコマンド'
|
||||||
save_cause_backup_restore: 'backup restore'
|
save_cause_backup_restore: 'バックアップ復元'
|
||||||
save_cause_api: 'API'
|
save_cause_api: 'API'
|
||||||
save_cause_mpdb_migration: 'MPDB migration'
|
save_cause_mpdb_migration: 'MPDB移行'
|
||||||
save_cause_legacy_migration: 'legacy migration'
|
save_cause_legacy_migration: 'レガシー移行'
|
||||||
save_cause_converted_from_v2: 'converted from v2'
|
save_cause_converted_from_v2: 'v2からの変換'
|
||||||
up_to_date: '[HuskSync](#00fb9a bold) [| HuskSyncの最新バージョンを実行しています(v%1%).](#00fb9a)'
|
up_to_date: '[HuskSync](#00fb9a bold) [| HuskSyncの最新バージョンを実行しています(v%1%).](#00fb9a)'
|
||||||
update_available: '[HuskSync](#ff7e5e bold) [| HuskSyncの最新バージョンが更新されています: v%1% (実行中: v%2%).](#ff7e5e)'
|
update_available: '[HuskSync](#ff7e5e bold) [| HuskSyncの新バージョンが利用可能になりました: v%1% (実行中: v%2%).](#ff7e5e)'
|
||||||
reload_complete: '[HuskSync](#00fb9a bold) [| 設定ファイルとメッセージファイルを再読み込みしました。](#00fb9a)\n[⚠ すべてのサーバーで設定ファイルが最新であることを確認してください!](#00fb9a)\n[設定の変更を有効にするには再起動が必要です。](#00fb9a italic)'
|
reload_complete: '[HuskSync](#00fb9a bold) [| 設定ファイルとメッセージファイルを再読み込みしました。](#00fb9a)\n[⚠ すべてのサーバーで設定ファイルが最新であることを確認してください!](#00fb9a)\n[設定の変更を有効にするには再起動が必要です。](#00fb9a italic)'
|
||||||
system_status_header: '[HuskSync](#00fb9a bold) [| System status report:](#00fb9a)'
|
system_status_header: '[HuskSync](#00fb9a bold) [| システムステータスレポート:](#00fb9a)'
|
||||||
system_dump_confirm: '[HuskSync](#00fb9a bold) [| Prepare a system dump? This will include:](#00fb9a)\n[• Your latest server logs and HuskSync config files](gray)\n[• Current plugin system status information](gray)\n[• Information about your Java & Minecraft server environment](gray)\n[• A list of other currently installed plugins](gray)\n[To confirm, use:](#00fb9a) [/husksync dump confirm](#00fb9a italic show_text=&7Click to prepare dump run_command=/husksync dump confirm)'
|
system_dump_confirm: '[HuskSync](#00fb9a bold) [| システムダンプを作成しますか? 含まれる内容:](#00fb9a)\n[• 最新のサーバーログと HuskSync の設定ファイル](gray)\n[• 現在のプラグインシステムの状態](gray)\n[• Java と Minecraft サーバー環境の情報](gray)\n[• 現在インストールされている他のプラグイン一覧](gray)\n[確認するには、次を実行してください:](#00fb9a) [/husksync dump confirm](#00fb9a italic show_text=&7クリックでダンプを準備 run_command=/husksync dump confirm)'
|
||||||
system_dump_started: '[HuskSync](#00fb9a bold) [| Preparing system status dump, please wait…](#00fb9a)'
|
system_dump_started: '[HuskSync](#00fb9a bold) [| システムステータスダンプを準備中です。お待ちください…](#00fb9a)'
|
||||||
system_dump_ready: '[HuskSync](#00fb9a bold) [| System status dump prepared! Click to view:](#00fb9a)'
|
system_dump_ready: '[HuskSync](#00fb9a bold) [| システムステータスダンプが準備できました!クリックで表示:](#00fb9a)'
|
||||||
error_invalid_syntax: '[Error:](#ff3300) [構文が正しくありません。使用法:](#ff7e5e) [%1%](#ff7e5e italic show_text=&#ff7e5e&クリックでサジェスト suggest_command=%1%)'
|
error_invalid_syntax: '[エラー:](#ff3300) [構文が正しくありません。使用法:](#ff7e5e) [%1%](#ff7e5e italic show_text=&#ff7e5e&クリックでサジェスト suggest_command=%1%)'
|
||||||
error_invalid_player: '[Error:](#ff3300) [そのプレイヤーは見つかりませんでした](#ff7e5e)'
|
error_invalid_player: '[エラー:](#ff3300) [そのプレイヤーは見つかりませんでした](#ff7e5e)'
|
||||||
error_invalid_data: '[Error:](#ff3300) [Failed to unpack user data as the snapshot is invalid or corrupt.](#ff7e5e) [(Details…)](gray show_text=&7⚠ %1%)'
|
error_invalid_data: '[エラー:](#ff3300) [スナップショットが無効または破損しているため、ユーザーデータを展開できません。](#ff7e5e) [(詳細…)](gray show_text=&7⚠ %1%)'
|
||||||
error_no_permission: '[Error:](#ff3300) [このコマンドを実行する権限がありません](#ff7e5e)'
|
error_no_permission: '[エラー:](#ff3300) [このコマンドを実行する権限がありません](#ff7e5e)'
|
||||||
error_console_command_only: '[Error:](#ff3300) [そのコマンドは%1%コンソールからのみ実行できます](#ff7e5e)'
|
error_console_command_only: '[エラー:](#ff3300) [そのコマンドは%1%コンソールからのみ実行できます](#ff7e5e)'
|
||||||
error_in_game_command_only: 'Error: そのコマンドはゲーム内でしか使えません。'
|
error_in_game_command_only: 'エラー: そのコマンドはゲーム内でしか使えません。'
|
||||||
error_no_data_to_display: '[Error:](#ff3300) [表示するユーザーデータが見つかりませんでした。](#ff7e5e)'
|
error_no_data_to_display: '[エラー:](#ff3300) [表示するユーザーデータが見つかりませんでした。](#ff7e5e)'
|
||||||
error_invalid_version_uuid: '[Error:](#ff3300) [そのバージョンUUIDのユーザーデータが見つかりませんでした。](#ff7e5e)'
|
error_invalid_version_uuid: '[エラー:](#ff3300) [そのバージョンUUIDのユーザーデータが見つかりませんでした。](#ff7e5e)'
|
||||||
husksync_command_description: 'HuskSyncプラグインを管理する'
|
husksync_command_description: 'HuskSyncプラグインを管理する'
|
||||||
userdata_command_description: 'プレーヤーのユーザーデータを表示・管理・復元する'
|
userdata_command_description: 'プレイヤーのユーザーデータを表示・管理・復元する'
|
||||||
inventory_command_description: 'プレイヤーのインベントリを閲覧・編集する'
|
inventory_command_description: 'プレイヤーのインベントリを閲覧・編集する'
|
||||||
enderchest_command_description: 'プレイヤーのエンダーチェストを閲覧・編集する'
|
enderchest_command_description: 'プレイヤーのエンダーチェストを閲覧・編集する'
|
||||||
|
|||||||
@@ -2,7 +2,9 @@ HuskSync supports the following versions of Minecraft. Since v3.7, you must down
|
|||||||
|
|
||||||
| Minecraft | Latest HuskSync | Java Version | Platforms | Support Status |
|
| Minecraft | Latest HuskSync | Java Version | Platforms | Support Status |
|
||||||
|:---------------:|:---------------:|:------------:|:--------------|:------------------------------|
|
|:---------------:|:---------------:|:------------:|:--------------|:------------------------------|
|
||||||
| 1.21.5 | _latest_ | 21 | Paper | ✅ **Active Release** |
|
| 1.21.7 | _latest_ | 21 | Paper | ✅ **Active Release** |
|
||||||
|
| 1.21.6 | 3.8.5 | 21 | Paper | 🗃️ Archived (July 2025) |
|
||||||
|
| 1.21.5 | _latest_ | 21 | Paper | ✅ **January 2026** (Non-LTS) |
|
||||||
| 1.21.4 | _latest_ | 21 | Paper, Fabric | ✅ **November 2025** (Non-LTS) |
|
| 1.21.4 | _latest_ | 21 | Paper, Fabric | ✅ **November 2025** (Non-LTS) |
|
||||||
| 1.21.3 | 3.7.1 | 21 | Paper, Fabric | 🗃️ Archived (December 2024) |
|
| 1.21.3 | 3.7.1 | 21 | Paper, Fabric | 🗃️ Archived (December 2024) |
|
||||||
| 1.21.1 | _latest_ | 21 | Paper, Fabric | ✅ **November 2025** (LTS) |
|
| 1.21.1 | _latest_ | 21 | Paper, Fabric | ✅ **November 2025** (LTS) |
|
||||||
|
|||||||
@@ -26,6 +26,19 @@ If you are hosting your [[Redis]] server on the same node as your servers, you n
|
|||||||
### Database connection problems on Pterodactyl / Pelican
|
### Database connection problems on Pterodactyl / Pelican
|
||||||
If you have more than one [[Database]] server connected to your panel, you may need to set `useSSL=true` in the parameters.
|
If you have more than one [[Database]] server connected to your panel, you may need to set `useSSL=true` in the parameters.
|
||||||
|
|
||||||
|
### Unable to reset my server / wipe all player data
|
||||||
|
The following steps are required to completely wipe all HuskSync data and prepare your server for a reset. HuskSync stores data in MySQL and caches it in Redis, so if you are experiencing players getting their items back when they shouldn't be it's because data wasn't cleared in one of the two.
|
||||||
|
|
||||||
|
- Turn OFF ALL Minecraft servers and proxy
|
||||||
|
- Turn OFF your Redis server completely.
|
||||||
|
- It MUST be completely offline.
|
||||||
|
- Make sure data persistence is OFF and that it does not restore state following a reboot
|
||||||
|
- Access your MySQL Database using MySQL Workbench or similar. DROP your `husksync` database, or at the very least DROP ALL husksync tables.
|
||||||
|
- Double check you have done this
|
||||||
|
- On ALL Minecraft servers, DELETE the `playerdata` and `advancement` data directories WITHIN EVERY WORLD folder
|
||||||
|
- Deleting the world folders themselves works too if you are resetting these as well.
|
||||||
|
- ONLY THEN can you finally re-start ALL servers
|
||||||
|
|
||||||
### Issues with player data going out of sync during a server restart
|
### Issues with player data going out of sync during a server restart
|
||||||
This can happen due to the way in which your server restarts. If your server uses either:
|
This can happen due to the way in which your server restarts. If your server uses either:
|
||||||
|
|
||||||
|
|||||||
@@ -3,5 +3,5 @@ essential.defaults.loom.mappings=net.fabricmc:yarn:1.21.5+build.1:v2
|
|||||||
fabric_loader_version=0.16.14
|
fabric_loader_version=0.16.14
|
||||||
fabric_api_version=0.122.0+1.21.5
|
fabric_api_version=0.122.0+1.21.5
|
||||||
fabric_permissions_api_version=0.3.3
|
fabric_permissions_api_version=0.3.3
|
||||||
fabric_adventure_platform_version=6.4.0-SNAPSHOT
|
fabric_adventure_platform_version=6.4.0
|
||||||
fabric_sgui_version=1.9.0+1.21.5
|
fabric_sgui_version=1.9.0+1.21.5
|
||||||
7
fabric/1.21.7/gradle.properties
Normal file
7
fabric/1.21.7/gradle.properties
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
essential.defaults.loom.mappings=net.fabricmc:yarn:1.21.7+build.2:v2
|
||||||
|
|
||||||
|
fabric_loader_version=0.16.14
|
||||||
|
fabric_api_version=0.128.1+1.21.7
|
||||||
|
fabric_permissions_api_version=0.4.1
|
||||||
|
fabric_adventure_platform_version=6.5.0-SNAPSHOT
|
||||||
|
fabric_sgui_version=1.10.0+1.21.6
|
||||||
@@ -14,13 +14,13 @@ dependencies {
|
|||||||
modImplementation include("net.kyori:adventure-platform-fabric:${fabric_adventure_platform_version}")
|
modImplementation include("net.kyori:adventure-platform-fabric:${fabric_adventure_platform_version}")
|
||||||
modImplementation include("me.lucko:fabric-permissions-api:${fabric_permissions_api_version}")
|
modImplementation include("me.lucko:fabric-permissions-api:${fabric_permissions_api_version}")
|
||||||
modImplementation include("eu.pb4:sgui:${fabric_sgui_version}")
|
modImplementation include("eu.pb4:sgui:${fabric_sgui_version}")
|
||||||
modImplementation include("net.william278.uniform:uniform-fabric:1.3.4+${project.name}")
|
modImplementation include("net.william278.uniform:uniform-fabric:1.3.8+${project.name}")
|
||||||
modImplementation include("net.william278.toilet:toilet-fabric:1.0.13+${project.name}")
|
modImplementation include("net.william278.toilet:toilet-fabric:1.0.15+${project.name}")
|
||||||
modImplementation "net.fabricmc.fabric-api:fabric-api:${fabric_api_version}"
|
modImplementation "net.fabricmc.fabric-api:fabric-api:${fabric_api_version}"
|
||||||
|
|
||||||
// Manually include config deps due to the way including api deps works
|
// Manually include config deps due to the way including api deps works
|
||||||
implementation include("de.exlll:configlib-core:4.6.1")
|
implementation include("de.exlll:configlib-core:4.6.1")
|
||||||
implementation include("org.snakeyaml:snakeyaml-engine:2.7")
|
implementation include("org.snakeyaml:snakeyaml-engine:2.9")
|
||||||
implementation include('org.apache.commons:commons-pool2:2.12.1')
|
implementation include('org.apache.commons:commons-pool2:2.12.1')
|
||||||
|
|
||||||
// Include driver deps due to no runtime dep loading support
|
// Include driver deps due to no runtime dep loading support
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
1.21.5
|
1.21.7
|
||||||
@@ -3,13 +3,15 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
preprocess {
|
preprocess {
|
||||||
|
def fabric12107 = createNode("1.21.7", 12107, "yarn")
|
||||||
def fabric12105 = createNode("1.21.5", 12105, "yarn")
|
def fabric12105 = createNode("1.21.5", 12105, "yarn")
|
||||||
def fabric12104 = createNode("1.21.4", 12104, "yarn")
|
def fabric12104 = createNode("1.21.4", 12104, "yarn")
|
||||||
def fabric12101 = createNode("1.21.1", 12101, "yarn")
|
def fabric12101 = createNode("1.21.1", 12101, "yarn")
|
||||||
def fabric12001 = createNode("1.20.1", 12001, "yarn")
|
def fabric12001 = createNode("1.20.1", 12001, "yarn")
|
||||||
|
|
||||||
strictExtraMappings.set(true)
|
strictExtraMappings.set(true)
|
||||||
fabric12104.link(fabric12105, null)
|
fabric12105.link(fabric12107, null)
|
||||||
fabric12101.link(fabric12105, null)
|
fabric12104.link(fabric12107, null)
|
||||||
fabric12001.link(fabric12105, null)
|
fabric12101.link(fabric12107, null)
|
||||||
|
fabric12001.link(fabric12107, null)
|
||||||
}
|
}
|
||||||
@@ -99,8 +99,10 @@ public class FabricHuskSync implements DedicatedServerModInitializer, HuskSync,
|
|||||||
private static final int VERSION1_20_5 = 3837;
|
private static final int VERSION1_20_5 = 3837;
|
||||||
private static final int VERSION1_21_1 = 3955;
|
private static final int VERSION1_21_1 = 3955;
|
||||||
private static final int VERSION1_21_3 = 4082;
|
private static final int VERSION1_21_3 = 4082;
|
||||||
private static final int VERSION1_21_4 = 4189; // Current
|
private static final int VERSION1_21_4 = 4189;
|
||||||
private static final int VERSION1_21_5 = 4323;
|
private static final int VERSION1_21_5 = 4323;
|
||||||
|
private static final int VERSION1_21_6 = 4435;
|
||||||
|
private static final int VERSION1_21_7 = 4438;
|
||||||
|
|
||||||
private final HashMap<Identifier, Serializer<? extends Data>> serializers = Maps.newHashMap();
|
private final HashMap<Identifier, Serializer<? extends Data>> serializers = Maps.newHashMap();
|
||||||
private final Map<UUID, Map<Identifier, Data>> playerCustomDataStore = Maps.newConcurrentMap();
|
private final Map<UUID, Map<Identifier, Data>> playerCustomDataStore = Maps.newConcurrentMap();
|
||||||
@@ -387,10 +389,14 @@ public class FabricHuskSync implements DedicatedServerModInitializer, HuskSync,
|
|||||||
case "1.21.2", "1.21.3" -> VERSION1_21_3;
|
case "1.21.2", "1.21.3" -> VERSION1_21_3;
|
||||||
case "1.21.4" -> VERSION1_21_4;
|
case "1.21.4" -> VERSION1_21_4;
|
||||||
case "1.21.5" -> VERSION1_21_5;
|
case "1.21.5" -> VERSION1_21_5;
|
||||||
//#if MC==12105
|
case "1.21.6" -> VERSION1_21_6;
|
||||||
|
case "1.21.7" -> VERSION1_21_7;
|
||||||
|
//#if MC==12107
|
||||||
|
default -> VERSION1_21_7;
|
||||||
|
//#elseif MC==12105
|
||||||
//$$ default -> VERSION1_21_5;
|
//$$ default -> VERSION1_21_5;
|
||||||
//#elseif MC==12104
|
//#elseif MC==12104
|
||||||
default -> VERSION1_21_4;
|
//$$ default -> VERSION1_21_4;
|
||||||
//#elseif MC==12101
|
//#elseif MC==12101
|
||||||
//$$ default -> VERSION1_21_1;
|
//$$ default -> VERSION1_21_1;
|
||||||
//#elseif MC==12001
|
//#elseif MC==12001
|
||||||
|
|||||||
@@ -272,12 +272,14 @@ public abstract class FabricSerializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private NbtCompound encodeNbt(@NotNull ItemStack item, @NotNull DynamicRegistryManager registryManager) {
|
private NbtCompound encodeNbt(@NotNull ItemStack item, @NotNull DynamicRegistryManager reg) {
|
||||||
try {
|
try {
|
||||||
//#if MC>=12104
|
//#if MC>=12107
|
||||||
return (NbtCompound) item.toNbt(registryManager);
|
return (NbtCompound) ItemStack.CODEC.encodeStart(reg.getOps(NbtOps.INSTANCE), item).getOrThrow();
|
||||||
|
//#elseif MC>=12104
|
||||||
|
//$$ return (NbtCompound) item.toNbt(reg);
|
||||||
//#elseif MC==12101
|
//#elseif MC==12101
|
||||||
//$$ return (NbtCompound) item.encode(registryManager);
|
//$$ return (NbtCompound) item.encode(reg);
|
||||||
//#elseif MC==12001
|
//#elseif MC==12001
|
||||||
//$$ final NbtCompound compound = new NbtCompound();
|
//$$ final NbtCompound compound = new NbtCompound();
|
||||||
//$$ item.writeNbt(compound);
|
//$$ item.writeNbt(compound);
|
||||||
@@ -289,14 +291,16 @@ public abstract class FabricSerializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private ItemStack decodeNbt(@NotNull NbtElement item, @NotNull DynamicRegistryManager registryManager) {
|
private ItemStack decodeNbt(@NotNull NbtElement item, @NotNull DynamicRegistryManager reg) {
|
||||||
//#if MC==12001
|
//#if MC>=12107
|
||||||
|
final @Nullable ItemStack stack = ItemStack.CODEC.decode(reg.getOps(NbtOps.INSTANCE), item).getOrThrow().getFirst();
|
||||||
|
//#elseif MC>12001
|
||||||
|
//$$ final @Nullable ItemStack stack = ItemStack.fromNbt(reg, item).orElse(null);
|
||||||
|
//#elseif MC==12001
|
||||||
//$$ final @Nullable ItemStack stack = ItemStack.fromNbt((NbtCompound) item);
|
//$$ final @Nullable ItemStack stack = ItemStack.fromNbt((NbtCompound) item);
|
||||||
//#else
|
|
||||||
final @Nullable ItemStack stack = ItemStack.fromNbt(registryManager, item).orElse(null);
|
|
||||||
//#endif
|
//#endif
|
||||||
if (stack == null) {
|
if (stack == null) {
|
||||||
throw new IllegalStateException("Failed to decode item NBT (got null 'fromNbt'): (%s)".formatted(item));
|
throw new IllegalStateException("Failed to decode item NBT (decode got null): (%s)".formatted(item));
|
||||||
}
|
}
|
||||||
return stack;
|
return stack;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ org.gradle.daemon=true
|
|||||||
javaVersion=21
|
javaVersion=21
|
||||||
|
|
||||||
# Plugin metadata
|
# Plugin metadata
|
||||||
plugin_version=3.8.4
|
plugin_version=3.8.6
|
||||||
plugin_archive=husksync
|
plugin_archive=husksync
|
||||||
plugin_description=A modern, cross-server player data synchronization system
|
plugin_description=A modern, cross-server player data synchronization system
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,6 @@ certifi==2024.7.4
|
|||||||
charset-normalizer==3.2.0
|
charset-normalizer==3.2.0
|
||||||
colorama==0.4.6
|
colorama==0.4.6
|
||||||
idna==3.7
|
idna==3.7
|
||||||
requests==2.32.0
|
requests==2.32.4
|
||||||
tqdm==4.66.3
|
tqdm==4.66.3
|
||||||
urllib3==2.2.2
|
urllib3==2.5.0
|
||||||
|
|||||||
Reference in New Issue
Block a user