mirror of
https://github.com/WiIIiam278/HuskSync.git
synced 2025-12-24 09:09:18 +00:00
Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a9aa93a682 | ||
|
|
ef340840ab | ||
|
|
cf08015961 | ||
|
|
cb09e0cfb2 | ||
|
|
554fac89c0 | ||
|
|
215bed9908 | ||
|
|
935aafa74a | ||
|
|
c51ba85f38 | ||
|
|
6a67d1bbe0 | ||
|
|
20bc76a768 | ||
|
|
6928f97dff | ||
|
|
06742fb848 | ||
|
|
759983b000 | ||
|
|
5556e3b6ce | ||
|
|
bcffcb1f64 | ||
|
|
fa77e6e418 | ||
|
|
c8aa29c82f | ||
|
|
51cf982359 |
6
.github/workflows/ci.yml
vendored
6
.github/workflows/ci.yml
vendored
@@ -58,6 +58,7 @@ jobs:
|
||||
fabric-1.20.1
|
||||
fabric-1.21.1
|
||||
fabric-1.21.4
|
||||
fabric-1.21.5
|
||||
distro-groups: |
|
||||
paper
|
||||
paper
|
||||
@@ -66,6 +67,7 @@ jobs:
|
||||
fabric
|
||||
fabric
|
||||
fabric
|
||||
fabric
|
||||
distro-descriptions: |
|
||||
Paper 1.20.1
|
||||
Paper 1.21.1
|
||||
@@ -74,6 +76,7 @@ jobs:
|
||||
Fabric 1.20.1
|
||||
Fabric 1.21.1
|
||||
Fabric 1.21.4
|
||||
Fabric 1.21.5
|
||||
files: |
|
||||
target/HuskSync-Bukkit-${{ env.version_name }}+mc.1.20.1.jar
|
||||
target/HuskSync-Bukkit-${{ env.version_name }}+mc.1.21.1.jar
|
||||
@@ -81,4 +84,5 @@ jobs:
|
||||
target/HuskSync-Bukkit-${{ env.version_name }}+mc.1.21.5.jar
|
||||
target/HuskSync-Fabric-${{ env.version_name }}+mc.1.20.1.jar
|
||||
target/HuskSync-Fabric-${{ env.version_name }}+mc.1.21.1.jar
|
||||
target/HuskSync-Fabric-${{ env.version_name }}+mc.1.21.4.jar
|
||||
target/HuskSync-Fabric-${{ env.version_name }}+mc.1.21.4.jar
|
||||
target/HuskSync-Fabric-${{ env.version_name }}+mc.1.21.5.jar
|
||||
6
.github/workflows/release.yml
vendored
6
.github/workflows/release.yml
vendored
@@ -47,6 +47,7 @@ jobs:
|
||||
fabric-1.20.1
|
||||
fabric-1.21.1
|
||||
fabric-1.21.4
|
||||
fabric-1.21.5
|
||||
distro-groups: |
|
||||
paper
|
||||
paper
|
||||
@@ -55,6 +56,7 @@ jobs:
|
||||
fabric
|
||||
fabric
|
||||
fabric
|
||||
fabric
|
||||
distro-descriptions: |
|
||||
Paper 1.20.1
|
||||
Paper 1.21.1
|
||||
@@ -63,6 +65,7 @@ jobs:
|
||||
Fabric 1.20.1
|
||||
Fabric 1.21.1
|
||||
Fabric 1.21.4
|
||||
Fabric 1.21.5
|
||||
files: |
|
||||
target/HuskSync-Bukkit-${{ github.event.release.tag_name }}+mc.1.20.1.jar
|
||||
target/HuskSync-Bukkit-${{ github.event.release.tag_name }}+mc.1.21.1.jar
|
||||
@@ -70,4 +73,5 @@ jobs:
|
||||
target/HuskSync-Bukkit-${{ github.event.release.tag_name }}+mc.1.21.5.jar
|
||||
target/HuskSync-Fabric-${{ github.event.release.tag_name }}+mc.1.20.1.jar
|
||||
target/HuskSync-Fabric-${{ github.event.release.tag_name }}+mc.1.21.1.jar
|
||||
target/HuskSync-Fabric-${{ github.event.release.tag_name }}+mc.1.21.4.jar
|
||||
target/HuskSync-Fabric-${{ github.event.release.tag_name }}+mc.1.21.4.jar
|
||||
target/HuskSync-Fabric-${{ github.event.release.tag_name }}+mc.1.21.5.jar
|
||||
@@ -3,7 +3,7 @@ import org.apache.tools.ant.filters.ReplaceTokens
|
||||
plugins {
|
||||
id 'com.gradleup.shadow' version '8.3.6'
|
||||
id 'org.cadixdev.licenser' version '0.6.1' apply false
|
||||
id 'fabric-loom' version "$fabric_loom_version" apply false
|
||||
id 'dev.architectury.loom' version '1.9-SNAPSHOT' apply false
|
||||
id 'gg.essential.multi-version.root' apply false
|
||||
id 'org.ajoberstar.grgit' version '5.3.0'
|
||||
id 'maven-publish'
|
||||
@@ -137,7 +137,7 @@ subprojects {
|
||||
version += "+mc.${project.name}"
|
||||
|
||||
if (project.parent?.name?.equals('fabric')) {
|
||||
apply plugin: 'fabric-loom'
|
||||
apply plugin: 'dev.architectury.loom'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,26 +8,26 @@ plugins {
|
||||
dependencies {
|
||||
implementation project(path: ':common')
|
||||
|
||||
implementation 'net.william278.uniform:uniform-bukkit:1.3.3'
|
||||
implementation 'net.william278.uniform:uniform-paper:1.3.3'
|
||||
implementation 'net.william278.toilet:toilet-bukkit:1.0.12'
|
||||
implementation 'net.william278.uniform:uniform-bukkit:1.3.4'
|
||||
implementation 'net.william278.uniform:uniform-paper:1.3.4'
|
||||
implementation 'net.william278.toilet:toilet-bukkit:1.0.13'
|
||||
implementation 'net.william278:mpdbdataconverter:1.0.1'
|
||||
implementation 'net.william278:hsldataconverter:1.0'
|
||||
implementation 'net.william278:mapdataapi:2.0'
|
||||
implementation 'org.bstats:bstats-bukkit:3.1.0'
|
||||
implementation 'net.kyori:adventure-platform-bukkit:4.3.4'
|
||||
implementation 'net.kyori:adventure-platform-bukkit:4.4.0'
|
||||
implementation 'dev.triumphteam:triumph-gui:3.1.12'
|
||||
implementation 'space.arim.morepaperlib:morepaperlib:0.4.4'
|
||||
implementation 'de.tr7zw:item-nbt-api:2.15.0'
|
||||
implementation 'de.tr7zw:item-nbt-api:2.15.1-SNAPSHOT'
|
||||
|
||||
compileOnly "io.papermc.paper:paper-api:${paper_api_version}"
|
||||
compileOnly 'com.github.retrooper:packetevents-spigot:2.7.0'
|
||||
compileOnly 'com.github.retrooper:packetevents-spigot:2.8.0'
|
||||
compileOnly 'com.github.dmulloy2:ProtocolLib:5.3.0'
|
||||
compileOnly 'org.projectlombok:lombok:1.18.38'
|
||||
compileOnly 'commons-io:commons-io:2.19.0'
|
||||
compileOnly 'org.json:json:20250107'
|
||||
compileOnly 'org.json:json:20250517'
|
||||
compileOnly 'net.william278:minedown:1.8.2'
|
||||
compileOnly 'de.exlll:configlib-yaml:4.5.0'
|
||||
compileOnly 'de.exlll:configlib-yaml:4.6.1'
|
||||
compileOnly 'com.zaxxer:HikariCP:6.3.0'
|
||||
compileOnly 'net.william278:DesertWell:2.0.4'
|
||||
compileOnly 'net.william278:AdvancementAPI:97a9583413'
|
||||
@@ -93,5 +93,9 @@ shadowJar {
|
||||
tasks {
|
||||
runServer {
|
||||
minecraftVersion(project.name)
|
||||
|
||||
downloadPlugins {
|
||||
github("plan-player-analytics", "Plan", "5.6.2965", "Plan-5.6-build-2965.jar")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -93,9 +93,7 @@ public class BukkitHuskSync extends JavaPlugin implements HuskSync, BukkitTask.S
|
||||
private static final int METRICS_ID = 13140;
|
||||
private static final String PLATFORM_TYPE_ID = "bukkit";
|
||||
|
||||
private final TreeMap<Identifier, Serializer<? extends Data>> serializers = Maps.newTreeMap(
|
||||
SerializerRegistry.DEPENDENCY_ORDER_COMPARATOR
|
||||
);
|
||||
private final HashMap<Identifier, Serializer<? extends Data>> serializers = Maps.newHashMap();
|
||||
private final Map<UUID, Map<Identifier, Data>> playerCustomDataStore = Maps.newConcurrentMap();
|
||||
private final Map<Integer, MapView> mapViews = Maps.newConcurrentMap();
|
||||
private final List<Migrator> availableMigrators = Lists.newArrayList();
|
||||
|
||||
@@ -7,27 +7,27 @@ dependencies {
|
||||
api 'org.apache.commons:commons-text:1.13.1'
|
||||
api 'net.william278:minedown:1.8.2'
|
||||
api 'net.william278:mapdataapi:2.0'
|
||||
api 'org.json:json:20250107'
|
||||
api 'com.google.code.gson:gson:2.13.0'
|
||||
api 'org.json:json:20250517'
|
||||
api 'com.google.code.gson:gson:2.13.1'
|
||||
api 'com.fatboyindustrial.gson-javatime-serialisers:gson-javatime-serialisers:1.1.2'
|
||||
api 'de.exlll:configlib-yaml:4.5.0'
|
||||
api 'de.exlll:configlib-yaml:4.6.1'
|
||||
api 'net.william278:paginedown:1.1.2'
|
||||
api 'net.william278:DesertWell:2.0.4'
|
||||
api('com.zaxxer:HikariCP:6.3.0') {
|
||||
exclude module: 'slf4j-api'
|
||||
}
|
||||
|
||||
compileOnlyApi 'net.william278.toilet:toilet-common:1.0.12'
|
||||
compileOnlyApi 'net.william278.toilet:toilet-common:1.0.13'
|
||||
|
||||
compileOnly 'net.william278.uniform:uniform-common:1.3.3'
|
||||
compileOnly 'net.william278.uniform:uniform-common:1.3.4'
|
||||
compileOnly 'com.mojang:brigadier:1.1.8'
|
||||
compileOnly 'org.projectlombok:lombok:1.18.38'
|
||||
compileOnly 'org.jetbrains:annotations:26.0.2'
|
||||
compileOnly 'net.kyori:adventure-api:4.20.0'
|
||||
compileOnly 'net.kyori:adventure-platform-api:4.3.4'
|
||||
compileOnly "net.kyori:adventure-text-serializer-plain:4.20.0"
|
||||
compileOnly 'net.kyori:adventure-platform-api:4.4.0'
|
||||
compileOnly "net.kyori:adventure-text-serializer-plain:4.21.0"
|
||||
compileOnly 'com.google.guava:guava:33.4.8-jre'
|
||||
compileOnly 'com.github.plan-player-analytics:Plan:5.5.2272'
|
||||
compileOnly 'com.github.plan-player-analytics:Plan:5.6.2965'
|
||||
compileOnly "redis.clients:jedis:$jedis_version"
|
||||
compileOnly "com.mysql:mysql-connector-j:$mysql_driver_version"
|
||||
compileOnly "org.mariadb.jdbc:mariadb-java-client:$mariadb_driver_version"
|
||||
@@ -38,8 +38,8 @@ dependencies {
|
||||
testImplementation "redis.clients:jedis:$jedis_version"
|
||||
testImplementation "org.xerial.snappy:snappy-java:$snappy_version"
|
||||
testImplementation 'com.google.guava:guava:33.4.8-jre'
|
||||
testImplementation 'com.github.plan-player-analytics:Plan:5.5.2272'
|
||||
testCompileOnly 'de.exlll:configlib-yaml:4.5.0'
|
||||
testImplementation 'com.github.plan-player-analytics:Plan:5.6.2965'
|
||||
testCompileOnly 'de.exlll:configlib-yaml:4.6.1'
|
||||
testCompileOnly 'org.jetbrains:annotations:26.0.2'
|
||||
|
||||
annotationProcessor 'org.projectlombok:lombok:1.18.38'
|
||||
|
||||
@@ -44,7 +44,6 @@ public class InventoryCommand extends ItemsCommand {
|
||||
@NotNull User user, boolean allowEdit) {
|
||||
final Optional<Data.Items.Inventory> optionalInventory = snapshot.getInventory();
|
||||
if (optionalInventory.isEmpty()) {
|
||||
viewer.sendMessage(new MineDown("what the FUCK is happening"));
|
||||
plugin.getLocales().getLocale("error_no_data_to_display")
|
||||
.ifPresent(viewer::sendMessage);
|
||||
return;
|
||||
|
||||
@@ -159,7 +159,9 @@ public class Settings {
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public static class RedisSettings {
|
||||
|
||||
@Comment("Specify the credentials of your Redis server here. Set \"password\" to '' if you don't have one")
|
||||
@Comment({"Specify the credentials of your Redis server here.",
|
||||
"Set \"user\" to '' if you don't have one or would like to use the default user.",
|
||||
"Set \"password\" to '' if you don't have one."})
|
||||
private RedisCredentials credentials = new RedisCredentials();
|
||||
|
||||
@Getter
|
||||
@@ -168,6 +170,9 @@ public class Settings {
|
||||
public static class RedisCredentials {
|
||||
private String host = "localhost";
|
||||
private int port = 6379;
|
||||
@Comment("Only change the database if you know what you are doing. The default is 0.")
|
||||
private int database = 0;
|
||||
private String user = "";
|
||||
private String password = "";
|
||||
private boolean useSsl = false;
|
||||
}
|
||||
|
||||
@@ -370,7 +370,7 @@ public class DataSnapshot {
|
||||
public static class Unpacked extends DataSnapshot implements DataHolder {
|
||||
|
||||
@Expose(serialize = false, deserialize = false)
|
||||
private final TreeMap<Identifier, Data> deserialized;
|
||||
private final Map<Identifier, Data> deserialized;
|
||||
|
||||
private Unpacked(@NotNull UUID id, boolean pinned, @NotNull OffsetDateTime timestamp,
|
||||
@NotNull String saveCause, @NotNull String serverName, @NotNull Map<String, String> data,
|
||||
@@ -381,7 +381,7 @@ public class DataSnapshot {
|
||||
}
|
||||
|
||||
private Unpacked(@NotNull UUID id, boolean pinned, @NotNull OffsetDateTime timestamp,
|
||||
@NotNull String saveCause, @NotNull String serverName, @NotNull TreeMap<Identifier, Data> data,
|
||||
@NotNull String saveCause, @NotNull String serverName, @NotNull Map<Identifier, Data> data,
|
||||
@NotNull Version minecraftVersion, @NotNull String platformType, int formatVersion) {
|
||||
super(id, pinned, timestamp, saveCause, serverName, Map.of(), minecraftVersion, platformType, formatVersion);
|
||||
this.deserialized = data;
|
||||
@@ -389,14 +389,15 @@ public class DataSnapshot {
|
||||
|
||||
@NotNull
|
||||
@ApiStatus.Internal
|
||||
private TreeMap<Identifier, Data> deserializeData(@NotNull HuskSync plugin) {
|
||||
private Map<Identifier, Data> deserializeData(@NotNull HuskSync plugin) {
|
||||
return data.entrySet().stream()
|
||||
.filter(e -> plugin.getIdentifier(e.getKey()).isPresent())
|
||||
.map(entry -> Map.entry(plugin.getIdentifier(entry.getKey()).orElseThrow(), entry.getValue()))
|
||||
.collect(Collectors.toMap(
|
||||
Map.Entry::getKey,
|
||||
entry -> plugin.deserializeData(entry.getKey(), entry.getValue(), getMinecraftVersion()),
|
||||
(a, b) -> b, () -> Maps.newTreeMap(SerializerRegistry.DEPENDENCY_ORDER_COMPARATOR)
|
||||
(a, b) -> a,
|
||||
HashMap::new
|
||||
));
|
||||
}
|
||||
|
||||
@@ -423,6 +424,20 @@ public class DataSnapshot {
|
||||
return deserialized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a sorted iterable of the snapshots the snapshot is holding
|
||||
*
|
||||
* @return The data map
|
||||
* @since 3.8.2
|
||||
*/
|
||||
@NotNull
|
||||
@ApiStatus.Internal
|
||||
public Iterable<Map.Entry<Identifier, Data>> getSortedIterable() {
|
||||
final TreeMap<Identifier, Data> tree = Maps.newTreeMap(SerializerRegistry.DEPENDENCY_ORDER_COMPARATOR);
|
||||
tree.putAll(deserialized);
|
||||
return tree.entrySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Pack the {@link DataSnapshot} into a {@link DataSnapshot.Packed packed} snapshot
|
||||
*
|
||||
@@ -455,12 +470,12 @@ public class DataSnapshot {
|
||||
private String serverName;
|
||||
private boolean pinned;
|
||||
private OffsetDateTime timestamp;
|
||||
private final TreeMap<Identifier, Data> data;
|
||||
private final Map<Identifier, Data> data;
|
||||
|
||||
private Builder(@NotNull HuskSync plugin) {
|
||||
this.plugin = plugin;
|
||||
this.pinned = false;
|
||||
this.data = Maps.newTreeMap(SerializerRegistry.DEPENDENCY_ORDER_COMPARATOR);
|
||||
this.data = Maps.newHashMap();
|
||||
this.timestamp = OffsetDateTime.now();
|
||||
this.id = UUID.randomUUID();
|
||||
this.serverName = plugin.getServerName();
|
||||
|
||||
@@ -26,6 +26,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public interface SerializerRegistry {
|
||||
|
||||
@@ -40,7 +41,7 @@ public interface SerializerRegistry {
|
||||
* @since 3.0
|
||||
*/
|
||||
@NotNull
|
||||
<T extends Data> TreeMap<Identifier, Serializer<T>> getSerializers();
|
||||
<T extends Data> Map<Identifier, Serializer<T>> getSerializers();
|
||||
|
||||
/**
|
||||
* Register a data serializer for the given {@link Identifier}
|
||||
@@ -87,8 +88,7 @@ public interface SerializerRegistry {
|
||||
* @since 3.0
|
||||
*/
|
||||
default Optional<Identifier> getIdentifier(@NotNull String key) {
|
||||
return getSerializers().keySet().stream()
|
||||
.filter(id -> id.getKey().asString().equals(key)).findFirst();
|
||||
return getSerializers().keySet().stream().filter(e -> e.toString().equals(key)).findFirst();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -99,9 +99,7 @@ public interface SerializerRegistry {
|
||||
* @since 3.5.4
|
||||
*/
|
||||
default Optional<Serializer<Data>> getSerializer(@NotNull Identifier identifier) {
|
||||
return getSerializers().entrySet().stream()
|
||||
.filter(entry -> entry.getKey().getKey().equals(identifier.getKey()))
|
||||
.map(Map.Entry::getValue).findFirst();
|
||||
return Optional.ofNullable(getSerializers().get(identifier));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -153,14 +151,14 @@ public interface SerializerRegistry {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the set of registered data types
|
||||
* Get the list of registered data types, in dependency order
|
||||
*
|
||||
* @return the set of registered data types
|
||||
* @return the list of registered data types
|
||||
* @since 3.0
|
||||
*/
|
||||
@NotNull
|
||||
default Set<Identifier> getRegisteredDataTypes() {
|
||||
return getSerializers().keySet();
|
||||
default List<Identifier> getRegisteredDataTypes() {
|
||||
return getSerializers().keySet().stream().sorted(DEPENDENCY_ORDER_COMPARATOR).toList();
|
||||
}
|
||||
|
||||
// Returns if a data type is available and enabled in the config
|
||||
|
||||
@@ -26,7 +26,6 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -127,7 +126,7 @@ public interface UserDataHolder extends DataHolder {
|
||||
}
|
||||
|
||||
try {
|
||||
for (Map.Entry<Identifier, Data> entry : unpacked.getData().entrySet()) {
|
||||
for (Map.Entry<Identifier, Data> entry : unpacked.getSortedIterable()) {
|
||||
final Identifier identifier = entry.getKey();
|
||||
if (!identifier.isEnabled()) {
|
||||
continue;
|
||||
|
||||
@@ -65,9 +65,11 @@ public class RedisManager extends JedisPubSub {
|
||||
@Blocking
|
||||
public void initialize() throws IllegalStateException {
|
||||
final Settings.RedisSettings.RedisCredentials credentials = plugin.getSettings().getRedis().getCredentials();
|
||||
final String user = credentials.getUser();
|
||||
final String password = credentials.getPassword();
|
||||
final String host = credentials.getHost();
|
||||
final int port = credentials.getPort();
|
||||
final int database = credentials.getDatabase();
|
||||
final boolean useSSL = credentials.isUseSsl();
|
||||
|
||||
// Create the jedis pool
|
||||
@@ -79,9 +81,20 @@ public class RedisManager extends JedisPubSub {
|
||||
final Settings.RedisSettings.RedisSentinel sentinel = plugin.getSettings().getRedis().getSentinel();
|
||||
Set<String> redisSentinelNodes = new HashSet<>(sentinel.getNodes());
|
||||
if (redisSentinelNodes.isEmpty()) {
|
||||
this.jedisPool = password.isEmpty()
|
||||
? new JedisPool(config, host, port, 0, useSSL)
|
||||
: new JedisPool(config, host, port, 0, password, useSSL);
|
||||
DefaultJedisClientConfig.Builder clientConfigBuilder = DefaultJedisClientConfig.builder()
|
||||
.ssl(useSSL)
|
||||
.database(database)
|
||||
.timeoutMillis(0);
|
||||
|
||||
if (!user.isEmpty()) {
|
||||
clientConfigBuilder.user(user);
|
||||
}
|
||||
|
||||
if (!password.isEmpty()) {
|
||||
clientConfigBuilder.password(password);
|
||||
}
|
||||
|
||||
this.jedisPool = new JedisPool(config, new HostAndPort(host, port), clientConfigBuilder.build());
|
||||
} else {
|
||||
final String sentinelPassword = sentinel.getPassword();
|
||||
this.jedisPool = new JedisSentinelPool(sentinel.getMaster(), redisSentinelNodes, password.isEmpty()
|
||||
|
||||
@@ -100,6 +100,8 @@ public interface DumpProvider {
|
||||
Map.entry("Redis Version", StatusLine.REDIS_VERSION.getValue(getPlugin())),
|
||||
Map.entry("Redis Latency", StatusLine.REDIS_LATENCY.getValue(getPlugin())),
|
||||
Map.entry("Redis Sentinel", StatusLine.USING_REDIS_SENTINEL.getValue(getPlugin())),
|
||||
Map.entry("Redis Database", StatusLine.REDIS_DATABASE.getValue(getPlugin())),
|
||||
Map.entry("Redis User", StatusLine.USING_REDIS_USER.getValue(getPlugin())),
|
||||
Map.entry("Redis Password", StatusLine.USING_REDIS_PASSWORD.getValue(getPlugin())),
|
||||
Map.entry("Redis SSL", StatusLine.REDIS_USING_SSL.getValue(getPlugin())),
|
||||
Map.entry("Redis Local", StatusLine.IS_REDIS_LOCAL.getValue(getPlugin()))
|
||||
|
||||
@@ -60,6 +60,10 @@ public enum StatusLine {
|
||||
USING_REDIS_SENTINEL(plugin -> getBoolean(
|
||||
!plugin.getSettings().getRedis().getSentinel().getMaster().isBlank()
|
||||
)),
|
||||
REDIS_DATABASE(plugin -> Component.text(plugin.getSettings().getRedis().getCredentials().getDatabase())),
|
||||
USING_REDIS_USER(plugin -> getBoolean(
|
||||
!plugin.getSettings().getRedis().getCredentials().getUser().isBlank()
|
||||
)),
|
||||
USING_REDIS_PASSWORD(plugin -> getBoolean(
|
||||
!plugin.getSettings().getRedis().getCredentials().getPassword().isBlank()
|
||||
)),
|
||||
|
||||
@@ -23,7 +23,7 @@ locales:
|
||||
data_list_title: '[%1% 的玩家資料快照:](#00fb9a) [(%2%-%3% 共](#00fb9a) [%4%](#00fb9a bold)[)](#00fb9a)\n'
|
||||
data_list_item: '[%1%](gray show_text=&7玩家資料快照 %2%\n&8⚡ %4% run_command=/userdata view %2% %3%) [%5%](#d8ff2b show_text=&7已標記:\n&8標記的快照將不會自動輪換。 run_command=/userdata view %2% %3%) [%6%](color=#ffc43b-#f5c962 show_text=&7版本時間戳:\n&8資料儲存時間\n&8%7% run_command=/userdata view %2% %3%) [⚑ %8%](#23a825-#36f539 show_text=&7儲存原因:\n&8觸發儲存的原因 run_command=/userdata view %2% %3%) [⏏ %9%](color=#62a9f5-#7ab8fa show_text=&7快照大小:\n&8快照的預估檔案大小(KiB) run_command=/userdata view %2% %3%)'
|
||||
data_list_item_invalid: '[%1%](dark_gray show_text=&7玩家資料快照 %2%\n&8⚡ %4% suggest_command=/userdata delete %2% %3%) [%5%](dark_gray show_text=&7已標記:\n&8標記的快照將不會自動輪換。 suggest_command=/userdata delete %2% %3%) [%6% ⚑ %8% ⏏ %9%](gray strikethrough show_text=&#ff3300&無效的資料快照\n&#ff7e5e&點擊刪除\n\n&7⚠ %10% suggest_command=/userdata delete %2% %3%)'
|
||||
data_saved: '[Successfully saved a snapshot of %1%''s current user data.](#00fb9a)'
|
||||
data_saved: '[✅ 成功儲存 %1% 的目前使用者資料快照。](#00fb9a)'
|
||||
data_deleted: '[❌ 成功刪除:](#00fb9a) [%3%](#00fb9a show_text=&7玩家 UUID:\n&8%4%) [的快照:](#00fb9a) [%1%](#00fb9a show_text=&7Version UUID:\n&8%2%)'
|
||||
data_restored: '[⏪ 成功將玩家](#00fb9a) [%1%](#00fb9a show_text=&7玩家 UUID:\n&8%2%)[的資料恢復為 快照:](#00fb9a) [%3%.](#00fb9a show_text=&7Version UUID:\n&8%4%)'
|
||||
data_pinned: '[※ 成功標記](#00fb9a) [%3%](#00fb9a show_text=&7玩家 UUID:\n&8%4%) [的快照:](#00fb9a) [%1%](#00fb9a show_text=&7Version UUID:\n&8%2%)'
|
||||
@@ -41,8 +41,8 @@ locales:
|
||||
save_cause_world_save: '世界儲存'
|
||||
save_cause_death: '死亡'
|
||||
save_cause_server_shutdown: '伺服器關閉'
|
||||
save_cause_save_command: 'save command'
|
||||
save_cause_dump_command: 'dump command'
|
||||
save_cause_save_command: '儲存指令'
|
||||
save_cause_dump_command: '導出指令'
|
||||
save_cause_inventory_command: '背包指令'
|
||||
save_cause_enderchest_command: '終界箱指令'
|
||||
save_cause_backup_restore: '備份還原'
|
||||
@@ -54,9 +54,9 @@ locales:
|
||||
update_available: '[HuskSync](#ff7e5e bold) [| 發現可用的新版本: v%1% (running: v%2%).](#ff7e5e)'
|
||||
reload_complete: '[HuskSync](#00fb9a bold) [| 配置和語言文件已重新加載。](#00fb9a)\n[⚠ 確保所有伺服器上的配置文件都是最新的!](#00fb9a)\n[重啟後配置變更才會生效。](#00fb9a italic)'
|
||||
system_status_header: '[HuskSync](#00fb9a bold) [| 系統狀態報告:](#00fb9a)'
|
||||
system_dump_confirm: '[HuskSync](#00fb9a bold) [| Prepare a system dump? This will include:](#00fb9a)\n[• Your latest server logs and HuskSync config files](gray)\n[• Current plugin system status information](gray)\n[• Information about your Java & Minecraft server environment](gray)\n[• A list of other currently installed plugins](gray)\n[To confirm, use:](#00fb9a) [/husksync dump confirm](#00fb9a italic show_text=&7Click to prepare dump run_command=/husksync dump confirm)'
|
||||
system_dump_started: '[HuskSync](#00fb9a bold) [| Preparing system status dump, please wait…](#00fb9a)'
|
||||
system_dump_ready: '[HuskSync](#00fb9a bold) [| System status dump prepared! Click to view:](#00fb9a)'
|
||||
system_dump_confirm: '[HuskSync](#00fb9a bold) [| 要產生系統狀態紀錄檔嗎?這將包含以下內容:](#00fb9a)\n[• 最近的伺服器日誌與 HuskSync 設定檔](gray)\n[• 插件目前的系統狀態資訊](gray)\n[• 有關您的 Java 與 Minecraft 伺服器環境的資訊](gray)\n[• 目前已安裝的其他插件清單](gray)\n[若要確認,請輸入:](#00fb9a) [/husksync dump confirm](#00fb9a italic show_text=&7點擊以產生紀錄檔 run_command=/husksync dump confirm)'
|
||||
system_dump_started: '[HuskSync](#00fb9a bold) [| 正在產生系統狀態紀錄檔,請稍候…](#00fb9a)'
|
||||
system_dump_ready: '[HuskSync](#00fb9a bold) [| 系統狀態紀錄檔已完成!點擊以下連結以查看:](#00fb9a)'
|
||||
error_invalid_syntax: '[錯誤:](#ff3300) [語法不正確,用法:](#ff7e5e) [%1%](#ff7e5e italic show_text=&#ff7e5e&點擊建議 suggest_command=%1%)'
|
||||
error_invalid_player: '[錯誤:](#ff3300) [找不到這位玩家](#ff7e5e)'
|
||||
error_invalid_data: '[錯誤:](#ff3300) [無法解壓使用者資料,因為快照無效或已損壞。](#ff7e5e) [(詳細資訊…)](gray show_text=&7⚠ %1%)'
|
||||
|
||||
@@ -32,5 +32,5 @@ This plugin does not support the following software-Minecraft version combinatio
|
||||
## Incompatible plugins / mods
|
||||
Please note the following plugins / mods can cause issues with HuskSync:
|
||||
|
||||
* Restart plugins / mods are not supported. These will cause [player data to not save correctly when your server restarts](troubleshooting#issues-with-player-data-going-out-of-sync-during-a-server-restart) due to the way these plugins utilise bash scripts. It's important to understand that restart plugins don't actually restart yur server, they just trigger some (often unstable) process-killing scripting logic to occur!
|
||||
* Restart plugins / mods are not supported. These will cause [player data to not save correctly when your server restarts](troubleshooting#issues-with-player-data-going-out-of-sync-during-a-server-restart) due to the way these plugins utilise bash scripts. It's important to understand that restart plugins don't actually restart your server, they just trigger some (often unstable) process-killing scripting logic to occur!
|
||||
* Combat logging plugins / mods are not supported. Some have built-in support for HuskSync and should work as expected, but for others you may wish to modify the [[Event Priorities]]
|
||||
@@ -65,10 +65,15 @@ database:
|
||||
user_data: husksync_user_data
|
||||
# Redis settings
|
||||
redis:
|
||||
# Specify the credentials of your Redis server here. Set "password" to '' if you don't have one
|
||||
# Specify the credentials of your Redis server here.
|
||||
# Set "user" to '' if you don't have one or would like to use the default user.
|
||||
# Set "password" to '' if you don't have one.
|
||||
credentials:
|
||||
host: localhost
|
||||
port: 6379
|
||||
# Only change the database if you know what you are doing. The default is 0.
|
||||
database: 0
|
||||
user: ''
|
||||
password: ''
|
||||
use_ssl: false
|
||||
# Options for if you're using Redis sentinel. Don't modify this unless you know what you're doing!
|
||||
|
||||
@@ -16,10 +16,15 @@ To configure Redis, navigate to your [`config.yml`](Config-File) file and modify
|
||||
```yaml
|
||||
# Redis settings
|
||||
redis:
|
||||
# Specify the credentials of your Redis server here. Set "password" to '' if you don't have one
|
||||
# Specify the credentials of your Redis server here.
|
||||
# Set "user" to '' if you don't have one or would like to use the default user.
|
||||
# Set "password" to '' if you don't have one.
|
||||
credentials:
|
||||
host: localhost
|
||||
port: 6379
|
||||
# Only change the database if you know what you are doing. The default is 0.
|
||||
database: 0
|
||||
user: ''
|
||||
password: ''
|
||||
use_ssl: false
|
||||
# Options for if you're using Redis sentinel. Don't modify this unless you know what you're doing!
|
||||
@@ -33,8 +38,9 @@ redis:
|
||||
</details>
|
||||
|
||||
### Credentials
|
||||
Enter the hostname, port, and default user password of your Redis server.
|
||||
Enter the hostname, port, user, and password of your Redis server.
|
||||
|
||||
If you don't have a Redis user, just use the default user password and leave the user field empty (`user: ''`).
|
||||
If your Redis default user doesn't have a password, leave the password field blank (`password: ''`') and the plugin will attempt to connect without a password.
|
||||
|
||||
### Default user password
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
essential.defaults.loom.mappings=net.fabricmc:yarn:1.21.4+build.4:v2
|
||||
|
||||
fabric_loader_version=0.16.10
|
||||
fabric_api_version=0.115.0+1.21.4
|
||||
fabric_api_version=0.116.1+1.21.4
|
||||
fabric_permissions_api_version=0.3.3
|
||||
fabric_adventure_platform_version=6.2.0
|
||||
fabric_adventure_platform_version=6.3.0
|
||||
fabric_sgui_version=1.8.2+1.21.4
|
||||
7
fabric/1.21.5/gradle.properties
Normal file
7
fabric/1.21.5/gradle.properties
Normal file
@@ -0,0 +1,7 @@
|
||||
essential.defaults.loom.mappings=net.fabricmc:yarn:1.21.5+build.1:v2
|
||||
|
||||
fabric_loader_version=0.16.14
|
||||
fabric_api_version=0.122.0+1.21.5
|
||||
fabric_permissions_api_version=0.3.3
|
||||
fabric_adventure_platform_version=6.4.0-SNAPSHOT
|
||||
fabric_sgui_version=1.9.0+1.21.5
|
||||
@@ -14,16 +14,23 @@ dependencies {
|
||||
modImplementation include("net.kyori:adventure-platform-fabric:${fabric_adventure_platform_version}")
|
||||
modImplementation include("me.lucko:fabric-permissions-api:${fabric_permissions_api_version}")
|
||||
modImplementation include("eu.pb4:sgui:${fabric_sgui_version}")
|
||||
modImplementation include("net.william278.uniform:uniform-fabric:1.3.3+${project.name}")
|
||||
modImplementation include("net.william278.toilet:toilet-fabric:1.0.12+${project.name}")
|
||||
modImplementation include("net.william278.uniform:uniform-fabric:1.3.4+${project.name}")
|
||||
modImplementation include("net.william278.toilet:toilet-fabric:1.0.13+${project.name}")
|
||||
modImplementation "net.fabricmc.fabric-api:fabric-api:${fabric_api_version}"
|
||||
|
||||
// Manually include config deps due to the way including api deps works
|
||||
implementation include("de.exlll:configlib-core:4.6.1")
|
||||
implementation include("org.snakeyaml:snakeyaml-engine:2.7")
|
||||
implementation include('org.apache.commons:commons-pool2:2.12.1')
|
||||
|
||||
// Include driver deps due to no runtime dep loading support
|
||||
implementation include("com.mysql:mysql-connector-j:$mysql_driver_version")
|
||||
implementation include("org.postgresql:postgresql:$postgres_driver_version")
|
||||
implementation include("org.mariadb.jdbc:mariadb-java-client:$mariadb_driver_version")
|
||||
implementation include("redis.clients:jedis:$jedis_version")
|
||||
implementation include("org.xerial.snappy:snappy-java:$snappy_version")
|
||||
implementation include("redis.clients:jedis:$jedis_version")
|
||||
implementation include("redis.clients.authentication:redis-authx-core:0.1.1-beta2") // Redis dep
|
||||
implementation include('org.apache.commons:commons-pool2:2.12.1') // Redis dep
|
||||
|
||||
compileOnly 'net.william278:DesertWell:2.0.4'
|
||||
compileOnly 'org.jetbrains:annotations:26.0.2'
|
||||
|
||||
@@ -1 +1 @@
|
||||
1.21.4
|
||||
1.21.5
|
||||
@@ -3,11 +3,13 @@ plugins {
|
||||
}
|
||||
|
||||
preprocess {
|
||||
def fabric12105 = createNode("1.21.5", 12105, "yarn")
|
||||
def fabric12104 = createNode("1.21.4", 12104, "yarn")
|
||||
def fabric12101 = createNode("1.21.1", 12101, "yarn")
|
||||
def fabric12001 = createNode("1.20.1", 12001, "yarn")
|
||||
|
||||
strictExtraMappings.set(true)
|
||||
fabric12101.link(fabric12104, null)
|
||||
fabric12001.link(fabric12104, null)
|
||||
fabric12104.link(fabric12105, null)
|
||||
fabric12101.link(fabric12105, null)
|
||||
fabric12001.link(fabric12105, null)
|
||||
}
|
||||
@@ -102,9 +102,7 @@ public class FabricHuskSync implements DedicatedServerModInitializer, HuskSync,
|
||||
private static final int VERSION1_21_4 = 4189; // Current
|
||||
private static final int VERSION1_21_5 = 4323;
|
||||
|
||||
private final TreeMap<Identifier, Serializer<? extends Data>> serializers = Maps.newTreeMap(
|
||||
SerializerRegistry.DEPENDENCY_ORDER_COMPARATOR
|
||||
);
|
||||
private final HashMap<Identifier, Serializer<? extends Data>> serializers = Maps.newHashMap();
|
||||
private final Map<UUID, Map<Identifier, Data>> playerCustomDataStore = Maps.newConcurrentMap();
|
||||
private final Map<String, Boolean> permissions = Maps.newHashMap();
|
||||
private final List<Migrator> availableMigrators = Lists.newArrayList();
|
||||
|
||||
@@ -188,7 +188,11 @@ public abstract class FabricData implements Data {
|
||||
for (int slot = 0; slot < player.getInventory().size(); slot++) {
|
||||
player.getInventory().setStack(slot, items[slot] == null ? ItemStack.EMPTY : items[slot]);
|
||||
}
|
||||
player.getInventory().selectedSlot = heldItemSlot;
|
||||
//#if MC<12105
|
||||
//$$ player.getInventory().selectedSlot = heldItemSlot;
|
||||
//#else
|
||||
player.getInventory().setSelectedSlot(heldItemSlot);
|
||||
//#endif
|
||||
player.playerScreenHandler.sendContentUpdates();
|
||||
player.getInventory().updateItems();
|
||||
}
|
||||
@@ -552,13 +556,13 @@ public abstract class FabricData implements Data {
|
||||
// This is necessary to prevent weird re-mappings with Registry#getKey()
|
||||
//#if MC>0
|
||||
//$$ final Registry<?> registry = stat.getValue().getRegistry();
|
||||
//$$ final String registryId = registry.getKey().getValue().toString();
|
||||
//$$ final String registryId = registry.getKey().getValue().value();
|
||||
//$$ if (registryId.equals("custom_stat")) {
|
||||
//$$ return;
|
||||
//$$ }
|
||||
//#else
|
||||
final Registry<?> registry = stat.getValue().getRegistry();
|
||||
final String registryId = registry.getKey().getValue().toString();
|
||||
final String registryId = registry.getKey().getValue().value();
|
||||
if (registryId.equals("custom_stat")) {
|
||||
return;
|
||||
}
|
||||
@@ -888,7 +892,11 @@ public abstract class FabricData implements Data {
|
||||
|
||||
@Override
|
||||
public void apply(@NotNull FabricUser user, @NotNull FabricHuskSync plugin) throws IllegalStateException {
|
||||
user.getPlayer().changeGameMode(net.minecraft.world.GameMode.byName(gameMode));
|
||||
//#if MC<12105
|
||||
//$$ user.getPlayer().changeGameMode(net.minecraft.world.GameMode.byName(gameMode));
|
||||
//#else
|
||||
user.getPlayer().changeGameMode(net.minecraft.world.GameMode.byId(gameMode));
|
||||
//#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -76,17 +76,29 @@ public abstract class FabricSerializer {
|
||||
final FabricHuskSync plugin = (FabricHuskSync) getPlugin();
|
||||
final NbtCompound root;
|
||||
try {
|
||||
root = StringNbtReader.parse(serialized);
|
||||
//#if MC<12105
|
||||
//$$ root = StringNbtReader.parse(serialized);
|
||||
//#else
|
||||
root = StringNbtReader.readCompound(serialized);
|
||||
//#endif
|
||||
} catch (Throwable e) {
|
||||
throw new DeserializationException("Failed to read item NBT from string (%s)".formatted(serialized), e);
|
||||
}
|
||||
|
||||
// Deserialize the inventory data
|
||||
final NbtCompound items = root.contains(ITEMS_TAG) ? root.getCompound(ITEMS_TAG) : null;
|
||||
//#if MC<12105
|
||||
//$$ final NbtCompound items = root.contains(ITEMS_TAG) ? root.getCompound(ITEMS_TAG) : null;
|
||||
//$$ return FabricData.Items.Inventory.from(
|
||||
//$$ items != null ? getItems(items, dataMcVersion, plugin) : new ItemStack[INVENTORY_SLOT_COUNT],
|
||||
//$$ root.contains(HELD_ITEM_SLOT_TAG) ? root.getInt(HELD_ITEM_SLOT_TAG) : 0
|
||||
//$$ );
|
||||
//#else
|
||||
final NbtCompound items = root.contains(ITEMS_TAG) ? root.getCompoundOrEmpty(ITEMS_TAG) : null;
|
||||
return FabricData.Items.Inventory.from(
|
||||
items != null ? getItems(items, dataMcVersion, plugin) : new ItemStack[INVENTORY_SLOT_COUNT],
|
||||
root.contains(HELD_ITEM_SLOT_TAG) ? root.getInt(HELD_ITEM_SLOT_TAG) : 0
|
||||
items != null ? getItems(items, dataMcVersion, plugin) : new ItemStack[INVENTORY_SLOT_COUNT],
|
||||
root.getInt(HELD_ITEM_SLOT_TAG, 0)
|
||||
);
|
||||
//#endif
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -121,7 +133,11 @@ public abstract class FabricSerializer {
|
||||
throws DeserializationException {
|
||||
final FabricHuskSync plugin = (FabricHuskSync) getPlugin();
|
||||
try {
|
||||
final NbtCompound items = StringNbtReader.parse(serialized);
|
||||
//#if MC<12105
|
||||
//$$ final NbtCompound items = StringNbtReader.parse(serialized);
|
||||
//#else
|
||||
final NbtCompound items = StringNbtReader.readCompound(serialized);
|
||||
//#endif
|
||||
return FabricData.Items.EnderChest.adapt(getItems(items, dataMcVersion, plugin));
|
||||
} catch (Throwable e) {
|
||||
throw new DeserializationException("Failed to read item NBT from string (%s)".formatted(serialized), e);
|
||||
@@ -153,14 +169,26 @@ public abstract class FabricSerializer {
|
||||
return upgradeItemStacks(tag, mcVersion, plugin);
|
||||
}
|
||||
|
||||
final ItemStack[] contents = new ItemStack[tag.getInt("size")];
|
||||
final NbtList itemList = tag.getList("items", NbtElement.COMPOUND_TYPE);
|
||||
final DynamicRegistryManager registryManager = plugin.getMinecraftServer().getRegistryManager();
|
||||
//#if MC<12105
|
||||
//$$ final ItemStack[] contents = new ItemStack[tag.getInt("size")];
|
||||
//$$ final NbtList itemList = tag.getList("items", NbtElement.COMPOUND_TYPE);
|
||||
//$$ itemList.forEach(element -> {
|
||||
//$$ final NbtCompound compound = (NbtCompound) element;
|
||||
//$$ contents[compound.getInt("Slot")] = decodeNbt(element, registryManager);
|
||||
//$$ });
|
||||
//#else
|
||||
final ItemStack[] contents = new ItemStack[tag.getInt("size", 0)];
|
||||
final NbtList itemList = tag.getListOrEmpty("items");
|
||||
itemList.forEach(element -> {
|
||||
final NbtCompound compound = (NbtCompound) element;
|
||||
contents[compound.getInt("Slot")] = decodeNbt(element, registryManager);
|
||||
int i = compound.getInt("Slot", -1);
|
||||
if (i >= 0) {
|
||||
contents[i] = decodeNbt(element, registryManager);
|
||||
}
|
||||
});
|
||||
plugin.debug(Arrays.toString(contents));
|
||||
//#endif
|
||||
|
||||
return contents;
|
||||
} catch (Throwable e) {
|
||||
throw new Serializer.DeserializationException("Failed to read item NBT string (%s)".formatted(tag), e);
|
||||
@@ -199,19 +227,37 @@ public abstract class FabricSerializer {
|
||||
@NotNull
|
||||
private ItemStack @NotNull [] upgradeItemStacks(@NotNull NbtCompound items, @NotNull Version mcVersion,
|
||||
@NotNull FabricHuskSync plugin) {
|
||||
final int size = items.getInt("size");
|
||||
final NbtList list = items.getList("items", NbtElement.COMPOUND_TYPE);
|
||||
//#if MC<12105
|
||||
//$$ final int size = items.getInt("size");
|
||||
//$$ final NbtList list = items.getList("items", NbtElement.COMPOUND_TYPE);
|
||||
//$$ final ItemStack[] itemStacks = new ItemStack[size];
|
||||
//$$ final DynamicRegistryManager registryManager = plugin.getMinecraftServer().getRegistryManager();
|
||||
//$$ Arrays.fill(itemStacks, ItemStack.EMPTY);
|
||||
//$$ for (int i = 0; i < size; i++) {
|
||||
//$$ if (list.getCompound(i) == null) {
|
||||
//$$ continue;
|
||||
//$$ }
|
||||
//$$ final NbtCompound compound = list.getCompound(i);
|
||||
//$$ final int slot = compound.getInt("Slot");
|
||||
//$$ itemStacks[slot] = decodeNbt(upgradeItemData(list.getCompound(i), mcVersion, plugin), registryManager);
|
||||
//$$ }
|
||||
//#else
|
||||
final int size = items.getInt("size", 0);
|
||||
final NbtList list = items.getListOrEmpty("items");
|
||||
final ItemStack[] itemStacks = new ItemStack[size];
|
||||
final DynamicRegistryManager registryManager = plugin.getMinecraftServer().getRegistryManager();
|
||||
Arrays.fill(itemStacks, ItemStack.EMPTY);
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (list.getCompound(i) == null) {
|
||||
final NbtCompound compound = list.getCompoundOrEmpty(i);
|
||||
if (compound.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
final NbtCompound compound = list.getCompound(i);
|
||||
final int slot = compound.getInt("Slot");
|
||||
itemStacks[slot] = decodeNbt(upgradeItemData(list.getCompound(i), mcVersion, plugin), registryManager);
|
||||
final int slot = compound.getInt("Slot", -1);
|
||||
if (slot >= 0) {
|
||||
itemStacks[slot] = decodeNbt(upgradeItemData(compound, mcVersion, plugin), registryManager);
|
||||
}
|
||||
}
|
||||
//#endif
|
||||
return itemStacks;
|
||||
}
|
||||
|
||||
|
||||
@@ -79,27 +79,41 @@ public interface FabricUserDataHolder extends UserDataHolder {
|
||||
final PlayerInventory inventory = getPlayer().getInventory();
|
||||
return Optional.of(FabricData.Items.Inventory.from(
|
||||
getCombinedInventory(inventory),
|
||||
inventory.selectedSlot
|
||||
//#if MC<12105
|
||||
//$$ inventory.selectedSlot
|
||||
//#else
|
||||
inventory.getSelectedSlot()
|
||||
//#endif
|
||||
));
|
||||
}
|
||||
|
||||
// Gets the player's combined inventory; their inventory, plus offhand and armor.
|
||||
@Nullable
|
||||
private ItemStack @NotNull [] getCombinedInventory(@NotNull PlayerInventory inv) {
|
||||
final ItemStack[] combined = new ItemStack[inv.main.size() + inv.armor.size() + inv.offHand.size()];
|
||||
System.arraycopy(
|
||||
inv.main.toArray(new ItemStack[0]), 0, combined,
|
||||
0, inv.main.size()
|
||||
);
|
||||
System.arraycopy(
|
||||
inv.armor.toArray(new ItemStack[0]), 0, combined,
|
||||
inv.main.size(), inv.armor.size()
|
||||
);
|
||||
System.arraycopy(
|
||||
inv.offHand.toArray(new ItemStack[0]), 0, combined,
|
||||
inv.main.size() + inv.armor.size(), inv.offHand.size()
|
||||
);
|
||||
//#if MC<12105
|
||||
//$$ final ItemStack[] combined = new ItemStack[inv.main.size() + inv.armor.size() + inv.offHand.size()];
|
||||
//$$ System.arraycopy(
|
||||
//$$ inv.main.toArray(new ItemStack[0]), 0, combined,
|
||||
//$$ 0, inv.main.size()
|
||||
//$$ );
|
||||
//$$ System.arraycopy(
|
||||
//$$ inv.armor.toArray(new ItemStack[0]), 0, combined,
|
||||
//$$ inv.main.size(), inv.armor.size()
|
||||
//$$ );
|
||||
//$$ System.arraycopy(
|
||||
//$$ inv.offHand.toArray(new ItemStack[0]), 0, combined,
|
||||
//$$ inv.main.size() + inv.armor.size(), inv.offHand.size()
|
||||
//$$ );
|
||||
//$$ return combined;
|
||||
//#else
|
||||
final ItemStack[] combined = new ItemStack[inv.size()];
|
||||
int slot = 0;
|
||||
for (ItemStack itemStack : inv) {
|
||||
combined[slot] = itemStack;
|
||||
slot++;
|
||||
}
|
||||
return combined;
|
||||
//#endif
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -71,7 +71,11 @@ public abstract class ServerPlayNetworkHandlerMixin {
|
||||
|
||||
@Inject(method = "onClickSlot", at = @At("HEAD"), cancellable = true)
|
||||
public void onClickSlot(ClickSlotC2SPacket packet, CallbackInfo ci) {
|
||||
int slot = packet.getSlot();
|
||||
//#if MC<12105
|
||||
//$$ int slot = packet.getSlot();
|
||||
//#else
|
||||
int slot = packet.slot();
|
||||
//#endif
|
||||
if (slot < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ org.gradle.daemon=true
|
||||
javaVersion=21
|
||||
|
||||
# Plugin metadata
|
||||
plugin_version=3.8.1
|
||||
plugin_version=3.8.4
|
||||
plugin_archive=husksync
|
||||
plugin_description=A modern, cross-server player data synchronization system
|
||||
|
||||
@@ -17,4 +17,4 @@ mongodb_driver_version=5.5.0
|
||||
snappy_version=1.1.10.7
|
||||
|
||||
# Fabric settings
|
||||
fabric_loom_version=1.9-SNAPSHOT
|
||||
loom.ignoreDependencyLoomVersionValidation=true
|
||||
@@ -66,6 +66,9 @@ redis:
|
||||
credentials:
|
||||
host: localhost
|
||||
port: 6379
|
||||
# Only change the database if you know what you are doing. The default is 0.
|
||||
database: 0
|
||||
user: ''
|
||||
password: ''
|
||||
use_ssl: false
|
||||
|
||||
|
||||
Reference in New Issue
Block a user