mirror of
https://github.com/WiIIiam278/HuskSync.git
synced 2025-12-26 18:19:10 +00:00
Compare commits
60 Commits
3.8.6
...
dependabot
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
96c2edc21a | ||
|
|
0772f09e98 | ||
|
|
e916673454 | ||
|
|
ac163d5130 | ||
|
|
d656b67570 | ||
|
|
3c66b65ac6 | ||
|
|
c227933b3b | ||
|
|
5cf9cb8e50 | ||
|
|
693cd6120f | ||
|
|
6efd800481 | ||
|
|
a723a7cba3 | ||
|
|
b1a5eb5f44 | ||
|
|
8232282d13 | ||
|
|
404d359f89 | ||
|
|
62e84d92fc | ||
|
|
9b2246eac2 | ||
|
|
e6d3935246 | ||
|
|
5c4111b6a7 | ||
|
|
51a700600a | ||
|
|
23c3ee08e9 | ||
|
|
c1d08f9c23 | ||
|
|
4cabdbe952 | ||
|
|
abdebd960b | ||
|
|
a7aea51a45 | ||
|
|
c8a4376208 | ||
|
|
315cd4ba6b | ||
|
|
6607ac5a6e | ||
|
|
562939498a | ||
|
|
e686d43ca8 | ||
|
|
e9ac400215 | ||
|
|
234870537a | ||
|
|
b5f392a20f | ||
|
|
9ea8eb4101 | ||
|
|
dc7cde1c33 | ||
|
|
4e75b5ca1d | ||
|
|
fe0bdccf40 | ||
|
|
c615ab592b | ||
|
|
16d4a8fd9b | ||
|
|
96f34092f6 | ||
|
|
a31c3c48f7 | ||
|
|
0e96374a03 | ||
|
|
24545563fa | ||
|
|
a9ea4d34e5 | ||
|
|
11453393d4 | ||
|
|
1d850a9ddb | ||
|
|
5b90b3d006 | ||
|
|
d85ec65384 | ||
|
|
9d681db030 | ||
|
|
c5c2dde0bf | ||
|
|
807bffe9aa | ||
|
|
a1956c6822 | ||
|
|
321dccb0b5 | ||
|
|
1015c50802 | ||
|
|
c5e759390b | ||
|
|
883695b0b0 | ||
|
|
879aef471a | ||
|
|
64c81a9a5a | ||
|
|
b61a9a7bc3 | ||
|
|
3f725eb40c | ||
|
|
8f1e4a5198 |
32
.github/workflows/ci.yml
vendored
32
.github/workflows/ci.yml
vendored
@@ -17,9 +17,9 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 'Checkout for CI 🛎️'
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
- name: 'Set up JDK 21 📦'
|
||||
uses: actions/setup-java@v4
|
||||
uses: actions/setup-java@v5
|
||||
with:
|
||||
java-version: '21'
|
||||
distribution: 'temurin'
|
||||
@@ -31,7 +31,7 @@ jobs:
|
||||
SNAPSHOTS_MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }}
|
||||
SNAPSHOTS_MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }}
|
||||
- name: 'Publish Test Report 📊'
|
||||
uses: mikepenz/action-junit-report@v5
|
||||
uses: mikepenz/action-junit-report@v6
|
||||
if: success() || failure() # Continue on failure
|
||||
with:
|
||||
report_paths: '**/build/test-results/test/TEST-*.xml'
|
||||
@@ -51,46 +51,46 @@ jobs:
|
||||
version: ${{ env.version_name }}
|
||||
changelog: ${{ github.event.head_commit.message }}
|
||||
distro-names: |
|
||||
paper-1.20.1
|
||||
paper-1.21.1
|
||||
paper-1.21.4
|
||||
paper-1.21.5
|
||||
paper-1.21.7
|
||||
fabric-1.20.1
|
||||
paper-1.21.8
|
||||
paper-1.21.10
|
||||
paper-1.21.11
|
||||
fabric-1.21.1
|
||||
fabric-1.21.4
|
||||
fabric-1.21.5
|
||||
fabric-1.21.7
|
||||
fabric-1.21.8
|
||||
distro-groups: |
|
||||
paper
|
||||
paper
|
||||
paper
|
||||
paper
|
||||
paper
|
||||
fabric
|
||||
paper
|
||||
fabric
|
||||
fabric
|
||||
fabric
|
||||
fabric
|
||||
distro-descriptions: |
|
||||
Paper 1.20.1
|
||||
Paper 1.21.1
|
||||
Paper 1.21.4
|
||||
Paper 1.21.5
|
||||
Paper 1.21.7
|
||||
Fabric 1.20.1
|
||||
Paper 1.21.8
|
||||
Paper 1.21.10
|
||||
Paper 1.21.11
|
||||
Fabric 1.21.1
|
||||
Fabric 1.21.4
|
||||
Fabric 1.21.5
|
||||
Fabric 1.21.7
|
||||
Fabric 1.21.8
|
||||
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-Bukkit-${{ env.version_name }}+mc.1.21.8.jar
|
||||
target/HuskSync-Bukkit-${{ env.version_name }}+mc.1.21.10.jar
|
||||
target/HuskSync-Bukkit-${{ env.version_name }}+mc.1.21.11.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.7.jar
|
||||
target/HuskSync-Fabric-${{ env.version_name }}+mc.1.21.8.jar
|
||||
6
.github/workflows/pr_tests.yml
vendored
6
.github/workflows/pr_tests.yml
vendored
@@ -13,9 +13,9 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 'Checkout for CI 🛎'
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
- name: 'Set up JDK 21 📦'
|
||||
uses: actions/setup-java@v4
|
||||
uses: actions/setup-java@v5
|
||||
with:
|
||||
java-version: '21'
|
||||
distribution: 'temurin'
|
||||
@@ -24,7 +24,7 @@ jobs:
|
||||
with:
|
||||
arguments: test
|
||||
- name: 'Publish Test Report 📊'
|
||||
uses: mikepenz/action-junit-report@v5
|
||||
uses: mikepenz/action-junit-report@v6
|
||||
if: success() || failure() # Continue on failure
|
||||
with:
|
||||
report_paths: '**/build/test-results/test/TEST-*.xml'
|
||||
28
.github/workflows/release.yml
vendored
28
.github/workflows/release.yml
vendored
@@ -13,9 +13,9 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 'Checkout for CI 🛎️'
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
- name: 'Set up JDK 21 📦'
|
||||
uses: actions/setup-java@v4
|
||||
uses: actions/setup-java@v5
|
||||
with:
|
||||
java-version: '21'
|
||||
distribution: 'temurin'
|
||||
@@ -27,7 +27,7 @@ jobs:
|
||||
RELEASES_MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }}
|
||||
RELEASES_MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }}
|
||||
- name: 'Publish Test Report 📊'
|
||||
uses: mikepenz/action-junit-report@v5
|
||||
uses: mikepenz/action-junit-report@v6
|
||||
if: success() || failure() # Continue on failure
|
||||
with:
|
||||
report_paths: '**/build/test-results/test/TEST-*.xml'
|
||||
@@ -40,16 +40,15 @@ jobs:
|
||||
version: ${{ github.event.release.tag_name }}
|
||||
changelog: ${{ github.event.release.body }}
|
||||
distro-names: |
|
||||
paper-1.20.1
|
||||
paper-1.21.1
|
||||
paper-1.21.4
|
||||
paper-1.21.5
|
||||
paper-1.21.7
|
||||
fabric-1.20.1
|
||||
paper-1.21.8
|
||||
paper-1.21.10
|
||||
fabric-1.21.1
|
||||
fabric-1.21.4
|
||||
fabric-1.21.5
|
||||
fabric-1.21.7
|
||||
fabric-1.21.8
|
||||
distro-groups: |
|
||||
paper
|
||||
paper
|
||||
@@ -60,26 +59,23 @@ jobs:
|
||||
fabric
|
||||
fabric
|
||||
fabric
|
||||
fabric
|
||||
distro-descriptions: |
|
||||
Paper 1.20.1
|
||||
Paper 1.21.1
|
||||
Paper 1.21.4
|
||||
Paper 1.21.5
|
||||
Paper 1.21.7
|
||||
Fabric 1.20.1
|
||||
Paper 1.21.8
|
||||
Paper 1.21.10
|
||||
Fabric 1.21.1
|
||||
Fabric 1.21.4
|
||||
Fabric 1.21.5
|
||||
Fabric 1.21.7
|
||||
Fabric 1.21.8
|
||||
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-Bukkit-${{ github.event.release.tag_name }}+mc.1.21.8.jar
|
||||
target/HuskSync-Bukkit-${{ github.event.release.tag_name }}+mc.1.21.10.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.7.jar
|
||||
target/HuskSync-Fabric-${{ github.event.release.tag_name }}+mc.1.21.8.jar
|
||||
4
.github/workflows/update_docs.yml
vendored
4
.github/workflows/update_docs.yml
vendored
@@ -18,8 +18,8 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 'Checkout for CI 🛎️'
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
- name: 'Push Docs to Github Wiki 📄️'
|
||||
uses: Andrew-Chen-Wang/github-wiki-action@v4
|
||||
uses: Andrew-Chen-Wang/github-wiki-action@v5
|
||||
with:
|
||||
path: 'docs'
|
||||
11
README.md
11
README.md
@@ -48,15 +48,16 @@ HuskSync supports the following [compatible versions](https://william278.net/doc
|
||||
|
||||
| Minecraft | Latest HuskSync | Java Version | Platforms | Support Status |
|
||||
|:---------------:|:---------------:|:------------:|:--------------|:------------------------------|
|
||||
| 1.21.7 | _latest_ | 21 | Paper | ✅ **Active Release** |
|
||||
| 1.21.10 | _latest_ | 21 | Paper | ✅ **Active Release** |
|
||||
| 1.21.7/8 | _latest_ | 21 | Paper, Fabric | ✅ **August 2026** |
|
||||
| 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.5 | _latest_ | 21 | Paper | ✅ **February 2026** (Non-LTS) |
|
||||
| 1.21.4 | _latest_ | 21 | Paper, Fabric | ✅ **February 2026** (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.21.1 | _latest_ | 21 | Paper, Fabric | ✅ **May 2026** (LTS) |
|
||||
| 1.20.6 | 3.6.8 | 17 | Paper | 🗃️ Archived (October 2024) |
|
||||
| 1.20.4 | 3.6.8 | 17 | Paper | 🗃️ Archived (July 2024) |
|
||||
| 1.20.1 | _latest_ | 17 | Paper, Fabric | ✅ **November 2025** (LTS) |
|
||||
| 1.20.1 | 3.8.7 | 17 | Paper, Fabric | 🗃️ Archived (November 2024) |
|
||||
| 1.17.1 - 1.19.4 | 3.6.8 | 17 | Paper | 🗃️ Archived |
|
||||
| 1.16.5 | 3.2.1 | 16 | Paper | 🗃️ Archived |
|
||||
|
||||
|
||||
12
build.gradle
12
build.gradle
@@ -1,7 +1,7 @@
|
||||
import org.apache.tools.ant.filters.ReplaceTokens
|
||||
|
||||
plugins {
|
||||
id 'com.gradleup.shadow' version '8.3.7'
|
||||
id 'com.gradleup.shadow' version '9.3.0'
|
||||
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
|
||||
@@ -89,10 +89,10 @@ allprojects {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testImplementation(platform("org.junit:junit-bom:5.13.2"))
|
||||
testImplementation(platform("org.junit:junit-bom:6.0.1"))
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter'
|
||||
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
|
||||
testCompileOnly 'org.jetbrains:annotations:26.0.2'
|
||||
testCompileOnly 'org.jetbrains:annotations:26.0.2-1'
|
||||
}
|
||||
|
||||
license {
|
||||
@@ -100,14 +100,14 @@ allprojects {
|
||||
include '**/*.java'
|
||||
newLine = true
|
||||
}
|
||||
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
|
||||
processResources {
|
||||
def tokenMap = rootProject.ext.properties
|
||||
tokenMap.merge("grgit",'',(s, s2) -> s)
|
||||
tokenMap.merge("grgit", '', (s, s2) -> s)
|
||||
filesMatching(['**/*.json', '**/*.yml']) {
|
||||
filter ReplaceTokens as Class, beginToken: '${', endToken: '}',
|
||||
tokens: tokenMap
|
||||
@@ -133,7 +133,7 @@ subprojects {
|
||||
|
||||
// Version-specific configuration
|
||||
if (['fabric', 'bukkit'].contains(project.parent?.name)) {
|
||||
compileJava.options.release.set (project.name == '1.20.1' ? 17 : 21) // 1.20.1 requires Java 17
|
||||
compileJava.options.release.set 21
|
||||
version += "+mc.${project.name}"
|
||||
|
||||
if (project.parent?.name?.equals('fabric')) {
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
minecraft_version_numeric=12001
|
||||
minecraft_api_version=1.20
|
||||
paper_api_version=1.20.1-R0.1-SNAPSHOT
|
||||
@@ -1,3 +1,4 @@
|
||||
minecraft_version_range=1.21.1
|
||||
minecraft_version_numeric=12101
|
||||
minecraft_api_version=1.21
|
||||
paper_api_version=1.21.1-R0.1-SNAPSHOT
|
||||
4
bukkit/1.21.10/gradle.properties
Normal file
4
bukkit/1.21.10/gradle.properties
Normal file
@@ -0,0 +1,4 @@
|
||||
minecraft_version_range=>=1.21.9 <=1.21.10
|
||||
minecraft_version_numeric=12110
|
||||
minecraft_api_version=1.21
|
||||
paper_api_version=1.21.10-R0.1-SNAPSHOT
|
||||
4
bukkit/1.21.11/gradle.properties
Normal file
4
bukkit/1.21.11/gradle.properties
Normal file
@@ -0,0 +1,4 @@
|
||||
minecraft_version_range=>=1.21.11 <=1.21.11
|
||||
minecraft_version_numeric=12111
|
||||
minecraft_api_version=1.21
|
||||
paper_api_version=1.21.11-R0.1-SNAPSHOT
|
||||
@@ -1,3 +1,4 @@
|
||||
minecraft_version_range=1.21.4
|
||||
minecraft_version_numeric=12104
|
||||
minecraft_api_version=1.21
|
||||
paper_api_version=1.21.4-R0.1-SNAPSHOT
|
||||
@@ -1,3 +1,4 @@
|
||||
minecraft_version_range=1.21.5
|
||||
minecraft_version_numeric=12105
|
||||
minecraft_api_version=1.21
|
||||
paper_api_version=1.21.5-R0.1-SNAPSHOT
|
||||
@@ -1,3 +0,0 @@
|
||||
minecraft_version_numeric=12107
|
||||
minecraft_api_version=1.21
|
||||
paper_api_version=1.21.7-R0.1-SNAPSHOT
|
||||
4
bukkit/1.21.8/gradle.properties
Normal file
4
bukkit/1.21.8/gradle.properties
Normal file
@@ -0,0 +1,4 @@
|
||||
minecraft_version_range=>=1.21.7 <=1.21.8
|
||||
minecraft_version_numeric=12108
|
||||
minecraft_api_version=1.21
|
||||
paper_api_version=1.21.8-R0.1-SNAPSHOT
|
||||
@@ -8,32 +8,32 @@ plugins {
|
||||
dependencies {
|
||||
implementation project(path: ':common')
|
||||
|
||||
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.uniform:uniform-bukkit:1.3.9'
|
||||
implementation 'net.william278.uniform:uniform-paper:1.3.9'
|
||||
implementation 'net.william278.toilet:toilet-bukkit:1.0.16'
|
||||
implementation 'net.william278:mpdbdataconverter:1.0.1'
|
||||
implementation 'net.william278:hsldataconverter:1.0'
|
||||
implementation 'net.william278:mapdataapi:2.0'
|
||||
implementation 'org.bstats:bstats-bukkit:3.1.0'
|
||||
implementation 'net.kyori:adventure-platform-bukkit:4.4.0'
|
||||
implementation 'net.kyori:adventure-platform-bukkit:4.4.1'
|
||||
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'
|
||||
implementation 'de.tr7zw:item-nbt-api:2.15.5'
|
||||
|
||||
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.10.1'
|
||||
compileOnly 'com.github.dmulloy2:ProtocolLib:5.3.0'
|
||||
compileOnly 'org.projectlombok:lombok:1.18.38'
|
||||
compileOnly 'commons-io:commons-io:2.19.0'
|
||||
compileOnly 'org.projectlombok:lombok:1.18.42'
|
||||
compileOnly 'commons-io:commons-io:2.21.0'
|
||||
compileOnly 'org.json:json:20250517'
|
||||
compileOnly 'net.william278:minedown:1.8.2'
|
||||
compileOnly 'de.exlll:configlib-yaml:4.6.1'
|
||||
compileOnly 'com.zaxxer:HikariCP:6.3.0'
|
||||
compileOnly 'de.exlll:configlib-yaml:4.6.4'
|
||||
compileOnly 'com.zaxxer:HikariCP:7.0.2'
|
||||
compileOnly 'net.william278:DesertWell:2.0.4'
|
||||
compileOnly 'net.william278:AdvancementAPI:97a9583413'
|
||||
compileOnly "redis.clients:jedis:$jedis_version"
|
||||
|
||||
annotationProcessor 'org.projectlombok:lombok:1.18.38'
|
||||
annotationProcessor 'org.projectlombok:lombok:1.18.42'
|
||||
}
|
||||
|
||||
processResources {
|
||||
@@ -42,6 +42,7 @@ processResources {
|
||||
version: version,
|
||||
paper_api_version: paper_api_version,
|
||||
minecraft_version: project.name,
|
||||
minecraft_version_range: minecraft_version_range,
|
||||
minecraft_api_version: minecraft_api_version
|
||||
])
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.gson.Gson;
|
||||
import de.tr7zw.changeme.nbtapi.NBT;
|
||||
import de.tr7zw.changeme.nbtapi.utils.DataFixerUtil;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
@@ -49,6 +48,7 @@ import net.william278.husksync.event.BukkitEventDispatcher;
|
||||
import net.william278.husksync.hook.PlanHook;
|
||||
import net.william278.husksync.listener.BukkitEventListener;
|
||||
import net.william278.husksync.listener.LockedHandler;
|
||||
import net.william278.husksync.maps.BukkitMapHandler;
|
||||
import net.william278.husksync.migrator.LegacyMigrator;
|
||||
import net.william278.husksync.migrator.Migrator;
|
||||
import net.william278.husksync.migrator.MpdbMigrator;
|
||||
@@ -57,7 +57,6 @@ import net.william278.husksync.sync.DataSyncer;
|
||||
import net.william278.husksync.user.BukkitUser;
|
||||
import net.william278.husksync.user.OnlineUser;
|
||||
import net.william278.husksync.util.BukkitLegacyConverter;
|
||||
import net.william278.husksync.maps.BukkitMapHandler;
|
||||
import net.william278.husksync.util.BukkitTask;
|
||||
import net.william278.husksync.util.LegacyConverter;
|
||||
import net.william278.toilet.BukkitToilet;
|
||||
@@ -344,25 +343,6 @@ public class BukkitHuskSync extends JavaPlugin implements HuskSync, BukkitTask.S
|
||||
return Version.fromString(getServer().getBukkitVersion());
|
||||
}
|
||||
|
||||
public int getDataVersion(@NotNull Version mcVersion) {
|
||||
return switch (mcVersion.toStringWithoutMetadata()) {
|
||||
case "1.16", "1.16.1", "1.16.2", "1.16.3", "1.16.4", "1.16.5" -> DataFixerUtil.VERSION1_16_5;
|
||||
case "1.17", "1.17.1" -> DataFixerUtil.VERSION1_17_1;
|
||||
case "1.18", "1.18.1", "1.18.2" -> DataFixerUtil.VERSION1_18_2;
|
||||
case "1.19", "1.19.1", "1.19.2" -> DataFixerUtil.VERSION1_19_2;
|
||||
case "1.20", "1.20.1", "1.20.2" -> DataFixerUtil.VERSION1_20_2;
|
||||
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" -> 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();
|
||||
};
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getPlatformType() {
|
||||
|
||||
@@ -38,13 +38,10 @@ import org.bukkit.attribute.AttributeModifier;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.inventory.InventoryType;
|
||||
//#if MC==12001
|
||||
//$$ import org.bukkit.inventory.EquipmentSlot;
|
||||
//#else
|
||||
import org.bukkit.inventory.EquipmentSlotGroup;
|
||||
//#endif
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.persistence.PersistentDataContainer;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -198,7 +195,9 @@ public abstract class BukkitData implements Data {
|
||||
|
||||
@Override
|
||||
public void apply(@NotNull BukkitUser user, @NotNull BukkitHuskSync plugin) throws IllegalStateException {
|
||||
user.getPlayer().getEnderChest().setContents(plugin.setMapViews(getContents()));
|
||||
ItemStack[] fullContents = plugin.setMapViews(getContents());
|
||||
ItemStack[] enderChestContents = Arrays.copyOf(fullContents, Math.min(fullContents.length, user.getPlayer().getEnderChest().getSize()));
|
||||
user.getPlayer().getEnderChest().setContents(enderChestContents);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -366,7 +365,7 @@ public abstract class BukkitData implements Data {
|
||||
|
||||
// Set player experience and level (prevent advancement awards applying twice), reset game rule
|
||||
if (!toAward.isEmpty()
|
||||
&& (player.getLevel() != expLevel || player.getExp() != expProgress)) {
|
||||
&& (player.getLevel() != expLevel || player.getExp() != expProgress)) {
|
||||
player.setLevel(expLevel);
|
||||
player.setExp(expProgress);
|
||||
}
|
||||
@@ -486,8 +485,13 @@ public abstract class BukkitData implements Data {
|
||||
@NotNull Map<String, Map<String, Integer>> map) {
|
||||
registry.forEach(i -> {
|
||||
try {
|
||||
final int stat = i instanceof Material m ? p.getStatistic(id, m) :
|
||||
(i instanceof EntityType e ? p.getStatistic(id, e) : -1);
|
||||
int stat = 0;
|
||||
if (i instanceof Material mat && ((id.getType() == Statistic.Type.BLOCK && mat.isBlock())
|
||||
|| (id.getType() == Statistic.Type.ITEM && mat.isItem()))) {
|
||||
stat = p.getStatistic(id, mat);
|
||||
} else if (i instanceof EntityType ent && id.getType() == Statistic.Type.ENTITY) {
|
||||
stat = p.getStatistic(id, ent);
|
||||
}
|
||||
if (stat != 0) {
|
||||
map.compute(id.getKey().getKey(), (k, v) -> v == null ? Maps.newHashMap() : v)
|
||||
.put(i.getKey().getKey(), stat);
|
||||
@@ -516,8 +520,18 @@ public abstract class BukkitData implements Data {
|
||||
try {
|
||||
switch (type) {
|
||||
case UNTYPED -> player.setStatistic(stat, value);
|
||||
case BLOCK, ITEM -> player.setStatistic(stat, Objects.requireNonNull(matchMaterial(key[0])), value);
|
||||
case ENTITY -> player.setStatistic(stat, Objects.requireNonNull(matchEntityType(key[0])), value);
|
||||
case BLOCK, ITEM -> {
|
||||
Material material = matchMaterial(key.length > 0 ? key[0] : null);
|
||||
if (material != null) {
|
||||
player.setStatistic(stat, material, value);
|
||||
}
|
||||
}
|
||||
case ENTITY -> {
|
||||
EntityType entity = matchEntityType(key.length > 0 ? key[0] : null);
|
||||
if (entity != null) {
|
||||
player.setStatistic(stat, entity, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Throwable a) {
|
||||
plugin.log(Level.WARNING, "Failed to apply statistic " + id, a);
|
||||
@@ -562,6 +576,14 @@ public abstract class BukkitData implements Data {
|
||||
|
||||
@NotNull
|
||||
public static BukkitData.Attributes adapt(@NotNull Player player, @NotNull HuskSync plugin) {
|
||||
if (!Bukkit.isPrimaryThread()) {
|
||||
try {
|
||||
return Bukkit.getScheduler().callSyncMethod((Plugin) plugin, () -> adapt(player, plugin)).get();
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException("Failed to adapt attributes on main thread", e);
|
||||
}
|
||||
}
|
||||
|
||||
final List<Attribute> attributes = Lists.newArrayList();
|
||||
final AttributeSettings settings = plugin.getSettings().getSynchronization().getAttributes();
|
||||
Registry.ATTRIBUTE.forEach(id -> {
|
||||
@@ -594,33 +616,19 @@ public abstract class BukkitData implements Data {
|
||||
instance.getBaseValue(),
|
||||
instance.getModifiers().stream()
|
||||
.filter(modifier -> !settings.isIgnoredModifier(modifier.getName()))
|
||||
//#if MC==12001
|
||||
//$$ .filter(modifier -> modifier.getSlot() == null)
|
||||
//#else
|
||||
.filter(modifier -> modifier.getSlotGroup() != EquipmentSlotGroup.ANY)
|
||||
//#endif
|
||||
.map(BukkitData.Attributes::adapt).collect(Collectors.toSet())
|
||||
);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Modifier adapt(@NotNull AttributeModifier modifier) {
|
||||
//#if MC==12001
|
||||
//$$ return new Modifier(
|
||||
//$$ modifier.getUniqueId(),
|
||||
//$$ modifier.getName(),
|
||||
//$$ modifier.getAmount(),
|
||||
//$$ modifier.getOperation().ordinal(),
|
||||
//$$ modifier.getSlot() != null ? modifier.getSlot().ordinal() : -1
|
||||
//$$ );
|
||||
//#else
|
||||
return new Modifier(
|
||||
modifier.getKey().toString(),
|
||||
modifier.getAmount(),
|
||||
modifier.getOperation().ordinal(),
|
||||
modifier.getSlotGroup().toString()
|
||||
);
|
||||
//#endif
|
||||
}
|
||||
|
||||
private static void applyAttribute(@Nullable AttributeInstance instance, @Nullable Attribute attribute) {
|
||||
@@ -640,26 +648,25 @@ public abstract class BukkitData implements Data {
|
||||
|
||||
@NotNull
|
||||
private static AttributeModifier adapt(@NotNull Modifier modifier) {
|
||||
//#if MC==12001
|
||||
//$$ return new AttributeModifier(
|
||||
//$$ modifier.uuid(),
|
||||
//$$ modifier.name(),
|
||||
//$$ modifier.amount(),
|
||||
//$$ AttributeModifier.Operation.values()[modifier.operation()],
|
||||
//$$ modifier.equipmentSlot() != -1 ? EquipmentSlot.values()[modifier.equipmentSlot()] : null
|
||||
//$$ );
|
||||
//#else
|
||||
return new AttributeModifier(
|
||||
Objects.requireNonNull(NamespacedKey.fromString(modifier.name())),
|
||||
modifier.amount(),
|
||||
AttributeModifier.Operation.values()[modifier.operation()],
|
||||
Optional.ofNullable(EquipmentSlotGroup.getByName(modifier.slotGroup())).orElse(EquipmentSlotGroup.ANY)
|
||||
);
|
||||
//#endif
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(@NotNull BukkitUser user, @NotNull BukkitHuskSync plugin) throws IllegalStateException {
|
||||
if (!Bukkit.isPrimaryThread()) {
|
||||
try {
|
||||
Bukkit.getScheduler().callSyncMethod(plugin, () -> { this.apply(user, plugin); return null; }).get();
|
||||
return;
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException("Failed to apply attributes on main thread", e);
|
||||
}
|
||||
}
|
||||
|
||||
final AttributeSettings settings = plugin.getSettings().getSynchronization().getAttributes();
|
||||
Registry.ATTRIBUTE.forEach(id -> {
|
||||
if (settings.isIgnoredAttribute(id.getKey().toString())) {
|
||||
|
||||
@@ -47,8 +47,8 @@ import java.awt.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.logging.Level;
|
||||
|
||||
@@ -124,8 +124,8 @@ public interface BukkitMapHandler {
|
||||
|
||||
@Nullable
|
||||
@Blocking
|
||||
private Map.Entry<MapData, Boolean> readMapData(@NotNull String serverName, int mapId) {
|
||||
final Map.Entry<byte[], Boolean> readData = fetchMapData(serverName, mapId);
|
||||
private MapData readMapData(@NotNull String serverName, int mapId) {
|
||||
final byte[] readData = fetchMapData(serverName, mapId);
|
||||
if (readData == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -134,23 +134,23 @@ public interface BukkitMapHandler {
|
||||
|
||||
@Nullable
|
||||
@Blocking
|
||||
private Map.Entry<byte[], Boolean> fetchMapData(@NotNull String serverName, int mapId) {
|
||||
private byte[] fetchMapData(@NotNull String serverName, int mapId) {
|
||||
return fetchMapData(serverName, mapId, true);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Blocking
|
||||
private Map.Entry<byte[], Boolean> fetchMapData(@NotNull String serverName, int mapId, boolean doReverseLookup) {
|
||||
private byte[] fetchMapData(@NotNull String serverName, int mapId, boolean doReverseLookup) {
|
||||
// Read from Redis cache
|
||||
final byte[] redisData = getRedisManager().getMapData(serverName, mapId);
|
||||
if (redisData != null) {
|
||||
return new AbstractMap.SimpleImmutableEntry<>(redisData, true);
|
||||
return redisData;
|
||||
}
|
||||
|
||||
// Read from database and set to Redis
|
||||
@Nullable Map.Entry<byte[], Boolean> databaseData = getPlugin().getDatabase().getMapData(serverName, mapId);
|
||||
final byte[] databaseData = getPlugin().getDatabase().getMapData(serverName, mapId);
|
||||
if (databaseData != null) {
|
||||
getRedisManager().setMapData(serverName, mapId, databaseData.getKey());
|
||||
getRedisManager().setMapData(serverName, mapId, databaseData);
|
||||
return databaseData;
|
||||
}
|
||||
|
||||
@@ -162,7 +162,7 @@ public interface BukkitMapHandler {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Map.Entry<byte[], Boolean> fetchReversedMapData(@NotNull String serverName, int mapId) {
|
||||
private byte[] fetchReversedMapData(@NotNull String serverName, int mapId) {
|
||||
// Lookup binding from Redis cache, then fetch data if found
|
||||
Map.Entry<String, Integer> binding = getRedisManager().getReversedMapBound(serverName, mapId);
|
||||
if (binding != null) {
|
||||
@@ -179,13 +179,10 @@ public interface BukkitMapHandler {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Map.Entry<MapData, Boolean> deserializeMapData(@NotNull Map.Entry<byte[], Boolean> data) {
|
||||
private MapData deserializeMapData(byte @NotNull [] data) {
|
||||
try {
|
||||
return new AbstractMap.SimpleImmutableEntry<>(
|
||||
getPlugin().getDataAdapter().fromBytes(data.getKey(), AdaptableMapData.class)
|
||||
.getData(getPlugin().getDataVersion(getPlugin().getMinecraftVersion())),
|
||||
data.getValue()
|
||||
);
|
||||
return getPlugin().getDataAdapter().fromBytes(data, AdaptableMapData.class)
|
||||
.getData(getPlugin().getDataVersion(getPlugin().getMinecraftVersion()));
|
||||
} catch (IOException e) {
|
||||
getPlugin().log(Level.WARNING, "Failed to deserialize map data", e);
|
||||
return null;
|
||||
@@ -297,7 +294,7 @@ public interface BukkitMapHandler {
|
||||
}
|
||||
|
||||
getPlugin().debug("Deserializing map data from NBT and generating view...");
|
||||
Map.Entry<MapData, Boolean> mapData = readMapData(originServer, originalId);
|
||||
MapData mapData = readMapData(originServer, originalId);
|
||||
if (mapData == null && nbt.hasTag(MAP_LEGACY_PIXEL_DATA_KEY)) {
|
||||
mapData = readLegacyMapItemData(nbt);
|
||||
}
|
||||
@@ -308,14 +305,14 @@ public interface BukkitMapHandler {
|
||||
}
|
||||
|
||||
MapView newView = view != null ? view : Bukkit.createMap(getDefaultMapWorld());
|
||||
generateRenderedMap(Objects.requireNonNull(mapData).getKey(), newView);
|
||||
generateRenderedMap(mapData, 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);
|
||||
MapData mapData = readMapData(originServer, originalId);
|
||||
if (mapData == null && nbt.hasTag(MAP_LEGACY_PIXEL_DATA_KEY)) {
|
||||
mapData = readLegacyMapItemData(nbt);
|
||||
}
|
||||
@@ -325,7 +322,7 @@ public interface BukkitMapHandler {
|
||||
return;
|
||||
}
|
||||
|
||||
final MapView view = generateRenderedMap(Objects.requireNonNull(mapData, "Pixel data null!").getKey());
|
||||
final MapView view = generateRenderedMap(Objects.requireNonNull(mapData, "Pixel data null!"));
|
||||
meta.setMapView(view);
|
||||
|
||||
final int id = view.getId();
|
||||
@@ -345,13 +342,13 @@ public interface BukkitMapHandler {
|
||||
view.getRenderers().clear();
|
||||
view.getRenderers().addAll(optionalView.get().getRenderers());
|
||||
view.setLocked(true);
|
||||
view.setScale(MapView.Scale.NORMAL);
|
||||
view.setScale(MapView.Scale.CLOSEST);
|
||||
view.setTrackingPosition(false);
|
||||
view.setUnlimitedTracking(false);
|
||||
return;
|
||||
}
|
||||
|
||||
Map.Entry<MapData, Boolean> data = readMapData(getPlugin().getServerName(), view.getId());
|
||||
MapData data = readMapData(getPlugin().getServerName(), view.getId());
|
||||
if (data == null) {
|
||||
data = readLegacyMapFileData(view.getId());
|
||||
}
|
||||
@@ -362,10 +359,7 @@ public interface BukkitMapHandler {
|
||||
.formatted(world.getName(), view.getId()));
|
||||
return;
|
||||
}
|
||||
if (data.getValue()) {
|
||||
return;
|
||||
}
|
||||
renderMapView(view, data.getKey());
|
||||
renderMapView(view, data);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -383,7 +377,7 @@ public interface BukkitMapHandler {
|
||||
view.getRenderers().clear();
|
||||
view.addRenderer(new PersistentMapRenderer(canvasData));
|
||||
view.setLocked(true);
|
||||
view.setScale(MapView.Scale.NORMAL);
|
||||
view.setScale(MapView.Scale.CLOSEST);
|
||||
view.setTrackingPosition(false);
|
||||
view.setUnlimitedTracking(false);
|
||||
setMapView(view);
|
||||
@@ -471,11 +465,11 @@ public interface BukkitMapHandler {
|
||||
// Legacy - read maps from item stacks
|
||||
@Nullable
|
||||
@Blocking
|
||||
private Map.Entry<MapData, Boolean> readLegacyMapItemData(@NotNull ReadableItemNBT nbt) {
|
||||
private MapData readLegacyMapItemData(@NotNull ReadableItemNBT nbt) {
|
||||
final int dataVer = getPlugin().getDataVersion(getPlugin().getMinecraftVersion());
|
||||
try {
|
||||
return new AbstractMap.SimpleImmutableEntry<>(MapData.fromByteArray(dataVer,
|
||||
Objects.requireNonNull(nbt.getByteArray(MAP_LEGACY_PIXEL_DATA_KEY))), false);
|
||||
return MapData.fromByteArray(dataVer,
|
||||
Objects.requireNonNull(nbt.getByteArray(MAP_LEGACY_PIXEL_DATA_KEY)));
|
||||
} catch (IOException e) {
|
||||
getPlugin().log(Level.WARNING, "Failed to read legacy map data", e);
|
||||
return null;
|
||||
@@ -484,14 +478,14 @@ public interface BukkitMapHandler {
|
||||
|
||||
// Legacy - read maps from files
|
||||
@Nullable
|
||||
private Map.Entry<MapData, Boolean> readLegacyMapFileData(int mapId) {
|
||||
private MapData readLegacyMapFileData(int mapId) {
|
||||
final Path path = getPlugin().getDataFolder().toPath().resolve("maps").resolve(mapId + ".dat");
|
||||
final File file = path.toFile();
|
||||
if (!file.exists()) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return new AbstractMap.SimpleImmutableEntry<>(MapData.fromNbt(file), false);
|
||||
return MapData.fromNbt(file);
|
||||
} catch (IOException e) {
|
||||
getPlugin().log(Level.WARNING, "Failed to read legacy map file", e);
|
||||
return null;
|
||||
@@ -597,11 +591,7 @@ public interface BukkitMapHandler {
|
||||
final List<MapBanner> banners = Lists.newArrayList();
|
||||
for (int i = 0; i < getCursors().size(); i++) {
|
||||
final MapCursor cursor = getCursors().getCursor(i);
|
||||
//#if MC==12001
|
||||
//$$ final String type = cursor.getType().name().toLowerCase(Locale.ENGLISH);
|
||||
//#else
|
||||
final String type = cursor.getType().getKey().getKey();
|
||||
//#endif
|
||||
if (type.startsWith(BANNER_PREFIX)) {
|
||||
banners.add(new MapBanner(
|
||||
type.replaceAll(BANNER_PREFIX, ""),
|
||||
@@ -613,7 +603,7 @@ public interface BukkitMapHandler {
|
||||
}
|
||||
|
||||
}
|
||||
return MapData.fromPixels(mapDataVersion, pixels, getDimension(), (byte) 2, banners, List.of());
|
||||
return MapData.fromPixels(mapDataVersion, pixels, getDimension(), (byte) 0, banners, List.of());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -51,11 +51,7 @@ public final class BukkitKeyedAdapter {
|
||||
|
||||
@Nullable
|
||||
public static PotionEffectType matchEffectType(@NotNull String key) {
|
||||
//#if MC==12001
|
||||
//$$ return PotionEffectType.getByName(key);
|
||||
//#else
|
||||
return getRegistryValue(Registry.EFFECT, key);
|
||||
//#endif
|
||||
}
|
||||
|
||||
private static <T extends Keyed> T getRegistryValue(@NotNull Registry<T> registry, @NotNull String keyString) {
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
# File used for checking Minecraft server compatibility with this version of HuskSync
|
||||
minecraft_version: '${minecraft_version}'
|
||||
minecraft_version_range: '${minecraft_version_range}'
|
||||
@@ -3,30 +3,30 @@ plugins {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api 'commons-io:commons-io:2.19.0'
|
||||
api 'org.apache.commons:commons-text:1.13.1'
|
||||
api 'commons-io:commons-io:2.21.0'
|
||||
api 'org.apache.commons:commons-text:1.14.0'
|
||||
api 'net.william278:minedown:1.8.2'
|
||||
api 'net.william278:mapdataapi:2.0'
|
||||
api 'org.json:json:20250517'
|
||||
api 'com.google.code.gson:gson:2.13.1'
|
||||
api 'com.google.code.gson:gson:2.13.2'
|
||||
api 'com.fatboyindustrial.gson-javatime-serialisers:gson-javatime-serialisers:1.1.2'
|
||||
api 'de.exlll:configlib-yaml:4.6.1'
|
||||
api 'de.exlll:configlib-yaml:4.6.4'
|
||||
api 'net.william278:paginedown:1.1.2'
|
||||
api 'net.william278:DesertWell:2.0.4'
|
||||
api('com.zaxxer:HikariCP:6.3.0') {
|
||||
api('com.zaxxer:HikariCP:7.0.2') {
|
||||
exclude module: 'slf4j-api'
|
||||
}
|
||||
|
||||
compileOnlyApi 'net.william278.toilet:toilet-common:1.0.15'
|
||||
compileOnlyApi 'net.william278.toilet:toilet-common:1.0.16'
|
||||
|
||||
compileOnly 'net.william278.uniform:uniform-common:1.3.8'
|
||||
compileOnly 'net.william278.uniform:uniform-common:1.3.9'
|
||||
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.23.0'
|
||||
compileOnly 'org.projectlombok:lombok:1.18.42'
|
||||
compileOnly 'org.jetbrains:annotations:26.0.2-1'
|
||||
compileOnly 'net.kyori:adventure-api:4.25.0'
|
||||
compileOnly 'net.kyori:adventure-platform-api:4.4.0'
|
||||
compileOnly "net.kyori:adventure-text-serializer-plain:4.23.0"
|
||||
compileOnly 'com.google.guava:guava:33.4.8-jre'
|
||||
compileOnly "net.kyori:adventure-text-serializer-plain:4.25.0"
|
||||
compileOnly 'com.google.guava:guava:33.5.0-jre'
|
||||
compileOnly 'com.github.plan-player-analytics:Plan:5.6.2965'
|
||||
compileOnly "redis.clients:jedis:$jedis_version"
|
||||
compileOnly "com.mysql:mysql-connector-j:$mysql_driver_version"
|
||||
@@ -37,10 +37,10 @@ dependencies {
|
||||
|
||||
testImplementation "redis.clients:jedis:$jedis_version"
|
||||
testImplementation "org.xerial.snappy:snappy-java:$snappy_version"
|
||||
testImplementation 'com.google.guava:guava:33.4.8-jre'
|
||||
testImplementation 'com.google.guava:guava:33.5.0-jre'
|
||||
testImplementation 'com.github.plan-player-analytics:Plan:5.6.2965'
|
||||
testCompileOnly 'de.exlll:configlib-yaml:4.6.1'
|
||||
testCompileOnly 'org.jetbrains:annotations:26.0.2'
|
||||
testCompileOnly 'de.exlll:configlib-yaml:4.6.4'
|
||||
testCompileOnly 'org.jetbrains:annotations:26.0.2-1'
|
||||
|
||||
annotationProcessor 'org.projectlombok:lombok:1.18.38'
|
||||
annotationProcessor 'org.projectlombok:lombok:1.18.42'
|
||||
}
|
||||
@@ -41,10 +41,7 @@ import net.william278.husksync.redis.RedisManager;
|
||||
import net.william278.husksync.sync.DataSyncer;
|
||||
import net.william278.husksync.user.ConsoleUser;
|
||||
import net.william278.husksync.user.OnlineUser;
|
||||
import net.william278.husksync.util.CompatibilityChecker;
|
||||
import net.william278.husksync.util.DumpProvider;
|
||||
import net.william278.husksync.util.LegacyConverter;
|
||||
import net.william278.husksync.util.Task;
|
||||
import net.william278.husksync.util.*;
|
||||
import net.william278.uniform.Uniform;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -57,7 +54,7 @@ import java.util.logging.Level;
|
||||
* Abstract implementation of the HuskSync plugin.
|
||||
*/
|
||||
public interface HuskSync extends Task.Supplier, EventDispatcher, ConfigProvider, SerializerRegistry,
|
||||
CompatibilityChecker, DumpProvider {
|
||||
CompatibilityChecker, DumpProvider, DataVersionSupplier {
|
||||
|
||||
int SPIGOT_RESOURCE_ID = 97144;
|
||||
|
||||
@@ -252,14 +249,6 @@ public interface HuskSync extends Task.Supplier, EventDispatcher, ConfigProvider
|
||||
@NotNull
|
||||
Version getMinecraftVersion();
|
||||
|
||||
/**
|
||||
* Returns the data version for a Minecraft version
|
||||
*
|
||||
* @param minecraftVersion the Minecraft version
|
||||
* @return the data version int
|
||||
*/
|
||||
int getDataVersion(@NotNull Version minecraftVersion);
|
||||
|
||||
/**
|
||||
* Returns the platform type
|
||||
*
|
||||
|
||||
@@ -22,13 +22,11 @@ package net.william278.husksync.config;
|
||||
import de.exlll.configlib.Configuration;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
@Getter
|
||||
@Configuration
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@@ -66,5 +64,9 @@ public class Server {
|
||||
}
|
||||
return super.equals(other);
|
||||
}
|
||||
|
||||
|
||||
public String getName() {
|
||||
final String envServerName = System.getenv("HUSKSYNC_SERVER_NAME");
|
||||
return envServerName == null ? name : envServerName;
|
||||
}
|
||||
}
|
||||
@@ -174,7 +174,45 @@ public class Settings {
|
||||
private int database = 0;
|
||||
private String user = "";
|
||||
private String password = "";
|
||||
|
||||
@Comment("Use SSL/TLS for encrypted connections.")
|
||||
private boolean useSsl = false;
|
||||
|
||||
@Comment("Connection timeout in milliseconds.")
|
||||
private int connectionTimeout = 2000;
|
||||
|
||||
@Comment("Socket (read/write) timeout in milliseconds.")
|
||||
private int socketTimeout = 2000;
|
||||
|
||||
@Comment("Max number of connections in the pool.")
|
||||
private int maxTotalConnections = 50;
|
||||
|
||||
@Comment("Max number of idle connections in the pool.")
|
||||
private int maxIdleConnections = 8;
|
||||
|
||||
@Comment("Min number of idle connections in the pool.")
|
||||
private int minIdleConnections = 2;
|
||||
|
||||
@Comment("Enable health checks when borrowing connections from the pool.")
|
||||
private boolean testOnBorrow = true;
|
||||
|
||||
@Comment("Enable health checks when returning connections to the pool.")
|
||||
private boolean testOnReturn = true;
|
||||
|
||||
@Comment("Enable periodic idle connection health checks.")
|
||||
private boolean testWhileIdle = true;
|
||||
|
||||
@Comment("Min evictable idle time (ms) before a connection is eligible for eviction.")
|
||||
private long minEvictableIdleTimeMillis = 60000;
|
||||
|
||||
@Comment("Time (ms) between eviction runs.")
|
||||
private long timeBetweenEvictionRunsMillis = 30000;
|
||||
|
||||
@Comment("Number of retries for commands when connection fails.")
|
||||
private int maxRetries = 3;
|
||||
|
||||
@Comment("Base backoff time in ms for retries (exponential backoff multiplier).")
|
||||
private int retryBackoffMillis = 200;
|
||||
}
|
||||
|
||||
@Comment("Options for if you're using Redis sentinel. Don't modify this unless you know what you're doing!")
|
||||
@@ -327,7 +365,7 @@ public class Settings {
|
||||
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;
|
||||
private boolean checkinPetitions = false;
|
||||
|
||||
public boolean doAutoPin(@NotNull DataSnapshot.SaveCause cause) {
|
||||
return autoPinnedSaveCauses.contains(cause.name());
|
||||
|
||||
@@ -274,17 +274,17 @@ public abstract class Database {
|
||||
*
|
||||
* @param serverName Name of the server the map originates from
|
||||
* @param mapId Original map ID
|
||||
* @return Map.Entry (key: map data, value: is from current world)
|
||||
* @return the map data bytes, or null if not found
|
||||
*/
|
||||
@Blocking
|
||||
public abstract @Nullable Map.Entry<byte[], Boolean> getMapData(@NotNull String serverName, int mapId);
|
||||
public abstract byte @Nullable [] getMapData(@NotNull String serverName, int mapId);
|
||||
|
||||
/**
|
||||
* Get a map server -> ID binding in the database
|
||||
* Reverse lookup: given a local map binding, find the origin server and map ID.
|
||||
*
|
||||
* @param serverName Name of the server the map originates from
|
||||
* @param mapId Original map ID
|
||||
* @return Map.Entry (key: server name, value: map ID)
|
||||
* @param serverName Name of the local server (to_server_name in the binding)
|
||||
* @param mapId Local map ID on this server (to_id in the binding)
|
||||
* @return Map.Entry with origin server name (key) and origin map ID (value), or null if not found
|
||||
*/
|
||||
@Blocking
|
||||
public abstract @Nullable Map.Entry<String, Integer> getMapBinding(@NotNull String serverName, int mapId);
|
||||
|
||||
@@ -376,14 +376,14 @@ public class MongoDbDatabase extends Database {
|
||||
|
||||
@Blocking
|
||||
@Override
|
||||
public @Nullable Map.Entry<byte[], Boolean> getMapData(@NotNull String serverName, int mapId) {
|
||||
public byte @Nullable [] getMapData(@NotNull String serverName, int mapId) {
|
||||
try {
|
||||
Document filter = new Document("server_name", serverName).append("map_id", mapId);
|
||||
FindIterable<Document> iterable = mongoCollectionHelper.getCollection(mapDataTable).find(filter);
|
||||
Document doc = iterable.first();
|
||||
if (doc != null) {
|
||||
final Binary bin = doc.get("data", Binary.class);
|
||||
return Map.entry(bin.getData(), true);
|
||||
return bin.getData();
|
||||
}
|
||||
} catch (MongoException e) {
|
||||
plugin.log(Level.SEVERE, "Failed to get map data from the database", e);
|
||||
@@ -399,8 +399,8 @@ public class MongoDbDatabase extends Database {
|
||||
final Document doc = iterable.first();
|
||||
if (doc != null) {
|
||||
return new AbstractMap.SimpleImmutableEntry<>(
|
||||
doc.getString("server_name"),
|
||||
doc.getInteger("to_id")
|
||||
doc.getString("from_server_name"),
|
||||
doc.getInteger("from_id")
|
||||
);
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -473,7 +473,7 @@ public class MySqlDatabase extends Database {
|
||||
|
||||
@Blocking
|
||||
@Override
|
||||
public @Nullable Map.Entry<byte[], Boolean> getMapData(@NotNull String serverName, int mapId) {
|
||||
public byte @Nullable [] getMapData(@NotNull String serverName, int mapId) {
|
||||
try (Connection connection = getConnection()) {
|
||||
try (PreparedStatement statement = connection.prepareStatement(formatStatementTables("""
|
||||
SELECT `data`
|
||||
@@ -488,7 +488,7 @@ public class MySqlDatabase extends Database {
|
||||
final Blob blob = resultSet.getBlob("data");
|
||||
final byte[] dataByteArray = blob.getBytes(1, (int) blob.length());
|
||||
blob.free();
|
||||
return Map.entry(dataByteArray, true);
|
||||
return dataByteArray;
|
||||
}
|
||||
}
|
||||
} catch (SQLException | DataAdapter.AdaptionException e) {
|
||||
|
||||
@@ -297,10 +297,10 @@ public class PostgresDatabase extends Database {
|
||||
public int getUnpinnedSnapshotCount(@NotNull User user) {
|
||||
try (Connection connection = getConnection()) {
|
||||
try (PreparedStatement statement = connection.prepareStatement(formatStatementTables("""
|
||||
SELECT COUNT(`version_uuid`)
|
||||
FROM `%user_data_table%`
|
||||
WHERE `player_uuid`=? AND `pinned`=false;"""))) {
|
||||
statement.setString(1, user.getUuid().toString());
|
||||
SELECT COUNT(version_uuid)
|
||||
FROM %user_data_table%
|
||||
WHERE player_uuid=? AND pinned=false;"""))) {
|
||||
statement.setObject(1, user.getUuid());
|
||||
final ResultSet resultSet = statement.executeQuery();
|
||||
if (resultSet.next()) {
|
||||
return resultSet.getInt(1);
|
||||
@@ -469,7 +469,7 @@ public class PostgresDatabase extends Database {
|
||||
|
||||
@Blocking
|
||||
@Override
|
||||
public @Nullable Map.Entry<byte[], Boolean> getMapData(@NotNull String serverName, int mapId) {
|
||||
public byte @Nullable [] getMapData(@NotNull String serverName, int mapId) {
|
||||
try (Connection connection = getConnection()) {
|
||||
try (PreparedStatement statement = connection.prepareStatement(formatStatementTables("""
|
||||
SELECT data
|
||||
@@ -480,8 +480,7 @@ public class PostgresDatabase extends Database {
|
||||
statement.setInt(2, mapId);
|
||||
final ResultSet resultSet = statement.executeQuery();
|
||||
if (resultSet.next()) {
|
||||
final byte[] data = resultSet.getBytes("data");
|
||||
return new AbstractMap.SimpleImmutableEntry<>(data, true);
|
||||
return resultSet.getBytes("data");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -62,9 +62,11 @@ public class RedisManager extends JedisPubSub {
|
||||
/**
|
||||
* Initialize Redis connection pool
|
||||
*/
|
||||
|
||||
@Blocking
|
||||
public void initialize() throws IllegalStateException {
|
||||
final Settings.RedisSettings.RedisCredentials credentials = plugin.getSettings().getRedis().getCredentials();
|
||||
|
||||
final String user = credentials.getUser();
|
||||
final String password = credentials.getPassword();
|
||||
final String host = credentials.getHost();
|
||||
@@ -72,44 +74,50 @@ public class RedisManager extends JedisPubSub {
|
||||
final int database = credentials.getDatabase();
|
||||
final boolean useSSL = credentials.isUseSsl();
|
||||
|
||||
// Create the jedis pool
|
||||
// Configure JedisPoolConfig
|
||||
final JedisPoolConfig config = new JedisPoolConfig();
|
||||
config.setMaxIdle(0);
|
||||
config.setTestOnBorrow(true);
|
||||
config.setTestOnReturn(true);
|
||||
config.setMaxTotal(credentials.getMaxTotalConnections());
|
||||
config.setMaxIdle(credentials.getMaxIdleConnections());
|
||||
config.setMinIdle(credentials.getMinIdleConnections());
|
||||
config.setTestOnBorrow(credentials.isTestOnBorrow());
|
||||
config.setTestOnReturn(credentials.isTestOnReturn());
|
||||
config.setTestWhileIdle(credentials.isTestWhileIdle());
|
||||
config.setMinEvictableIdleTimeMillis(credentials.getMinEvictableIdleTimeMillis());
|
||||
config.setTimeBetweenEvictionRunsMillis(credentials.getTimeBetweenEvictionRunsMillis());
|
||||
|
||||
final Settings.RedisSettings.RedisSentinel sentinel = plugin.getSettings().getRedis().getSentinel();
|
||||
Set<String> redisSentinelNodes = new HashSet<>(sentinel.getNodes());
|
||||
|
||||
if (redisSentinelNodes.isEmpty()) {
|
||||
// Standalone Redis setup
|
||||
DefaultJedisClientConfig.Builder clientConfigBuilder = DefaultJedisClientConfig.builder()
|
||||
.ssl(useSSL)
|
||||
.database(database)
|
||||
.timeoutMillis(0);
|
||||
|
||||
if (!user.isEmpty()) {
|
||||
clientConfigBuilder.user(user);
|
||||
}
|
||||
|
||||
if (!password.isEmpty()) {
|
||||
clientConfigBuilder.password(password);
|
||||
}
|
||||
.timeoutMillis(credentials.getConnectionTimeout()) // connection and socket timeout combined
|
||||
.user(user.isEmpty() ? null : user)
|
||||
.password(password.isEmpty() ? null : password);
|
||||
|
||||
this.jedisPool = new JedisPool(config, new HostAndPort(host, port), clientConfigBuilder.build());
|
||||
} else {
|
||||
final String sentinelPassword = sentinel.getPassword();
|
||||
this.jedisPool = new JedisSentinelPool(sentinel.getMaster(), redisSentinelNodes, password.isEmpty()
|
||||
? null : password, sentinelPassword.isEmpty() ? null : sentinelPassword);
|
||||
this.jedisPool = new JedisSentinelPool(
|
||||
sentinel.getMaster(),
|
||||
redisSentinelNodes,
|
||||
config,
|
||||
credentials.getConnectionTimeout(),
|
||||
credentials.getSocketTimeout(),
|
||||
password.isEmpty() ? null : password,
|
||||
sentinelPassword.isEmpty() ? null : sentinelPassword,
|
||||
database);
|
||||
}
|
||||
|
||||
// Ping the server to check the connection
|
||||
try {
|
||||
jedisPool.getResource().ping();
|
||||
try (var jedis = jedisPool.getResource()) {
|
||||
jedis.ping();
|
||||
} catch (JedisException e) {
|
||||
throw new IllegalStateException("Failed to establish connection with Redis. "
|
||||
+ "Please check the supplied credentials in the config file", e);
|
||||
throw new IllegalStateException("Failed to establish connection with Redis. " +
|
||||
"Please check the supplied credentials in the config file", e);
|
||||
}
|
||||
|
||||
// Subscribe using a thread (rather than a task)
|
||||
enabled = true;
|
||||
new Thread(this::subscribe, "husksync:redis_subscriber").start();
|
||||
}
|
||||
@@ -126,8 +134,7 @@ public class RedisManager extends JedisPubSub {
|
||||
this,
|
||||
Arrays.stream(RedisMessage.Type.values())
|
||||
.map(type -> type.getMessageChannel(clusterId))
|
||||
.toArray(String[]::new)
|
||||
);
|
||||
.toArray(String[]::new));
|
||||
} catch (Throwable t) {
|
||||
// Thread was unlocked due error
|
||||
onThreadUnlock(t);
|
||||
@@ -175,20 +182,19 @@ public class RedisManager extends JedisPubSub {
|
||||
user -> {
|
||||
plugin.lockPlayer(user.getUuid());
|
||||
try {
|
||||
final DataSnapshot.Packed data = DataSnapshot.deserialize(plugin, redisMessage.getPayload());
|
||||
final DataSnapshot.Packed data = DataSnapshot.deserialize(plugin,
|
||||
redisMessage.getPayload());
|
||||
user.applySnapshot(data, DataSnapshot.UpdateCause.UPDATED);
|
||||
} catch (Throwable e) {
|
||||
plugin.log(Level.SEVERE, "An exception occurred updating user data from Redis", e);
|
||||
user.completeSync(false, DataSnapshot.UpdateCause.UPDATED, plugin);
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
case REQUEST_USER_DATA -> redisMessage.getTargetUser(plugin).ifPresent(
|
||||
user -> RedisMessage.create(
|
||||
UUID.fromString(new String(redisMessage.getPayload(), StandardCharsets.UTF_8)),
|
||||
user.createSnapshot(DataSnapshot.SaveCause.INVENTORY_COMMAND).asBytes(plugin)
|
||||
).dispatch(plugin, RedisMessage.Type.RETURN_USER_DATA)
|
||||
);
|
||||
user.createSnapshot(DataSnapshot.SaveCause.INVENTORY_COMMAND).asBytes(plugin))
|
||||
.dispatch(plugin, RedisMessage.Type.RETURN_USER_DATA));
|
||||
case CHECK_IN_PETITION -> {
|
||||
if (!redisMessage.isTargetServer(plugin)
|
||||
|| !plugin.getSettings().getSynchronization().isCheckinPetitions()) {
|
||||
@@ -196,14 +202,19 @@ public class RedisManager extends JedisPubSub {
|
||||
}
|
||||
final String payload = new String(redisMessage.getPayload(), StandardCharsets.UTF_8);
|
||||
final User user = new User(UUID.fromString(payload.split("/")[0]), payload.split("/")[1]);
|
||||
boolean online = plugin.getDisconnectingPlayers().contains(user.getUuid())
|
||||
|| plugin.getOnlineUser(user.getUuid()).isEmpty();
|
||||
if (!online && !plugin.isLocked(user.getUuid())) {
|
||||
plugin.debug("[%s] Received check-in petition for online/unlocked user, ignoring".formatted(user.getName()));
|
||||
|
||||
// Only release checkout if user is truly offline AND not being processed
|
||||
final boolean isOnline = plugin.getOnlineUser(user.getUuid()).isPresent();
|
||||
final boolean isLocked = plugin.isLocked(user.getUuid());
|
||||
|
||||
if (isOnline || isLocked) {
|
||||
plugin.debug("[%s] Petition ignored - user still being processed (online=%s, locked=%s)"
|
||||
.formatted(user.getName(), isOnline, isLocked));
|
||||
return;
|
||||
}
|
||||
|
||||
plugin.getRedisManager().setUserCheckedOut(user, false);
|
||||
plugin.debug("[%s] Received petition for offline user, checking them in".formatted(user.getName()));
|
||||
plugin.debug("[%s] Petition accepted - user checked in".formatted(user.getName()));
|
||||
}
|
||||
case RETURN_USER_DATA -> {
|
||||
final UUID target = redisMessage.getTargetUuid().orElse(null);
|
||||
@@ -252,31 +263,30 @@ public class RedisManager extends JedisPubSub {
|
||||
redisMessage.dispatch(plugin, RedisMessage.Type.CHECK_IN_PETITION);
|
||||
}
|
||||
|
||||
public CompletableFuture<Optional<DataSnapshot.Packed>> getOnlineUserData(@NotNull UUID requestId, @NotNull User user,
|
||||
@NotNull DataSnapshot.SaveCause saveCause) {
|
||||
public CompletableFuture<Optional<DataSnapshot.Packed>> getOnlineUserData(@NotNull UUID requestId,
|
||||
@NotNull User user,
|
||||
@NotNull DataSnapshot.SaveCause saveCause) {
|
||||
return plugin.getOnlineUser(user.getUuid())
|
||||
.map(online -> CompletableFuture.completedFuture(
|
||||
Optional.of(online.createSnapshot(saveCause)))
|
||||
)
|
||||
Optional.of(online.createSnapshot(saveCause))))
|
||||
.orElse(this.getNetworkedUserData(requestId, user));
|
||||
}
|
||||
|
||||
// Request a user's dat x-server
|
||||
private CompletableFuture<Optional<DataSnapshot.Packed>> getNetworkedUserData(@NotNull UUID requestId, @NotNull User user) {
|
||||
private CompletableFuture<Optional<DataSnapshot.Packed>> getNetworkedUserData(@NotNull UUID requestId,
|
||||
@NotNull User user) {
|
||||
final CompletableFuture<Optional<DataSnapshot.Packed>> future = new CompletableFuture<>();
|
||||
pendingRequests.put(requestId, future);
|
||||
plugin.runAsync(() -> {
|
||||
final RedisMessage redisMessage = RedisMessage.create(
|
||||
user.getUuid(),
|
||||
requestId.toString().getBytes(StandardCharsets.UTF_8)
|
||||
);
|
||||
requestId.toString().getBytes(StandardCharsets.UTF_8));
|
||||
redisMessage.dispatch(plugin, RedisMessage.Type.REQUEST_USER_DATA);
|
||||
});
|
||||
return future
|
||||
.orTimeout(
|
||||
plugin.getSettings().getSynchronization().getNetworkLatencyMilliseconds(),
|
||||
TimeUnit.MILLISECONDS
|
||||
)
|
||||
TimeUnit.MILLISECONDS)
|
||||
.exceptionally(throwable -> {
|
||||
pendingRequests.remove(requestId);
|
||||
return Optional.empty();
|
||||
@@ -290,8 +300,7 @@ public class RedisManager extends JedisPubSub {
|
||||
jedis.setex(
|
||||
getKey(RedisKeyType.LATEST_SNAPSHOT, user.getUuid(), clusterId),
|
||||
RedisKeyType.TTL_1_YEAR,
|
||||
data.asBytes(plugin)
|
||||
);
|
||||
data.asBytes(plugin));
|
||||
plugin.debug(String.format("[%s] Set %s key on Redis", user.getName(), RedisKeyType.LATEST_SNAPSHOT));
|
||||
} catch (Throwable e) {
|
||||
plugin.log(Level.SEVERE, "An exception occurred setting user data on Redis", e);
|
||||
@@ -302,8 +311,7 @@ public class RedisManager extends JedisPubSub {
|
||||
public void clearUserData(@NotNull User user) {
|
||||
try (Jedis jedis = jedisPool.getResource()) {
|
||||
jedis.del(
|
||||
getKey(RedisKeyType.LATEST_SNAPSHOT, user.getUuid(), clusterId)
|
||||
);
|
||||
getKey(RedisKeyType.LATEST_SNAPSHOT, user.getUuid(), clusterId));
|
||||
plugin.debug(String.format("[%s] Cleared %s on Redis", user.getName(), RedisKeyType.LATEST_SNAPSHOT));
|
||||
} catch (Throwable e) {
|
||||
plugin.log(Level.SEVERE, "An exception occurred clearing user data on Redis", e);
|
||||
@@ -317,8 +325,7 @@ public class RedisManager extends JedisPubSub {
|
||||
if (checkedOut) {
|
||||
jedis.set(
|
||||
key.getBytes(StandardCharsets.UTF_8),
|
||||
plugin.getServerName().getBytes(StandardCharsets.UTF_8)
|
||||
);
|
||||
plugin.getServerName().getBytes(StandardCharsets.UTF_8));
|
||||
} else {
|
||||
if (jedis.del(key.getBytes(StandardCharsets.UTF_8)) == 0) {
|
||||
plugin.debug(String.format("[%s] %s key not set on Redis when attempting removal (%s)",
|
||||
@@ -382,8 +389,7 @@ public class RedisManager extends JedisPubSub {
|
||||
jedis.setex(
|
||||
getKey(RedisKeyType.SERVER_SWITCH, user.getUuid(), clusterId),
|
||||
RedisKeyType.TTL_10_SECONDS,
|
||||
new byte[0]
|
||||
);
|
||||
new byte[0]);
|
||||
plugin.debug(String.format("[%s] Set %s key to Redis",
|
||||
user.getName(), RedisKeyType.SERVER_SWITCH));
|
||||
} catch (Throwable e) {
|
||||
@@ -395,7 +401,8 @@ public class RedisManager extends JedisPubSub {
|
||||
* Fetch a user's data from Redis and consume the key if found
|
||||
*
|
||||
* @param user The user to fetch data for
|
||||
* @return The user's data, if it's present on the database. Otherwise, an empty optional.
|
||||
* @return The user's data, if it's present on the database. Otherwise, an empty
|
||||
* optional.
|
||||
*/
|
||||
@Blocking
|
||||
public Optional<DataSnapshot.Packed> getUserData(@NotNull User user) {
|
||||
@@ -476,13 +483,11 @@ public class RedisManager extends JedisPubSub {
|
||||
jedis.setex(
|
||||
getMapIdKey(fromServer, fromId, toServer, clusterId),
|
||||
RedisKeyType.TTL_1_YEAR,
|
||||
String.valueOf(toId).getBytes(StandardCharsets.UTF_8)
|
||||
);
|
||||
String.valueOf(toId).getBytes(StandardCharsets.UTF_8));
|
||||
jedis.setex(
|
||||
getReversedMapIdKey(toServer, toId, clusterId),
|
||||
RedisKeyType.TTL_1_YEAR,
|
||||
String.format("%s:%s", fromServer, fromId).getBytes(StandardCharsets.UTF_8)
|
||||
);
|
||||
String.format("%s:%s", fromServer, fromId).getBytes(StandardCharsets.UTF_8));
|
||||
plugin.debug(String.format("Bound map %s:%s -> %s:%s on Redis", fromServer, fromId, toServer, toId));
|
||||
} catch (Throwable e) {
|
||||
plugin.log(Level.SEVERE, "An exception occurred binding map ids on Redis", e);
|
||||
@@ -534,8 +539,7 @@ public class RedisManager extends JedisPubSub {
|
||||
jedis.setex(
|
||||
getMapDataKey(serverName, mapId, clusterId),
|
||||
RedisKeyType.TTL_1_YEAR,
|
||||
data
|
||||
);
|
||||
data);
|
||||
plugin.debug(String.format("Set map data %s:%s on Redis", serverName, mapId));
|
||||
} catch (Throwable e) {
|
||||
plugin.log(Level.SEVERE, "An exception occurred setting map data on Redis", e);
|
||||
@@ -581,16 +585,20 @@ public class RedisManager extends JedisPubSub {
|
||||
return String.format("%s:%s", keyType.getKeyPrefix(clusterId), uuid);
|
||||
}
|
||||
|
||||
private static byte[] getMapIdKey(@NotNull String fromServer, int fromId, @NotNull String toServer, @NotNull String clusterId) {
|
||||
return String.format("%s:%s:%s:%s", RedisKeyType.MAP_ID.getKeyPrefix(clusterId), fromServer, fromId, toServer).getBytes(StandardCharsets.UTF_8);
|
||||
private static byte[] getMapIdKey(@NotNull String fromServer, int fromId, @NotNull String toServer,
|
||||
@NotNull String clusterId) {
|
||||
return String.format("%s:%s:%s:%s", RedisKeyType.MAP_ID.getKeyPrefix(clusterId), fromServer, fromId, toServer)
|
||||
.getBytes(StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
private static byte[] getReversedMapIdKey(@NotNull String toServer, int toId, @NotNull String clusterId) {
|
||||
return String.format("%s:%s:%s", RedisKeyType.MAP_ID_REVERSED.getKeyPrefix(clusterId), toServer, toId).getBytes(StandardCharsets.UTF_8);
|
||||
return String.format("%s:%s:%s", RedisKeyType.MAP_ID_REVERSED.getKeyPrefix(clusterId), toServer, toId)
|
||||
.getBytes(StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
private static byte[] getMapDataKey(@NotNull String serverName, int mapId, @NotNull String clusterId) {
|
||||
return String.format("%s:%s:%s", RedisKeyType.MAP_DATA.getKeyPrefix(clusterId), serverName, mapId).getBytes(StandardCharsets.UTF_8);
|
||||
return String.format("%s:%s:%s", RedisKeyType.MAP_DATA.getKeyPrefix(clusterId), serverName, mapId)
|
||||
.getBytes(StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -22,12 +22,13 @@ package net.william278.husksync.util;
|
||||
import de.exlll.configlib.Configuration;
|
||||
import de.exlll.configlib.YamlConfigurationProperties;
|
||||
import de.exlll.configlib.YamlConfigurationStore;
|
||||
import lombok.AllArgsConstructor;
|
||||
import net.william278.desertwell.util.Version;
|
||||
import net.william278.husksync.HuskSync;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Objects;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import static net.william278.husksync.config.ConfigProvider.YAML_CONFIGURATION_PROPERTIES;
|
||||
@@ -38,23 +39,22 @@ public interface CompatibilityChecker {
|
||||
|
||||
default void checkCompatibility() throws HuskSync.FailedToLoadException {
|
||||
final YamlConfigurationProperties p = YAML_CONFIGURATION_PROPERTIES.build();
|
||||
final Version compatible;
|
||||
final CompatibilityConfig compat;
|
||||
|
||||
// Load compatibility file
|
||||
try (InputStream input = getResource(COMPATIBILITY_FILE)) {
|
||||
final CompatibilityConfig compat = new YamlConfigurationStore<>(CompatibilityConfig.class, p).read(input);
|
||||
compatible = Objects.requireNonNull(compat.getCompatibleWith());
|
||||
compat = new YamlConfigurationStore<>(CompatibilityConfig.class, p).read(input);
|
||||
} catch (Throwable e) {
|
||||
getPlugin().log(Level.WARNING, "Failed to load compatibility config, skipping check.", e);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check compatibility
|
||||
if (compatible.compareTo(getPlugin().getMinecraftVersion()) != 0) {
|
||||
if (!compat.isCompatibleWith(getPlugin().getMinecraftVersion())) {
|
||||
throw new HuskSync.FailedToLoadException("""
|
||||
Incompatible Minecraft version. This version of HuskSync is designed for Minecraft %s.
|
||||
Please download the correct version of HuskSync for your server's Minecraft version (%s)."""
|
||||
.formatted(compatible.toString(), getPlugin().getMinecraftVersion().toString()));
|
||||
.formatted(compat.minecraftVersionRange(), getPlugin().getMinecraftVersion().toString()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,11 +64,38 @@ public interface CompatibilityChecker {
|
||||
HuskSync getPlugin();
|
||||
|
||||
@Configuration
|
||||
record CompatibilityConfig(@NotNull String minecraftVersion) {
|
||||
record CompatibilityConfig(@NotNull String minecraftVersionRange) {
|
||||
|
||||
@NotNull
|
||||
public Version getCompatibleWith() {
|
||||
return Version.fromString(minecraftVersion);
|
||||
@AllArgsConstructor
|
||||
enum ExpressionType {
|
||||
GTE(">=", (v, s) -> v.compareTo(Version.fromString(s.substring(2))) >= 0),
|
||||
LTE("<=", (v, s) -> v.compareTo(Version.fromString(s.substring(2))) <= 0),
|
||||
GT(">", (v, s) -> v.compareTo(Version.fromString(s.substring(1))) > 0),
|
||||
LT("<", (v, s) -> v.compareTo(Version.fromString(s.substring(1))) < 0),
|
||||
NOT("!", (v, s) -> v.compareTo(Version.fromString(s.substring(1))) != 0),
|
||||
E("=", (v, s) -> v.compareTo(Version.fromString(s.substring(1))) == 0);
|
||||
|
||||
private final String match;
|
||||
private final BiFunction<Version, String, Boolean> function;
|
||||
|
||||
private static boolean check(@NotNull String versionRange, @NotNull Version mcVer) {
|
||||
boolean passes = true;
|
||||
versions:
|
||||
for (String exp : versionRange.split(" ")) {
|
||||
for (ExpressionType type : values()) {
|
||||
if (exp.trim().startsWith(type.match)) {
|
||||
passes = passes && type.function.apply(mcVer, exp.trim());
|
||||
continue versions;
|
||||
}
|
||||
}
|
||||
passes = passes && mcVer.compareTo(Version.fromString(exp.trim())) == 0;
|
||||
}
|
||||
return passes;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isCompatibleWith(@NotNull Version version) {
|
||||
return ExpressionType.check(minecraftVersionRange, version);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* This file is part of HuskSync, licensed under the Apache License 2.0.
|
||||
*
|
||||
* Copyright (c) William278 <will27528@gmail.com>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.william278.husksync.util;
|
||||
|
||||
import net.william278.desertwell.util.Version;
|
||||
import net.william278.husksync.HuskSync;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public interface DataVersionSupplier {
|
||||
|
||||
int VERSION1_16_5 = 2586;
|
||||
int VERSION1_17_1 = 2730;
|
||||
int VERSION1_18_2 = 2975;
|
||||
int VERSION1_19_2 = 3120;
|
||||
int VERSION1_19_4 = 3337;
|
||||
int VERSION1_20_1 = 3465;
|
||||
int VERSION1_20_2 = 3578;
|
||||
int VERSION1_20_4 = 3700;
|
||||
int VERSION1_20_5 = 3837;
|
||||
int VERSION1_21_1 = 3955;
|
||||
int VERSION1_21_3 = 4082;
|
||||
int VERSION1_21_4 = 4189;
|
||||
int VERSION1_21_5 = 4323;
|
||||
int VERSION1_21_6 = 4435;
|
||||
int VERSION1_21_7 = 4438;
|
||||
int VERSION1_21_8 = 4438;
|
||||
int VERSION1_21_9 = 4554;
|
||||
int VERSION1_21_10 = 4556;
|
||||
int VERSION1_21_11 = 4671;
|
||||
|
||||
/**
|
||||
* Returns the data version for a Minecraft version
|
||||
*
|
||||
* @param mcVersion the Minecraft version
|
||||
* @return the data version int
|
||||
*/
|
||||
default int getDataVersion(@NotNull Version mcVersion) {
|
||||
return switch (mcVersion.toStringWithoutMetadata()) {
|
||||
case "1.16", "1.16.1", "1.16.2", "1.16.3", "1.16.4", "1.16.5" -> VERSION1_16_5;
|
||||
case "1.17", "1.17.1" -> VERSION1_17_1;
|
||||
case "1.18", "1.18.1", "1.18.2" -> VERSION1_18_2;
|
||||
case "1.19", "1.19.1", "1.19.2" -> VERSION1_19_2;
|
||||
case "1.19.4" -> VERSION1_19_4;
|
||||
case "1.20", "1.20.1" -> VERSION1_20_1;
|
||||
case "1.20.2" -> VERSION1_20_2;
|
||||
case "1.20.4" -> VERSION1_20_4;
|
||||
case "1.20.5", "1.20.6" -> VERSION1_20_5;
|
||||
case "1.21", "1.21.1" -> VERSION1_21_1;
|
||||
case "1.21.2", "1.21.3" -> VERSION1_21_3;
|
||||
case "1.21.4" -> VERSION1_21_4;
|
||||
case "1.21.5" -> VERSION1_21_5;
|
||||
case "1.21.6" -> VERSION1_21_6;
|
||||
case "1.21.7" -> VERSION1_21_7;
|
||||
case "1.21.8" -> VERSION1_21_8;
|
||||
case "1.21.9" -> VERSION1_21_9;
|
||||
case "1.21.10" -> VERSION1_21_10;
|
||||
case "1.21.11" -> VERSION1_21_11;
|
||||
default -> VERSION1_21_11; // Latest supported version
|
||||
};
|
||||
}
|
||||
|
||||
@NotNull
|
||||
HuskSync getPlugin();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* This file is part of HuskSync, licensed under the Apache License 2.0.
|
||||
*
|
||||
* Copyright (c) William278 <will27528@gmail.com>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.william278.husksync.util;
|
||||
|
||||
import net.william278.desertwell.util.Version;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.CsvSource;
|
||||
|
||||
@DisplayName("Compatibility Checker Tests")
|
||||
public class CompatibilityCheckerTests {
|
||||
|
||||
@ParameterizedTest(name = "Ver: {0}, Range: {1}")
|
||||
@DisplayName("Test Compatibility Checker")
|
||||
@CsvSource({
|
||||
"1.20.1, 1.21.1, false",
|
||||
"1.21.1, 1.20.1, false",
|
||||
"1.7.2, 1.21.5, false",
|
||||
"1.19.4, 1.21.1, false",
|
||||
"1.21.3, 1.21.3, true",
|
||||
"1.20.1, 1.20.1, true",
|
||||
"1.21.7, 1.21.7, true",
|
||||
"1.21.8, >=1.21.7, true",
|
||||
"1.21.8, >1.21.7, true",
|
||||
"1.0, <1.21.7, true",
|
||||
"1.17.1, !1.17.1, false",
|
||||
"1.21.7, '>=1.21.7 <=1.21.8', true",
|
||||
"1.21.8, '>=1.21.7 <=1.21.8', true",
|
||||
"1.21.5, '>=1.21.7 <=1.21.8', false",
|
||||
})
|
||||
public void testCompatibilityChecker(@NotNull String mcVer, @NotNull String range, boolean exp) {
|
||||
final Version version = Version.fromString(mcVer);
|
||||
Assertions.assertNotNull(version, "Version should not be null");
|
||||
|
||||
final CompatibilityChecker.CompatibilityConfig config = new CompatibilityChecker.CompatibilityConfig(range);
|
||||
Assertions.assertEquals(exp, config.isCompatibleWith(version), "Checker should return " + exp);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -52,7 +52,7 @@ Add the repository to your `pom.xml` as per below. You can alternatively specify
|
||||
</repository>
|
||||
</repositories>
|
||||
```
|
||||
Add the dependency to your `pom.xml` as per below. Replace `HUSKSYNC_VERSION` with the latest version of HuskSync (without the v): . and `MINECRAFT_VERSION` with the version of Minecraft you want to target (e.g. `1.20.1`). A correctly formed version target should look like: `3.7+1.20.1`. Omit the plus symbol and Minecraft version if you are targeting the `common` platform.
|
||||
Add the dependency to your `pom.xml` as per below. Replace `HUSKSYNC_VERSION` with the latest version of HuskSync (without the v): . and `MINECRAFT_VERSION` with the version of Minecraft you want to target (e.g. `1.21.10`). A correctly formed version target should look like: `3.7+1.21.10`. Omit the plus symbol and Minecraft version if you are targeting the `common` platform.
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>net.william278.husksync</groupId>
|
||||
@@ -75,7 +75,7 @@ allprojects {
|
||||
}
|
||||
}
|
||||
```
|
||||
Add the dependency as per below. Replace `HUSKSYNC_VERSION` with the latest version of HuskSync (without the v): . and `MINECRAFT_VERSION` with the version of Minecraft you want to target (e.g. `1.20.1`). A correctly formed version target should look like: `3.7+1.20.1`. Omit the plus symbol and Minecraft version if you are targeting the `common` platform.
|
||||
Add the dependency as per below. Replace `HUSKSYNC_VERSION` with the latest version of HuskSync (without the v): . and `MINECRAFT_VERSION` with the version of Minecraft you want to target (e.g. `1.21.10`). A correctly formed version target should look like: `3.7+1.21.10`. Omit the plus symbol and Minecraft version if you are targeting the `common` platform.
|
||||
|
||||
```groovy
|
||||
dependencies {
|
||||
|
||||
@@ -2,15 +2,16 @@ HuskSync supports the following versions of Minecraft. Since v3.7, you must down
|
||||
|
||||
| Minecraft | Latest HuskSync | Java Version | Platforms | Support Status |
|
||||
|:---------------:|:---------------:|:------------:|:--------------|:------------------------------|
|
||||
| 1.21.7 | _latest_ | 21 | Paper | ✅ **Active Release** |
|
||||
| 1.21.10 | _latest_ | 21 | Paper | ✅ **Active Release** |
|
||||
| 1.21.7/8 | _latest_ | 21 | Paper, Fabric | ✅ **August 2026** |
|
||||
| 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.5 | _latest_ | 21 | Paper | ✅ **February 2026** (Non-LTS) |
|
||||
| 1.21.4 | _latest_ | 21 | Paper, Fabric | ✅ **February 2026** (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.21.1 | _latest_ | 21 | Paper, Fabric | ✅ **May 2026** (LTS) |
|
||||
| 1.20.6 | 3.6.8 | 17 | Paper | 🗃️ Archived (October 2024) |
|
||||
| 1.20.4 | 3.6.8 | 17 | Paper | 🗃️ Archived (July 2024) |
|
||||
| 1.20.1 | _latest_ | 17 | Paper, Fabric | ✅ **November 2025** (LTS) |
|
||||
| 1.20.1 | 3.8.7 | 17 | Paper, Fabric | 🗃️ Archived (November 2024) |
|
||||
| 1.17.1 - 1.19.4 | 3.6.8 | 17 | Paper | 🗃️ Archived |
|
||||
| 1.16.5 | 3.2.1 | 16 | Paper | 🗃️ Archived |
|
||||
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
essential.defaults.loom.mappings=net.fabricmc:yarn:1.20.1+build.10:v2
|
||||
|
||||
fabric_loader_version=0.15.11
|
||||
fabric_api_version=0.92.2+1.20.1
|
||||
fabric_permissions_api_version=0.2-SNAPSHOT
|
||||
fabric_adventure_platform_version=5.9.0
|
||||
fabric_sgui_version=1.2.2+1.20
|
||||
@@ -1,17 +0,0 @@
|
||||
{
|
||||
"required": true,
|
||||
"minVersion": "0.8",
|
||||
"package": "net.william278.husksync.mixins",
|
||||
"compatibilityLevel": "JAVA_17",
|
||||
"server": [
|
||||
"ItemEntityMixin",
|
||||
"PlayerEntityMixin",
|
||||
"ServerPlayerEntityMixin",
|
||||
"ServerPlayNetworkHandlerMixin",
|
||||
"ServerWorldMixin"
|
||||
],
|
||||
"client": [],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
essential.defaults.loom.mappings=net.fabricmc:yarn:1.21.1+build.3:v2
|
||||
|
||||
minecraft_version_range=1.21.1
|
||||
|
||||
fabric_loader_version=0.16.10
|
||||
fabric_api_version=0.107.0+1.21.1
|
||||
fabric_permissions_api_version=0.3.1
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
essential.defaults.loom.mappings=net.fabricmc:yarn:1.21.4+build.4:v2
|
||||
|
||||
minecraft_version_range=1.21.4
|
||||
|
||||
fabric_loader_version=0.16.10
|
||||
fabric_api_version=0.116.1+1.21.4
|
||||
fabric_permissions_api_version=0.3.3
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
essential.defaults.loom.mappings=net.fabricmc:yarn:1.21.5+build.1:v2
|
||||
|
||||
minecraft_version_range=1.21.5
|
||||
|
||||
fabric_loader_version=0.16.14
|
||||
fabric_api_version=0.122.0+1.21.5
|
||||
fabric_permissions_api_version=0.3.3
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
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
|
||||
9
fabric/1.21.8/gradle.properties
Normal file
9
fabric/1.21.8/gradle.properties
Normal file
@@ -0,0 +1,9 @@
|
||||
essential.defaults.loom.mappings=net.fabricmc:yarn:1.21.8+build.1:v2
|
||||
|
||||
minecraft_version_range=>=1.21.7 <=1.21.8
|
||||
|
||||
fabric_loader_version=0.17.2
|
||||
fabric_api_version=0.131.0+1.21.8
|
||||
fabric_permissions_api_version=0.4.1
|
||||
fabric_adventure_platform_version=6.6.0
|
||||
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.8+${project.name}")
|
||||
modImplementation include("net.william278.toilet:toilet-fabric:1.0.15+${project.name}")
|
||||
modImplementation include("net.william278.uniform:uniform-fabric:1.3.9+${project.name}")
|
||||
modImplementation include("net.william278.toilet:toilet-fabric:1.0.16+${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.9")
|
||||
implementation include("de.exlll:configlib-core:4.6.3")
|
||||
implementation include("org.snakeyaml:snakeyaml-engine:2.10")
|
||||
implementation include('org.apache.commons:commons-pool2:2.12.1')
|
||||
|
||||
// Include driver deps due to no runtime dep loading support
|
||||
@@ -33,10 +33,10 @@ dependencies {
|
||||
implementation include('org.apache.commons:commons-pool2:2.12.1') // Redis dep
|
||||
|
||||
compileOnly 'net.william278:DesertWell:2.0.4'
|
||||
compileOnly 'org.jetbrains:annotations:26.0.2'
|
||||
compileOnly 'org.projectlombok:lombok:1.18.38'
|
||||
compileOnly 'org.jetbrains:annotations:26.0.2-1'
|
||||
compileOnly 'org.projectlombok:lombok:1.18.42'
|
||||
|
||||
annotationProcessor 'org.projectlombok:lombok:1.18.38'
|
||||
annotationProcessor 'org.projectlombok:lombok:1.18.42'
|
||||
|
||||
implementation include(project(path: ":common"))
|
||||
project(":common").configurations.api.dependencies.each { dependency ->
|
||||
@@ -49,7 +49,8 @@ processResources {
|
||||
expand([
|
||||
version: version,
|
||||
fabric_loader_version: fabric_loader_version,
|
||||
fabric_minecraft_version: project.name
|
||||
fabric_minecraft_version: project.name,
|
||||
minecraft_version_range: minecraft_version_range
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
1.21.7
|
||||
1.21.8
|
||||
@@ -3,15 +3,13 @@ plugins {
|
||||
}
|
||||
|
||||
preprocess {
|
||||
def fabric12107 = createNode("1.21.7", 12107, "yarn")
|
||||
def fabric12108 = createNode("1.21.8", 12108, "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)
|
||||
fabric12105.link(fabric12107, null)
|
||||
fabric12104.link(fabric12107, null)
|
||||
fabric12101.link(fabric12107, null)
|
||||
fabric12001.link(fabric12107, null)
|
||||
fabric12105.link(fabric12108, null)
|
||||
fabric12104.link(fabric12108, null)
|
||||
fabric12101.link(fabric12108, null)
|
||||
}
|
||||
@@ -88,22 +88,6 @@ public class FabricHuskSync implements DedicatedServerModInitializer, HuskSync,
|
||||
|
||||
private static final String PLATFORM_TYPE_ID = "fabric";
|
||||
|
||||
private static final int VERSION1_16_5 = 2586;
|
||||
private static final int VERSION1_17_1 = 2730;
|
||||
private static final int VERSION1_18_2 = 2975;
|
||||
private static final int VERSION1_19_2 = 3120;
|
||||
private static final int VERSION1_19_4 = 3337;
|
||||
private static final int VERSION1_20_1 = 3465;
|
||||
private static final int VERSION1_20_2 = 3578;
|
||||
private static final int VERSION1_20_4 = 3700;
|
||||
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;
|
||||
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();
|
||||
private final Map<String, Boolean> permissions = Maps.newHashMap();
|
||||
@@ -374,37 +358,6 @@ public class FabricHuskSync implements DedicatedServerModInitializer, HuskSync,
|
||||
return Version.fromString(minecraftServer.getVersion());
|
||||
}
|
||||
|
||||
public int getDataVersion(@NotNull Version mcVersion) {
|
||||
return switch (mcVersion.toStringWithoutMetadata()) {
|
||||
case "1.16", "1.16.1", "1.16.2", "1.16.3", "1.16.4", "1.16.5" -> VERSION1_16_5;
|
||||
case "1.17", "1.17.1" -> VERSION1_17_1;
|
||||
case "1.18", "1.18.1", "1.18.2" -> VERSION1_18_2;
|
||||
case "1.19", "1.19.1", "1.19.2" -> VERSION1_19_2;
|
||||
case "1.19.4" -> VERSION1_19_4;
|
||||
case "1.20", "1.20.1" -> VERSION1_20_1;
|
||||
case "1.20.2" -> VERSION1_20_2;
|
||||
case "1.20.4" -> VERSION1_20_4;
|
||||
case "1.20.5", "1.20.6" -> VERSION1_20_5;
|
||||
case "1.21", "1.21.1" -> VERSION1_21_1;
|
||||
case "1.21.2", "1.21.3" -> VERSION1_21_3;
|
||||
case "1.21.4" -> VERSION1_21_4;
|
||||
case "1.21.5" -> VERSION1_21_5;
|
||||
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;
|
||||
//#elseif MC==12101
|
||||
//$$ default -> VERSION1_21_1;
|
||||
//#elseif MC==12001
|
||||
//$$ default -> VERSION1_20_1;
|
||||
//#endif
|
||||
};
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getPlatformType() {
|
||||
|
||||
@@ -26,12 +26,7 @@ import com.google.gson.annotations.SerializedName;
|
||||
import lombok.*;
|
||||
import net.minecraft.advancement.AdvancementProgress;
|
||||
import net.minecraft.advancement.PlayerAdvancementTracker;
|
||||
//#if MC==12001
|
||||
//$$ import net.minecraft.enchantment.EnchantmentHelper;
|
||||
//$$ import net.minecraft.nbt.NbtCompound;
|
||||
//#else
|
||||
import net.minecraft.component.DataComponentTypes;
|
||||
//#endif
|
||||
import net.minecraft.entity.attribute.EntityAttribute;
|
||||
import net.minecraft.entity.attribute.EntityAttributeInstance;
|
||||
import net.minecraft.entity.attribute.EntityAttributeModifier;
|
||||
@@ -95,16 +90,6 @@ public abstract class FabricData implements Data {
|
||||
stack.getItem().toString(),
|
||||
stack.getCount(),
|
||||
stack.getName().getString(),
|
||||
//#if MC==12001
|
||||
//$$ Optional.ofNullable(stack.getSubNbt(ItemStack.DISPLAY_KEY))
|
||||
//$$ .flatMap(display -> Optional.ofNullable(display.get(ItemStack.LORE_KEY))
|
||||
//$$ .map(lore -> ((List<String>) lore).stream().toList()))
|
||||
//$$ .orElse(null),
|
||||
//$$ stack.getEnchantments().stream()
|
||||
//$$ .map(element -> EnchantmentHelper.getIdFromNbt((NbtCompound) element))
|
||||
//$$ .filter(Objects::nonNull).map(Identifier::toString)
|
||||
//$$ .toList()
|
||||
//#else
|
||||
stack.getComponents().get(DataComponentTypes.LORE).lines().stream()
|
||||
.map(Text::getString)
|
||||
.toList(),
|
||||
@@ -112,7 +97,6 @@ public abstract class FabricData implements Data {
|
||||
.map(RegistryEntry::getIdAsString)
|
||||
.filter(Objects::nonNull)
|
||||
.toList()
|
||||
//#endif
|
||||
) : null)
|
||||
.toArray(Stack[]::new);
|
||||
}
|
||||
@@ -274,11 +258,7 @@ public abstract class FabricData implements Data {
|
||||
.map(effect -> {
|
||||
final StatusEffect type = matchEffectType(effect.type());
|
||||
return type != null ? new StatusEffectInstance(
|
||||
//#if MC==12001
|
||||
//$$ type,
|
||||
//#else
|
||||
RegistryEntry.of(type),
|
||||
//#endif
|
||||
effect.duration(),
|
||||
effect.amplifier(),
|
||||
effect.isAmbient(),
|
||||
@@ -300,16 +280,10 @@ public abstract class FabricData implements Data {
|
||||
@Override
|
||||
public void apply(@NotNull FabricUser user, @NotNull FabricHuskSync plugin) throws IllegalStateException {
|
||||
final ServerPlayerEntity player = user.getPlayer();
|
||||
//#if MC==12001
|
||||
//$$ final List<StatusEffect> effectsToRemove = player.getActiveStatusEffects().entrySet().stream()
|
||||
//$$ .filter(e -> !e.getValue().isAmbient()).map(Map.Entry::getKey).toList();
|
||||
//$$ effectsToRemove.forEach(player::removeStatusEffect);
|
||||
//#else
|
||||
//todo ambient check
|
||||
final List<StatusEffect> effectsToRemove = new ArrayList<>(player.getActiveStatusEffects().keySet().stream()
|
||||
.map(RegistryEntry::value).toList());
|
||||
effectsToRemove.forEach(effect -> player.removeStatusEffect(RegistryEntry.of(effect)));
|
||||
//#endif
|
||||
getEffects().forEach(player::addStatusEffect);
|
||||
}
|
||||
|
||||
@@ -319,11 +293,7 @@ public abstract class FabricData implements Data {
|
||||
public List<Effect> getActiveEffects() {
|
||||
return effects.stream()
|
||||
.map(potionEffect -> {
|
||||
//#if MC==12001
|
||||
//$$ final String key = getEffectId(potionEffect.getEffectType());
|
||||
//#else
|
||||
final String key = getEffectId(potionEffect.getEffectType().value());
|
||||
//#endif
|
||||
return key != null ? new Effect(
|
||||
key,
|
||||
potionEffect.getAmplifier(),
|
||||
@@ -357,21 +327,13 @@ public abstract class FabricData implements Data {
|
||||
|
||||
advancementProgress.getObtainedCriteria().forEach((criteria) -> awardedCriteria.put(
|
||||
criteria,
|
||||
//#if MC==12001
|
||||
//$$ advancementProgress.getEarliestProgressObtainDate()
|
||||
//#else
|
||||
Date.from(advancementProgress.getEarliestProgressObtainDate())
|
||||
//#endif
|
||||
));
|
||||
|
||||
// Only save the advancement if criteria has been completed
|
||||
if (!awardedCriteria.isEmpty()) {
|
||||
advancements.add(Advancement.adapt(
|
||||
//#if MC==12001
|
||||
//$$ advancementEntry.getId().toString(),
|
||||
//#else
|
||||
advancementEntry.id().asString(),
|
||||
//#endif
|
||||
awardedCriteria
|
||||
));
|
||||
}
|
||||
@@ -392,11 +354,7 @@ public abstract class FabricData implements Data {
|
||||
final AdvancementProgress progress = player.getAdvancementTracker().getProgress(advancementEntry);
|
||||
final Optional<Advancement> record = completed.stream()
|
||||
.filter(r -> r.getKey().equals(
|
||||
//#if MC==12001
|
||||
//$$ advancementEntry.getId().toString()
|
||||
//#else
|
||||
advancementEntry.id().asString()
|
||||
//#endif
|
||||
))
|
||||
.findFirst();
|
||||
if (record.isEmpty()) {
|
||||
@@ -414,11 +372,7 @@ public abstract class FabricData implements Data {
|
||||
}
|
||||
|
||||
private void setAdvancement(@NotNull FabricHuskSync plugin,
|
||||
//#if MC==12001
|
||||
//$$ @NotNull net.minecraft.advancement.Advancement advancementEntry,
|
||||
//#else
|
||||
@NotNull net.minecraft.advancement.AdvancementEntry advancementEntry,
|
||||
//#endif
|
||||
@NotNull ServerPlayerEntity player,
|
||||
@NotNull FabricUser user,
|
||||
@NotNull List<String> toAward,
|
||||
@@ -445,11 +399,7 @@ public abstract class FabricData implements Data {
|
||||
// Performs a consuming function for every advancement entry registered on the server
|
||||
private static void forEachAdvancementEntry(
|
||||
@NotNull MinecraftServer server,
|
||||
//#if MC==12001
|
||||
//$$ @NotNull ThrowingConsumer<net.minecraft.advancement.Advancement> con
|
||||
//#else
|
||||
@NotNull ThrowingConsumer<net.minecraft.advancement.AdvancementEntry> con
|
||||
//#endif
|
||||
) {
|
||||
server.getAdvancementLoader().getAdvancements().forEach(con);
|
||||
}
|
||||
@@ -482,11 +432,7 @@ public abstract class FabricData implements Data {
|
||||
|
||||
@NotNull
|
||||
public static FabricData.Location adapt(@NotNull ServerPlayerEntity player) {
|
||||
//#if MC==12001
|
||||
//$$ final String worldName = player.getWorld().getDimensionKey().getValue().toString();
|
||||
//#else
|
||||
final String worldName = player.getWorld().getDimensionEntry().getIdAsString();
|
||||
//#endif
|
||||
return from(
|
||||
player.getX(),
|
||||
player.getY(),
|
||||
@@ -659,21 +605,6 @@ public abstract class FabricData implements Data {
|
||||
final List<Attribute> attributes = Lists.newArrayList();
|
||||
final AttributeSettings settings = plugin.getSettings().getSynchronization().getAttributes();
|
||||
Registries.ATTRIBUTE.forEach(id -> {
|
||||
//#if MC==12001
|
||||
//$$ final EntityAttributeInstance instance = player.getAttributeInstance(id);
|
||||
//$$ final Identifier key = Registries.ATTRIBUTE.getId(id);
|
||||
//$$ if (instance == null || key == null || settings.isIgnoredAttribute(key.asString())) {
|
||||
//$$ return;
|
||||
//$$ }
|
||||
//$$ final Set<Modifier> modifiers = Sets.newHashSet();
|
||||
//$$ instance.getModifiers().forEach(modifier -> modifiers.add(new Modifier(
|
||||
//$$ modifier.getId(),
|
||||
//$$ modifier.getName(),
|
||||
//$$ modifier.getValue(),
|
||||
//$$ modifier.getOperation().getId(),
|
||||
//$$ -1
|
||||
//$$ )));
|
||||
//#else
|
||||
final EntityAttributeInstance instance = player.getAttributeInstance(RegistryEntry.of(id));
|
||||
final Identifier key = Registries.ATTRIBUTE.getId(id);
|
||||
if (instance == null || key == null || settings.isIgnoredAttribute(key.asString())) {
|
||||
@@ -686,7 +617,6 @@ public abstract class FabricData implements Data {
|
||||
modifier.operation().getId(),
|
||||
Modifier.ANY_EQUIPMENT_SLOT_GROUP
|
||||
)));
|
||||
//#endif
|
||||
attributes.add(new Attribute(
|
||||
key.toString(),
|
||||
instance.getBaseValue(),
|
||||
@@ -719,11 +649,7 @@ public abstract class FabricData implements Data {
|
||||
return;
|
||||
}
|
||||
applyAttribute(
|
||||
//#if MC==12001
|
||||
//$$ user.getPlayer().getAttributeInstance(id),
|
||||
//#else
|
||||
user.getPlayer().getAttributeInstance(RegistryEntry.of(id)),
|
||||
//#endif
|
||||
getAttribute(id).orElse(null)
|
||||
);
|
||||
});
|
||||
|
||||
@@ -26,9 +26,6 @@ import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import net.minecraft.datafixer.TypeReferences;
|
||||
import net.minecraft.item.ItemStack;
|
||||
//#if MC==12001
|
||||
//$$ import net.minecraft.nbt.NbtCompound;
|
||||
//#endif
|
||||
import net.minecraft.nbt.*;
|
||||
import net.minecraft.registry.DynamicRegistryManager;
|
||||
import net.william278.desertwell.util.Version;
|
||||
@@ -274,16 +271,12 @@ public abstract class FabricSerializer {
|
||||
@Nullable
|
||||
private NbtCompound encodeNbt(@NotNull ItemStack item, @NotNull DynamicRegistryManager reg) {
|
||||
try {
|
||||
//#if MC>=12107
|
||||
//#if MC>=12108
|
||||
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(reg);
|
||||
//#elseif MC==12001
|
||||
//$$ final NbtCompound compound = new NbtCompound();
|
||||
//$$ item.writeNbt(compound);
|
||||
//$$ return compound;
|
||||
//#endif
|
||||
} catch (Throwable e) {
|
||||
return null;
|
||||
@@ -292,12 +285,10 @@ public abstract class FabricSerializer {
|
||||
|
||||
@NotNull
|
||||
private ItemStack decodeNbt(@NotNull NbtElement item, @NotNull DynamicRegistryManager reg) {
|
||||
//#if MC>=12107
|
||||
//#if MC>=12108
|
||||
final @Nullable ItemStack stack = ItemStack.CODEC.decode(reg.getOps(NbtOps.INSTANCE), item).getOrThrow().getFirst();
|
||||
//#elseif MC>12001
|
||||
//#else
|
||||
//$$ final @Nullable ItemStack stack = ItemStack.fromNbt(reg, item).orElse(null);
|
||||
//#elseif MC==12001
|
||||
//$$ final @Nullable ItemStack stack = ItemStack.fromNbt((NbtCompound) item);
|
||||
//#endif
|
||||
if (stack == null) {
|
||||
throw new IllegalStateException("Failed to decode item NBT (decode got null): (%s)".formatted(item));
|
||||
|
||||
@@ -120,11 +120,7 @@ public interface FabricUserDataHolder extends UserDataHolder {
|
||||
@Override
|
||||
default Optional<Data.Items.EnderChest> getEnderChest() {
|
||||
return Optional.of(FabricData.Items.EnderChest.adapt(
|
||||
//#if MC==12001
|
||||
//$$ getPlayer().getEnderChestInventory().stacks
|
||||
//#else
|
||||
getPlayer().getEnderChestInventory().getHeldStacks()
|
||||
//#endif
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
@@ -82,13 +82,9 @@ public class PlayerEntityMixin {
|
||||
|
||||
@Unique
|
||||
private boolean hasVanishingCurse(@NotNull ItemStack stack) {
|
||||
//#if MC==12001
|
||||
//$$ return EnchantmentHelper.hasVanishingCurse(stack);
|
||||
//#else
|
||||
return EnchantmentHelper.hasAnyEnchantmentsIn(
|
||||
stack, TagKey.of(Enchantments.VANISHING_CURSE.getRegistryRef(), Enchantments.VANISHING_CURSE.getValue())
|
||||
);
|
||||
//#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -92,11 +92,7 @@ public abstract class ServerPlayNetworkHandlerMixin {
|
||||
|
||||
@Inject(method = "onCreativeInventoryAction", at = @At("HEAD"), cancellable = true)
|
||||
public void onCreativeInventoryAction(CreativeInventoryActionC2SPacket packet, CallbackInfo ci) {
|
||||
//#if MC==12001
|
||||
//$$ int slot = packet.getSlot();
|
||||
//#else
|
||||
int slot = packet.slot();
|
||||
//#endif
|
||||
if (slot < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
# File used for checking Minecraft server compatibility with this version of HuskSync
|
||||
minecraft_version: '${fabric_minecraft_version}'
|
||||
minecraft_version_range: '${minecraft_version_range}'
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
},
|
||||
"depends": {
|
||||
"fabricloader": ">=${fabric_loader_version}",
|
||||
"minecraft": "${fabric_minecraft_version}",
|
||||
"minecraft": "${minecraft_version_range}",
|
||||
"fabric-api": "*"
|
||||
},
|
||||
"suggests": {
|
||||
|
||||
@@ -4,7 +4,7 @@ org.gradle.daemon=true
|
||||
javaVersion=21
|
||||
|
||||
# Plugin metadata
|
||||
plugin_version=3.8.6
|
||||
plugin_version=3.8.8
|
||||
plugin_archive=husksync
|
||||
plugin_description=A modern, cross-server player data synchronization system
|
||||
|
||||
@@ -17,4 +17,5 @@ mongodb_driver_version=5.5.0
|
||||
snappy_version=1.1.10.7
|
||||
|
||||
# Fabric settings
|
||||
loom.ignoreDependencyLoomVersionValidation=true
|
||||
loom.ignoreDependencyLoomVersionValidation=true
|
||||
loom.disableUnpick=true
|
||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
6
gradlew
vendored
6
gradlew
vendored
@@ -114,7 +114,7 @@ case "$( uname )" in #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
CLASSPATH="\\\"\\\""
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
@@ -205,7 +205,7 @@ fi
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
@@ -213,7 +213,7 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
|
||||
4
gradlew.bat
vendored
4
gradlew.bat
vendored
@@ -70,11 +70,11 @@ goto fail
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
set CLASSPATH=
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
|
||||
@@ -5,11 +5,11 @@ pluginManagement {
|
||||
maven { url 'https://maven.fabricmc.net/' }
|
||||
maven { url 'https://maven.architectury.dev/' }
|
||||
maven { url 'https://maven.minecraftforge.net' }
|
||||
maven { url 'https://repo.essential.gg/repository/maven-public' }
|
||||
maven { url 'https://repo.essential.gg/public' }
|
||||
}
|
||||
|
||||
plugins {
|
||||
def egtVersion = "0.6.5"
|
||||
def egtVersion = "0.6.10"
|
||||
id("gg.essential.defaults") version egtVersion
|
||||
id("gg.essential.multi-version.root") version egtVersion
|
||||
}
|
||||
|
||||
@@ -4,4 +4,4 @@ colorama==0.4.6
|
||||
idna==3.7
|
||||
requests==2.32.4
|
||||
tqdm==4.66.3
|
||||
urllib3==2.5.0
|
||||
urllib3==2.6.0
|
||||
|
||||
Reference in New Issue
Block a user