mirror of
https://github.com/WiIIiam278/HuskSync.git
synced 2025-12-25 17:49:20 +00:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c4adec3082 | ||
|
|
107238360c | ||
|
|
6141adbdb9 | ||
|
|
eaa2ed74a6 | ||
|
|
44c652c452 | ||
|
|
78cf6bff63 | ||
|
|
8ad4158ec0 | ||
|
|
405e6d7162 | ||
|
|
cff1c8f982 | ||
|
|
f43ca2f043 | ||
|
|
3114ab1a62 | ||
|
|
2da9749b0c | ||
|
|
d4d510e100 | ||
|
|
550ea26097 | ||
|
|
2b1e72a42e |
@@ -13,6 +13,7 @@ dependencies {
|
||||
implementation 'de.tr7zw:item-nbt-api:2.12.4'
|
||||
|
||||
compileOnly 'org.spigotmc:spigot-api:1.17.1-R0.1-SNAPSHOT'
|
||||
compileOnly 'com.github.retrooper.packetevents:spigot:2.3.0'
|
||||
compileOnly 'com.comphenix.protocol:ProtocolLib:5.1.0'
|
||||
compileOnly 'org.projectlombok:lombok:1.18.32'
|
||||
compileOnly 'commons-io:commons-io:2.16.1'
|
||||
|
||||
@@ -46,7 +46,6 @@ import net.william278.husksync.database.PostgresDatabase;
|
||||
import net.william278.husksync.event.BukkitEventDispatcher;
|
||||
import net.william278.husksync.hook.PlanHook;
|
||||
import net.william278.husksync.listener.BukkitEventListener;
|
||||
import net.william278.husksync.listener.EventListener;
|
||||
import net.william278.husksync.migrator.LegacyMigrator;
|
||||
import net.william278.husksync.migrator.Migrator;
|
||||
import net.william278.husksync.migrator.MpdbMigrator;
|
||||
@@ -98,7 +97,7 @@ public class BukkitHuskSync extends JavaPlugin implements HuskSync, BukkitTask.S
|
||||
private MorePaperLib paperLib;
|
||||
private Database database;
|
||||
private RedisManager redisManager;
|
||||
private EventListener eventListener;
|
||||
private BukkitEventListener eventListener;
|
||||
private DataAdapter dataAdapter;
|
||||
private DataSyncer dataSyncer;
|
||||
private LegacyConverter legacyConverter;
|
||||
@@ -113,11 +112,10 @@ public class BukkitHuskSync extends JavaPlugin implements HuskSync, BukkitTask.S
|
||||
private Server serverName;
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
public void onLoad() {
|
||||
// Initial plugin setup
|
||||
this.disabling = false;
|
||||
this.gson = createGson();
|
||||
this.audiences = BukkitAudiences.create(this);
|
||||
this.paperLib = new MorePaperLib(this);
|
||||
|
||||
// Load settings and locales
|
||||
@@ -127,6 +125,13 @@ public class BukkitHuskSync extends JavaPlugin implements HuskSync, BukkitTask.S
|
||||
loadServer();
|
||||
});
|
||||
|
||||
this.eventListener = createEventListener();
|
||||
eventListener.onLoad();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
this.audiences = BukkitAudiences.create(this);
|
||||
// Prepare data adapter
|
||||
initialize("data adapter", (plugin) -> {
|
||||
if (settings.getSynchronization().isCompressData()) {
|
||||
@@ -185,7 +190,7 @@ public class BukkitHuskSync extends JavaPlugin implements HuskSync, BukkitTask.S
|
||||
});
|
||||
|
||||
// Register events
|
||||
initialize("events", (plugin) -> this.eventListener = createEventListener());
|
||||
initialize("events", (plugin) -> eventListener.onEnable());
|
||||
|
||||
// Register commands
|
||||
initialize("commands", (plugin) -> BukkitCommand.Type.registerCommands(this));
|
||||
|
||||
@@ -237,21 +237,20 @@ public abstract class BukkitData implements Data {
|
||||
|
||||
@NotNull
|
||||
public static BukkitData.PotionEffects adapt(@NotNull Collection<Effect> effects) {
|
||||
return from(
|
||||
effects.stream()
|
||||
.map(effect -> new PotionEffect(
|
||||
Objects.requireNonNull(
|
||||
PotionEffectType.getByName(effect.type()),
|
||||
"Invalid potion effect type"
|
||||
),
|
||||
effect.duration(),
|
||||
effect.amplifier(),
|
||||
effect.isAmbient(),
|
||||
effect.showParticles(),
|
||||
effect.hasIcon()
|
||||
))
|
||||
.toList()
|
||||
);
|
||||
return from(effects.stream()
|
||||
.map(effect -> {
|
||||
final PotionEffectType type = matchEffectType(effect.type());
|
||||
return type != null ? new PotionEffect(
|
||||
type,
|
||||
effect.duration(),
|
||||
effect.amplifier(),
|
||||
effect.isAmbient(),
|
||||
effect.showParticles(),
|
||||
effect.hasIcon()
|
||||
) : null;
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.toList());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -616,7 +615,7 @@ public abstract class BukkitData implements Data {
|
||||
if (instance == null) {
|
||||
return;
|
||||
}
|
||||
instance.setBaseValue(attribute == null ? instance.getDefaultValue() : instance.getBaseValue());
|
||||
instance.setBaseValue(attribute == null ? instance.getDefaultValue() : attribute.baseValue());
|
||||
instance.getModifiers().forEach(instance::removeModifier);
|
||||
if (attribute != null) {
|
||||
attribute.modifiers().forEach(modifier -> instance.addModifier(new AttributeModifier(
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
package net.william278.husksync.listener;
|
||||
|
||||
import net.william278.husksync.BukkitHuskSync;
|
||||
import net.william278.husksync.HuskSync;
|
||||
import net.william278.husksync.data.BukkitData;
|
||||
import net.william278.husksync.user.BukkitUser;
|
||||
import net.william278.husksync.user.OnlineUser;
|
||||
@@ -40,21 +39,38 @@ import java.util.stream.Collectors;
|
||||
public class BukkitEventListener extends EventListener implements BukkitJoinEventListener, BukkitQuitEventListener,
|
||||
BukkitDeathEventListener, Listener {
|
||||
|
||||
protected final LockedHandler lockedHandler;
|
||||
protected LockedHandler lockedHandler;
|
||||
|
||||
public BukkitEventListener(@NotNull BukkitHuskSync plugin) {
|
||||
super(plugin);
|
||||
plugin.getServer().getPluginManager().registerEvents(this, plugin);
|
||||
this.lockedHandler = createLockedHandler(plugin);
|
||||
}
|
||||
|
||||
public void onLoad() {
|
||||
this.lockedHandler = createLockedHandler((BukkitHuskSync) plugin);
|
||||
}
|
||||
|
||||
public void onEnable() {
|
||||
getPlugin().getServer().getPluginManager().registerEvents(this, getPlugin());
|
||||
lockedHandler.onEnable();
|
||||
}
|
||||
|
||||
public void handlePluginDisable() {
|
||||
super.handlePluginDisable();
|
||||
lockedHandler.onDisable();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private LockedHandler createLockedHandler(@NotNull BukkitHuskSync plugin) {
|
||||
if (getPlugin().isDependencyLoaded("ProtocolLib") && getPlugin().getSettings().isCancelPackets()) {
|
||||
return new BukkitLockedPacketListener(plugin);
|
||||
} else {
|
||||
if (!getPlugin().getSettings().isCancelPackets()) {
|
||||
return new BukkitLockedEventListener(plugin);
|
||||
}
|
||||
if (getPlugin().isDependencyLoaded("PacketEvents")) {
|
||||
return new BukkitPacketEventsLockedPacketListener(plugin);
|
||||
} else if (getPlugin().isDependencyLoaded("ProtocolLib")) {
|
||||
return new BukkitProtocolLibLockedPacketListener(plugin);
|
||||
}
|
||||
|
||||
return new BukkitLockedEventListener(plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -134,8 +150,8 @@ public class BukkitEventListener extends EventListener implements BukkitJoinEven
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public HuskSync getPlugin() {
|
||||
return plugin;
|
||||
public BukkitHuskSync getPlugin() {
|
||||
return (BukkitHuskSync) plugin;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -50,6 +50,10 @@ public class BukkitLockedEventListener implements LockedHandler, Listener {
|
||||
|
||||
protected BukkitLockedEventListener(@NotNull BukkitHuskSync plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
plugin.getServer().getPluginManager().registerEvents(this, plugin);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* 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.listener;
|
||||
|
||||
import com.github.retrooper.packetevents.PacketEvents;
|
||||
import com.github.retrooper.packetevents.event.PacketListenerAbstract;
|
||||
import com.github.retrooper.packetevents.event.PacketListenerPriority;
|
||||
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.google.common.collect.Sets;
|
||||
import io.github.retrooper.packetevents.factory.spigot.SpigotPacketEventsBuilder;
|
||||
import net.william278.husksync.BukkitHuskSync;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class BukkitPacketEventsLockedPacketListener extends BukkitLockedEventListener implements LockedHandler {
|
||||
|
||||
protected BukkitPacketEventsLockedPacketListener(@NotNull BukkitHuskSync plugin) {
|
||||
super(plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
super.onLoad();
|
||||
PacketEvents.setAPI(SpigotPacketEventsBuilder.build(getPlugin()));
|
||||
PacketEvents.getAPI().getSettings().reEncodeByDefault(false)
|
||||
.checkForUpdates(false)
|
||||
.bStats(true);
|
||||
PacketEvents.getAPI().load();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
super.onEnable();
|
||||
PacketEvents.getAPI().getEventManager().registerListener(new PlayerPacketAdapter(this));
|
||||
PacketEvents.getAPI().init();
|
||||
plugin.log(Level.INFO, "Using PacketEvents to cancel packets for locked players");
|
||||
}
|
||||
|
||||
private static class PlayerPacketAdapter extends PacketListenerAbstract {
|
||||
|
||||
private static final Set<PacketType.Play.Client> ALLOWED_PACKETS = Set.of(
|
||||
PacketType.Play.Client.KEEP_ALIVE, PacketType.Play.Client.PONG, PacketType.Play.Client.PLUGIN_MESSAGE, // Connection packets
|
||||
PacketType.Play.Client.CHAT_MESSAGE, PacketType.Play.Client.CHAT_COMMAND, PacketType.Play.Client.CHAT_SESSION_UPDATE, // Chat / command packets
|
||||
PacketType.Play.Client.PLAYER_POSITION, PacketType.Play.Client.PLAYER_POSITION_AND_ROTATION, PacketType.Play.Client.PLAYER_ROTATION, // Movement packets
|
||||
PacketType.Play.Client.HELD_ITEM_CHANGE, PacketType.Play.Client.ANIMATION, PacketType.Play.Client.TELEPORT_CONFIRM, // Animation packets
|
||||
PacketType.Play.Client.CLIENT_SETTINGS // Video setting packets
|
||||
);
|
||||
|
||||
private static final Set<PacketType.Play.Client> CANCEL_PACKETS = getPacketsToListenFor();
|
||||
|
||||
|
||||
private final BukkitPacketEventsLockedPacketListener listener;
|
||||
|
||||
public PlayerPacketAdapter(@NotNull BukkitPacketEventsLockedPacketListener listener) {
|
||||
super(PacketListenerPriority.HIGH);
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent 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
|
||||
@NotNull
|
||||
private static Set<PacketType.Play.Client> getPacketsToListenFor() {
|
||||
return Sets.difference(
|
||||
Sets.newHashSet(PacketType.Play.Client.values()),
|
||||
ALLOWED_PACKETS
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -34,10 +34,15 @@ import java.util.stream.Collectors;
|
||||
|
||||
import static com.comphenix.protocol.PacketType.Play.Client;
|
||||
|
||||
public class BukkitLockedPacketListener extends BukkitLockedEventListener implements LockedHandler {
|
||||
public class BukkitProtocolLibLockedPacketListener extends BukkitLockedEventListener implements LockedHandler {
|
||||
|
||||
protected BukkitLockedPacketListener(@NotNull BukkitHuskSync plugin) {
|
||||
protected BukkitProtocolLibLockedPacketListener(@NotNull BukkitHuskSync plugin) {
|
||||
super(plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
super.onEnable();
|
||||
ProtocolLibrary.getProtocolManager().addPacketListener(new PlayerPacketAdapter(this));
|
||||
plugin.log(Level.INFO, "Using ProtocolLib to cancel packets for locked players");
|
||||
}
|
||||
@@ -53,9 +58,9 @@ public class BukkitLockedPacketListener extends BukkitLockedEventListener implem
|
||||
Client.SETTINGS // Video setting packets
|
||||
);
|
||||
|
||||
private final BukkitLockedPacketListener listener;
|
||||
private final BukkitProtocolLibLockedPacketListener listener;
|
||||
|
||||
public PlayerPacketAdapter(@NotNull BukkitLockedPacketListener listener) {
|
||||
public PlayerPacketAdapter(@NotNull BukkitProtocolLibLockedPacketListener listener) {
|
||||
super(listener.getPlugin(), ListenerPriority.HIGHEST, getPacketsToListenFor());
|
||||
this.listener = listener;
|
||||
}
|
||||
@@ -19,38 +19,44 @@
|
||||
|
||||
package net.william278.husksync.util;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.Registry;
|
||||
import org.bukkit.Statistic;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.attribute.Attribute;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
// Utility class for adapting "Keyed" Bukkit objects
|
||||
public final class BukkitKeyedAdapter {
|
||||
|
||||
@Nullable
|
||||
public static Statistic matchStatistic(@NotNull String key) {
|
||||
return Registry.STATISTIC.get(Objects.requireNonNull(NamespacedKey.fromString(key), "Null key"));
|
||||
return getRegistryValue(Registry.STATISTIC, key);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static EntityType matchEntityType(@NotNull String key) {
|
||||
return Registry.ENTITY_TYPE.get(Objects.requireNonNull(NamespacedKey.fromString(key), "Null key"));
|
||||
return getRegistryValue(Registry.ENTITY_TYPE, key);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Material matchMaterial(@NotNull String key) {
|
||||
return Registry.MATERIAL.get(Objects.requireNonNull(NamespacedKey.fromString(key), "Null key"));
|
||||
return getRegistryValue(Registry.MATERIAL, key);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Attribute matchAttribute(@NotNull String key) {
|
||||
return Registry.ATTRIBUTE.get(Objects.requireNonNull(NamespacedKey.fromString(key), "Null key"));
|
||||
return getRegistryValue(Registry.ATTRIBUTE, key);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PotionEffectType matchEffectType(@NotNull String key) {
|
||||
return PotionEffectType.getByName(key); // No registry for this in 1.17 API
|
||||
}
|
||||
|
||||
private static <T extends Keyed> T getRegistryValue(@NotNull Registry<T> registry, @NotNull String keyString) {
|
||||
final NamespacedKey key = NamespacedKey.fromString(keyString);
|
||||
return key != null ? registry.get(key) : null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ description: '${description}'
|
||||
website: 'https://william278.net'
|
||||
folia-supported: true
|
||||
softdepend:
|
||||
- 'packetevents'
|
||||
- 'ProtocolLib'
|
||||
- 'MysqlPlayerDataBridge'
|
||||
- 'Plan'
|
||||
|
||||
@@ -7,7 +7,7 @@ dependencies {
|
||||
api 'org.apache.commons:commons-text:1.12.0'
|
||||
api 'net.william278:minedown:1.8.2'
|
||||
api 'org.json:json:20240303'
|
||||
api 'com.google.code.gson:gson:2.10.1'
|
||||
api 'com.google.code.gson:gson:2.11.0'
|
||||
api 'com.fatboyindustrial.gson-javatime-serialisers:gson-javatime-serialisers:1.1.2'
|
||||
api 'de.exlll:configlib-yaml:4.5.0'
|
||||
api 'net.william278:paginedown:1.1.2'
|
||||
@@ -18,7 +18,7 @@ dependencies {
|
||||
|
||||
compileOnly 'org.projectlombok:lombok:1.18.32'
|
||||
compileOnly 'org.jetbrains:annotations:24.1.0'
|
||||
compileOnly 'net.kyori:adventure-api:4.16.0'
|
||||
compileOnly 'net.kyori:adventure-api:4.17.0'
|
||||
compileOnly 'net.kyori:adventure-platform-api:4.3.2'
|
||||
compileOnly 'com.google.guava:guava:33.2.0-jre'
|
||||
compileOnly 'com.github.plan-player-analytics:Plan:5.5.2272'
|
||||
|
||||
@@ -75,7 +75,7 @@ public class Settings {
|
||||
@Comment({"Whether to enable the Player Analytics hook.", "Docs: https://william278.net/docs/husksync/plan-hook"})
|
||||
private boolean enablePlanHook = true;
|
||||
|
||||
@Comment("Whether to cancel game event packets directly when handling locked players if ProtocolLib is installed")
|
||||
@Comment("Whether to cancel game event packets directly when handling locked players if ProtocolLib or PacketEvents is installed")
|
||||
private boolean cancelPackets = true;
|
||||
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ public class MongoDbDatabase extends Database {
|
||||
throw new MongoException("User document returned null!");
|
||||
}
|
||||
|
||||
Bson updates = Updates.set("uuid", user.getUuid().toString());
|
||||
Bson updates = Updates.set("username", user.getUsername());
|
||||
mongoCollectionHelper.updateDocument(usersTable, doc, updates);
|
||||
} catch (MongoException e) {
|
||||
plugin.log(Level.SEVERE, "Failed to insert a user into the database", e);
|
||||
|
||||
@@ -107,7 +107,7 @@ public abstract class EventListener {
|
||||
/**
|
||||
* Handle the plugin disabling
|
||||
*/
|
||||
public final void handlePluginDisable() {
|
||||
public void handlePluginDisable() {
|
||||
// Save for all online players
|
||||
plugin.getOnlineUsers().stream()
|
||||
.filter(user -> !plugin.isLocked(user.getUuid()) && !user.isNpc())
|
||||
|
||||
@@ -54,4 +54,16 @@ public interface LockedHandler {
|
||||
@ApiStatus.Internal
|
||||
HuskSync getPlugin();
|
||||
|
||||
default void onLoad() {
|
||||
|
||||
}
|
||||
|
||||
default void onEnable() {
|
||||
|
||||
}
|
||||
|
||||
default void onDisable() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ CREATE TABLE IF NOT EXISTS "%user_data_table%"
|
||||
timestamp timestamp NOT NULL,
|
||||
save_cause varchar(32) NOT NULL,
|
||||
pinned boolean NOT NULL DEFAULT FALSE,
|
||||
data longblob NOT NULL,
|
||||
data bytea NOT NULL,
|
||||
|
||||
PRIMARY KEY (version_uuid, player_uuid),
|
||||
FOREIGN KEY (player_uuid) REFERENCES "%users_table%" (uuid) ON DELETE CASCADE
|
||||
|
||||
@@ -33,7 +33,7 @@ brigadier_tab_completion: false
|
||||
# Whether to enable the Player Analytics hook.
|
||||
# Docs: https://william278.net/docs/husksync/plan-hook
|
||||
enable_plan_hook: true
|
||||
# Whether to cancel game event packets directly when handling locked players if ProtocolLib is installed
|
||||
# Whether to cancel game event packets directly when handling locked players if ProtocolLib or PacketEvents is installed
|
||||
cancel_packets: true
|
||||
# Database settings
|
||||
database:
|
||||
|
||||
@@ -11,7 +11,7 @@ This will walk you through installing HuskSync on your network of Spigot servers
|
||||
### 1. Install the jar
|
||||
- Place the plugin jar file in the `/plugins/` directory of each Spigot server.
|
||||
- You do not need to install HuskSync as a proxy plugin.
|
||||
- You can additionally install [ProtocolLib](https://www.spigotmc.org/resources/protocollib.1997/) for better locked user handling, and [Plan](https://www.spigotmc.org/resources/plan-player-analytics.32536/) for analytics.
|
||||
- You can additionally install [ProtocolLib](https://www.spigotmc.org/resources/protocollib.1997/) or [PacketEvents](https://www.spigotmc.org/resources/packetevents-api.80279/) for better locked user handling, and [Plan](https://www.spigotmc.org/resources/plan-player-analytics.32536/) for analytics.
|
||||
|
||||
### 2. Restart servers
|
||||
- Start, then stop every server to let HuskSync generate the [[config file]].
|
||||
|
||||
@@ -3,13 +3,13 @@ org.gradle.jvmargs='-Dfile.encoding=UTF-8'
|
||||
org.gradle.daemon=true
|
||||
javaVersion=17
|
||||
|
||||
plugin_version=3.5.1
|
||||
plugin_version=3.5.3
|
||||
plugin_archive=husksync
|
||||
plugin_description=A modern, cross-server player data synchronization system
|
||||
|
||||
jedis_version=5.1.2
|
||||
mysql_driver_version=8.3.0
|
||||
mariadb_driver_version=3.3.3
|
||||
jedis_version=5.1.3
|
||||
mysql_driver_version=8.4.0
|
||||
mariadb_driver_version=3.4.0
|
||||
postgres_driver_version=42.7.3
|
||||
mongodb_driver_version=5.0.1
|
||||
mongodb_driver_version=5.1.0
|
||||
snappy_version=1.1.10.5
|
||||
|
||||
@@ -9,6 +9,10 @@ api-version: '1.19'
|
||||
folia-supported: true
|
||||
dependencies:
|
||||
server:
|
||||
packetevents:
|
||||
required: false
|
||||
load: BEFORE
|
||||
join-classpath: true
|
||||
ProtocolLib:
|
||||
required: false
|
||||
load: BEFORE
|
||||
|
||||
@@ -2,6 +2,6 @@ certifi==2023.7.22
|
||||
charset-normalizer==3.2.0
|
||||
colorama==0.4.6
|
||||
idna==3.7
|
||||
requests==2.31.0
|
||||
requests==2.32.0
|
||||
tqdm==4.66.3
|
||||
urllib3==2.0.7
|
||||
|
||||
Reference in New Issue
Block a user