9
0
mirror of https://github.com/WiIIiam278/HuskSync.git synced 2025-12-19 14:59:21 +00:00

build: Use multi-version and preprocessor to build all target versions from one branch (#463)

* feat: convert Fabric to use essential-multi-version

* fix: populate compatibility.yml with mc version

* feat: start WIP work on doing the same for bukkit

* refactor: use preprocessor plugin to multi-version bukkit

* docs: update README to mention multi-version stuff

* build: also include javadocs for Bukkit

* build: update CI workflows

also slightly simplifies buildscript
This commit is contained in:
William
2025-03-05 16:52:21 +00:00
committed by GitHub
parent 1ff4cab88d
commit be6bebe361
46 changed files with 594 additions and 398 deletions

View File

@@ -1,4 +1,4 @@
name: CI Tests
name: CI Tests & Publish
on:
push:
@@ -14,23 +14,19 @@ permissions:
jobs:
build:
name: 'Build - 1.21.4'
runs-on: ubuntu-latest
steps:
- name: 'Setup JDK 21 📦'
- name: 'Checkout for CI 🛎️'
uses: actions/checkout@v4
- name: 'Set up JDK 21 📦'
uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'temurin'
- name: 'Setup Gradle 8.12 🏗️'
uses: gradle/actions/setup-gradle@v4
- name: 'Build with Gradle 🏗️'
uses: gradle/gradle-build-action@v3
with:
gradle-version: '8.12'
- name: 'Checkout for CI 🛎️'
uses: actions/checkout@v4
- name: '[Current - 1.21.4] Build 🛎️'
run: |
./gradlew clean build publish
arguments: build test publish
env:
SNAPSHOTS_MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }}
SNAPSHOTS_MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }}
@@ -39,11 +35,11 @@ jobs:
if: success() || failure() # Continue on failure
with:
report_paths: '**/build/test-results/test/TEST-*.xml'
- name: 'Fetch Version String 📝'
- name: 'Fetch Version Name 📝'
run: |
echo "::set-output name=VERSION_NAME::$(./gradlew properties --no-daemon --console=plain -q | grep "^version:" | awk '{printf $2}')"
echo "::set-output name=VERSION_NAME::$(${{github.workspace}}/gradlew properties --no-daemon --console=plain -q | grep "^version:" | awk '{printf $2}')"
id: fetch-version
- name: 'Set Version Variable 📝'
- name: Get Version
run: |
echo "version_name=${{steps.fetch-version.outputs.VERSION_NAME}}" >> $GITHUB_ENV
- name: 'Publish to William278.net 🚀'
@@ -55,14 +51,30 @@ 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
fabric-1.20.1
fabric-1.21.1
fabric-1.21.4
distro-groups: |
paper
paper
paper
fabric
fabric
fabric
distro-descriptions: |
Paper 1.20.1
Paper 1.21.1
Paper 1.21.4
Fabric 1.20.1
Fabric 1.21.1
Fabric 1.21.4
files: |
target/HuskSync-Paper-${{ env.version_name }}+mc.1.21.4.jar
target/HuskSync-Bukkit-${{ env.version_name }}+mc.1.20.1.jar
target/HuskSync-Bukkit-${{ env.version_name }}+mc.1.21.1.jar
target/HuskSync-Bukkit-${{ env.version_name }}+mc.1.21.4.jar
target/HuskSync-Fabric-${{ env.version_name }}+mc.1.20.1.jar
target/HuskSync-Fabric-${{ env.version_name }}+mc.1.21.1.jar
target/HuskSync-Fabric-${{ env.version_name }}+mc.1.21.4.jar

View File

@@ -1,70 +0,0 @@
name: CI Tests
on:
push:
branches: [ 'minecraft/1.20.1' ]
paths-ignore:
- 'docs/**'
- 'workflows/**'
- 'README.md'
permissions:
contents: read
checks: write
jobs:
build:
name: 'Build - 1.20.1'
runs-on: ubuntu-latest
steps:
- name: 'Setup JDK 21 📦'
uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'temurin'
- name: 'Setup Gradle 8.8 🏗️'
uses: gradle/actions/setup-gradle@v4
with:
gradle-version: '8.8'
- name: 'Checkout for CI 🛎️'
uses: actions/checkout@v4
with:
ref: 'minecraft/1.20.1'
- name: '[Current - 1.20.1] Build 🛎️'
run: |
./gradlew clean build publish
env:
SNAPSHOTS_MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }}
SNAPSHOTS_MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }}
- name: 'Publish Test Report 📊'
uses: mikepenz/action-junit-report@v5
if: success() || failure() # Continue on failure
with:
report_paths: '**/build/test-results/test/TEST-*.xml'
- name: 'Fetch Version String 📝'
run: |
echo "::set-output name=VERSION_NAME::$(./gradlew properties --no-daemon --console=plain -q | grep "^version:" | awk '{printf $2}')"
id: fetch-version
- name: 'Set Version Variable 📝'
run: |
echo "version_name=${{steps.fetch-version.outputs.VERSION_NAME}}" >> $GITHUB_ENV
- name: 'Publish to William278.net 🚀'
uses: WiIIiam278/bones-publish-action@v1
with:
api-key: ${{ secrets.BONES_API_KEY }}
project: 'husksync'
channel: 'alpha'
version: ${{ env.version_name }}
changelog: ${{ github.event.head_commit.message }}
distro-names: |
paper-1.20.1
fabric-1.20.1
distro-groups: |
paper
fabric
distro-descriptions: |
Paper 1.20.1
Fabric 1.20.1
files: |
target/HuskSync-Paper-${{ env.version_name }}+mc.1.20.1.jar
target/HuskSync-Fabric-${{ env.version_name }}+mc.1.20.1.jar

View File

@@ -1,70 +0,0 @@
name: CI Tests
on:
push:
branches: [ 'minecraft/1.21.1' ]
paths-ignore:
- 'docs/**'
- 'workflows/**'
- 'README.md'
permissions:
contents: read
checks: write
jobs:
build:
name: 'Build - 1.21.1'
runs-on: ubuntu-latest
steps:
- name: 'Setup JDK 21 📦'
uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'temurin'
- name: 'Setup Gradle 8.8 🏗️'
uses: gradle/actions/setup-gradle@v4
with:
gradle-version: '8.8'
- name: 'Checkout for CI 🛎️'
uses: actions/checkout@v4
with:
ref: 'minecraft/1.21.1'
- name: '[Current - 1.21.1] Build 🛎️'
run: |
./gradlew clean build publish
env:
SNAPSHOTS_MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }}
SNAPSHOTS_MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }}
- name: 'Publish Test Report 📊'
uses: mikepenz/action-junit-report@v5
if: success() || failure() # Continue on failure
with:
report_paths: '**/build/test-results/test/TEST-*.xml'
- name: 'Fetch Version String 📝'
run: |
echo "::set-output name=VERSION_NAME::$(./gradlew properties --no-daemon --console=plain -q | grep "^version:" | awk '{printf $2}')"
id: fetch-version
- name: 'Set Version Variable 📝'
run: |
echo "version_name=${{steps.fetch-version.outputs.VERSION_NAME}}" >> $GITHUB_ENV
- name: 'Publish to William278.net 🚀'
uses: WiIIiam278/bones-publish-action@v1
with:
api-key: ${{ secrets.BONES_API_KEY }}
project: 'husksync'
channel: 'alpha'
version: ${{ env.version_name }}
changelog: ${{ github.event.head_commit.message }}
distro-names: |
paper-1.21.1
fabric-1.21.1
distro-groups: |
paper
fabric
distro-descriptions: |
Paper 1.21.1
Fabric 1.21.1
files: |
target/HuskSync-Paper-${{ env.version_name }}+mc.1.21.1.jar
target/HuskSync-Fabric-${{ env.version_name }}+mc.1.21.1.jar

View File

@@ -1,4 +1,4 @@
name: Release Tests
name: Release Tests & Publish
on:
release:
@@ -8,60 +8,21 @@ permissions:
contents: read
checks: write
jobs:
build:
name: 'Publish Release'
runs-on: ubuntu-latest
steps:
- name: 'Setup JDK 21 📦'
- name: 'Checkout for CI 🛎️'
uses: actions/checkout@v4
- name: 'Set up JDK 21 📦'
uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'temurin'
- name: 'Setup Gradle 8.12 🏗️'
uses: gradle/actions/setup-gradle@v4
- name: 'Build with Gradle 🏗️'
uses: gradle/gradle-build-action@v3
with:
gradle-version: '8.12'
- name: '[Current - 1.21.4] Checkout for CI 🛎️'
uses: actions/checkout@v4
with:
path: '1_21_4'
- name: '[Non-LTS - 1.21.1] Checkout for CI 🛎️'
uses: actions/checkout@v4
with:
ref: 'minecraft/1.21.1'
path: '1_21_1'
- name: '[LTS - 1.20.1] Checkout for CI 🛎️'
uses: actions/checkout@v4
with:
ref: 'minecraft/1.20.1'
path: '1_20_1'
- name: '[Current - 1.21.4] Build 🛎️'
run: |
mkdir target
cd 1_21_4
./gradlew clean build publish -Dforce-hide-version-meta=1
cp -rf target/* ../target/
cd ..
env:
RELEASES_MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }}
RELEASES_MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }}
- name: '[Non-LTS - 1.21.1] Build 🛎️'
run: |
cd 1_21_1
./gradlew clean build publish -Dforce-hide-version-meta=1
cp -rf target/* ../target/
cd ..
env:
RELEASES_MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }}
RELEASES_MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }}
- name: '[LTS - 1.20.1] Build 🛎️'
run: |
cd 1_20_1
./gradlew clean build publish -Dforce-hide-version-meta=1
cp -rf target/* ../target/
cd ..
arguments: build test publish
env:
RELEASES_MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }}
RELEASES_MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }}
@@ -79,30 +40,30 @@ jobs:
version: ${{ github.event.release.tag_name }}
changelog: ${{ github.event.release.body }}
distro-names: |
paper-1.21.4
fabric-1.21.4
paper-1.21.1
fabric-1.21.1
paper-1.20.1
paper-1.21.1
paper-1.21.4
fabric-1.20.1
fabric-1.21.1
fabric-1.21.4
distro-groups: |
paper
fabric
paper
paper
fabric
paper
fabric
fabric
distro-descriptions: |
Paper 1.21.4
Fabric 1.21.4
Paper 1.21.1
Fabric 1.21.1
Paper 1.20.1
Paper 1.21.1
Paper 1.21.4
Fabric 1.20.1
Fabric 1.21.1
Fabric 1.21.4
files: |
target/HuskSync-Paper-${{ github.event.release.tag_name }}+mc.1.21.4.jar
target/HuskSync-Fabric-${{ github.event.release.tag_name }}+mc.1.21.4.jar
target/HuskSync-Paper-${{ github.event.release.tag_name }}+mc.1.21.1.jar
target/HuskSync-Fabric-${{ github.event.release.tag_name }}+mc.1.21.1.jar
target/HuskSync-Paper-${{ github.event.release.tag_name }}+mc.1.20.1.jar
target/HuskSync-Bukkit-${{ github.event.release.tag_name }}+mc.1.20.1.jar
target/HuskSync-Bukkit-${{ github.event.release.tag_name }}+mc.1.21.1.jar
target/HuskSync-Bukkit-${{ github.event.release.tag_name }}+mc.1.21.4.jar
target/HuskSync-Fabric-${{ github.event.release.tag_name }}+mc.1.20.1.jar
target/HuskSync-Fabric-${{ github.event.release.tag_name }}+mc.1.21.1.jar
target/HuskSync-Fabric-${{ github.event.release.tag_name }}+mc.1.21.4.jar

View File

@@ -1,8 +1,8 @@
<!--suppress ALL -->
<p align="center">
<img src="images/banner.png" alt="HuskSync" />
<a href="https://github.com/WiIIiam278/HuskSync/actions/workflows/ci_master.yml">
<img src="https://img.shields.io/github/actions/workflow/status/WiIIiam278/HuskSync/ci_master.yml?branch=master&logo=github"/>
<a href="https://github.com/WiIIiam278/HuskSync/actions/workflows/ci.yml">
<img src="https://img.shields.io/github/actions/workflow/status/WiIIiam278/HuskSync/ci.yml?branch=master&logo=github"/>
</a>
<a href="https://repo.william278.net/#/releases/net/william278/husksync/">
<img src="https://repo.william278.net/api/badge/latest/releases/net/william278/husksync/husksync-common?color=00fb9a&name=Maven&prefix=v" />
@@ -79,6 +79,8 @@ To build HuskSync, simply run the following in the root of the repository (build
./gradlew clean build
```
HuskSync uses `essential-multi-version` (Fabric) and `preprocessor` (Bukkit) to target multiple versions of Minecraft in one codebase - [check here](https://github.com/WiIIiam278/PreProcessor?tab=readme-ov-file#code-example) for a preprocessor comment logic reference.
### License
HuskSync is licensed under the Apache 2.0 license.

View File

@@ -4,6 +4,7 @@ plugins {
id 'com.gradleup.shadow' version '8.3.6'
id 'org.cadixdev.licenser' version '0.6.1' apply false
id 'fabric-loom' version "$fabric_loom_version" apply false
id 'gg.essential.multi-version.root' apply false
id 'org.ajoberstar.grgit' version '5.3.0'
id 'maven-publish'
id 'java'
@@ -18,7 +19,6 @@ ext {
set 'version', version.toString()
set 'description', description.toString()
set 'minecraft_version', minecraft_version.toString()
set 'jedis_version', jedis_version.toString()
set 'mysql_driver_version', mysql_driver_version.toString()
set 'mariadb_driver_version', mariadb_driver_version.toString()
@@ -59,13 +59,17 @@ publishing {
}
allprojects {
// Ignore parent projects (no jars)
if (project.name == 'fabric' || project.name == 'bukkit') {
return
}
apply plugin: 'com.gradleup.shadow'
apply plugin: 'org.cadixdev.licenser'
apply plugin: 'java'
compileJava.options.encoding = 'UTF-8'
compileJava.options.compilerArgs += ['-Xlint:unchecked', '-Xlint:deprecation']
compileJava.options.release.set Integer.parseInt(rootProject.ext.javaVersion)
compileJava.options.release.set 17
javadoc.options.encoding = 'UTF-8'
javadoc.options.addStringOption('Xdoclint:none', '-quiet')
@@ -89,10 +93,7 @@ allprojects {
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.11.4'
testImplementation 'org.junit.jupiter:junit-jupiter-params:5.11.4'
testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.11.4'
}
test {
useJUnitPlatform()
testCompileOnly 'org.jetbrains:annotations:26.0.2'
}
license {
@@ -101,6 +102,10 @@ allprojects {
newLine = true
}
test {
useJUnitPlatform()
}
processResources {
def tokenMap = rootProject.ext.properties
tokenMap.merge("grgit",'',(s, s2) -> s)
@@ -112,12 +117,30 @@ allprojects {
}
subprojects {
if (['fabric'].contains(project.name)) {
apply plugin: 'fabric-loom'
// Ignore parent projects (no jars)
if (['fabric', 'bukkit'].contains(project.name)) {
return
}
// Project naming
version rootProject.version
archivesBaseName = "${rootProject.name}-${project.name.capitalize()}"
def name = "$rootProject.name"
if (rootProject != project.parent) {
name += "-${project.parent.name.capitalize()}"
} else {
name += "-${project.name.capitalize()}"
}
archivesBaseName = name
// 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
version += "+mc.${project.name}"
if (project.parent?.name?.equals('fabric')) {
apply plugin: 'fabric-loom'
}
}
jar {
from '../LICENSE'
@@ -128,13 +151,8 @@ subprojects {
archiveClassifier.set('')
}
// Append the compatible Minecraft version to the version
if (['bukkit', 'paper', 'fabric'].contains(project.name)) {
version += "+mc.${minecraft_version}"
}
// API publishing
if (['common', 'bukkit', 'fabric'].contains(project.name)) {
if (project.name == 'common' || ['fabric', 'bukkit'].contains(project.parent?.name)) {
java {
withSourcesJar()
withJavadocJar()
@@ -161,12 +179,12 @@ subprojects {
}
}
if (['bukkit'].contains(project.name)) {
if (project.parent?.name?.equals('bukkit')) {
publications {
mavenJavaBukkit(MavenPublication) {
"mavenJavaBukkit_${project.name.replace('.', '_')}"(MavenPublication) {
groupId = 'net.william278.husksync'
artifactId = 'husksync-bukkit'
version = "$rootProject.version+${minecraft_version}"
version = "$rootProject.version+$project.name"
artifact shadowJar
artifact sourcesJar
artifact javadocJar
@@ -174,12 +192,12 @@ subprojects {
}
}
if (['fabric'].contains(project.name)) {
if (project.parent?.name?.equals('fabric')) {
publications {
mavenJavaFabric(MavenPublication) {
"mavenJavaFabric_${project.name.replace('.', '_')}"(MavenPublication) {
groupId = 'net.william278.husksync'
artifactId = 'husksync-fabric'
version = "$rootProject.version+${minecraft_version}"
version = "$rootProject.version+$project.name"
artifact remapJar
artifact sourcesJar
artifact javadocJar
@@ -189,19 +207,14 @@ subprojects {
}
}
jar.dependsOn(shadowJar)
jar.dependsOn shadowJar
clean.delete "$rootDir/target"
}
logger.lifecycle("Building HuskSync ${version} by William278 for Minecraft ${minecraft_version}")
logger.lifecycle("Building HuskSync ${version} by William278")
@SuppressWarnings('GrMethodMayBeStatic')
def versionMetadata() {
// If the force-hide-version-meta environment variable is set, return ''
if (System.getProperty('force-hide-version-meta') != null) {
return ''
}
// Require grgit
if (grgit == null) {
return '-unknown'

View File

@@ -0,0 +1,3 @@
minecraft_version_numeric=12001
minecraft_api_version=1.20
paper_api_version=1.20.1-R0.1-SNAPSHOT

View File

@@ -0,0 +1,3 @@
minecraft_version_numeric=12101
minecraft_api_version=1.21
paper_api_version=1.21.1-R0.1-SNAPSHOT

View File

@@ -0,0 +1,3 @@
minecraft_version_numeric=12104
minecraft_api_version=1.21
paper_api_version=1.21.4-R0.1-SNAPSHOT

View File

@@ -1,7 +1,15 @@
plugins {
id 'java'
id 'net.william278.preprocessor' version '1.0'
id 'xyz.jpenilla.run-paper' version '2.3.1'
id 'maven-publish'
}
dependencies {
implementation project(path: ':common')
implementation 'net.william278.uniform:uniform-bukkit:1.3.1'
implementation 'net.william278.uniform:uniform-paper:1.3.1'
implementation 'net.william278:mpdbdataconverter:1.0.1'
implementation 'net.william278:hsldataconverter:1.0'
implementation 'net.william278:mapdataapi:2.0'
@@ -11,7 +19,7 @@ dependencies {
implementation 'space.arim.morepaperlib:morepaperlib:0.4.4'
implementation 'de.tr7zw:item-nbt-api:2.14.2-SNAPSHOT'
compileOnly "org.spigotmc:spigot-api:${bukkit_spigot_api}"
compileOnly "io.papermc.paper:paper-api:${paper_api_version}"
compileOnly 'com.github.retrooper:packetevents-spigot:2.7.0'
compileOnly 'com.comphenix.protocol:ProtocolLib:5.3.0'
compileOnly 'org.projectlombok:lombok:1.18.36'
@@ -27,10 +35,32 @@ dependencies {
annotationProcessor 'org.projectlombok:lombok:1.18.36'
}
processResources {
filesMatching(['**/*.json', '**/*.yml']) {
expand([
version: version,
paper_api_version: paper_api_version,
minecraft_version: project.name,
minecraft_api_version: minecraft_api_version
])
}
}
sourceSets.main {
java.srcDirs '../src/main/java'
resources.srcDirs '../src/main/resources'
}
javadoc.setSource('./build/generated/preprocessed/main/java')
preprocess {
vars.put('MC', minecraft_version_numeric)
}
shadowJar {
dependencies {
exclude(dependency('com.mojang:brigadier'))
}
relocate 'org.apache.commons.io', 'net.william278.husksync.libraries.commons.io'
relocate 'org.apache.commons.text', 'net.william278.husksync.libraries.commons.text'
relocate 'org.apache.commons.lang3', 'net.william278.husksync.libraries.commons.lang3'
@@ -57,3 +87,9 @@ shadowJar {
minimize()
}
tasks {
runServer {
minecraftVersion(project.name)
}
}

5
bukkit/gradle.properties Normal file
View File

@@ -0,0 +1,5 @@
org.gradle.daemon=false
org.gradle.parallel=true
org.gradle.configureoncommand=true
org.gradle.parallel.threads=4
org.gradle.jvmargs=-Xmx8G

0
bukkit/root.gradle Normal file
View File

View File

@@ -30,7 +30,7 @@ import org.jetbrains.annotations.NotNull;
import java.util.UUID;
@SuppressWarnings({"unchecked", "unused"})
@SuppressWarnings({"unused"})
public class PaperHuskSync extends BukkitHuskSync {
@NotNull

View File

@@ -38,7 +38,11 @@ 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.potion.PotionEffect;
@@ -590,19 +594,33 @@ 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) {
@@ -622,12 +640,22 @@ 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

View File

@@ -51,7 +51,11 @@ 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) {

View File

@@ -279,7 +279,7 @@ public interface BukkitMapPersister {
@NotNull
private static World getDefaultMapWorld() {
final World world = Bukkit.getWorlds().getFirst();
final World world = Bukkit.getWorlds().get(0);
if (world == null) {
throw new IllegalStateException("No worlds are loaded on the server!");
}
@@ -359,7 +359,7 @@ public interface BukkitMapPersister {
/**
* A {@link MapCanvas} implementation used for pre-rendering maps to be converted into {@link MapData}
*/
@SuppressWarnings("deprecation")
@SuppressWarnings({"deprecation", "removal"})
class PersistentMapCanvas implements MapCanvas {
private final int mapDataVersion;
@@ -454,7 +454,11 @@ public interface BukkitMapPersister {
final String BANNER_PREFIX = "banner_";
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, ""),

View File

@@ -5,7 +5,7 @@ website: 'https://william278.net/'
main: 'net.william278.husksync.PaperHuskSync'
loader: 'net.william278.husksync.PaperHuskSyncLoader'
version: '${version}'
api-version: '1.19'
api-version: '${minecraft_api_version}'
folia-supported: true
dependencies:
server:

View File

@@ -1,7 +1,7 @@
name: 'HuskSync'
version: '${version}'
main: 'net.william278.husksync.BukkitHuskSync'
api-version: 1.17
api-version: '${minecraft_api_version}'
author: 'William278'
description: '${description}'
website: 'https://william278.net'

View File

@@ -0,0 +1,7 @@
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

View File

@@ -0,0 +1,17 @@
{
"required": true,
"minVersion": "0.8",
"package": "net.william278.husksync.mixins",
"compatibilityLevel": "JAVA_17",
"server": [
"ItemEntityMixin",
"PlayerEntityMixin",
"ServerPlayerEntityMixin",
"ServerPlayNetworkHandlerMixin",
"ServerWorldMixin"
],
"client": [],
"injectors": {
"defaultRequire": 1
}
}

View File

@@ -0,0 +1,7 @@
essential.defaults.loom.mappings=net.fabricmc:yarn:1.21.1+build.3:v2
fabric_loader_version=0.16.10
fabric_api_version=0.107.0+1.21.1
fabric_permissions_api_version=0.3.1
fabric_adventure_platform_version=5.14.2
fabric_sgui_version=1.6.0+1.21

View File

@@ -0,0 +1,17 @@
{
"required": true,
"minVersion": "0.8",
"package": "net.william278.husksync.mixins",
"compatibilityLevel": "JAVA_17",
"server": [
"ItemEntityMixin",
"PlayerEntityMixin",
"ServerPlayerEntityMixin",
"ServerPlayNetworkHandlerMixin",
"ServerWorldMixin"
],
"client": [],
"injectors": {
"defaultRequire": 1
}
}

View File

@@ -0,0 +1,7 @@
essential.defaults.loom.mappings=net.fabricmc:yarn:1.21.4+build.4:v2
fabric_loader_version=0.16.10
fabric_api_version=0.115.0+1.21.4
fabric_permissions_api_version=0.3.3
fabric_adventure_platform_version=6.2.0
fabric_sgui_version=1.8.2+1.21.4

View File

@@ -1,8 +1,8 @@
plugins {
id 'fabric-loom' version "$fabric_loom_version"
id 'gg.essential.multi-version'
id 'gg.essential.defaults'
}
apply plugin: 'fabric-loom'
loom.serverOnlyMinecraftJar()
repositories {
@@ -11,30 +11,39 @@ repositories {
}
dependencies {
minecraft "com.mojang:minecraft:${minecraft_version}"
mappings "net.fabricmc:yarn:${fabric_yarn_mappings}:v2"
modImplementation "net.fabricmc:fabric-loader:${fabric_loader_version}"
modImplementation include("net.kyori:adventure-platform-fabric:${fabric_adventure_platform_version}")
modImplementation include("me.lucko:fabric-permissions-api:${fabric_permissions_api_version}")
modImplementation include("eu.pb4:sgui:${fabric_sgui_version}")
modImplementation include("net.william278.uniform:uniform-fabric:1.3.1+${minecraft_version}")
modCompileOnly "net.fabricmc.fabric-api:fabric-api:${fabric_api_version}"
modImplementation include("net.william278.uniform:uniform-fabric:1.3.1+${project.name}")
modImplementation "net.fabricmc.fabric-api:fabric-api:${fabric_api_version}"
implementation include('org.apache.commons:commons-pool2:2.12.1')
implementation include("redis.clients:jedis:$jedis_version")
implementation include("com.mysql:mysql-connector-j:$mysql_driver_version")
implementation include("org.mariadb.jdbc:mariadb-java-client:$mariadb_driver_version")
implementation include("org.postgresql:postgresql:$postgres_driver_version")
implementation include("org.mariadb.jdbc:mariadb-java-client:$mariadb_driver_version")
implementation include("redis.clients:jedis:$jedis_version")
implementation include("org.xerial.snappy:snappy-java:$snappy_version")
compileOnly 'org.jetbrains:annotations:26.0.2'
compileOnly 'net.william278:DesertWell:2.0.4'
compileOnly 'org.jetbrains:annotations:26.0.2'
compileOnly 'org.projectlombok:lombok:1.18.36'
annotationProcessor 'org.projectlombok:lombok:1.18.36'
shadow project(path: ":common")
implementation include(project(path: ":common"))
project(":common").configurations.api.dependencies.each { dependency ->
include(dependency)
}
}
processResources {
filesMatching(Arrays.asList("fabric.mod.json", "compatibility.yml")) {
expand([
version: version,
fabric_loader_version: fabric_loader_version,
fabric_minecraft_version: project.name
])
}
}
shadowJar {
@@ -44,20 +53,6 @@ shadowJar {
exclude('net.fabricmc:.*')
exclude('net.kyori:.*')
exclude '/mappings/*'
relocate 'org.apache.commons.io', 'net.william278.husksync.libraries.commons.io'
relocate 'org.apache.commons.text', 'net.william278.husksync.libraries.commons.text'
relocate 'org.apache.commons.lang3', 'net.william278.husksync.libraries.commons.lang3'
relocate 'com.google.gson', 'net.william278.husksync.libraries.gson'
relocate 'com.fatboyindustrial', 'net.william278.husksync.libraries'
relocate 'de.themoep', 'net.william278.husksync.libraries'
relocate 'org.jetbrains', 'net.william278.husksync.libraries'
relocate 'org.intellij', 'net.william278.husksync.libraries'
relocate 'com.zaxxer', 'net.william278.husksync.libraries'
relocate 'de.exlll', 'net.william278.husksync.libraries'
relocate 'net.william278.desertwell', 'net.william278.husksync.libraries.desertwell'
relocate 'net.william278.paginedown', 'net.william278.husksync.libraries.paginedown'
relocate 'org.json', 'net.william278.husksync.libraries.json'
}
remapJar {

10
fabric/gradle.properties Normal file
View File

@@ -0,0 +1,10 @@
loom.platform=fabric
essential.defaults.loom=1
essential.defaults.loom.fabric-loader=net.fabricmc:fabric-loader:0.16.10
org.gradle.daemon=false
org.gradle.parallel=true
org.gradle.configureoncommand=true
org.gradle.parallel.threads=4
org.gradle.jvmargs=-Xmx8G

1
fabric/mainProject Normal file
View File

@@ -0,0 +1 @@
1.21.4

13
fabric/root.gradle Normal file
View File

@@ -0,0 +1,13 @@
plugins {
id("gg.essential.multi-version.root")
}
preprocess {
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)
fabric12101.link(fabric12104, null)
fabric12001.link(fabric12104, null)
}

View File

@@ -31,8 +31,11 @@ import net.fabricmc.api.DedicatedServerModInitializer;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
import net.fabricmc.loader.api.FabricLoader;
import net.fabricmc.loader.api.ModContainer;
import net.kyori.adventure.platform.AudienceProvider;
//#if MC==12104
import net.kyori.adventure.platform.modcommon.MinecraftServerAudiences;
//#else
//$$ import net.kyori.adventure.platform.fabric.FabricServerAudiences;
//#endif
import net.minecraft.server.MinecraftServer;
import net.william278.desertwell.util.Version;
import net.william278.husksync.adapter.DataAdapter;
@@ -78,7 +81,6 @@ import java.util.logging.Level;
@Getter
@NoArgsConstructor
@SuppressWarnings("unchecked")
public class FabricHuskSync implements DedicatedServerModInitializer, HuskSync, FabricTask.Supplier,
FabricEventDispatcher {
@@ -111,7 +113,11 @@ public class FabricHuskSync implements DedicatedServerModInitializer, HuskSync,
private MinecraftServer minecraftServer;
private boolean disabling;
private Gson gson;
private AudienceProvider audiences;
//#if MC==12104
private MinecraftServerAudiences audiences;
//#else
//$$ private FabricServerAudiences audiences;
//#endif
private Database database;
private RedisManager redisManager;
private EventListener eventListener;
@@ -156,11 +162,21 @@ public class FabricHuskSync implements DedicatedServerModInitializer, HuskSync,
}
private void onEnable() {
// Initial plugin setup
// Audiences
//#if MC==12104
this.audiences = MinecraftServerAudiences.of(minecraftServer);
//#else
//$$ this.audiences = FabricServerAudiences.of(minecraftServer);
//#endif
// Check compatibility
checkCompatibility();
log(Level.WARNING, """
**************
WARNING:
HuskSync for Fabric is still in an alpha state and is
not considered production ready.
**************""");
// Prepare data adapter
initialize("data adapter", (plugin) -> {
@@ -352,7 +368,6 @@ public class FabricHuskSync implements DedicatedServerModInitializer, HuskSync,
return Version.fromString(minecraftServer.getVersion());
}
@NotNull
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;
@@ -367,7 +382,13 @@ public class FabricHuskSync implements DedicatedServerModInitializer, HuskSync,
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;
default -> VERSION1_21_4; // Current supported ver
//#if MC==12104
default -> VERSION1_21_4;
//#elseif MC==12101
//$$ default -> VERSION1_21_1;
//#elseif MC==12001
//$$ default -> VERSION1_20_1;
//#endif
};
}

View File

@@ -26,7 +26,12 @@ 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;
@@ -39,17 +44,19 @@ import net.minecraft.registry.Registry;
import net.minecraft.registry.entry.RegistryEntry;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.stat.StatType;
import net.minecraft.stat.Stats;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
import net.minecraft.world.TeleportTarget;
import net.william278.desertwell.util.ThrowingConsumer;
import net.william278.husksync.FabricHuskSync;
import net.william278.husksync.HuskSync;
import net.william278.husksync.adapter.Adaptable;
import net.william278.husksync.config.Settings.SynchronizationSettings.AttributeSettings;
//#if MC==12104
import net.william278.husksync.mixins.HungerManagerMixin;
//#endif
import net.william278.husksync.user.FabricUser;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -88,11 +95,24 @@ public abstract class FabricData implements Data {
stack.getItem().toString(),
stack.getCount(),
stack.getName().getString(),
stack.getComponents().get(DataComponentTypes.LORE).lines().stream().map(Text::getString).toList(),
//#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(),
stack.getEnchantments().getEnchantments().stream()
.map(RegistryEntry::getIdAsString)
.filter(Objects::nonNull)
.toList()
//#endif
) : null)
.toArray(Stack[]::new);
}
@@ -158,7 +178,11 @@ 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==12104
player.playerScreenHandler.getCraftingInput().clear();
//#else
//$$ player.playerScreenHandler.clearCraftingSlots();
//#endif
player.currentScreenHandler.setCursorStack(ItemStack.EMPTY);
final ItemStack[] items = getContents();
for (int slot = 0; slot < player.getInventory().size(); slot++) {
@@ -246,7 +270,11 @@ 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(),
@@ -268,10 +296,16 @@ 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
List<StatusEffect> effectsToRemove = new ArrayList<>(player.getActiveStatusEffects().keySet().stream()
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);
}
@@ -281,7 +315,11 @@ 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(),
@@ -313,12 +351,25 @@ public abstract class FabricData implements Data {
final AdvancementProgress advancementProgress = player.getAdvancementTracker().getProgress(advancementEntry);
final Map<String, Date> awardedCriteria = Maps.newHashMap();
advancementProgress.getObtainedCriteria().forEach((criteria) -> awardedCriteria.put(criteria,
Date.from(advancementProgress.getEarliestProgressObtainDate())));
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(advancementEntry.id().asString(), awardedCriteria));
advancements.add(Advancement.adapt(
//#if MC==12001
//$$ advancementEntry.getId().toString(),
//#else
advancementEntry.id().asString(),
//#endif
awardedCriteria
));
}
});
return new FabricData.Advancements(advancements);
@@ -336,7 +387,13 @@ public abstract class FabricData implements Data {
plugin.runAsync(() -> forEachAdvancementEntry(server, advancementEntry -> {
final AdvancementProgress progress = player.getAdvancementTracker().getProgress(advancementEntry);
final Optional<Advancement> record = completed.stream()
.filter(r -> r.getKey().equals(advancementEntry.id().toString()))
.filter(r -> r.getKey().equals(
//#if MC==12001
//$$ advancementEntry.getId().toString()
//#else
advancementEntry.id().asString()
//#endif
))
.findFirst();
if (record.isEmpty()) {
return;
@@ -353,7 +410,11 @@ 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,
@@ -378,8 +439,14 @@ 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,
@NotNull ThrowingConsumer<net.minecraft.advancement.AdvancementEntry> con) {
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);
}
@@ -411,6 +478,11 @@ 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(),
@@ -421,10 +493,8 @@ public abstract class FabricData implements Data {
Objects.requireNonNull(
player.getWorld(), "World is null"
).getRegistryKey().getValue().toString(),
UUID.nameUUIDFromBytes(
player.getWorld().getDimensionEntry().getIdAsString().getBytes()
),
player.getWorld().getDimensionEntry().getIdAsString()
UUID.nameUUIDFromBytes(worldName.getBytes()),
worldName
)
);
}
@@ -433,19 +503,21 @@ public abstract class FabricData implements Data {
public void apply(@NotNull FabricUser user, @NotNull FabricHuskSync plugin) throws IllegalStateException {
final ServerPlayerEntity player = user.getPlayer();
final MinecraftServer server = plugin.getMinecraftServer();
// Find world
final String worldName = world.name();
final ServerWorld target = server.getWorld(server.getWorldRegistryKeys().stream()
.filter(key -> key.getValue().equals(Identifier.tryParse(worldName))).findFirst()
.orElseThrow(() -> new IllegalStateException("Invalid target world: %s".formatted(worldName))));
// Apply teleport
try {
player.dismountVehicle();
player.teleportTo(
new TeleportTarget(
server.getWorld(server.getWorldRegistryKeys().stream()
.filter(key -> key.getValue().equals(Identifier.tryParse(world.name())))
.findFirst().orElseThrow(
() -> new IllegalStateException("Invalid world")
)),
player,
TeleportTarget.NO_OP
)
);
//#if MC==12104
player.teleport(target, x, y, z, Set.of(), yaw, pitch, true);
//#else
//$$ player.teleport(target, x, y, z, yaw, pitch);
//#endif
} catch (Throwable e) {
throw new IllegalStateException("Failed to apply location", e);
}
@@ -477,12 +549,21 @@ public abstract class FabricData implements Data {
final Map<String, Map<String, Integer>> blocks = Maps.newHashMap(),
items = Maps.newHashMap(), entities = Maps.newHashMap();
Registries.STAT_TYPE.getEntrySet().forEach(stat -> {
// This is necessary to prevent weird re-mappings with Registry#getKey()
//#if MC>0
//$$ final Registry<?> registry = stat.getValue().getRegistry();
//$$ final String registryId = registry.getKey().getValue().toString();
//$$ if (registryId.equals("custom_stat")) {
//$$ return;
//$$ }
//#else
final Registry<?> registry = stat.getValue().getRegistry();
final String registryId = registry.getKey().getValue().getPath();
final String registryId = registry.getKey().getValue().toString();
if (registryId.equals("custom_stat")) {
return;
}
//#endif
final Map<String, Integer> map = (switch (registryId) {
case BLOCK_STAT_TYPE -> blocks;
case ITEM_STAT_TYPE -> items;
@@ -574,6 +655,21 @@ 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())) {
@@ -586,6 +682,7 @@ public abstract class FabricData implements Data {
modifier.operation().getId(),
Modifier.ANY_EQUIPMENT_SLOT_GROUP
)));
//#endif
attributes.add(new Attribute(
key.toString(),
instance.getBaseValue(),
@@ -618,7 +715,11 @@ 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)
);
});
@@ -633,11 +734,20 @@ public abstract class FabricData implements Data {
instance.getModifiers().forEach(instance::removeModifier);
instance.setBaseValue(attribute == null ? instance.getValue() : attribute.baseValue());
if (attribute != null) {
//#if MC==12001
//$$ attribute.modifiers().forEach(modifier -> instance.addPersistentModifier(new EntityAttributeModifier(
//$$ modifier.uuid(),
//$$ modifier.name(),
//$$ modifier.amount(),
//$$ EntityAttributeModifier.Operation.fromId(modifier.operation())
//$$ )));
//#else
attribute.modifiers().forEach(modifier -> instance.addTemporaryModifier(new EntityAttributeModifier(
Identifier.of(modifier.uuid().toString()),
Identifier.of(modifier.name()),
modifier.amount(),
EntityAttributeModifier.Operation.ID_TO_VALUE.apply(modifier.operation())
)));
//#endif
}
}
@@ -694,7 +804,12 @@ public abstract class FabricData implements Data {
@NotNull
public static FabricData.Hunger adapt(@NotNull ServerPlayerEntity player) {
final HungerManager hunger = player.getHungerManager();
return from(hunger.getFoodLevel(), hunger.getSaturationLevel(), ((HungerManagerMixin) hunger).getExhaustion());
//#if MC==12104
float exhaustion = ((HungerManagerMixin) hunger).getExhaustion();
//#else
//$$ float exhaustion = hunger.getExhaustion();
//#endif
return from(hunger.getFoodLevel(), hunger.getSaturationLevel(), exhaustion);
}
@NotNull
@@ -708,7 +823,11 @@ public abstract class FabricData implements Data {
final HungerManager hunger = player.getHungerManager();
hunger.setFoodLevel(foodLevel);
hunger.setSaturationLevel(saturation);
//#if MC==12104
((HungerManagerMixin) hunger).setExhaustion(exhaustion);
//#else
//$$ hunger.setExhaustion(exhaustion);
//#endif
}
}

View File

@@ -26,6 +26,9 @@ 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;
@@ -154,7 +157,7 @@ public abstract class FabricSerializer {
final DynamicRegistryManager registryManager = plugin.getMinecraftServer().getRegistryManager();
itemList.forEach(element -> {
final NbtCompound compound = (NbtCompound) element;
contents[compound.getInt("Slot")] = ItemStack.fromNbt(registryManager, element).get();
contents[compound.getInt("Slot")] = decodeNbt(element, registryManager);
});
plugin.debug(Arrays.toString(contents));
return contents;
@@ -175,7 +178,8 @@ public abstract class FabricSerializer {
if (item == null || item.isEmpty()) {
continue;
}
NbtCompound entry = (NbtCompound) item.toNbt(registryManager);
final NbtCompound entry = encodeNbt(item, registryManager);
entry.putInt("Slot", i);
itemList.add(entry);
}
@@ -197,7 +201,7 @@ public abstract class FabricSerializer {
}
final NbtCompound compound = list.getCompound(i);
final int slot = compound.getInt("Slot");
itemStacks[slot] = ItemStack.fromNbt(registryManager, upgradeItemData(list.getCompound(i), mcVersion, plugin)).get();
itemStacks[slot] = decodeNbt(upgradeItemData(list.getCompound(i), mcVersion, plugin), registryManager);
}
return itemStacks;
}
@@ -212,6 +216,32 @@ public abstract class FabricSerializer {
).getValue();
}
@NotNull
private NbtCompound encodeNbt(@NotNull ItemStack item, @NotNull DynamicRegistryManager registryManager) {
//#if MC==12104
return (NbtCompound) item.toNbt(registryManager);
//#elseif MC==12101
//$$ return (NbtCompound) item.encode(registryManager);
//#elseif MC==12001
//$$ final NbtCompound compound = new NbtCompound();
//$$ item.writeNbt(compound);
//$$ return compound;
//#endif
}
@NotNull
private ItemStack decodeNbt(@NotNull NbtElement item, @NotNull DynamicRegistryManager registryManager) {
//#if MC==12001
//$$ final @Nullable ItemStack stack = ItemStack.fromNbt((NbtCompound) item);
//#else
final @Nullable ItemStack stack = ItemStack.fromNbt(registryManager, item).orElse(null);
//#endif
if (stack == null) {
throw new IllegalStateException("Failed to decode item NBT (got null 'fromNbt'): (%s)".formatted(item));
}
return stack;
}
}
public static class PotionEffects extends FabricSerializer implements Serializer<FabricData.PotionEffects> {

View File

@@ -104,7 +104,11 @@ 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
));
}

View File

@@ -39,6 +39,9 @@ import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
//#if MC<12104
//$$ import net.minecraft.util.TypedActionResult;
//#endif
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.hit.EntityHitResult;
import net.minecraft.util.math.BlockPos;
@@ -123,9 +126,16 @@ public class FabricEventListener extends EventListener implements LockedHandler
return (cancelPlayerEvent(player.getUuid())) ? ActionResult.FAIL : ActionResult.PASS;
}
//#if MC==12104
private ActionResult handleItemInteract(PlayerEntity player, World world, Hand hand) {
return (cancelPlayerEvent(player.getUuid())) ? ActionResult.FAIL : ActionResult.PASS;
}
//#else
//$$ private TypedActionResult<ItemStack> handleItemInteract(PlayerEntity player, World world, Hand hand) {
//$$ final ItemStack stackInHand = player.getStackInHand(hand);
//$$ return (cancelPlayerEvent(player.getUuid())) ? TypedActionResult.fail(stackInHand) : TypedActionResult.pass(stackInHand);
//$$ }
//#endif
private boolean handleBlockBreak(World world, PlayerEntity player, BlockPos blockPos, BlockState blockState, BlockEntity blockEntity) {
return !cancelPlayerEvent(player.getUuid());

View File

@@ -17,6 +17,7 @@
* limitations under the License.
*/
//#if MC==12104
package net.william278.husksync.mixins;
import net.minecraft.entity.player.HungerManager;
@@ -33,3 +34,4 @@ public interface HungerManagerMixin {
void setExhaustion(float exhaustion);
}
//#endif

View File

@@ -42,7 +42,7 @@ public class PlayerEntityMixin {
@Final
@Shadow
private PlayerInventory inventory;
PlayerInventory inventory;
@Inject(method = "dropInventory", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/player/PlayerEntity;vanishCursedItems()V"))
protected void dropInventory(@NotNull CallbackInfo ci) {
@@ -56,7 +56,7 @@ public class PlayerEntityMixin {
final @Nullable ItemStack @NotNull [] toKeep = new ItemStack[inventory.size()];
for (int i = 0; i < inventory.size(); ++i) {
ItemStack itemStack = inventory.getStack(i);
if (!itemStack.isEmpty() && EnchantmentHelper.hasAnyEnchantmentsIn(itemStack, TagKey.of(Enchantments.VANISHING_CURSE.getRegistryRef(), Enchantments.VANISHING_CURSE.getValue()))) {
if (!itemStack.isEmpty() && hasVanishingCurse(itemStack)) {
toKeep[i] = null;
continue;
}
@@ -71,7 +71,7 @@ public class PlayerEntityMixin {
final @Nullable ItemStack @NotNull [] toDrop = new ItemStack[inventory.size()];
for (int i = 0; i < inventory.size(); ++i) {
ItemStack itemStack = inventory.getStack(i);
if (!itemStack.isEmpty() && EnchantmentHelper.hasAnyEnchantmentsIn(itemStack, TagKey.of(Enchantments.VANISHING_CURSE.getRegistryRef(), Enchantments.VANISHING_CURSE.getValue()))) {
if (!itemStack.isEmpty() && hasVanishingCurse(itemStack)) {
toDrop[i] = itemStack;
continue;
}
@@ -80,4 +80,15 @@ public class PlayerEntityMixin {
return toDrop;
}
@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
}
}

View File

@@ -88,7 +88,11 @@ 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;
}
@@ -111,4 +115,5 @@ public abstract class ServerPlayNetworkHandlerMixin {
ci.cancel();
}
}
}

View File

@@ -36,7 +36,11 @@ public class ServerWorldMixin {
@Shadow
private MinecraftServer server;
//#if MC==12104
@Inject(method = "savePersistentState", at = @At("HEAD"))
//#else
//$$ @Inject(method = "saveLevel", at = @At("HEAD"))
//#endif
public void saveLevel(CallbackInfo ci) {
if (server.isStopping() || server.isStopped()) {
return;

View File

@@ -25,7 +25,11 @@ import eu.pb4.sgui.api.elements.GuiElementInterface;
import eu.pb4.sgui.api.gui.SimpleGui;
import me.lucko.fabric.api.permissions.v0.Permissions;
import net.kyori.adventure.audience.Audience;
//#if MC==12104
import net.kyori.adventure.platform.modcommon.MinecraftServerAudiences;
//#else
//$$ import net.kyori.adventure.platform.fabric.FabricServerAudiences;
//#endif
import net.minecraft.item.ItemStack;
import net.minecraft.screen.GenericContainerScreenHandler;
import net.minecraft.screen.ScreenHandlerType;
@@ -102,7 +106,11 @@ public class FabricUser extends OnlineUser implements FabricUserDataHolder {
this.editable = editable;
// Set title, items
//#if MC==12104
this.setTitle(((MinecraftServerAudiences) plugin.getAudiences()).asNative(title.toComponent()));
//#else
//$$ this.setTitle(((FabricServerAudiences) plugin.getAudiences()).toNative(title.toComponent()));
//#endif
this.setLockPlayerInventory(!editable);
for (int i = 0; i < size; i++) {
final ItemStack item = items.getContents()[i];

View File

@@ -0,0 +1,2 @@
# File used for checking Minecraft server compatibility with this version of HuskSync
minecraft_version: '${fabric_minecraft_version}'

View File

@@ -40,11 +40,12 @@
},
"depends": {
"fabricloader": ">=${fabric_loader_version}",
"minecraft": ">=${minecraft_version}",
"minecraft": "${fabric_minecraft_version}",
"fabric-api": "*"
},
"suggests": {
"plan": "*"
"luckperms": ">=5.4",
"plan": ">=5.5"
},
"mixins": [
"husksync.mixins.json"

View File

@@ -3,13 +3,12 @@ org.gradle.jvmargs='-Dfile.encoding=UTF-8'
org.gradle.daemon=true
javaVersion=21
# Plugin settings
# Plugin metadata
plugin_version=3.7.3
minecraft_version=1.21.4
plugin_archive=husksync
plugin_description=A modern, cross-server player data synchronization system
# Drivers
# General settings
jedis_version=5.2.0
mysql_driver_version=9.2.0
mariadb_driver_version=3.5.1
@@ -17,15 +16,5 @@ postgres_driver_version=42.7.5
mongodb_driver_version=5.3.1
snappy_version=1.1.10.7
# Spigot/Paper build settings
bukkit_spigot_api=1.21.4-R0.1-SNAPSHOT
bukkit_paper_api=1.21.4-R0.1-SNAPSHOT
# Fabric build settings
# Fabric settings
fabric_loom_version=1.9-SNAPSHOT
fabric_loader_version=0.16.10
fabric_yarn_mappings=1.21.4+build.8
fabric_api_version=0.115.0+1.21.4
fabric_adventure_platform_version=6.2.0
fabric_permissions_api_version=0.3.3
fabric_sgui_version=1.8.2+1.21.4

View File

@@ -1,54 +0,0 @@
plugins {
id 'xyz.jpenilla.run-paper' version '2.3.1'
}
dependencies {
implementation project(':bukkit')
compileOnly project(':common')
implementation 'net.william278.uniform:uniform-paper:1.3.1'
compileOnly "io.papermc.paper:paper-api:${bukkit_paper_api}"
compileOnly 'org.jetbrains:annotations:26.0.2'
compileOnly 'org.projectlombok:lombok:1.18.36'
annotationProcessor 'org.projectlombok:lombok:1.18.36'
}
shadowJar {
dependencies {
exclude(dependency('com.mojang:brigadier'))
}
relocate 'org.apache.commons.io', 'net.william278.husksync.libraries.commons.io'
relocate 'org.apache.commons.text', 'net.william278.husksync.libraries.commons.text'
relocate 'org.apache.commons.lang3', 'net.william278.husksync.libraries.commons.lang3'
relocate 'com.google.gson', 'net.william278.husksync.libraries.gson'
relocate 'com.fatboyindustrial', 'net.william278.husksync.libraries'
relocate 'de.themoep', 'net.william278.husksync.libraries'
relocate 'org.jetbrains', 'net.william278.husksync.libraries'
relocate 'org.intellij', 'net.william278.husksync.libraries'
relocate 'com.zaxxer', 'net.william278.husksync.libraries'
relocate 'de.exlll', 'net.william278.husksync.libraries'
relocate 'net.william278.uniform', 'net.william278.husksync.libraries.uniform'
relocate 'net.william278.desertwell', 'net.william278.husksync.libraries.desertwell'
relocate 'net.william278.paginedown', 'net.william278.husksync.libraries.paginedown'
relocate 'net.william278.mapdataapi', 'net.william278.husksync.libraries.mapdataapi'
relocate 'net.william278.mpdbconverter', 'net.william278.husksync.libraries.mpdbconverter'
relocate 'net.william278.hslmigrator', 'net.william278.husksync.libraries.hslconverter'
relocate 'org.json', 'net.william278.husksync.libraries.json'
relocate 'net.querz', 'net.william278.husksync.libraries.nbtparser'
relocate 'net.roxeez', 'net.william278.husksync.libraries'
relocate 'org.bstats', 'net.william278.husksync.libraries.bstats'
relocate 'dev.triumphteam.gui', 'net.william278.husksync.libraries.triumphgui'
relocate 'space.arim.morepaperlib', 'net.william278.husksync.libraries.paperlib'
relocate 'de.tr7zw.changeme.nbtapi', 'net.william278.husksync.libraries.nbtapi'
minimize()
}
tasks {
runServer {
minecraftVersion('1.21.4')
}
}

View File

@@ -1,14 +1,50 @@
pluginManagement {
repositories {
gradlePluginPortal()
maven { url 'https://repo.william278.net/releases' }
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' }
}
plugins {
def egtVersion = "0.6.5"
id("gg.essential.defaults") version egtVersion
id("gg.essential.multi-version.root") version egtVersion
}
}
// Common
rootProject.name = 'HuskSync'
include(
'common',
'bukkit',
'paper',
'fabric'
)
include("common")
// Bukkit
include("bukkit")
project(":bukkit").with {
projectDir = file("bukkit/")
buildFileName = "root.gradle"
}
file('bukkit').listFiles((FileFilter) ((File file) -> file.isDirectory() && file.name ==~ /(\d+)\.(\d+)(\.(\d+))?/)).each {
include("bukkit:$it.name")
project(":bukkit:$it.name").with {
projectDir = file("bukkit/${it.name}")
buildFileName = '../build.gradle'
}
}
// Fabric
include("fabric")
project(":fabric").with {
projectDir = file("fabric/")
buildFileName = "root.gradle"
}
file('fabric').listFiles((FileFilter) ((File file) -> file.isDirectory() && file.name ==~ /(\d+)\.(\d+)(\.(\d+))?/)).each {
include("fabric:$it.name")
project(":fabric:$it.name").with {
projectDir = file("fabric/${it.name}")
buildFileName = '../build.gradle'
}
}