9
0
mirror of https://github.com/WiIIiam278/HuskSync.git synced 2025-12-26 18:19:10 +00:00

Compare commits

...

17 Commits
3.8.4 ... 3.8.5

Author SHA1 Message Date
William278
2ada0497ec docs: update compatibility 2025-06-25 18:55:44 +01:00
William278
e9f2856040 feat: add support for Minecraft 1.21.6 2025-06-23 00:15:11 +01:00
William278
6050c584c0 refactor(paper): improve handling of locked maps in item frames 2025-06-22 14:23:52 +01:00
William278
7ebf91bfae refactor(paper): further refactors to locked maps 2025-06-22 00:24:36 +01:00
William278
2d7799628a refactor(paper): avoid use of default maven central URL 2025-06-21 15:32:02 +01:00
William278
1627de732b refactor: enable check-in petitions by default 2025-06-21 15:09:17 +01:00
William278
fea882c642 fix(paper): locked maps losing data on restart, close #498 2025-06-21 15:08:16 +01:00
dependabot[bot]
8b749357f7 build(deps): bump urllib3 from 2.2.2 to 2.5.0 in /test (#528)
Bumps [urllib3](https://github.com/urllib3/urllib3) from 2.2.2 to 2.5.0.
- [Release notes](https://github.com/urllib3/urllib3/releases)
- [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst)
- [Commits](https://github.com/urllib3/urllib3/compare/2.2.2...2.5.0)

---
updated-dependencies:
- dependency-name: urllib3
  dependency-version: 2.5.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-19 23:34:42 +01:00
dependabot[bot]
e4ff7e6d6c deps: bump org.ajoberstar.grgit from 5.3.0 to 5.3.2 (#526)
Bumps [org.ajoberstar.grgit](https://github.com/ajoberstar/grgit) from 5.3.0 to 5.3.2.
- [Release notes](https://github.com/ajoberstar/grgit/releases)
- [Commits](https://github.com/ajoberstar/grgit/compare/5.3.0...5.3.2)

---
updated-dependencies:
- dependency-name: org.ajoberstar.grgit
  dependency-version: 5.3.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-19 23:34:33 +01:00
William278
396630821f fix: return false if user is checked out if CIPs are off 2025-06-18 22:19:54 +01:00
William278
70f65d126b build: bump adventure platform to 6.4.0 2025-06-15 16:28:00 +01:00
dependabot[bot]
e8925a0d79 build(deps): bump requests from 2.32.0 to 2.32.4 in /test (#523)
Bumps [requests](https://github.com/psf/requests) from 2.32.0 to 2.32.4.
- [Release notes](https://github.com/psf/requests/releases)
- [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md)
- [Commits](https://github.com/psf/requests/compare/v2.32.0...v2.32.4)

---
updated-dependencies:
- dependency-name: requests
  dependency-version: 2.32.4
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-14 13:28:07 +01:00
dependabot[bot]
2a3cf9be7d deps: bump org.junit:junit-bom from 5.12.2 to 5.13.1 (#519)
Bumps [org.junit:junit-bom](https://github.com/junit-team/junit5) from 5.12.2 to 5.13.1.
- [Release notes](https://github.com/junit-team/junit5/releases)
- [Commits](https://github.com/junit-team/junit5/compare/r5.12.2...r5.13.1)

---
updated-dependencies:
- dependency-name: org.junit:junit-bom
  dependency-version: 5.13.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-14 13:27:59 +01:00
dependabot[bot]
971d3f5167 deps: bump net.kyori:adventure-api from 4.20.0 to 4.21.0 (#520)
Bumps [net.kyori:adventure-api](https://github.com/KyoriPowered/adventure) from 4.20.0 to 4.21.0.
- [Release notes](https://github.com/KyoriPowered/adventure/releases)
- [Commits](https://github.com/KyoriPowered/adventure/compare/v4.20.0...v4.21.0)

---
updated-dependencies:
- dependency-name: net.kyori:adventure-api
  dependency-version: 4.21.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-14 13:27:51 +01:00
dependabot[bot]
99da65a4d8 deps: bump org.snakeyaml:snakeyaml-engine from 2.7 to 2.9 (#522)
Bumps [org.snakeyaml:snakeyaml-engine](https://bitbucket.org/snakeyaml/snakeyaml-engine) from 2.7 to 2.9.
- [Commits](https://bitbucket.org/snakeyaml/snakeyaml-engine/branches/compare/snakeyaml-engine-2.9..snakeyaml-engine-2.7)

---
updated-dependencies:
- dependency-name: org.snakeyaml:snakeyaml-engine
  dependency-version: '2.9'
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-14 13:27:39 +01:00
William278
25744b4ef7 Merge remote-tracking branch 'origin/master' 2025-06-13 19:25:31 +01:00
William278
8f2d1c7298 refactor: place checkin petitions behind experimental setting 2025-06-13 17:51:09 +01:00
24 changed files with 193 additions and 111 deletions

View File

@@ -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.6
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.6
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.6
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.6
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.6.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.6.jar

View File

@@ -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.6
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.6
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.6
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.6
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.6.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.6.jar

View File

@@ -48,7 +48,8 @@ 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.6 | _latest_ | 21 | Paper | ✅ **Active Release** |
| 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) |

View File

@@ -5,7 +5,7 @@ plugins {
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.1"))
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'

View File

@@ -0,0 +1,3 @@
minecraft_version_numeric=12106
minecraft_api_version=1.21
paper_api_version=1.21.6-R0.1-SNAPSHOT

View File

@@ -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.5'
implementation 'net.william278.uniform:uniform-paper:1.3.4' implementation 'net.william278.uniform:uniform-paper:1.3.5'
implementation 'net.william278.toilet:toilet-bukkit:1.0.13' implementation 'net.william278.toilet:toilet-bukkit:1.0.14'
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'

View File

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

View File

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

View File

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

View File

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

View File

@@ -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.14'
compileOnly 'net.william278.uniform:uniform-common:1.3.4' compileOnly 'net.william278.uniform:uniform-common:1.3.5'
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"

View File

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

View File

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

View File

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

View File

@@ -2,7 +2,8 @@ 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.6 | _latest_ | 21 | Paper | ✅ **Active Release** |
| 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) |

View File

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

View File

@@ -0,0 +1,7 @@
essential.defaults.loom.mappings=net.fabricmc:yarn:1.21.6+build.1:v2
fabric_loader_version=0.16.14
fabric_api_version=0.127.1+1.21.6
fabric_permissions_api_version=0.4.0
fabric_adventure_platform_version=6.5.0-SNAPSHOT
fabric_sgui_version=1.10.0+1.21.6

View File

@@ -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.5+${project.name}")
modImplementation include("net.william278.toilet:toilet-fabric:1.0.13+${project.name}") modImplementation include("net.william278.toilet:toilet-fabric:1.0.14+${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

View File

@@ -1 +1 @@
1.21.5 1.21.6

View File

@@ -3,13 +3,15 @@ plugins {
} }
preprocess { preprocess {
def fabric12106 = createNode("1.21.6", 12106, "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(fabric12106, null)
fabric12101.link(fabric12105, null) fabric12104.link(fabric12106, null)
fabric12001.link(fabric12105, null) fabric12101.link(fabric12106, null)
fabric12001.link(fabric12106, null)
} }

View File

@@ -99,8 +99,9 @@ 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 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 +388,13 @@ 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;
//#if MC==12106
default -> VERSION1_21_6;
//#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

View File

@@ -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>=12106
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>=12106
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;
} }

View File

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

View File

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