mirror of
https://github.com/WiIIiam278/HuskSync.git
synced 2026-01-04 15:31:37 +00:00
Compare commits
41 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
52ec138273 | ||
|
|
0f7a866652 | ||
|
|
eeb52ac41e | ||
|
|
4c7ec9ec21 | ||
|
|
2f9064c4c6 | ||
|
|
5c234cdb1d | ||
|
|
7d8a74381b | ||
|
|
04a7793585 | ||
|
|
ea068529f6 | ||
|
|
fead3df0d8 | ||
|
|
0c5a42a344 | ||
|
|
75a2378ea8 | ||
|
|
662fc96ad5 | ||
|
|
07da1c04ce | ||
|
|
845abf370a | ||
|
|
83b5209a75 | ||
|
|
8e9850dd19 | ||
|
|
1d24209b68 | ||
|
|
da70a54d78 | ||
|
|
32ac57e2a4 | ||
|
|
c949c976d6 | ||
|
|
ab736829f2 | ||
|
|
4433926ce7 | ||
|
|
f819fd4d5e | ||
|
|
e7659255fe | ||
|
|
0dee2e8319 | ||
|
|
7b35c47315 | ||
|
|
5056a794d8 | ||
|
|
5e6068431a | ||
|
|
8d69508689 | ||
|
|
efb6d8a7de | ||
|
|
79d9778378 | ||
|
|
6a6695e447 | ||
|
|
8862e6cd70 | ||
|
|
0b29de9efc | ||
|
|
962cdfce0b | ||
|
|
0c527202e5 | ||
|
|
d4e33aa9d2 | ||
|
|
2fcd58fc18 | ||
|
|
3d10b2324f | ||
|
|
31419f3b97 |
20
.github/workflows/ci.yml
vendored
20
.github/workflows/ci.yml
vendored
@@ -42,3 +42,23 @@ jobs:
|
|||||||
- name: Get Version
|
- name: Get Version
|
||||||
run: |
|
run: |
|
||||||
echo "version_name=${{steps.fetch-version.outputs.VERSION_NAME}}" >> $GITHUB_ENV
|
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
|
||||||
|
fabric-1.20.1
|
||||||
|
distro-groups: |
|
||||||
|
paper
|
||||||
|
fabric
|
||||||
|
distro-descriptions: |
|
||||||
|
Paper
|
||||||
|
Fabric 1.20.1
|
||||||
|
files: |
|
||||||
|
target/HuskSync-Paper-${{ env.version_name }}.jar
|
||||||
|
target/HuskSync-Fabric-${{ env.version_name }}+mc.1.20.1.jar
|
||||||
20
.github/workflows/release.yml
vendored
20
.github/workflows/release.yml
vendored
@@ -31,3 +31,23 @@ jobs:
|
|||||||
if: success() || failure() # Continue on failure
|
if: success() || failure() # Continue on failure
|
||||||
with:
|
with:
|
||||||
report_paths: '**/build/test-results/test/TEST-*.xml'
|
report_paths: '**/build/test-results/test/TEST-*.xml'
|
||||||
|
- name: 'Publish to William278.net 🚀'
|
||||||
|
uses: WiIIiam278/bones-publish-action@v1
|
||||||
|
with:
|
||||||
|
api-key: ${{ secrets.BONES_API_KEY }}
|
||||||
|
project: 'husksync'
|
||||||
|
channel: 'release'
|
||||||
|
version: ${{ github.event.release.tag_name }}
|
||||||
|
changelog: ${{ github.event.release.body }}
|
||||||
|
distro-names: |
|
||||||
|
paper
|
||||||
|
fabric-1.20.1
|
||||||
|
distro-groups: |
|
||||||
|
paper
|
||||||
|
fabric
|
||||||
|
distro-descriptions: |
|
||||||
|
Paper
|
||||||
|
Fabric 1.20.1
|
||||||
|
files: |
|
||||||
|
target/HuskSync-Paper-${{ github.event.release.tag_name }}.jar
|
||||||
|
target/HuskSync-Fabric-${{ github.event.release.tag_name }}+mc.1.20.1.jar
|
||||||
10
build.gradle
10
build.gradle
@@ -83,9 +83,9 @@ allprojects {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.10.2'
|
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.10.3'
|
||||||
testImplementation 'org.junit.jupiter:junit-jupiter-params:5.10.2'
|
testImplementation 'org.junit.jupiter:junit-jupiter-params:5.10.3'
|
||||||
testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.10.2'
|
testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.10.3'
|
||||||
}
|
}
|
||||||
|
|
||||||
test {
|
test {
|
||||||
@@ -99,9 +99,11 @@ allprojects {
|
|||||||
}
|
}
|
||||||
|
|
||||||
processResources {
|
processResources {
|
||||||
|
def tokenMap = rootProject.ext.properties
|
||||||
|
tokenMap.merge("grgit",'',(s, s2) -> s)
|
||||||
filesMatching(['**/*.json', '**/*.yml']) {
|
filesMatching(['**/*.json', '**/*.yml']) {
|
||||||
filter ReplaceTokens as Class, beginToken: '${', endToken: '}',
|
filter ReplaceTokens as Class, beginToken: '${', endToken: '}',
|
||||||
tokens: rootProject.ext.properties
|
tokens: tokenMap
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,20 @@
|
|||||||
dependencies {
|
dependencies {
|
||||||
implementation project(path: ':common')
|
implementation project(path: ':common')
|
||||||
|
|
||||||
implementation 'net.william278.uniform:uniform-bukkit:1.1.8'
|
implementation 'net.william278.uniform:uniform-bukkit:1.2.1'
|
||||||
implementation 'net.william278:mpdbdataconverter:1.0.1'
|
implementation 'net.william278:mpdbdataconverter:1.0.1'
|
||||||
implementation 'net.william278:hsldataconverter:1.0'
|
implementation 'net.william278:hsldataconverter:1.0'
|
||||||
implementation 'net.william278:mapdataapi:1.0.3'
|
implementation 'net.william278:mapdataapi:1.0.3'
|
||||||
implementation 'net.william278:andjam:1.0.2'
|
|
||||||
implementation 'org.bstats:bstats-bukkit:3.0.2'
|
implementation 'org.bstats:bstats-bukkit:3.0.2'
|
||||||
implementation 'net.kyori:adventure-platform-bukkit:4.3.3'
|
implementation 'net.kyori:adventure-platform-bukkit:4.3.3'
|
||||||
implementation 'dev.triumphteam:triumph-gui:3.1.10'
|
implementation 'dev.triumphteam:triumph-gui:3.1.10'
|
||||||
implementation 'space.arim.morepaperlib:morepaperlib:0.4.4'
|
implementation 'space.arim.morepaperlib:morepaperlib:0.4.4'
|
||||||
implementation 'de.tr7zw:item-nbt-api:2.13.1-SNAPSHOT'
|
implementation 'de.tr7zw:item-nbt-api:2.13.2'
|
||||||
|
|
||||||
compileOnly 'org.spigotmc:spigot-api:1.17.1-R0.1-SNAPSHOT'
|
compileOnly 'org.spigotmc:spigot-api:1.17.1-R0.1-SNAPSHOT'
|
||||||
compileOnly 'com.github.retrooper.packetevents:spigot:2.3.0'
|
compileOnly 'com.github.retrooper.packetevents:spigot:2.3.0'
|
||||||
compileOnly 'com.comphenix.protocol:ProtocolLib:5.1.0'
|
compileOnly 'com.comphenix.protocol:ProtocolLib:5.1.0'
|
||||||
compileOnly 'org.projectlombok:lombok:1.18.32'
|
compileOnly 'org.projectlombok:lombok:1.18.34'
|
||||||
compileOnly 'commons-io:commons-io:2.16.1'
|
compileOnly 'commons-io:commons-io:2.16.1'
|
||||||
compileOnly 'org.json:json:20240303'
|
compileOnly 'org.json:json:20240303'
|
||||||
compileOnly 'net.william278:minedown:1.8.2'
|
compileOnly 'net.william278:minedown:1.8.2'
|
||||||
@@ -25,7 +24,7 @@ dependencies {
|
|||||||
compileOnly 'net.william278:AdvancementAPI:97a9583413'
|
compileOnly 'net.william278:AdvancementAPI:97a9583413'
|
||||||
compileOnly "redis.clients:jedis:$jedis_version"
|
compileOnly "redis.clients:jedis:$jedis_version"
|
||||||
|
|
||||||
annotationProcessor 'org.projectlombok:lombok:1.18.32'
|
annotationProcessor 'org.projectlombok:lombok:1.18.34'
|
||||||
}
|
}
|
||||||
|
|
||||||
shadowJar {
|
shadowJar {
|
||||||
@@ -46,7 +45,6 @@ shadowJar {
|
|||||||
relocate 'net.william278.desertwell', 'net.william278.husksync.libraries.desertwell'
|
relocate 'net.william278.desertwell', 'net.william278.husksync.libraries.desertwell'
|
||||||
relocate 'net.william278.paginedown', 'net.william278.husksync.libraries.paginedown'
|
relocate 'net.william278.paginedown', 'net.william278.husksync.libraries.paginedown'
|
||||||
relocate 'net.william278.mapdataapi', 'net.william278.husksync.libraries.mapdataapi'
|
relocate 'net.william278.mapdataapi', 'net.william278.husksync.libraries.mapdataapi'
|
||||||
relocate 'net.william278.andjam', 'net.william278.husksync.libraries.andjam'
|
|
||||||
relocate 'net.william278.mpdbconverter', 'net.william278.husksync.libraries.mpdbconverter'
|
relocate 'net.william278.mpdbconverter', 'net.william278.husksync.libraries.mpdbconverter'
|
||||||
relocate 'net.william278.hslmigrator', 'net.william278.husksync.libraries.hslconverter'
|
relocate 'net.william278.hslmigrator', 'net.william278.husksync.libraries.hslconverter'
|
||||||
relocate 'org.json', 'net.william278.husksync.libraries.json'
|
relocate 'org.json', 'net.william278.husksync.libraries.json'
|
||||||
|
|||||||
@@ -290,7 +290,7 @@ public class BukkitHuskSync extends JavaPlugin implements HuskSync, BukkitTask.S
|
|||||||
@Override
|
@Override
|
||||||
public boolean isDependencyLoaded(@NotNull String name) {
|
public boolean isDependencyLoaded(@NotNull String name) {
|
||||||
final Plugin plugin = getServer().getPluginManager().getPlugin(name);
|
final Plugin plugin = getServer().getPluginManager().getPlugin(name);
|
||||||
return plugin != null && plugin.isEnabled();
|
return plugin != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register bStats metrics
|
// Register bStats metrics
|
||||||
@@ -333,6 +333,12 @@ public class BukkitHuskSync extends JavaPlugin implements HuskSync, BukkitTask.S
|
|||||||
return PLATFORM_TYPE_ID;
|
return PLATFORM_TYPE_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NotNull
|
||||||
|
public String getServerVersion() {
|
||||||
|
return String.format("%s/%s", getServer().getName(), getServer().getVersion());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<LegacyConverter> getLegacyConverter() {
|
public Optional<LegacyConverter> getLegacyConverter() {
|
||||||
return Optional.of(legacyConverter);
|
return Optional.of(legacyConverter);
|
||||||
|
|||||||
@@ -25,16 +25,15 @@ import com.google.gson.annotations.SerializedName;
|
|||||||
import de.tr7zw.changeme.nbtapi.NBTCompound;
|
import de.tr7zw.changeme.nbtapi.NBTCompound;
|
||||||
import de.tr7zw.changeme.nbtapi.NBTPersistentDataContainer;
|
import de.tr7zw.changeme.nbtapi.NBTPersistentDataContainer;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
|
import net.kyori.adventure.util.TriState;
|
||||||
import net.william278.desertwell.util.ThrowingConsumer;
|
import net.william278.desertwell.util.ThrowingConsumer;
|
||||||
import net.william278.desertwell.util.Version;
|
import net.william278.desertwell.util.Version;
|
||||||
import net.william278.husksync.BukkitHuskSync;
|
import net.william278.husksync.BukkitHuskSync;
|
||||||
import net.william278.husksync.HuskSync;
|
import net.william278.husksync.HuskSync;
|
||||||
import net.william278.husksync.adapter.Adaptable;
|
import net.william278.husksync.adapter.Adaptable;
|
||||||
|
import net.william278.husksync.config.Settings.SynchronizationSettings.AttributeSettings;
|
||||||
import net.william278.husksync.user.BukkitUser;
|
import net.william278.husksync.user.BukkitUser;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.*;
|
||||||
import org.bukkit.Material;
|
|
||||||
import org.bukkit.Registry;
|
|
||||||
import org.bukkit.Statistic;
|
|
||||||
import org.bukkit.advancement.AdvancementProgress;
|
import org.bukkit.advancement.AdvancementProgress;
|
||||||
import org.bukkit.attribute.AttributeInstance;
|
import org.bukkit.attribute.AttributeInstance;
|
||||||
import org.bukkit.attribute.AttributeModifier;
|
import org.bukkit.attribute.AttributeModifier;
|
||||||
@@ -48,7 +47,9 @@ import org.bukkit.potion.PotionEffectType;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.annotations.Range;
|
import org.jetbrains.annotations.Range;
|
||||||
|
import org.jetbrains.annotations.Unmodifiable;
|
||||||
|
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@@ -236,8 +237,9 @@ public abstract class BukkitData implements Data {
|
|||||||
private final Collection<PotionEffect> effects;
|
private final Collection<PotionEffect> effects;
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static BukkitData.PotionEffects from(@NotNull Collection<PotionEffect> effects) {
|
public static BukkitData.PotionEffects from(@NotNull Collection<PotionEffect> sei) {
|
||||||
return new BukkitData.PotionEffects(effects);
|
return new BukkitData.PotionEffects(Lists.newArrayList(sei.stream().filter(e -> !e.isAmbient()).toList()));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@@ -261,7 +263,7 @@ public abstract class BukkitData implements Data {
|
|||||||
@NotNull
|
@NotNull
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public static BukkitData.PotionEffects empty() {
|
public static BukkitData.PotionEffects empty() {
|
||||||
return new BukkitData.PotionEffects(List.of());
|
return new BukkitData.PotionEffects(Lists.newArrayList());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -277,6 +279,7 @@ public abstract class BukkitData implements Data {
|
|||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
|
@Unmodifiable
|
||||||
public List<Effect> getActiveEffects() {
|
public List<Effect> getActiveEffects() {
|
||||||
return effects.stream()
|
return effects.stream()
|
||||||
.map(potionEffect -> new Effect(
|
.map(potionEffect -> new Effect(
|
||||||
@@ -565,19 +568,24 @@ public abstract class BukkitData implements Data {
|
|||||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
public static class Attributes extends BukkitData implements Data.Attributes, Adaptable {
|
public static class Attributes extends BukkitData implements Data.Attributes, Adaptable {
|
||||||
|
|
||||||
|
private static final String EQUIPMENT_SLOT_GROUP = "org.bukkit.inventory.EquipmentSlotGroup";
|
||||||
|
private static final String EQUIPMENT_SLOT_GROUP$ANY = "ANY";
|
||||||
|
private static final String EQUIPMENT_SLOT$getGroup = "getGroup";
|
||||||
|
private static TriState USE_KEYED_MODIFIERS = TriState.NOT_SET;
|
||||||
|
|
||||||
private List<Attribute> attributes;
|
private List<Attribute> attributes;
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static BukkitData.Attributes adapt(@NotNull Player player, @NotNull HuskSync plugin) {
|
public static BukkitData.Attributes adapt(@NotNull Player player, @NotNull HuskSync plugin) {
|
||||||
final List<Attribute> attributes = Lists.newArrayList();
|
final List<Attribute> attributes = Lists.newArrayList();
|
||||||
|
final AttributeSettings settings = plugin.getSettings().getSynchronization().getAttributes();
|
||||||
Registry.ATTRIBUTE.forEach(id -> {
|
Registry.ATTRIBUTE.forEach(id -> {
|
||||||
final AttributeInstance instance = player.getAttribute(id);
|
final AttributeInstance instance = player.getAttribute(id);
|
||||||
if (instance == null || instance.getValue() == instance.getDefaultValue() || plugin
|
if (instance == null || Double.compare(instance.getValue(), instance.getDefaultValue()) == 0
|
||||||
.getSettings().getSynchronization().isIgnoredAttribute(id.getKey().toString())) {
|
|| settings.isIgnoredAttribute(id.getKey().toString())) {
|
||||||
// We don't sync unmodified or disabled attributes
|
return; // We don't sync unmodified or disabled attributes
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
attributes.add(adapt(instance, plugin.getMinecraftVersion()));
|
attributes.add(adapt(instance, settings));
|
||||||
});
|
});
|
||||||
return new BukkitData.Attributes(attributes);
|
return new BukkitData.Attributes(attributes);
|
||||||
}
|
}
|
||||||
@@ -596,18 +604,20 @@ public abstract class BukkitData implements Data {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private static Attribute adapt(@NotNull AttributeInstance instance, @NotNull Version version) {
|
private static Attribute adapt(@NotNull AttributeInstance instance, @NotNull AttributeSettings settings) {
|
||||||
return new Attribute(
|
return new Attribute(
|
||||||
instance.getAttribute().getKey().toString(),
|
instance.getAttribute().getKey().toString(),
|
||||||
instance.getBaseValue(),
|
instance.getBaseValue(),
|
||||||
instance.getModifiers().stream().map(m -> adapt(m, version)).collect(Collectors.toSet())
|
instance.getModifiers().stream()
|
||||||
|
.filter(modifier -> !settings.isIgnoredModifier(modifier.getName()))
|
||||||
|
.map(BukkitData.Attributes::adapt).collect(Collectors.toSet())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private static Modifier adapt(@NotNull AttributeModifier modifier, @NotNull Version version) {
|
private static Modifier adapt(@NotNull AttributeModifier modifier) {
|
||||||
return new Modifier(
|
return new Modifier(
|
||||||
version.compareTo(Version.fromString("1.21")) >= 0 ? null : modifier.getUniqueId(),
|
getModifierId(modifier),
|
||||||
modifier.getName(),
|
modifier.getName(),
|
||||||
modifier.getAmount(),
|
modifier.getAmount(),
|
||||||
modifier.getOperation().ordinal(),
|
modifier.getOperation().ordinal(),
|
||||||
@@ -615,26 +625,81 @@ public abstract class BukkitData implements Data {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Nullable
|
||||||
public void apply(@NotNull BukkitUser user, @NotNull BukkitHuskSync plugin) throws IllegalStateException {
|
private static UUID getModifierId(@NotNull AttributeModifier modifier) {
|
||||||
Registry.ATTRIBUTE.forEach(id -> applyAttribute(user.getPlayer().getAttribute(id), getAttribute(id).orElse(null)));
|
try {
|
||||||
|
return modifier.getUniqueId();
|
||||||
|
} catch (Throwable e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void applyAttribute(@Nullable AttributeInstance instance, @Nullable Attribute attribute) {
|
private static boolean useKeyedModifiers(@NotNull HuskSync plugin) {
|
||||||
|
if (USE_KEYED_MODIFIERS == TriState.NOT_SET) {
|
||||||
|
boolean is1_21 = plugin.getMinecraftVersion().compareTo(Version.fromString("1.21")) >= 0;
|
||||||
|
USE_KEYED_MODIFIERS = TriState.byBoolean(is1_21);
|
||||||
|
return is1_21;
|
||||||
|
}
|
||||||
|
return Boolean.TRUE.equals(USE_KEYED_MODIFIERS.toBoolean());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void applyAttribute(@Nullable AttributeInstance instance, @Nullable Attribute attribute,
|
||||||
|
@NotNull HuskSync plugin) {
|
||||||
if (instance == null) {
|
if (instance == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
instance.setBaseValue(attribute == null ? instance.getDefaultValue() : attribute.baseValue());
|
instance.setBaseValue(attribute == null ? instance.getDefaultValue() : attribute.baseValue());
|
||||||
instance.getModifiers().forEach(instance::removeModifier);
|
instance.getModifiers().forEach(instance::removeModifier);
|
||||||
if (attribute != null) {
|
if (attribute != null) {
|
||||||
attribute.modifiers().forEach(modifier -> instance.addModifier(new AttributeModifier(
|
attribute.modifiers().stream()
|
||||||
|
.filter(mod -> instance.getModifiers().stream().map(AttributeModifier::getName)
|
||||||
|
.noneMatch(n -> n.equals(mod.name())))
|
||||||
|
.distinct()
|
||||||
|
.filter(mod -> useKeyedModifiers(plugin) == !mod.hasUuid())
|
||||||
|
.forEach(mod -> instance.addModifier(adapt(mod, plugin)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("JavaReflectionMemberAccess")
|
||||||
|
@NotNull
|
||||||
|
private static AttributeModifier adapt(@NotNull Modifier modifier, @NotNull HuskSync plugin) {
|
||||||
|
final int slotId = modifier.equipmentSlot();
|
||||||
|
if (useKeyedModifiers(plugin)) {
|
||||||
|
try {
|
||||||
|
// Reflexively create a modern keyed attribute modifier instance. Remove in favor of API long-term.
|
||||||
|
final EquipmentSlot slot = slotId != -1 ? EquipmentSlot.values()[slotId] : null;
|
||||||
|
final Class<?> slotGroup = Class.forName(EQUIPMENT_SLOT_GROUP);
|
||||||
|
final String modifierName = modifier.name() == null ? modifier.uuid().toString() : modifier.name();
|
||||||
|
final NamespacedKey modifierKey = Objects.requireNonNull(NamespacedKey.fromString(modifierName),
|
||||||
|
"Modifier key returned null");
|
||||||
|
final Constructor<AttributeModifier> constructor = AttributeModifier.class.getDeclaredConstructor(
|
||||||
|
NamespacedKey.class, double.class, AttributeModifier.Operation.class, slotGroup);
|
||||||
|
return constructor.newInstance(
|
||||||
|
modifierKey,
|
||||||
|
modifier.amount(),
|
||||||
|
AttributeModifier.Operation.values()[modifier.operationType()],
|
||||||
|
slot == null ? slotGroup.getField(EQUIPMENT_SLOT_GROUP$ANY).get(null)
|
||||||
|
: EquipmentSlot.class.getDeclaredMethod(EQUIPMENT_SLOT$getGroup).invoke(slot)
|
||||||
|
);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
plugin.log(Level.WARNING, "Error reflectively creating keyed attribute modifier", e);
|
||||||
|
USE_KEYED_MODIFIERS = TriState.FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new AttributeModifier(
|
||||||
modifier.uuid(),
|
modifier.uuid(),
|
||||||
modifier.name(),
|
modifier.name(),
|
||||||
modifier.amount(),
|
modifier.amount(),
|
||||||
AttributeModifier.Operation.values()[modifier.operationType()],
|
AttributeModifier.Operation.values()[modifier.operationType()],
|
||||||
modifier.equipmentSlot() != -1 ? EquipmentSlot.values()[modifier.equipmentSlot()] : null
|
slotId != -1 ? EquipmentSlot.values()[slotId] : null
|
||||||
)));
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void apply(@NotNull BukkitUser user, @NotNull BukkitHuskSync plugin) throws IllegalStateException {
|
||||||
|
Registry.ATTRIBUTE.forEach(id -> applyAttribute(
|
||||||
|
user.getPlayer().getAttribute(id), getAttribute(id).orElse(null), plugin
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -696,11 +761,12 @@ public abstract class BukkitData implements Data {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set health scale
|
// Set health scale
|
||||||
|
double scale = healthScale <= 0 ? player.getMaxHealth() : healthScale;
|
||||||
try {
|
try {
|
||||||
player.setHealthScale(healthScale);
|
player.setHealthScale(scale);
|
||||||
player.setHealthScaled(isHealthScaled);
|
player.setHealthScaled(isHealthScaled);
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
plugin.log(Level.WARNING, "Error setting %s's health scale to %s".formatted(player.getName(), healthScale), e);
|
plugin.log(Level.WARNING, "Error setting %s's health scale to %s".formatted(player.getName(), scale), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -165,6 +165,7 @@ public class BukkitSerializer {
|
|||||||
case "1.20", "1.20.1", "1.20.2" -> DataFixerUtil.VERSION1_20_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.3", "1.20.4" -> DataFixerUtil.VERSION1_20_4;
|
||||||
case "1.20.5", "1.20.6" -> DataFixerUtil.VERSION1_20_5;
|
case "1.20.5", "1.20.6" -> DataFixerUtil.VERSION1_20_5;
|
||||||
|
case "1.21" -> DataFixerUtil.VERSION1_21;
|
||||||
default -> DataFixerUtil.getCurrentVersion();
|
default -> DataFixerUtil.getCurrentVersion();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import com.github.retrooper.packetevents.PacketEvents;
|
|||||||
import com.github.retrooper.packetevents.event.PacketListenerAbstract;
|
import com.github.retrooper.packetevents.event.PacketListenerAbstract;
|
||||||
import com.github.retrooper.packetevents.event.PacketListenerPriority;
|
import com.github.retrooper.packetevents.event.PacketListenerPriority;
|
||||||
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||||
|
import com.github.retrooper.packetevents.event.PacketSendEvent;
|
||||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
import io.github.retrooper.packetevents.factory.spigot.SpigotPacketEventsBuilder;
|
import io.github.retrooper.packetevents.factory.spigot.SpigotPacketEventsBuilder;
|
||||||
@@ -89,6 +90,19 @@ public class BukkitPacketEventsLockedPacketListener extends BukkitLockedEventLis
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPacketSend(PacketSendEvent event) {
|
||||||
|
if (!(event.getPacketType() instanceof PacketType.Play.Client client)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!CANCEL_PACKETS.contains(client)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (listener.cancelPlayerEvent(event.getUser().getUUID())) {
|
||||||
|
event.setCancelled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Returns the set of ALL Server packets, excluding the set of allowed packets
|
// Returns the set of ALL Server packets, excluding the set of allowed packets
|
||||||
@NotNull
|
@NotNull
|
||||||
private static Set<PacketType.Play.Client> getPacketsToListenFor() {
|
private static Set<PacketType.Play.Client> getPacketsToListenFor() {
|
||||||
|
|||||||
@@ -255,7 +255,7 @@ public class MpdbMigrator extends Migrator {
|
|||||||
If any of these are not correct, please correct them
|
If any of these are not correct, please correct them
|
||||||
using the command:
|
using the command:
|
||||||
"husksync migrate mpdb set <parameter> <value>"
|
"husksync migrate mpdb set <parameter> <value>"
|
||||||
(e.g.: "husksync migrate mpdb set host 1.2.3.4")
|
(e.g.: "husksync migrate set mpdb host 1.2.3.4")
|
||||||
|
|
||||||
STEP 3] HuskSync will migrate data into the database
|
STEP 3] HuskSync will migrate data into the database
|
||||||
tables configures in the config.yml file of this
|
tables configures in the config.yml file of this
|
||||||
@@ -263,7 +263,7 @@ public class MpdbMigrator extends Migrator {
|
|||||||
before proceeding.
|
before proceeding.
|
||||||
|
|
||||||
STEP 4] To start the migration, please run:
|
STEP 4] To start the migration, please run:
|
||||||
"husksync migrate mpdb start"
|
"husksync migrate start mpdb"
|
||||||
|
|
||||||
NOTE: This migrator currently WORKS WITH MPDB version
|
NOTE: This migrator currently WORKS WITH MPDB version
|
||||||
v4.9.2 and below!
|
v4.9.2 and below!
|
||||||
|
|||||||
@@ -23,14 +23,10 @@ import de.themoep.minedown.adventure.MineDown;
|
|||||||
import dev.triumphteam.gui.builder.gui.StorageBuilder;
|
import dev.triumphteam.gui.builder.gui.StorageBuilder;
|
||||||
import dev.triumphteam.gui.guis.Gui;
|
import dev.triumphteam.gui.guis.Gui;
|
||||||
import dev.triumphteam.gui.guis.StorageGui;
|
import dev.triumphteam.gui.guis.StorageGui;
|
||||||
import net.roxeez.advancement.display.FrameType;
|
|
||||||
import net.william278.andjam.Toast;
|
|
||||||
import net.william278.husksync.BukkitHuskSync;
|
|
||||||
import net.william278.husksync.HuskSync;
|
import net.william278.husksync.HuskSync;
|
||||||
import net.william278.husksync.data.BukkitData;
|
import net.william278.husksync.data.BukkitData;
|
||||||
import net.william278.husksync.data.BukkitUserDataHolder;
|
import net.william278.husksync.data.BukkitUserDataHolder;
|
||||||
import net.william278.husksync.data.Data;
|
import net.william278.husksync.data.Data;
|
||||||
import org.bukkit.Material;
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
@@ -40,8 +36,6 @@ import java.util.Arrays;
|
|||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
import static net.william278.husksync.util.BukkitKeyedAdapter.matchMaterial;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bukkit platform implementation of an {@link OnlineUser}
|
* Bukkit platform implementation of an {@link OnlineUser}
|
||||||
*/
|
*/
|
||||||
@@ -68,20 +62,12 @@ public class BukkitUser extends OnlineUser implements BukkitUserDataHolder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Deprecated(since = "3.6.7")
|
||||||
public void sendToast(@NotNull MineDown title, @NotNull MineDown description,
|
public void sendToast(@NotNull MineDown title, @NotNull MineDown description,
|
||||||
@NotNull String iconMaterial, @NotNull String backgroundType) {
|
@NotNull String iconMaterial, @NotNull String backgroundType) {
|
||||||
try {
|
plugin.log(Level.WARNING, "Toast notifications are deprecated. " +
|
||||||
final Material material = matchMaterial(iconMaterial);
|
"Please change your notification display slot to CHAT, ACTION_BAR or NONE.");
|
||||||
Toast.builder((BukkitHuskSync) plugin)
|
this.sendActionBar(title);
|
||||||
.setTitle(title.toComponent())
|
|
||||||
.setDescription(description.toComponent())
|
|
||||||
.setIcon(material != null ? material : Material.BARRIER)
|
|
||||||
.setFrameType(FrameType.valueOf(backgroundType))
|
|
||||||
.build()
|
|
||||||
.show(player);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
plugin.log(Level.WARNING, "Failed to send toast to player " + player.getName(), e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -424,6 +424,7 @@ public interface BukkitMapPersister {
|
|||||||
@NotNull
|
@NotNull
|
||||||
private MapData extractMapData() {
|
private MapData extractMapData() {
|
||||||
final List<MapBanner> banners = Lists.newArrayList();
|
final List<MapBanner> banners = Lists.newArrayList();
|
||||||
|
try {
|
||||||
final String BANNER_PREFIX = "banner_";
|
final String BANNER_PREFIX = "banner_";
|
||||||
for (int i = 0; i < getCursors().size(); i++) {
|
for (int i = 0; i < getCursors().size(); i++) {
|
||||||
final MapCursor cursor = getCursors().getCursor(i);
|
final MapCursor cursor = getCursors().getCursor(i);
|
||||||
@@ -437,6 +438,9 @@ public interface BukkitMapPersister {
|
|||||||
cursor.getY()
|
cursor.getY()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
} catch (Throwable ignored) {
|
||||||
}
|
}
|
||||||
return MapData.fromPixels(pixels, getDimension(), (byte) 2, banners, List.of());
|
return MapData.fromPixels(pixels, getDimension(), (byte) 2, banners, List.of());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,9 +16,9 @@ dependencies {
|
|||||||
exclude module: 'slf4j-api'
|
exclude module: 'slf4j-api'
|
||||||
}
|
}
|
||||||
|
|
||||||
compileOnly 'net.william278.uniform:uniform-common:1.1.8'
|
compileOnly 'net.william278.uniform:uniform-common:1.2.1'
|
||||||
compileOnly 'com.mojang:brigadier:1.1.8'
|
compileOnly 'com.mojang:brigadier:1.1.8'
|
||||||
compileOnly 'org.projectlombok:lombok:1.18.32'
|
compileOnly 'org.projectlombok:lombok:1.18.34'
|
||||||
compileOnly 'org.jetbrains:annotations:24.1.0'
|
compileOnly 'org.jetbrains:annotations:24.1.0'
|
||||||
compileOnly 'net.kyori:adventure-api:4.17.0'
|
compileOnly 'net.kyori:adventure-api:4.17.0'
|
||||||
compileOnly 'net.kyori:adventure-platform-api:4.3.3'
|
compileOnly 'net.kyori:adventure-platform-api:4.3.3'
|
||||||
@@ -38,5 +38,5 @@ dependencies {
|
|||||||
testCompileOnly 'de.exlll:configlib-yaml:4.5.0'
|
testCompileOnly 'de.exlll:configlib-yaml:4.5.0'
|
||||||
testCompileOnly 'org.jetbrains:annotations:24.1.0'
|
testCompileOnly 'org.jetbrains:annotations:24.1.0'
|
||||||
|
|
||||||
annotationProcessor 'org.projectlombok:lombok:1.18.32'
|
annotationProcessor 'org.projectlombok:lombok:1.18.34'
|
||||||
}
|
}
|
||||||
@@ -255,6 +255,14 @@ public interface HuskSync extends Task.Supplier, EventDispatcher, ConfigProvider
|
|||||||
@NotNull
|
@NotNull
|
||||||
String getPlatformType();
|
String getPlatformType();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the server software version
|
||||||
|
*
|
||||||
|
* @return the server software version string
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
String getServerVersion();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the legacy data converter if it exists
|
* Returns the legacy data converter if it exists
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ public class HuskSyncCommand extends PluginCommand {
|
|||||||
private final AboutMenu aboutMenu;
|
private final AboutMenu aboutMenu;
|
||||||
|
|
||||||
public HuskSyncCommand(@NotNull HuskSync plugin) {
|
public HuskSyncCommand(@NotNull HuskSync plugin) {
|
||||||
super("husksync", List.of(), Permission.Default.TRUE, plugin);
|
super("husksync", List.of(), Permission.Default.TRUE, ExecutionScope.ALL, plugin);
|
||||||
this.updateChecker = plugin.getUpdateChecker();
|
this.updateChecker = plugin.getUpdateChecker();
|
||||||
this.aboutMenu = AboutMenu.builder()
|
this.aboutMenu = AboutMenu.builder()
|
||||||
.title(Component.text("HuskSync"))
|
.title(Component.text("HuskSync"))
|
||||||
@@ -152,7 +152,7 @@ public class HuskSyncCommand extends PluginCommand {
|
|||||||
return (sub) -> {
|
return (sub) -> {
|
||||||
sub.setCondition((ctx) -> sub.getUser(ctx).isConsole());
|
sub.setCondition((ctx) -> sub.getUser(ctx).isConsole());
|
||||||
sub.setDefaultExecutor((ctx) -> {
|
sub.setDefaultExecutor((ctx) -> {
|
||||||
plugin.log(Level.INFO, "Please choose a migrator, then run \"husksync migrate <migrator>\"");
|
plugin.log(Level.INFO, "Please choose a migrator, then run \"husksync migrate start <migrator>\"");
|
||||||
plugin.log(Level.INFO, String.format(
|
plugin.log(Level.INFO, String.format(
|
||||||
"List of available migrators:\nMigrator ID / Migrator Name:\n%s",
|
"List of available migrators:\nMigrator ID / Migrator Name:\n%s",
|
||||||
plugin.getAvailableMigrators().stream()
|
plugin.getAvailableMigrators().stream()
|
||||||
@@ -160,6 +160,10 @@ public class HuskSyncCommand extends PluginCommand {
|
|||||||
.collect(Collectors.joining("\n"))
|
.collect(Collectors.joining("\n"))
|
||||||
));
|
));
|
||||||
});
|
});
|
||||||
|
sub.addSubCommand("help", (help) -> help.addSyntax((cmd) -> {
|
||||||
|
final Migrator migrator = cmd.getArgument("migrator", Migrator.class);
|
||||||
|
plugin.log(Level.INFO, migrator.getHelpMenu());
|
||||||
|
}, migrator()));
|
||||||
sub.addSubCommand("start", (start) -> start.addSyntax((cmd) -> {
|
sub.addSubCommand("start", (start) -> start.addSyntax((cmd) -> {
|
||||||
final Migrator migrator = cmd.getArgument("migrator", Migrator.class);
|
final Migrator migrator = cmd.getArgument("migrator", Migrator.class);
|
||||||
migrator.start().thenAccept(succeeded -> {
|
migrator.start().thenAccept(succeeded -> {
|
||||||
@@ -173,7 +177,7 @@ public class HuskSyncCommand extends PluginCommand {
|
|||||||
sub.addSubCommand("set", (set) -> set.addSyntax((cmd) -> {
|
sub.addSubCommand("set", (set) -> set.addSyntax((cmd) -> {
|
||||||
final Migrator migrator = cmd.getArgument("migrator", Migrator.class);
|
final Migrator migrator = cmd.getArgument("migrator", Migrator.class);
|
||||||
final String[] args = cmd.getArgument("args", String.class).split(" ");
|
final String[] args = cmd.getArgument("args", String.class).split(" ");
|
||||||
migrator.handleConfigurationCommand(Arrays.copyOfRange(args, 3, args.length));
|
migrator.handleConfigurationCommand(args);
|
||||||
}, migrator(), BaseCommand.greedyString("args")));
|
}, migrator(), BaseCommand.greedyString("args")));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -200,19 +204,19 @@ public class HuskSyncCommand extends PluginCommand {
|
|||||||
PLUGIN_VERSION(plugin -> Component.text("v" + plugin.getPluginVersion().toStringWithoutMetadata())
|
PLUGIN_VERSION(plugin -> Component.text("v" + plugin.getPluginVersion().toStringWithoutMetadata())
|
||||||
.appendSpace().append(plugin.getPluginVersion().getMetadata().isBlank() ? Component.empty()
|
.appendSpace().append(plugin.getPluginVersion().getMetadata().isBlank() ? Component.empty()
|
||||||
: Component.text("(build " + plugin.getPluginVersion().getMetadata() + ")"))),
|
: Component.text("(build " + plugin.getPluginVersion().getMetadata() + ")"))),
|
||||||
PLATFORM_TYPE(plugin -> Component.text(WordUtils.capitalizeFully(plugin.getPlatformType()))),
|
SERVER_VERSION(plugin -> Component.text(plugin.getServerVersion())),
|
||||||
LANGUAGE(plugin -> Component.text(plugin.getSettings().getLanguage())),
|
LANGUAGE(plugin -> Component.text(plugin.getSettings().getLanguage())),
|
||||||
MINECRAFT_VERSION(plugin -> Component.text(plugin.getMinecraftVersion().toString())),
|
MINECRAFT_VERSION(plugin -> Component.text(plugin.getMinecraftVersion().toString())),
|
||||||
JAVA_VERSION(plugin -> Component.text(System.getProperty("java.version"))),
|
JAVA_VERSION(plugin -> Component.text(System.getProperty("java.version"))),
|
||||||
JAVA_VENDOR(plugin -> Component.text(System.getProperty("java.vendor"))),
|
JAVA_VENDOR(plugin -> Component.text(System.getProperty("java.vendor"))),
|
||||||
|
SERVER_NAME(plugin -> Component.text(plugin.getServerName())),
|
||||||
|
CLUSTER_ID(plugin -> Component.text(plugin.getSettings().getClusterId().isBlank() ? "None" : plugin.getSettings().getClusterId())),
|
||||||
SYNC_MODE(plugin -> Component.text(WordUtils.capitalizeFully(
|
SYNC_MODE(plugin -> Component.text(WordUtils.capitalizeFully(
|
||||||
plugin.getSettings().getSynchronization().getMode().toString()
|
plugin.getSettings().getSynchronization().getMode().toString()
|
||||||
))),
|
))),
|
||||||
DELAY_LATENCY(plugin -> Component.text(
|
DELAY_LATENCY(plugin -> Component.text(
|
||||||
plugin.getSettings().getSynchronization().getNetworkLatencyMilliseconds() + "ms"
|
plugin.getSettings().getSynchronization().getNetworkLatencyMilliseconds() + "ms"
|
||||||
)),
|
)),
|
||||||
SERVER_NAME(plugin -> Component.text(plugin.getServerName())),
|
|
||||||
CLUSTER_ID(plugin -> Component.text(plugin.getSettings().getClusterId().isBlank() ? "None" : plugin.getSettings().getClusterId())),
|
|
||||||
DATABASE_TYPE(plugin ->
|
DATABASE_TYPE(plugin ->
|
||||||
Component.text(plugin.getSettings().getDatabase().getType().getDisplayName() +
|
Component.text(plugin.getSettings().getDatabase().getType().getDisplayName() +
|
||||||
(plugin.getSettings().getDatabase().getType() == Database.Type.MONGO ?
|
(plugin.getSettings().getDatabase().getType() == Database.Type.MONGO ?
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ import java.util.UUID;
|
|||||||
public abstract class ItemsCommand extends PluginCommand {
|
public abstract class ItemsCommand extends PluginCommand {
|
||||||
|
|
||||||
protected ItemsCommand(@NotNull String name, @NotNull List<String> aliases, @NotNull HuskSync plugin) {
|
protected ItemsCommand(@NotNull String name, @NotNull List<String> aliases, @NotNull HuskSync plugin) {
|
||||||
super(name, aliases, Permission.Default.IF_OP, plugin);
|
super(name, aliases, Permission.Default.IF_OP, ExecutionScope.IN_GAME, plugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -39,9 +39,9 @@ public abstract class PluginCommand extends Command {
|
|||||||
|
|
||||||
protected final HuskSync plugin;
|
protected final HuskSync plugin;
|
||||||
|
|
||||||
protected PluginCommand(@NotNull String name, @NotNull List<String> aliases,
|
protected PluginCommand(@NotNull String name, @NotNull List<String> aliases, @NotNull Permission.Default defPerm,
|
||||||
@NotNull Permission.Default permissionDefault, @NotNull HuskSync plugin) {
|
@NotNull ExecutionScope scope, @NotNull HuskSync plugin) {
|
||||||
super(name, aliases, getDescription(plugin, name), new Permission(createPermission(name), permissionDefault));
|
super(name, aliases, getDescription(plugin, name), new Permission(createPermission(name), defPerm), scope);
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ import java.util.logging.Level;
|
|||||||
public class UserDataCommand extends PluginCommand {
|
public class UserDataCommand extends PluginCommand {
|
||||||
|
|
||||||
public UserDataCommand(@NotNull HuskSync plugin) {
|
public UserDataCommand(@NotNull HuskSync plugin) {
|
||||||
super("userdata", List.of("playerdata"), Permission.Default.IF_OP, plugin);
|
super("userdata", List.of("playerdata"), Permission.Default.IF_OP, ExecutionScope.ALL, plugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -193,14 +193,20 @@ public class Locales {
|
|||||||
* Displays the notification in the action bar
|
* Displays the notification in the action bar
|
||||||
*/
|
*/
|
||||||
ACTION_BAR,
|
ACTION_BAR,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Displays the notification in the chat
|
* Displays the notification in the chat
|
||||||
*/
|
*/
|
||||||
CHAT,
|
CHAT,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Displays the notification in an Advancement Toast
|
* Displays the notification in an Advancement Toast
|
||||||
|
*
|
||||||
|
* @deprecated No longer supported
|
||||||
*/
|
*/
|
||||||
|
@Deprecated(since = "3.6.7")
|
||||||
TOAST,
|
TOAST,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Does not display the notification
|
* Does not display the notification
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -250,7 +250,7 @@ public class Settings {
|
|||||||
@Comment("Whether to use the snappy data compression algorithm. Keep on unless you know what you're doing")
|
@Comment("Whether to use the snappy data compression algorithm. Keep on unless you know what you're doing")
|
||||||
private boolean compressData = true;
|
private boolean compressData = true;
|
||||||
|
|
||||||
@Comment("Where to display sync notifications (ACTION_BAR, CHAT, TOAST or NONE)")
|
@Comment("Where to display sync notifications (ACTION_BAR, CHAT or NONE)")
|
||||||
private Locales.NotificationSlot notificationDisplaySlot = Locales.NotificationSlot.ACTION_BAR;
|
private Locales.NotificationSlot notificationDisplaySlot = Locales.NotificationSlot.ACTION_BAR;
|
||||||
|
|
||||||
@Comment("Persist maps locked in a Cartography Table to let them be viewed on any server")
|
@Comment("Persist maps locked in a Cartography Table to let them be viewed on any server")
|
||||||
@@ -267,11 +267,46 @@ public class Settings {
|
|||||||
@Comment("Commands which should be blocked before a player has finished syncing (Use * to block all commands)")
|
@Comment("Commands which should be blocked before a player has finished syncing (Use * to block all commands)")
|
||||||
private List<String> blacklistedCommandsWhileLocked = new ArrayList<>(List.of("*"));
|
private List<String> blacklistedCommandsWhileLocked = new ArrayList<>(List.of("*"));
|
||||||
|
|
||||||
@Comment({"For attribute syncing, which attributes should be ignored/skipped when syncing",
|
@Comment("Configuration for how to sync attributes")
|
||||||
"(e.g. ['minecraft:generic.max_health', 'minecraft:generic.attack_damage'])"})
|
private AttributeSettings attributes = new AttributeSettings();
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Configuration
|
||||||
|
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
|
public static class AttributeSettings {
|
||||||
|
|
||||||
|
@Comment({"Which attributes should not be saved when syncing users. Supports wildcard matching.",
|
||||||
|
"(e.g. ['minecraft:generic.max_health', 'minecraft:generic.*'])"})
|
||||||
@Getter(AccessLevel.NONE)
|
@Getter(AccessLevel.NONE)
|
||||||
private List<String> ignoredAttributes = new ArrayList<>(List.of(""));
|
private List<String> ignoredAttributes = new ArrayList<>(List.of(""));
|
||||||
|
|
||||||
|
@Comment({"Which modifiers should not be saved when syncing users. Supports wildcard matching.",
|
||||||
|
"(e.g. ['minecraft:effect.speed', 'minecraft:effect.*'])"})
|
||||||
|
@Getter(AccessLevel.NONE)
|
||||||
|
private List<String> ignoredModifiers = new ArrayList<>(List.of(
|
||||||
|
"minecraft:effect.*", "minecraft:creative_mode_*"
|
||||||
|
));
|
||||||
|
|
||||||
|
private boolean matchesWildcard(@NotNull String pat, @NotNull String value) {
|
||||||
|
if (!pat.contains(":")) {
|
||||||
|
pat = "minecraft:%s".formatted(pat);
|
||||||
|
}
|
||||||
|
if (!value.contains(":")) {
|
||||||
|
value = "minecraft:%s".formatted(value);
|
||||||
|
}
|
||||||
|
return pat.contains("*") ? value.matches(pat.replace("*", ".*")) : pat.equals(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isIgnoredAttribute(@NotNull String attribute) {
|
||||||
|
return ignoredAttributes.stream().anyMatch(wildcard -> matchesWildcard(wildcard, attribute));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isIgnoredModifier(@NotNull String modifier) {
|
||||||
|
return ignoredModifiers.stream().anyMatch(wildcard -> matchesWildcard(wildcard, modifier));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Comment("Event priorities for listeners (HIGHEST, NORMAL, LOWEST). Change if you encounter plugin conflicts")
|
@Comment("Event priorities for listeners (HIGHEST, NORMAL, LOWEST). Change if you encounter plugin conflicts")
|
||||||
@Getter(AccessLevel.NONE)
|
@Getter(AccessLevel.NONE)
|
||||||
private Map<String, String> eventPriorities = EventListener.ListenerType.getDefaults();
|
private Map<String, String> eventPriorities = EventListener.ListenerType.getDefaults();
|
||||||
@@ -284,10 +319,6 @@ public class Settings {
|
|||||||
return id.isCustom() || features.getOrDefault(id.getKeyValue(), id.isEnabledByDefault());
|
return id.isCustom() || features.getOrDefault(id.getKeyValue(), id.isEnabledByDefault());
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isIgnoredAttribute(@NotNull String attribute) {
|
|
||||||
return ignoredAttributes.contains(attribute);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public EventListener.Priority getEventPriority(@NotNull EventListener.ListenerType type) {
|
public EventListener.Priority getEventPriority(@NotNull EventListener.ListenerType type) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -155,14 +155,14 @@ public interface Data {
|
|||||||
*/
|
*/
|
||||||
interface Advancements extends Data {
|
interface Advancements extends Data {
|
||||||
|
|
||||||
|
String RECIPE_ADVANCEMENT = "minecraft:recipe";
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
List<Advancement> getCompleted();
|
List<Advancement> getCompleted();
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
default List<Advancement> getCompletedExcludingRecipes() {
|
default List<Advancement> getCompletedExcludingRecipes() {
|
||||||
return getCompleted().stream()
|
return getCompleted().stream().filter(adv -> !adv.getKey().startsWith(RECIPE_ADVANCEMENT)).toList();
|
||||||
.filter(advancement -> !advancement.getKey().startsWith("minecraft:recipe"))
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setCompleted(@NotNull List<Advancement> completed);
|
void setCompleted(@NotNull List<Advancement> completed);
|
||||||
@@ -366,7 +366,13 @@ public interface Data {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
return obj instanceof Modifier modifier && modifier.uuid().equals(uuid());
|
if (obj instanceof Modifier other) {
|
||||||
|
if (uuid == null || other.uuid == null) {
|
||||||
|
return name.equals(other.name);
|
||||||
|
}
|
||||||
|
return uuid.equals(other.uuid);
|
||||||
|
}
|
||||||
|
return super.equals(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
public double modify(double value) {
|
public double modify(double value) {
|
||||||
@@ -378,6 +384,10 @@ public interface Data {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasUuid() {
|
||||||
|
return uuid != null;
|
||||||
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public UUID uuid() {
|
public UUID uuid() {
|
||||||
return uuid != null ? uuid : UUID.nameUUIDFromBytes(name.getBytes());
|
return uuid != null ? uuid : UUID.nameUUIDFromBytes(name.getBytes());
|
||||||
|
|||||||
@@ -395,7 +395,7 @@ public class DataSnapshot {
|
|||||||
.map(entry -> Map.entry(plugin.getIdentifier(entry.getKey()).orElseThrow(), entry.getValue()))
|
.map(entry -> Map.entry(plugin.getIdentifier(entry.getKey()).orElseThrow(), entry.getValue()))
|
||||||
.collect(Collectors.toMap(
|
.collect(Collectors.toMap(
|
||||||
Map.Entry::getKey,
|
Map.Entry::getKey,
|
||||||
entry -> plugin.deserializeData(entry.getKey(), entry.getValue()),
|
entry -> plugin.deserializeData(entry.getKey(), entry.getValue(), getMinecraftVersion()),
|
||||||
(a, b) -> b, () -> Maps.newTreeMap(SerializerRegistry.DEPENDENCY_ORDER_COMPARATOR)
|
(a, b) -> b, () -> Maps.newTreeMap(SerializerRegistry.DEPENDENCY_ORDER_COMPARATOR)
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,8 @@ public class Identifier {
|
|||||||
Dependency.optional("game_mode")
|
Dependency.optional("game_mode")
|
||||||
);
|
);
|
||||||
public static final Identifier ATTRIBUTES = huskSync("attributes", true,
|
public static final Identifier ATTRIBUTES = huskSync("attributes", true,
|
||||||
Dependency.required("potion_effects")
|
Dependency.optional("inventory"),
|
||||||
|
Dependency.optional("potion_effects")
|
||||||
);
|
);
|
||||||
public static final Identifier HEALTH = huskSync("health", true,
|
public static final Identifier HEALTH = huskSync("health", true,
|
||||||
Dependency.optional("attributes")
|
Dependency.optional("attributes")
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
package net.william278.husksync.data;
|
package net.william278.husksync.data;
|
||||||
|
|
||||||
|
import net.william278.desertwell.util.Version;
|
||||||
import net.william278.husksync.HuskSync;
|
import net.william278.husksync.HuskSync;
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@@ -119,19 +120,36 @@ public interface SerializerRegistry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deserialize data for the given {@link Identifier}
|
* Deserialize data of a given {@link Version Minecraft version} for the given {@link Identifier data identifier}
|
||||||
|
*
|
||||||
|
* @param identifier the {@link Identifier} to deserialize data for
|
||||||
|
* @param data the data to deserialize
|
||||||
|
* @param dataMcVersion the Minecraft version of the data
|
||||||
|
* @return the deserialized data
|
||||||
|
* @throws IllegalStateException if no serializer is found for the given {@link Identifier}
|
||||||
|
* @since 3.6.4
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
default Data deserializeData(@NotNull Identifier identifier, @NotNull String data,
|
||||||
|
@NotNull Version dataMcVersion) throws IllegalStateException {
|
||||||
|
return getSerializer(identifier).map(serializer -> serializer.deserialize(data, dataMcVersion)).orElseThrow(
|
||||||
|
() -> new IllegalStateException("No serializer found for %s".formatted(identifier))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserialize data for the given {@link Identifier data identifier}
|
||||||
*
|
*
|
||||||
* @param identifier the {@link Identifier} to deserialize data for
|
* @param identifier the {@link Identifier} to deserialize data for
|
||||||
* @param data the data to deserialize
|
* @param data the data to deserialize
|
||||||
* @return the deserialized data
|
* @return the deserialized data
|
||||||
* @throws IllegalStateException if no serializer is found for the given {@link Identifier}
|
|
||||||
* @since 3.5.4
|
* @since 3.5.4
|
||||||
|
* @deprecated Use {@link #deserializeData(Identifier, String, Version)} instead
|
||||||
*/
|
*/
|
||||||
@NotNull
|
@NotNull
|
||||||
default Data deserializeData(@NotNull Identifier identifier, @NotNull String data) throws IllegalStateException {
|
@Deprecated(since = "3.6.5")
|
||||||
return getSerializer(identifier).map(serializer -> serializer.deserialize(data)).orElseThrow(
|
default Data deserializeData(@NotNull Identifier identifier, @NotNull String data) {
|
||||||
() -> new IllegalStateException("No serializer found for %s".formatted(identifier))
|
return deserializeData(identifier, data, getPlugin().getMinecraftVersion());
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ public class MongoDbDatabase extends Database {
|
|||||||
|
|
||||||
private final String usersTable;
|
private final String usersTable;
|
||||||
private final String userDataTable;
|
private final String userDataTable;
|
||||||
|
|
||||||
public MongoDbDatabase(@NotNull HuskSync plugin) {
|
public MongoDbDatabase(@NotNull HuskSync plugin) {
|
||||||
super(plugin);
|
super(plugin);
|
||||||
this.usersTable = plugin.getSettings().getDatabase().getTableName(TableName.USERS);
|
this.usersTable = plugin.getSettings().getDatabase().getTableName(TableName.USERS);
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ public class MongoCollectionHelper {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the collection helper
|
* Initialize the collection helper
|
||||||
|
*
|
||||||
* @param database Instance of {@link MongoConnectionHandler}
|
* @param database Instance of {@link MongoConnectionHandler}
|
||||||
*/
|
*/
|
||||||
public MongoCollectionHelper(@NotNull MongoConnectionHandler database) {
|
public MongoCollectionHelper(@NotNull MongoConnectionHandler database) {
|
||||||
@@ -37,6 +38,7 @@ public class MongoCollectionHelper {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a collection
|
* Create a collection
|
||||||
|
*
|
||||||
* @param collectionName the collection name
|
* @param collectionName the collection name
|
||||||
*/
|
*/
|
||||||
public void createCollection(@NotNull String collectionName) {
|
public void createCollection(@NotNull String collectionName) {
|
||||||
@@ -45,6 +47,7 @@ public class MongoCollectionHelper {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete a collection
|
* Delete a collection
|
||||||
|
*
|
||||||
* @param collectionName the collection name
|
* @param collectionName the collection name
|
||||||
*/
|
*/
|
||||||
public void deleteCollection(@NotNull String collectionName) {
|
public void deleteCollection(@NotNull String collectionName) {
|
||||||
@@ -53,6 +56,7 @@ public class MongoCollectionHelper {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a collection
|
* Get a collection
|
||||||
|
*
|
||||||
* @param collectionName the collection name
|
* @param collectionName the collection name
|
||||||
* @return MongoCollection<Document>
|
* @return MongoCollection<Document>
|
||||||
*/
|
*/
|
||||||
@@ -62,6 +66,7 @@ public class MongoCollectionHelper {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a document to a collection
|
* Add a document to a collection
|
||||||
|
*
|
||||||
* @param collectionName collection to add to
|
* @param collectionName collection to add to
|
||||||
* @param document Document to add
|
* @param document Document to add
|
||||||
*/
|
*/
|
||||||
@@ -72,6 +77,7 @@ public class MongoCollectionHelper {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Update a document
|
* Update a document
|
||||||
|
*
|
||||||
* @param collectionName collection the document is in
|
* @param collectionName collection the document is in
|
||||||
* @param document filter of document
|
* @param document filter of document
|
||||||
* @param updates Bson of updates
|
* @param updates Bson of updates
|
||||||
@@ -83,6 +89,7 @@ public class MongoCollectionHelper {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete a document
|
* Delete a document
|
||||||
|
*
|
||||||
* @param collectionName collection the document is in
|
* @param collectionName collection the document is in
|
||||||
* @param document filter to remove
|
* @param document filter to remove
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ public class MongoConnectionHandler {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Initiate a connection to a Mongo Server
|
* Initiate a connection to a Mongo Server
|
||||||
|
*
|
||||||
* @param uri The connection string
|
* @param uri The connection string
|
||||||
*/
|
*/
|
||||||
public MongoConnectionHandler(@NotNull ConnectionString uri, @NotNull String databaseName) {
|
public MongoConnectionHandler(@NotNull ConnectionString uri, @NotNull String databaseName) {
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ public abstract class EventListener {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
plugin.lockPlayer(user.getUuid());
|
plugin.lockPlayer(user.getUuid());
|
||||||
plugin.getDataSyncer().setUserData(user);
|
plugin.getDataSyncer().syncApplyUserData(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -66,7 +66,7 @@ public abstract class EventListener {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
plugin.lockPlayer(user.getUuid());
|
plugin.lockPlayer(user.getUuid());
|
||||||
plugin.getDataSyncer().saveUserData(user);
|
plugin.getDataSyncer().syncSaveUserData(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -281,16 +281,21 @@ public class RedisManager extends JedisPubSub {
|
|||||||
@Blocking
|
@Blocking
|
||||||
public void setUserCheckedOut(@NotNull User user, boolean checkedOut) {
|
public void setUserCheckedOut(@NotNull User user, boolean checkedOut) {
|
||||||
try (Jedis jedis = jedisPool.getResource()) {
|
try (Jedis jedis = jedisPool.getResource()) {
|
||||||
|
final String key = getKeyString(RedisKeyType.DATA_CHECKOUT, user.getUuid(), clusterId);
|
||||||
if (checkedOut) {
|
if (checkedOut) {
|
||||||
jedis.set(
|
jedis.set(
|
||||||
getKey(RedisKeyType.DATA_CHECKOUT, user.getUuid(), clusterId),
|
key.getBytes(StandardCharsets.UTF_8),
|
||||||
plugin.getServerName().getBytes(StandardCharsets.UTF_8)
|
plugin.getServerName().getBytes(StandardCharsets.UTF_8)
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
jedis.del(getKey(RedisKeyType.DATA_CHECKOUT, user.getUuid(), clusterId));
|
if (jedis.del(key.getBytes(StandardCharsets.UTF_8)) == 0) {
|
||||||
|
plugin.debug(String.format("[%s] %s key not set on Redis when attempting removal (%s)",
|
||||||
|
user.getUsername(), RedisKeyType.DATA_CHECKOUT, key));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
plugin.debug(String.format("[%s] %s %s key to/from Redis", user.getUsername(),
|
}
|
||||||
checkedOut ? "Set" : "Removed", RedisKeyType.DATA_CHECKOUT));
|
plugin.debug(String.format("[%s] %s %s key %s Redis (%s)", user.getUsername(),
|
||||||
|
checkedOut ? "Set" : "Removed", RedisKeyType.DATA_CHECKOUT, checkedOut ? "to" : "from", key));
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
plugin.log(Level.SEVERE, "An exception occurred setting checkout to", e);
|
plugin.log(Level.SEVERE, "An exception occurred setting checkout to", e);
|
||||||
}
|
}
|
||||||
@@ -418,7 +423,12 @@ public class RedisManager extends JedisPubSub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static byte[] getKey(@NotNull RedisKeyType keyType, @NotNull UUID uuid, @NotNull String clusterId) {
|
private static byte[] getKey(@NotNull RedisKeyType keyType, @NotNull UUID uuid, @NotNull String clusterId) {
|
||||||
return String.format("%s:%s", keyType.getKeyPrefix(clusterId), uuid).getBytes(StandardCharsets.UTF_8);
|
return getKeyString(keyType, uuid, clusterId).getBytes(StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private static String getKeyString(@NotNull RedisKeyType keyType, @NotNull UUID uuid, @NotNull String clusterId) {
|
||||||
|
return String.format("%s:%s", keyType.getKeyPrefix(clusterId), uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,18 +81,18 @@ public abstract class DataSyncer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when a user's data should be fetched and applied to them
|
* Called when a user's data should be fetched and applied to them as part of a synchronization process
|
||||||
*
|
*
|
||||||
* @param user the user to fetch data for
|
* @param user the user to fetch data for
|
||||||
*/
|
*/
|
||||||
public abstract void setUserData(@NotNull OnlineUser user);
|
public abstract void syncApplyUserData(@NotNull OnlineUser user);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when a user's data should be serialized and saved
|
* Called when a user's data should be serialized and saved as part of a synchronization process
|
||||||
*
|
*
|
||||||
* @param user the user to save
|
* @param user the user to save
|
||||||
*/
|
*/
|
||||||
public abstract void saveUserData(@NotNull OnlineUser user);
|
public abstract void syncSaveUserData(@NotNull OnlineUser user);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save a {@link DataSnapshot.Packed user's data snapshot} to the database,
|
* Save a {@link DataSnapshot.Packed user's data snapshot} to the database,
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ public class DelayDataSyncer extends DataSyncer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setUserData(@NotNull OnlineUser user) {
|
public void syncApplyUserData(@NotNull OnlineUser user) {
|
||||||
plugin.runAsyncDelayed(
|
plugin.runAsyncDelayed(
|
||||||
() -> {
|
() -> {
|
||||||
// Fetch from the database if the user isn't changing servers
|
// Fetch from the database if the user isn't changing servers
|
||||||
@@ -58,7 +58,7 @@ public class DelayDataSyncer extends DataSyncer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void saveUserData(@NotNull OnlineUser onlineUser) {
|
public void syncSaveUserData(@NotNull OnlineUser onlineUser) {
|
||||||
plugin.runAsync(() -> {
|
plugin.runAsync(() -> {
|
||||||
getRedis().setUserServerSwitch(onlineUser);
|
getRedis().setUserServerSwitch(onlineUser);
|
||||||
saveData(
|
saveData(
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ public class LockstepDataSyncer extends DataSyncer {
|
|||||||
|
|
||||||
// Consume their data when they are checked in
|
// Consume their data when they are checked in
|
||||||
@Override
|
@Override
|
||||||
public void setUserData(@NotNull OnlineUser user) {
|
public void syncApplyUserData(@NotNull OnlineUser user) {
|
||||||
this.listenForRedisData(user, () -> {
|
this.listenForRedisData(user, () -> {
|
||||||
if (getRedis().getUserCheckedOut(user).isPresent()) {
|
if (getRedis().getUserCheckedOut(user).isPresent()) {
|
||||||
return false;
|
return false;
|
||||||
@@ -58,7 +58,7 @@ public class LockstepDataSyncer extends DataSyncer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void saveUserData(@NotNull OnlineUser onlineUser) {
|
public void syncSaveUserData(@NotNull OnlineUser onlineUser) {
|
||||||
plugin.runAsync(() -> saveData(
|
plugin.runAsync(() -> saveData(
|
||||||
onlineUser, onlineUser.createSnapshot(DataSnapshot.SaveCause.DISCONNECT),
|
onlineUser, onlineUser.createSnapshot(DataSnapshot.SaveCause.DISCONNECT),
|
||||||
(user, data) -> {
|
(user, data) -> {
|
||||||
|
|||||||
@@ -89,7 +89,9 @@ public abstract class OnlineUser extends User implements CommandUser, UserDataHo
|
|||||||
* @param description the description of the toast
|
* @param description the description of the toast
|
||||||
* @param iconMaterial the namespace-keyed material to use as an hasIcon of the toast
|
* @param iconMaterial the namespace-keyed material to use as an hasIcon of the toast
|
||||||
* @param backgroundType the background ("ToastType") of the toast
|
* @param backgroundType the background ("ToastType") of the toast
|
||||||
|
* @deprecated No longer supported
|
||||||
*/
|
*/
|
||||||
|
@Deprecated(since = "3.6.7")
|
||||||
public abstract void sendToast(@NotNull MineDown title, @NotNull MineDown description,
|
public abstract void sendToast(@NotNull MineDown title, @NotNull MineDown description,
|
||||||
@NotNull String iconMaterial, @NotNull String backgroundType);
|
@NotNull String iconMaterial, @NotNull String backgroundType);
|
||||||
|
|
||||||
@@ -145,12 +147,6 @@ public abstract class OnlineUser extends User implements CommandUser, UserDataHo
|
|||||||
switch (plugin.getSettings().getSynchronization().getNotificationDisplaySlot()) {
|
switch (plugin.getSettings().getSynchronization().getNotificationDisplaySlot()) {
|
||||||
case CHAT -> cause.getCompletedLocale(plugin).ifPresent(this::sendMessage);
|
case CHAT -> cause.getCompletedLocale(plugin).ifPresent(this::sendMessage);
|
||||||
case ACTION_BAR -> cause.getCompletedLocale(plugin).ifPresent(this::sendActionBar);
|
case ACTION_BAR -> cause.getCompletedLocale(plugin).ifPresent(this::sendActionBar);
|
||||||
case TOAST -> cause.getCompletedLocale(plugin)
|
|
||||||
.ifPresent(locale -> this.sendToast(
|
|
||||||
locale, new MineDown(""),
|
|
||||||
"minecraft:bell",
|
|
||||||
"TASK"
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
plugin.fireEvent(
|
plugin.fireEvent(
|
||||||
plugin.getSyncCompleteEvent(this),
|
plugin.getSyncCompleteEvent(this),
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ synchronization:
|
|||||||
sync_dead_players_changing_server: true
|
sync_dead_players_changing_server: true
|
||||||
# Whether to use the snappy data compression algorithm. Keep on unless you know what you're doing
|
# Whether to use the snappy data compression algorithm. Keep on unless you know what you're doing
|
||||||
compress_data: true
|
compress_data: true
|
||||||
# Where to display sync notifications (ACTION_BAR, CHAT, TOAST or NONE)
|
# Where to display sync notifications (ACTION_BAR, CHAT or NONE)
|
||||||
notification_display_slot: ACTION_BAR
|
notification_display_slot: ACTION_BAR
|
||||||
# Persist maps locked in a Cartography Table to let them be viewed on any server
|
# Persist maps locked in a Cartography Table to let them be viewed on any server
|
||||||
persist_locked_maps: true
|
persist_locked_maps: true
|
||||||
@@ -134,9 +134,14 @@ synchronization:
|
|||||||
# Commands which should be blocked before a player has finished syncing (Use * to block all commands)
|
# Commands which should be blocked before a player has finished syncing (Use * to block all commands)
|
||||||
blacklisted_commands_while_locked:
|
blacklisted_commands_while_locked:
|
||||||
- '*'
|
- '*'
|
||||||
# For attribute syncing, which attributes should be ignored/skipped when syncing
|
# Configuration for how to sync attributes
|
||||||
# (e.g. ['minecraft:generic.max_health', 'minecraft:generic.attack_damage'])
|
attributes:
|
||||||
|
# Which attributes should not be saved when syncing users. Supports wildcard matching.
|
||||||
|
# (e.g. ['minecraft:generic.max_health', 'minecraft:generic.*'])
|
||||||
ignored_attributes: []
|
ignored_attributes: []
|
||||||
|
# Which modifiers should not be saved when syncing users. Supports wildcard matching.
|
||||||
|
# (e.g. ['minecraft:effect.speed', 'minecraft:effect.*'])
|
||||||
|
ignored_modifiers: ['minecraft:effect.*', 'minecraft:creative_mode_*']
|
||||||
# Event priorities for listeners (HIGHEST, NORMAL, LOWEST). Change if you encounter plugin conflicts
|
# Event priorities for listeners (HIGHEST, NORMAL, LOWEST). Change if you encounter plugin conflicts
|
||||||
event_priorities:
|
event_priorities:
|
||||||
quit_listener: LOWEST
|
quit_listener: LOWEST
|
||||||
|
|||||||
@@ -18,12 +18,12 @@ This guide will walk you through how to upgrade from HuskSync v1.4.x to HuskSync
|
|||||||
|
|
||||||
### 3. Configure the migrator
|
### 3. Configure the migrator
|
||||||
- With your servers back on and correctly configured to run HuskSync v3.x, ensure nobody is online.
|
- With your servers back on and correctly configured to run HuskSync v3.x, ensure nobody is online.
|
||||||
- Use the console on one of your Spigot servers to enter: `husksync migrate legacy`
|
- Use the console on one of your Spigot servers to enter: `husksync migrate help legacy`
|
||||||
- Carefully read the migration configuration instructions. In most cases, you won't have to change the settings, but if you do need to adjust them, use `husksync migrate legacy set <setting> <value>`.
|
- Carefully read the migration configuration instructions. In most cases, you won't have to change the settings, but if you do need to adjust them, use `husksync migrate set legacy <setting> <value>`.
|
||||||
- Migration will be carried out *from* the database you specify with the settings in console *to* the database configured in `config.yml`. If you're migrating from multiple clusters, ensure you run the migrator on the correct servers corresponding to the migrator.
|
- Migration will be carried out *from* the database you specify with the settings in console *to* the database configured in `config.yml`. If you're migrating from multiple clusters, ensure you run the migrator on the correct servers corresponding to the migrator.
|
||||||
|
|
||||||
### 4. Start the migrator
|
### 4. Start the migrator
|
||||||
- Run `husksync migrate legacy start` to begin the migration process. This may take some time, depending on the amount of data you're migrating.
|
- Run `husksync migrate start legacy` to begin the migration process. This may take some time, depending on the amount of data you're migrating.
|
||||||
|
|
||||||
### 5. Ensure the migration was successful
|
### 5. Ensure the migration was successful
|
||||||
- HuskSync will notify in console when migration is complete. Verify that the migration went OK by logging in and using the `/userdata list <username>` command to see if the data was imported with the `legacy migration` saveCause.
|
- HuskSync will notify in console when migration is complete. Verify that the migration went OK by logging in and using the `/userdata list <username>` command to see if the data was imported with the `legacy migration` saveCause.
|
||||||
|
|||||||
@@ -13,12 +13,12 @@ This guide will walk you through how to migrate from MySQLPlayerDataBridge (MPDB
|
|||||||
|
|
||||||
### 2. Configure the migrator
|
### 2. Configure the migrator
|
||||||
- With your servers back on and correctly configured to run HuskSync v3.x, ensure nobody is online.
|
- With your servers back on and correctly configured to run HuskSync v3.x, ensure nobody is online.
|
||||||
- Use the console on one of your Spigot servers to enter: `husksync migrate mpdb`. If the MPDB migrator is not available, ensure MySQLPlayerDataBridge is still installed.
|
- Use the console on one of your Spigot servers to enter: `husksync migrate help mpdb`. If the MPDB migrator is not available, ensure MySQLPlayerDataBridge is still installed.
|
||||||
- Adjust the migration setting as needed using the following command: `husksync migrate mpdb set <setting> <value>`.
|
- Adjust the migration setting as needed using the following command: `husksync migrate set mpdb <setting> <value>`.
|
||||||
- Note that migration will be carried out *from* the database you specify with the settings in console *to* the database configured in `config.yml`.
|
- Note that migration will be carried out *from* the database you specify with the settings in console *to* the database configured in `config.yml`.
|
||||||
|
|
||||||
### 3. Start the migrator
|
### 3. Start the migrator
|
||||||
- Run `husksync migrate mpdb start` to begin the migration process. This may take some time, depending on the amount of data you're migrating.
|
- Run `husksync migrate start mpdb` to begin the migration process. This may take some time, depending on the amount of data you're migrating.
|
||||||
|
|
||||||
### 4. Uninstall MySQLPlayerDataBridge
|
### 4. Uninstall MySQLPlayerDataBridge
|
||||||
- HuskSync will display a message in console when data migration is complete.
|
- HuskSync will display a message in console when data migration is complete.
|
||||||
|
|||||||
@@ -18,20 +18,21 @@ dependencies {
|
|||||||
modImplementation include("net.kyori:adventure-platform-fabric:${adventure_platform_fabric_version}")
|
modImplementation include("net.kyori:adventure-platform-fabric:${adventure_platform_fabric_version}")
|
||||||
modImplementation include("me.lucko:fabric-permissions-api:${fabric_permissions_api_version}")
|
modImplementation include("me.lucko:fabric-permissions-api:${fabric_permissions_api_version}")
|
||||||
modImplementation include("eu.pb4:sgui:${sgui_version}")
|
modImplementation include("eu.pb4:sgui:${sgui_version}")
|
||||||
modImplementation include('net.william278.uniform:uniform-fabric:1.1.8+1.20.1')
|
modImplementation include('net.william278.uniform:uniform-fabric:1.2.1+1.20.1')
|
||||||
modCompileOnly "net.fabricmc.fabric-api:fabric-api:${fabric_api_version}"
|
modCompileOnly "net.fabricmc.fabric-api:fabric-api:${fabric_api_version}"
|
||||||
|
|
||||||
implementation include('org.apache.commons:commons-pool2:2.12.0')
|
implementation include('org.apache.commons:commons-pool2:2.12.0')
|
||||||
implementation include("redis.clients:jedis:$jedis_version")
|
implementation include("redis.clients:jedis:$jedis_version")
|
||||||
implementation include("com.mysql:mysql-connector-j:$mysql_driver_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.mariadb.jdbc:mariadb-java-client:$mariadb_driver_version")
|
||||||
|
implementation include("org.postgresql:postgresql:$postgres_driver_version")
|
||||||
implementation include("org.xerial.snappy:snappy-java:$snappy_version")
|
implementation include("org.xerial.snappy:snappy-java:$snappy_version")
|
||||||
|
|
||||||
compileOnly 'org.jetbrains:annotations:24.1.0'
|
compileOnly 'org.jetbrains:annotations:24.1.0'
|
||||||
compileOnly 'net.william278:DesertWell:2.0.4'
|
compileOnly 'net.william278:DesertWell:2.0.4'
|
||||||
compileOnly 'org.projectlombok:lombok:1.18.32'
|
compileOnly 'org.projectlombok:lombok:1.18.34'
|
||||||
|
|
||||||
annotationProcessor 'org.projectlombok:lombok:1.18.32'
|
annotationProcessor 'org.projectlombok:lombok:1.18.34'
|
||||||
|
|
||||||
shadow project(path: ":common")
|
shadow project(path: ":common")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ import net.william278.husksync.database.MongoDbDatabase;
|
|||||||
import net.william278.husksync.database.MySqlDatabase;
|
import net.william278.husksync.database.MySqlDatabase;
|
||||||
import net.william278.husksync.database.PostgresDatabase;
|
import net.william278.husksync.database.PostgresDatabase;
|
||||||
import net.william278.husksync.event.FabricEventDispatcher;
|
import net.william278.husksync.event.FabricEventDispatcher;
|
||||||
|
import net.william278.husksync.event.ModLoadedCallback;
|
||||||
import net.william278.husksync.hook.PlanHook;
|
import net.william278.husksync.hook.PlanHook;
|
||||||
import net.william278.husksync.listener.EventListener;
|
import net.william278.husksync.listener.EventListener;
|
||||||
import net.william278.husksync.listener.FabricEventListener;
|
import net.william278.husksync.listener.FabricEventListener;
|
||||||
@@ -206,6 +207,16 @@ public class FabricHuskSync implements DedicatedServerModInitializer, HuskSync,
|
|||||||
|
|
||||||
// Check for updates
|
// Check for updates
|
||||||
this.checkForUpdates();
|
this.checkForUpdates();
|
||||||
|
|
||||||
|
log(Level.WARNING, """
|
||||||
|
**************
|
||||||
|
WARNING:
|
||||||
|
|
||||||
|
HuskSync for Fabric is still in an alpha state and is
|
||||||
|
not considered production ready.
|
||||||
|
**************""");
|
||||||
|
|
||||||
|
ModLoadedCallback.EVENT.invoker().post(FabricHuskSyncAPI.getInstance());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onDisable() {
|
private void onDisable() {
|
||||||
@@ -328,6 +339,14 @@ public class FabricHuskSync implements DedicatedServerModInitializer, HuskSync,
|
|||||||
return PLATFORM_TYPE_ID;
|
return PLATFORM_TYPE_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NotNull
|
||||||
|
public String getServerVersion() {
|
||||||
|
return String.format("%s %s/%s", getPlatformType(), FabricLoader.getInstance()
|
||||||
|
.getModContainer("fabricloader").map(l -> l.getMetadata().getVersion().getFriendlyString())
|
||||||
|
.orElse("unknown"), minecraftServer.getVersion());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<LegacyConverter> getLegacyConverter() {
|
public Optional<LegacyConverter> getLegacyConverter() {
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ import net.william278.husksync.user.FabricUser;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.annotations.Range;
|
import org.jetbrains.annotations.Range;
|
||||||
|
import org.jetbrains.annotations.Unmodifiable;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@@ -237,8 +238,8 @@ public abstract class FabricData implements Data {
|
|||||||
private final Collection<StatusEffectInstance> effects;
|
private final Collection<StatusEffectInstance> effects;
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static FabricData.PotionEffects from(@NotNull Collection<StatusEffectInstance> effects) {
|
public static FabricData.PotionEffects from(@NotNull Collection<StatusEffectInstance> sei) {
|
||||||
return new FabricData.PotionEffects(effects);
|
return new FabricData.PotionEffects(Lists.newArrayList(sei.stream().filter(e -> !e.isAmbient()).toList()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@@ -263,18 +264,21 @@ public abstract class FabricData implements Data {
|
|||||||
@NotNull
|
@NotNull
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public static FabricData.PotionEffects empty() {
|
public static FabricData.PotionEffects empty() {
|
||||||
return new FabricData.PotionEffects(List.of());
|
return new FabricData.PotionEffects(Lists.newArrayList());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void apply(@NotNull FabricUser user, @NotNull FabricHuskSync plugin) throws IllegalStateException {
|
public void apply(@NotNull FabricUser user, @NotNull FabricHuskSync plugin) throws IllegalStateException {
|
||||||
final ServerPlayerEntity player = user.getPlayer();
|
final ServerPlayerEntity player = user.getPlayer();
|
||||||
player.getActiveStatusEffects().forEach((effect, instance) -> player.removeStatusEffect(effect));
|
final List<StatusEffect> effectsToRemove = player.getActiveStatusEffects().entrySet().stream()
|
||||||
|
.filter(e -> !e.getValue().isAmbient()).map(Map.Entry::getKey).toList();
|
||||||
|
effectsToRemove.forEach(player::removeStatusEffect);
|
||||||
getEffects().forEach(player::addStatusEffect);
|
getEffects().forEach(player::addStatusEffect);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
|
@Unmodifiable
|
||||||
public List<Effect> getActiveEffects() {
|
public List<Effect> getActiveEffects() {
|
||||||
return effects.stream()
|
return effects.stream()
|
||||||
.map(potionEffect -> {
|
.map(potionEffect -> {
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* 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.event;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.event.Event;
|
||||||
|
import net.fabricmc.fabric.api.event.EventFactory;
|
||||||
|
import net.william278.husksync.api.HuskSyncAPI;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
public interface ModLoadedCallback {
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
Event<ModLoadedCallback> EVENT = EventFactory.createArrayBacked(
|
||||||
|
ModLoadedCallback.class,
|
||||||
|
(listeners) -> (api) -> Arrays.stream(listeners).forEach(listener -> listener.post(api))
|
||||||
|
);
|
||||||
|
|
||||||
|
void post(@NotNull HuskSyncAPI api);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -54,8 +54,6 @@ import net.william278.husksync.user.OnlineUser;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
public class FabricEventListener extends EventListener implements LockedHandler {
|
public class FabricEventListener extends EventListener implements LockedHandler {
|
||||||
|
|
||||||
public FabricEventListener(@NotNull HuskSync plugin) {
|
public FabricEventListener(@NotNull HuskSync plugin) {
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ package net.william278.husksync.mixins;
|
|||||||
|
|
||||||
import net.minecraft.entity.ItemEntity;
|
import net.minecraft.entity.ItemEntity;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.server.MinecraftServer;
|
|
||||||
import net.minecraft.server.network.ServerPlayerEntity;
|
import net.minecraft.server.network.ServerPlayerEntity;
|
||||||
import net.minecraft.util.ActionResult;
|
import net.minecraft.util.ActionResult;
|
||||||
import net.william278.husksync.event.ItemDropCallback;
|
import net.william278.husksync.event.ItemDropCallback;
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ import org.jetbrains.annotations.ApiStatus;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
|
||||||
public class FabricUser extends OnlineUser implements FabricUserDataHolder {
|
public class FabricUser extends OnlineUser implements FabricUserDataHolder {
|
||||||
|
|
||||||
@@ -70,9 +71,12 @@ public class FabricUser extends OnlineUser implements FabricUserDataHolder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Deprecated(since = "3.6.7")
|
||||||
public void sendToast(@NotNull MineDown title, @NotNull MineDown description, @NotNull String iconMaterial,
|
public void sendToast(@NotNull MineDown title, @NotNull MineDown description, @NotNull String iconMaterial,
|
||||||
@NotNull String backgroundType) {
|
@NotNull String backgroundType) {
|
||||||
getAudience().sendActionBar(title.toComponent()); // Toasts unimplemented for now
|
plugin.log(Level.WARNING, "Toast notifications are deprecated. " +
|
||||||
|
"Please change your notification display slot to CHAT, ACTION_BAR or NONE.");
|
||||||
|
this.sendActionBar(title);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -19,18 +19,21 @@
|
|||||||
|
|
||||||
package net.william278.husksync.util;
|
package net.william278.husksync.util;
|
||||||
|
|
||||||
|
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||||
import net.william278.husksync.FabricHuskSync;
|
import net.william278.husksync.FabricHuskSync;
|
||||||
import net.william278.husksync.HuskSync;
|
import net.william278.husksync.HuskSync;
|
||||||
import net.william278.husksync.data.UserDataHolder;
|
import net.william278.husksync.data.UserDataHolder;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.*;
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import java.util.concurrent.ScheduledFuture;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
public interface FabricTask extends Task {
|
public interface FabricTask extends Task {
|
||||||
|
ScheduledExecutorService ASYNC_EXEC = Executors.newScheduledThreadPool(4,
|
||||||
|
new ThreadFactoryBuilder()
|
||||||
|
.setDaemon(true)
|
||||||
|
.setNameFormat("HuskSync-ThreadPool")
|
||||||
|
.build());
|
||||||
|
|
||||||
class Sync extends Task.Sync implements FabricTask {
|
class Sync extends Task.Sync implements FabricTask {
|
||||||
|
|
||||||
@@ -46,7 +49,7 @@ public interface FabricTask extends Task {
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (!cancelled) {
|
if (!cancelled) {
|
||||||
Executors.newSingleThreadScheduledExecutor().schedule(
|
ASYNC_EXEC.schedule(
|
||||||
() -> ((FabricHuskSync) getPlugin()).getMinecraftServer().executeSync(runnable),
|
() -> ((FabricHuskSync) getPlugin()).getMinecraftServer().executeSync(runnable),
|
||||||
delayTicks * 50,
|
delayTicks * 50,
|
||||||
TimeUnit.MILLISECONDS
|
TimeUnit.MILLISECONDS
|
||||||
@@ -73,7 +76,7 @@ public interface FabricTask extends Task {
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (!cancelled) {
|
if (!cancelled) {
|
||||||
this.task = CompletableFuture.runAsync(runnable, ((FabricHuskSync) getPlugin()).getMinecraftServer());
|
this.task = CompletableFuture.runAsync(runnable, ASYNC_EXEC);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -97,7 +100,7 @@ public interface FabricTask extends Task {
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (!cancelled) {
|
if (!cancelled) {
|
||||||
this.task = Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(
|
this.task = ASYNC_EXEC.scheduleAtFixedRate(
|
||||||
runnable,
|
runnable,
|
||||||
0,
|
0,
|
||||||
repeatingTicks * 50,
|
repeatingTicks * 50,
|
||||||
@@ -129,7 +132,7 @@ public interface FabricTask extends Task {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
default void cancelTasks() {
|
default void cancelTasks() {
|
||||||
// Do nothing
|
ASYNC_EXEC.shutdownNow();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,16 +3,16 @@ org.gradle.jvmargs='-Dfile.encoding=UTF-8'
|
|||||||
org.gradle.daemon=true
|
org.gradle.daemon=true
|
||||||
javaVersion=17
|
javaVersion=17
|
||||||
|
|
||||||
plugin_version=3.6.3
|
plugin_version=3.6.8
|
||||||
plugin_archive=husksync
|
plugin_archive=husksync
|
||||||
plugin_description=A modern, cross-server player data synchronization system
|
plugin_description=A modern, cross-server player data synchronization system
|
||||||
|
|
||||||
jedis_version=5.1.3
|
jedis_version=5.1.4
|
||||||
mysql_driver_version=8.4.0
|
mysql_driver_version=9.0.0
|
||||||
mariadb_driver_version=3.4.0
|
mariadb_driver_version=3.4.1
|
||||||
postgres_driver_version=42.7.3
|
postgres_driver_version=42.7.3
|
||||||
mongodb_driver_version=5.1.0
|
mongodb_driver_version=5.1.2
|
||||||
snappy_version=1.1.10.5
|
snappy_version=1.1.10.6
|
||||||
|
|
||||||
fabric_minecraft_version=1.20.1
|
fabric_minecraft_version=1.20.1
|
||||||
fabric_loader_version=0.15.11
|
fabric_loader_version=0.15.11
|
||||||
|
|||||||
@@ -6,13 +6,13 @@ dependencies {
|
|||||||
implementation project(':bukkit')
|
implementation project(':bukkit')
|
||||||
compileOnly project(':common')
|
compileOnly project(':common')
|
||||||
|
|
||||||
implementation 'net.william278.uniform:uniform-paper:1.1.8'
|
implementation 'net.william278.uniform:uniform-paper:1.2.1'
|
||||||
|
|
||||||
compileOnly 'io.papermc.paper:paper-api:1.19.4-R0.1-SNAPSHOT'
|
compileOnly 'io.papermc.paper:paper-api:1.19.4-R0.1-SNAPSHOT'
|
||||||
compileOnly 'org.jetbrains:annotations:24.1.0'
|
compileOnly 'org.jetbrains:annotations:24.1.0'
|
||||||
compileOnly 'org.projectlombok:lombok:1.18.32'
|
compileOnly 'org.projectlombok:lombok:1.18.34'
|
||||||
|
|
||||||
annotationProcessor 'org.projectlombok:lombok:1.18.32'
|
annotationProcessor 'org.projectlombok:lombok:1.18.34'
|
||||||
}
|
}
|
||||||
|
|
||||||
shadowJar {
|
shadowJar {
|
||||||
@@ -34,7 +34,6 @@ shadowJar {
|
|||||||
relocate 'net.william278.desertwell', 'net.william278.husksync.libraries.desertwell'
|
relocate 'net.william278.desertwell', 'net.william278.husksync.libraries.desertwell'
|
||||||
relocate 'net.william278.paginedown', 'net.william278.husksync.libraries.paginedown'
|
relocate 'net.william278.paginedown', 'net.william278.husksync.libraries.paginedown'
|
||||||
relocate 'net.william278.mapdataapi', 'net.william278.husksync.libraries.mapdataapi'
|
relocate 'net.william278.mapdataapi', 'net.william278.husksync.libraries.mapdataapi'
|
||||||
relocate 'net.william278.andjam', 'net.william278.husksync.libraries.andjam'
|
|
||||||
relocate 'net.william278.mpdbconverter', 'net.william278.husksync.libraries.mpdbconverter'
|
relocate 'net.william278.mpdbconverter', 'net.william278.husksync.libraries.mpdbconverter'
|
||||||
relocate 'net.william278.hslmigrator', 'net.william278.husksync.libraries.hslconverter'
|
relocate 'net.william278.hslmigrator', 'net.william278.husksync.libraries.hslconverter'
|
||||||
relocate 'org.json', 'net.william278.husksync.libraries.json'
|
relocate 'org.json', 'net.william278.husksync.libraries.json'
|
||||||
@@ -50,10 +49,6 @@ shadowJar {
|
|||||||
|
|
||||||
tasks {
|
tasks {
|
||||||
runServer {
|
runServer {
|
||||||
minecraftVersion('1.20.4')
|
minecraftVersion('1.21.1')
|
||||||
|
|
||||||
downloadPlugins {
|
|
||||||
url('https://download.luckperms.net/1549/bukkit/loader/LuckPerms-Bukkit-5.4.134.jar')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
certifi==2023.7.22
|
certifi==2024.7.4
|
||||||
charset-normalizer==3.2.0
|
charset-normalizer==3.2.0
|
||||||
colorama==0.4.6
|
colorama==0.4.6
|
||||||
idna==3.7
|
idna==3.7
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ from tqdm import tqdm
|
|||||||
class Parameters:
|
class Parameters:
|
||||||
root_dir = './servers/'
|
root_dir = './servers/'
|
||||||
proxy_version = "1.21"
|
proxy_version = "1.21"
|
||||||
minecraft_version = '1.21'
|
minecraft_version = '1.21.1'
|
||||||
eula_agreement = 'true'
|
eula_agreement = 'true'
|
||||||
|
|
||||||
backend_names = ['alpha', 'beta']
|
backend_names = ['alpha', 'beta']
|
||||||
|
|||||||
Reference in New Issue
Block a user