mirror of
https://github.com/WiIIiam278/HuskSync.git
synced 2025-12-25 17:49:20 +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 |
10
.github/workflows/ci.yml
vendored
10
.github/workflows/ci.yml
vendored
@@ -55,15 +55,19 @@ jobs:
|
||||
paper-1.21.1
|
||||
paper-1.21.4
|
||||
paper-1.21.5
|
||||
paper-1.21.7
|
||||
fabric-1.20.1
|
||||
fabric-1.21.1
|
||||
fabric-1.21.4
|
||||
fabric-1.21.5
|
||||
fabric-1.21.7
|
||||
distro-groups: |
|
||||
paper
|
||||
paper
|
||||
paper
|
||||
paper
|
||||
paper
|
||||
fabric
|
||||
fabric
|
||||
fabric
|
||||
fabric
|
||||
@@ -73,16 +77,20 @@ jobs:
|
||||
Paper 1.21.1
|
||||
Paper 1.21.4
|
||||
Paper 1.21.5
|
||||
Paper 1.21.7
|
||||
Fabric 1.20.1
|
||||
Fabric 1.21.1
|
||||
Fabric 1.21.4
|
||||
Fabric 1.21.5
|
||||
Fabric 1.21.7
|
||||
files: |
|
||||
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.4.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.21.1.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
|
||||
10
.github/workflows/release.yml
vendored
10
.github/workflows/release.yml
vendored
@@ -44,15 +44,19 @@ jobs:
|
||||
paper-1.21.1
|
||||
paper-1.21.4
|
||||
paper-1.21.5
|
||||
paper-1.21.7
|
||||
fabric-1.20.1
|
||||
fabric-1.21.1
|
||||
fabric-1.21.4
|
||||
fabric-1.21.5
|
||||
fabric-1.21.7
|
||||
distro-groups: |
|
||||
paper
|
||||
paper
|
||||
paper
|
||||
paper
|
||||
paper
|
||||
fabric
|
||||
fabric
|
||||
fabric
|
||||
fabric
|
||||
@@ -62,16 +66,20 @@ jobs:
|
||||
Paper 1.21.1
|
||||
Paper 1.21.4
|
||||
Paper 1.21.5
|
||||
Paper 1.21.7
|
||||
Fabric 1.20.1
|
||||
Fabric 1.21.1
|
||||
Fabric 1.21.4
|
||||
Fabric 1.21.5
|
||||
Fabric 1.21.7
|
||||
files: |
|
||||
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.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.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.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.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 |
|
||||
|:---------------:|:---------------:|:------------:|:--------------|:------------------------------|
|
||||
| 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.3 | 3.7.1 | 21 | Paper, Fabric | 🗃️ Archived (December 2024) |
|
||||
| 1.21.1 | _latest_ | 21 | Paper, Fabric | ✅ **November 2025** (LTS) |
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import org.apache.tools.ant.filters.ReplaceTokens
|
||||
|
||||
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 'dev.architectury.loom' version '1.9-SNAPSHOT' 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 'java'
|
||||
}
|
||||
@@ -89,7 +89,7 @@ allprojects {
|
||||
}
|
||||
|
||||
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'
|
||||
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
|
||||
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 {
|
||||
implementation project(path: ':common')
|
||||
|
||||
implementation 'net.william278.uniform:uniform-bukkit:1.3.4'
|
||||
implementation 'net.william278.uniform:uniform-paper:1.3.4'
|
||||
implementation 'net.william278.toilet:toilet-bukkit:1.0.13'
|
||||
implementation 'net.william278.uniform:uniform-bukkit:1.3.8'
|
||||
implementation 'net.william278.uniform:uniform-paper:1.3.8'
|
||||
implementation 'net.william278.toilet:toilet-bukkit:1.0.15'
|
||||
implementation 'net.william278:mpdbdataconverter:1.0.1'
|
||||
implementation 'net.william278:hsldataconverter:1.0'
|
||||
implementation 'net.william278:mapdataapi:2.0'
|
||||
@@ -18,7 +18,7 @@ dependencies {
|
||||
implementation 'net.kyori:adventure-platform-bukkit:4.4.0'
|
||||
implementation 'dev.triumphteam:triumph-gui:3.1.12'
|
||||
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 '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.5", "1.20.6" -> DataFixerUtil.VERSION1_20_5;
|
||||
case "1.21", "1.21.1" -> DataFixerUtil.VERSION1_21;
|
||||
case "1.21.2", "1.21.3" -> DataFixerUtil.VERSION1_21_2;
|
||||
case "1.21.4" -> 4189;
|
||||
case "1.21.2" -> DataFixerUtil.VERSION1_21_2;
|
||||
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.6" -> 4435;
|
||||
default -> DataFixerUtil.getCurrentVersion();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@NoArgsConstructor
|
||||
@SuppressWarnings("UnstableApiUsage")
|
||||
@@ -46,13 +47,20 @@ public class PaperHuskSyncLoader implements PluginLoader {
|
||||
resolveLibraries(classpathBuilder).stream()
|
||||
.map(DefaultArtifact::new)
|
||||
.forEach(artifact -> resolver.addDependency(new Dependency(artifact, null)));
|
||||
resolver.addRepository(new RemoteRepository.Builder(
|
||||
"maven", "default", "https://repo.maven.apache.org/maven2/"
|
||||
).build());
|
||||
resolver.addRepository(new RemoteRepository.Builder("maven", "default", getMavenUrl()).build());
|
||||
|
||||
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
|
||||
private static List<String> resolveLibraries(@NotNull PluginClasspathBuilder classpathBuilder) {
|
||||
try (InputStream input = getLibraryListFile()) {
|
||||
|
||||
@@ -135,7 +135,7 @@ public class BukkitEventListener extends EventListener implements BukkitJoinEven
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onMapInitialize(@NotNull MapInitializeEvent event) {
|
||||
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)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final ReadableNBT mapData = nbt.getCompound(MAP_DATA_KEY);
|
||||
if (mapData == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Determine map ID
|
||||
final String originServerName = mapData.getString(MAP_ORIGIN_KEY);
|
||||
final String currentServerName = getPlugin().getServerName();
|
||||
final int originalMapId = mapData.getInteger(MAP_ID_KEY);
|
||||
int newId = currentServerName.equals(originServerName)
|
||||
? originalMapId : getBoundMapId(originServerName, originalMapId, currentServerName);
|
||||
// Server the map was originally created on, and the current server. If they match, isOrigin is true.
|
||||
final String originServer = mapData.getString(MAP_ORIGIN_KEY);
|
||||
final String currentServer = getPlugin().getServerName();
|
||||
final boolean isOrigin = currentServer.equals(originServer);
|
||||
|
||||
// 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) {
|
||||
final MapView view = Bukkit.getMap(newId);
|
||||
if (view != null) {
|
||||
meta.setMapView(view);
|
||||
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));
|
||||
handleBoundMap(meta, nbt, originServer, originalId, newId, isOrigin);
|
||||
} else {
|
||||
handleUnboundMap(meta, nbt, originServer, originalId, currentServer);
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
default void renderPersistedMap(@NotNull MapView view) {
|
||||
if (getMapView(view.getId()).isPresent()) {
|
||||
private void handleBoundMap(@NotNull MapMeta meta, @NotNull ReadableItemNBT nbt, @NotNull String originServer,
|
||||
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;
|
||||
}
|
||||
|
||||
// Read map data, or
|
||||
@Nullable Map.Entry<MapData, Boolean> data = readMapData(getPlugin().getServerName(), view.getId());
|
||||
Optional<MapView> optionalView = getMapView(newId);
|
||||
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) {
|
||||
data = readLegacyMapFileData(view.getId());
|
||||
}
|
||||
|
||||
// Don't render maps with no data
|
||||
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."
|
||||
.formatted(world.getName(), view.getId()));
|
||||
return;
|
||||
}
|
||||
// Don't render persisted maps on this server
|
||||
if (data.getValue()) {
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
renderMapView(view, data.getKey());
|
||||
}
|
||||
|
||||
// Sets the renderer of a map, and returns the generated MapView
|
||||
@NotNull
|
||||
private MapView generateRenderedMap(@NotNull MapData canvasData) {
|
||||
final MapView view = Bukkit.createMap(getDefaultMapWorld());
|
||||
view.getRenderers().clear();
|
||||
return generateRenderedMap(canvasData, Bukkit.createMap(getDefaultMapWorld()));
|
||||
}
|
||||
|
||||
// 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.setLocked(true);
|
||||
view.setScale(MapView.Scale.NORMAL);
|
||||
view.setTrackingPosition(false);
|
||||
view.setUnlimitedTracking(false);
|
||||
|
||||
// Set the view to the map and return it
|
||||
setMapView(view);
|
||||
return view;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -17,15 +17,15 @@ dependencies {
|
||||
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 'org.projectlombok:lombok:1.18.38'
|
||||
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-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.github.plan-player-analytics:Plan:5.6.2965'
|
||||
compileOnly "redis.clients:jedis:$jedis_version"
|
||||
|
||||
@@ -150,7 +150,7 @@ public class Settings {
|
||||
}
|
||||
}
|
||||
|
||||
// 𝓡𝓮𝓭𝓲𝓼 settings
|
||||
// Redis settings
|
||||
@Comment("Redis settings")
|
||||
private RedisSettings redis = new RedisSettings();
|
||||
|
||||
@@ -326,6 +326,9 @@ public class Settings {
|
||||
@Getter(AccessLevel.NONE)
|
||||
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) {
|
||||
return autoPinnedSaveCauses.contains(cause.name());
|
||||
}
|
||||
|
||||
@@ -190,7 +190,8 @@ public class RedisManager extends JedisPubSub {
|
||||
).dispatch(plugin, RedisMessage.Type.RETURN_USER_DATA)
|
||||
);
|
||||
case CHECK_IN_PETITION -> {
|
||||
if (!redisMessage.isTargetServer(plugin)) {
|
||||
if (!redisMessage.isTargetServer(plugin)
|
||||
|| !plugin.getSettings().getSynchronization().isCheckinPetitions()) {
|
||||
return;
|
||||
}
|
||||
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
|
||||
final Optional<String> server = getRedis().getUserCheckedOut(user);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ locales:
|
||||
data_manager_timestamp: '[⌚ %1%](#ffc43b-#f5c962 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_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_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'
|
||||
@@ -22,8 +22,8 @@ locales:
|
||||
data_manager_advancements_preview_remaining: 'さらに %1% 件…'
|
||||
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_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_saved: '[Successfully saved a snapshot of %1%''s current user data.](#00fb9a)'
|
||||
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: '[%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_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)'
|
||||
@@ -37,35 +37,35 @@ locales:
|
||||
list_page_jumper_current_page: '[%1%](#00fb9a)'
|
||||
list_page_jumper_separator: ' '
|
||||
list_page_jumper_group_separator: '…'
|
||||
save_cause_disconnect: 'disconnect'
|
||||
save_cause_world_save: 'world save'
|
||||
save_cause_death: 'death'
|
||||
save_cause_server_shutdown: 'server shutdown'
|
||||
save_cause_save_command: 'save command'
|
||||
save_cause_dump_command: 'dump command'
|
||||
save_cause_inventory_command: 'inventory command'
|
||||
save_cause_enderchest_command: 'enderchest command'
|
||||
save_cause_backup_restore: 'backup restore'
|
||||
save_cause_disconnect: '切断'
|
||||
save_cause_world_save: 'ワールド保存'
|
||||
save_cause_death: '死亡'
|
||||
save_cause_server_shutdown: 'サーバーシャットダウン'
|
||||
save_cause_save_command: 'セーブコマンド'
|
||||
save_cause_dump_command: 'ダンプコマンド'
|
||||
save_cause_inventory_command: 'インベントリコマンド'
|
||||
save_cause_enderchest_command: 'エンダーチェストコマンド'
|
||||
save_cause_backup_restore: 'バックアップ復元'
|
||||
save_cause_api: 'API'
|
||||
save_cause_mpdb_migration: 'MPDB migration'
|
||||
save_cause_legacy_migration: 'legacy migration'
|
||||
save_cause_converted_from_v2: 'converted from v2'
|
||||
save_cause_mpdb_migration: 'MPDB移行'
|
||||
save_cause_legacy_migration: 'レガシー移行'
|
||||
save_cause_converted_from_v2: 'v2からの変換'
|
||||
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)'
|
||||
system_status_header: '[HuskSync](#00fb9a bold) [| System status report:](#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_started: '[HuskSync](#00fb9a bold) [| Preparing system status dump, please wait…](#00fb9a)'
|
||||
system_dump_ready: '[HuskSync](#00fb9a bold) [| System status dump prepared! Click to view:](#00fb9a)'
|
||||
error_invalid_syntax: '[Error:](#ff3300) [構文が正しくありません。使用法:](#ff7e5e) [%1%](#ff7e5e italic show_text=&#ff7e5e&クリックでサジェスト suggest_command=%1%)'
|
||||
error_invalid_player: '[Error:](#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_no_permission: '[Error:](#ff3300) [このコマンドを実行する権限がありません](#ff7e5e)'
|
||||
error_console_command_only: '[Error:](#ff3300) [そのコマンドは%1%コンソールからのみ実行できます](#ff7e5e)'
|
||||
error_in_game_command_only: 'Error: そのコマンドはゲーム内でしか使えません。'
|
||||
error_no_data_to_display: '[Error:](#ff3300) [表示するユーザーデータが見つかりませんでした。](#ff7e5e)'
|
||||
error_invalid_version_uuid: '[Error:](#ff3300) [そのバージョンUUIDのユーザーデータが見つかりませんでした。](#ff7e5e)'
|
||||
system_status_header: '[HuskSync](#00fb9a bold) [| システムステータスレポート:](#00fb9a)'
|
||||
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) [| システムステータスダンプを準備中です。お待ちください…](#00fb9a)'
|
||||
system_dump_ready: '[HuskSync](#00fb9a bold) [| システムステータスダンプが準備できました!クリックで表示:](#00fb9a)'
|
||||
error_invalid_syntax: '[エラー:](#ff3300) [構文が正しくありません。使用法:](#ff7e5e) [%1%](#ff7e5e italic show_text=&#ff7e5e&クリックでサジェスト suggest_command=%1%)'
|
||||
error_invalid_player: '[エラー:](#ff3300) [そのプレイヤーは見つかりませんでした](#ff7e5e)'
|
||||
error_invalid_data: '[エラー:](#ff3300) [スナップショットが無効または破損しているため、ユーザーデータを展開できません。](#ff7e5e) [(詳細…)](gray show_text=&7⚠ %1%)'
|
||||
error_no_permission: '[エラー:](#ff3300) [このコマンドを実行する権限がありません](#ff7e5e)'
|
||||
error_console_command_only: '[エラー:](#ff3300) [そのコマンドは%1%コンソールからのみ実行できます](#ff7e5e)'
|
||||
error_in_game_command_only: 'エラー: そのコマンドはゲーム内でしか使えません。'
|
||||
error_no_data_to_display: '[エラー:](#ff3300) [表示するユーザーデータが見つかりませんでした。](#ff7e5e)'
|
||||
error_invalid_version_uuid: '[エラー:](#ff3300) [そのバージョンUUIDのユーザーデータが見つかりませんでした。](#ff7e5e)'
|
||||
husksync_command_description: 'HuskSyncプラグインを管理する'
|
||||
userdata_command_description: 'プレーヤーのユーザーデータを表示・管理・復元する'
|
||||
userdata_command_description: 'プレイヤーのユーザーデータを表示・管理・復元する'
|
||||
inventory_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 |
|
||||
|:---------------:|:---------------:|:------------:|:--------------|:------------------------------|
|
||||
| 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.3 | 3.7.1 | 21 | Paper, Fabric | 🗃️ Archived (December 2024) |
|
||||
| 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
|
||||
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
|
||||
This can happen due to the way in which your server restarts. If your server uses either:
|
||||
|
||||
@@ -38,4 +51,4 @@ These are **not compatible** with HuskSync in most cases due to the way in which
|
||||
* A cronjob to send a stop command / Power Action program stopcode, listen for the service to fully terminate, and then execute your startup command
|
||||
* For manual restarts, executing `/stop` and starting your server up with the startup command is totally fine.
|
||||
|
||||
It's not a great idea to use a plugin to handle restarts. Plugins are only able to operate when your server is turned on and must rely on scripts which don't safely shutdown servers when restarting.
|
||||
It's not a great idea to use a plugin to handle restarts. Plugins are only able to operate when your server is turned on and must rely on scripts which don't safely shutdown servers when restarting.
|
||||
|
||||
@@ -3,5 +3,5 @@ essential.defaults.loom.mappings=net.fabricmc:yarn:1.21.5+build.1:v2
|
||||
fabric_loader_version=0.16.14
|
||||
fabric_api_version=0.122.0+1.21.5
|
||||
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
|
||||
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("me.lucko:fabric-permissions-api:${fabric_permissions_api_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.toilet:toilet-fabric:1.0.13+${project.name}")
|
||||
modImplementation include("net.william278.uniform:uniform-fabric:1.3.8+${project.name}")
|
||||
modImplementation include("net.william278.toilet:toilet-fabric:1.0.15+${project.name}")
|
||||
modImplementation "net.fabricmc.fabric-api:fabric-api:${fabric_api_version}"
|
||||
|
||||
// Manually include config deps due to the way including api deps works
|
||||
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')
|
||||
|
||||
// Include driver deps due to no runtime dep loading support
|
||||
|
||||
@@ -1 +1 @@
|
||||
1.21.5
|
||||
1.21.7
|
||||
@@ -3,13 +3,15 @@ plugins {
|
||||
}
|
||||
|
||||
preprocess {
|
||||
def fabric12107 = createNode("1.21.7", 12107, "yarn")
|
||||
def fabric12105 = createNode("1.21.5", 12105, "yarn")
|
||||
def fabric12104 = createNode("1.21.4", 12104, "yarn")
|
||||
def fabric12101 = createNode("1.21.1", 12101, "yarn")
|
||||
def fabric12001 = createNode("1.20.1", 12001, "yarn")
|
||||
|
||||
strictExtraMappings.set(true)
|
||||
fabric12104.link(fabric12105, null)
|
||||
fabric12101.link(fabric12105, null)
|
||||
fabric12001.link(fabric12105, null)
|
||||
fabric12105.link(fabric12107, null)
|
||||
fabric12104.link(fabric12107, 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_21_1 = 3955;
|
||||
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_6 = 4435;
|
||||
private static final int VERSION1_21_7 = 4438;
|
||||
|
||||
private final HashMap<Identifier, Serializer<? extends Data>> serializers = Maps.newHashMap();
|
||||
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.4" -> VERSION1_21_4;
|
||||
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;
|
||||
//#elseif MC==12104
|
||||
default -> VERSION1_21_4;
|
||||
//$$ default -> VERSION1_21_4;
|
||||
//#elseif MC==12101
|
||||
//$$ default -> VERSION1_21_1;
|
||||
//#elseif MC==12001
|
||||
|
||||
@@ -272,12 +272,14 @@ public abstract class FabricSerializer {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private NbtCompound encodeNbt(@NotNull ItemStack item, @NotNull DynamicRegistryManager registryManager) {
|
||||
private NbtCompound encodeNbt(@NotNull ItemStack item, @NotNull DynamicRegistryManager reg) {
|
||||
try {
|
||||
//#if MC>=12104
|
||||
return (NbtCompound) item.toNbt(registryManager);
|
||||
//#if MC>=12107
|
||||
return (NbtCompound) ItemStack.CODEC.encodeStart(reg.getOps(NbtOps.INSTANCE), item).getOrThrow();
|
||||
//#elseif MC>=12104
|
||||
//$$ return (NbtCompound) item.toNbt(reg);
|
||||
//#elseif MC==12101
|
||||
//$$ return (NbtCompound) item.encode(registryManager);
|
||||
//$$ return (NbtCompound) item.encode(reg);
|
||||
//#elseif MC==12001
|
||||
//$$ final NbtCompound compound = new NbtCompound();
|
||||
//$$ item.writeNbt(compound);
|
||||
@@ -289,14 +291,16 @@ public abstract class FabricSerializer {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private ItemStack decodeNbt(@NotNull NbtElement item, @NotNull DynamicRegistryManager registryManager) {
|
||||
//#if MC==12001
|
||||
private ItemStack decodeNbt(@NotNull NbtElement item, @NotNull DynamicRegistryManager reg) {
|
||||
//#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);
|
||||
//#else
|
||||
final @Nullable ItemStack stack = ItemStack.fromNbt(registryManager, item).orElse(null);
|
||||
//#endif
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ org.gradle.daemon=true
|
||||
javaVersion=21
|
||||
|
||||
# Plugin metadata
|
||||
plugin_version=3.8.4
|
||||
plugin_version=3.8.6
|
||||
plugin_archive=husksync
|
||||
plugin_description=A modern, cross-server player data synchronization system
|
||||
|
||||
|
||||
@@ -2,6 +2,6 @@ certifi==2024.7.4
|
||||
charset-normalizer==3.2.0
|
||||
colorama==0.4.6
|
||||
idna==3.7
|
||||
requests==2.32.0
|
||||
requests==2.32.4
|
||||
tqdm==4.66.3
|
||||
urllib3==2.2.2
|
||||
urllib3==2.5.0
|
||||
|
||||
Reference in New Issue
Block a user