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

feat: add ability to run /userdata dump without args

This commit is contained in:
William278
2025-03-08 12:43:27 +00:00
parent b725015318
commit 02c8b899dc
24 changed files with 91 additions and 41 deletions

View File

@@ -149,7 +149,7 @@ public class HuskSyncAPI {
*/ */
public CompletableFuture<Optional<DataSnapshot.Unpacked>> getCurrentData(@NotNull User user) { public CompletableFuture<Optional<DataSnapshot.Unpacked>> getCurrentData(@NotNull User user) {
return plugin.getRedisManager() return plugin.getRedisManager()
.getUserData(UUID.randomUUID(), user) .getOnlineUserData(UUID.randomUUID(), user, DataSnapshot.SaveCause.API)
.thenApply(data -> data.or(() -> plugin.getDatabase().getLatestSnapshot(user))) .thenApply(data -> data.or(() -> plugin.getDatabase().getLatestSnapshot(user)))
.thenApply(data -> data.map(snapshot -> snapshot.unpack(plugin))); .thenApply(data -> data.map(snapshot -> snapshot.unpack(plugin)));
} }

View File

@@ -36,7 +36,7 @@ import java.util.Optional;
public class EnderChestCommand extends ItemsCommand { public class EnderChestCommand extends ItemsCommand {
public EnderChestCommand(@NotNull HuskSync plugin) { public EnderChestCommand(@NotNull HuskSync plugin) {
super("enderchest", List.of("echest", "openechest"), plugin); super("enderchest", List.of("echest", "openechest"), DataSnapshot.SaveCause.ENDERCHEST_COMMAND, plugin);
} }
@Override @Override
@@ -83,10 +83,10 @@ public class EnderChestCommand extends ItemsCommand {
// Create and pack the snapshot with the updated enderChest // Create and pack the snapshot with the updated enderChest
final DataSnapshot.Packed snapshot = latestData.get().copy(); final DataSnapshot.Packed snapshot = latestData.get().copy();
boolean pin = plugin.getSettings().getSynchronization().doAutoPin(DataSnapshot.SaveCause.ENDERCHEST_COMMAND); boolean pin = plugin.getSettings().getSynchronization().doAutoPin(saveCause);
snapshot.edit(plugin, (data) -> { snapshot.edit(plugin, (data) -> {
data.getEnderChest().ifPresent(enderChest -> enderChest.setContents(items)); data.getEnderChest().ifPresent(enderChest -> enderChest.setContents(items));
data.setSaveCause(DataSnapshot.SaveCause.ENDERCHEST_COMMAND); data.setSaveCause(saveCause);
data.setPinned(pin); data.setPinned(pin);
}); });

View File

@@ -36,7 +36,7 @@ import java.util.Optional;
public class InventoryCommand extends ItemsCommand { public class InventoryCommand extends ItemsCommand {
public InventoryCommand(@NotNull HuskSync plugin) { public InventoryCommand(@NotNull HuskSync plugin) {
super("inventory", List.of("invsee", "openinv"), plugin); super("inventory", List.of("invsee", "openinv"), DataSnapshot.SaveCause.INVENTORY_COMMAND, plugin);
} }
@Override @Override
@@ -84,10 +84,10 @@ public class InventoryCommand extends ItemsCommand {
// Create and pack the snapshot with the updated inventory // Create and pack the snapshot with the updated inventory
final DataSnapshot.Packed snapshot = latestData.get().copy(); final DataSnapshot.Packed snapshot = latestData.get().copy();
boolean pin = plugin.getSettings().getSynchronization().doAutoPin(DataSnapshot.SaveCause.INVENTORY_COMMAND); boolean pin = plugin.getSettings().getSynchronization().doAutoPin(saveCause);
snapshot.edit(plugin, (data) -> { snapshot.edit(plugin, (data) -> {
data.getInventory().ifPresent(inventory -> inventory.setContents(items)); data.getInventory().ifPresent(inventory -> inventory.setContents(items));
data.setSaveCause(DataSnapshot.SaveCause.INVENTORY_COMMAND); data.setSaveCause(saveCause);
data.setPinned(pin); data.setPinned(pin);
}); });

View File

@@ -34,8 +34,12 @@ 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 final DataSnapshot.SaveCause saveCause;
protected ItemsCommand(@NotNull String name, @NotNull List<String> aliases,
@NotNull DataSnapshot.SaveCause saveCause, @NotNull HuskSync plugin) {
super(name, aliases, Permission.Default.IF_OP, ExecutionScope.IN_GAME, plugin); super(name, aliases, Permission.Default.IF_OP, ExecutionScope.IN_GAME, plugin);
this.saveCause = saveCause;
} }
@Override @Override
@@ -50,7 +54,7 @@ public abstract class ItemsCommand extends PluginCommand {
return; return;
} }
this.showSnapshotItems(online, user, version); this.showSnapshotItems(online, user, version);
}, user("username"), uuid("version")); }, user("username"), versionUuid());
command.addSyntax((ctx) -> { command.addSyntax((ctx) -> {
final User user = ctx.getArgument("username", User.class); final User user = ctx.getArgument("username", User.class);
final CommandUser executor = user(command, ctx); final CommandUser executor = user(command, ctx);
@@ -65,7 +69,7 @@ public abstract class ItemsCommand extends PluginCommand {
// View (and edit) the latest user data // View (and edit) the latest user data
private void showLatestItems(@NotNull OnlineUser viewer, @NotNull User user) { private void showLatestItems(@NotNull OnlineUser viewer, @NotNull User user) {
plugin.getRedisManager().getUserData(user.getUuid(), user).thenAccept(data -> data plugin.getRedisManager().getOnlineUserData(user.getUuid(), user, saveCause).thenAccept(d -> d
.or(() -> plugin.getDatabase().getLatestSnapshot(user)) .or(() -> plugin.getDatabase().getLatestSnapshot(user))
.or(() -> { .or(() -> {
plugin.getLocales().getLocale("error_no_data_to_display") plugin.getLocales().getLocale("error_no_data_to_display")

View File

@@ -32,6 +32,7 @@ import net.william278.uniform.element.ArgumentElement;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.Arrays; import java.util.Arrays;
import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import java.util.function.Function; import java.util.function.Function;
@@ -104,14 +105,23 @@ public abstract class PluginCommand extends Command {
} }
@NotNull @NotNull
protected <S> ArgumentElement<S, UUID> uuid(@NotNull String name) { protected <S> ArgumentElement<S, UUID> versionUuid() {
return new ArgumentElement<>(name, reader -> { return new ArgumentElement<>("version", reader -> {
try { try {
return UUID.fromString(reader.readString()); return UUID.fromString(reader.readString());
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownArgument().createWithContext(reader); throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownArgument().createWithContext(reader);
} }
}, (context, builder) -> builder.buildFuture()); }, (context, builder) -> {
try {
plugin.getDatabase().getAllSnapshots(context.getArgument("username", User.class))
.stream().sorted(Comparator.comparing(d -> d.getTimestamp().toEpochSecond()))
.forEach(id -> builder.suggest(id.getId().toString()));
return builder.buildFuture();
} catch (IllegalArgumentException e) {
return builder.buildFuture();
}
});
} }
public enum Type { public enum Type {

View File

@@ -30,9 +30,9 @@ import net.william278.husksync.redis.RedisManager;
import net.william278.husksync.user.CommandUser; import net.william278.husksync.user.CommandUser;
import net.william278.husksync.user.OnlineUser; import net.william278.husksync.user.OnlineUser;
import net.william278.husksync.user.User; import net.william278.husksync.user.User;
import net.william278.husksync.util.UserDataDumper;
import net.william278.husksync.util.DataSnapshotList; import net.william278.husksync.util.DataSnapshotList;
import net.william278.husksync.util.DataSnapshotOverview; import net.william278.husksync.util.DataSnapshotOverview;
import net.william278.husksync.util.UserDataDumper;
import net.william278.uniform.BaseCommand; import net.william278.uniform.BaseCommand;
import net.william278.uniform.CommandProvider; import net.william278.uniform.CommandProvider;
import net.william278.uniform.Permission; import net.william278.uniform.Permission;
@@ -185,7 +185,7 @@ public class UserDataCommand extends PluginCommand {
.ifPresent(executor::sendMessage); .ifPresent(executor::sendMessage);
} }
// Dump a snapshot // Lookup a snapshot by UUID and dump
private void dumpSnapshot(@NotNull CommandUser executor, @NotNull User user, @NotNull UUID version, private void dumpSnapshot(@NotNull CommandUser executor, @NotNull User user, @NotNull UUID version,
@NotNull DumpType type) { @NotNull DumpType type) {
final Optional<DataSnapshot.Packed> data = plugin.getDatabase().getSnapshot(user, version); final Optional<DataSnapshot.Packed> data = plugin.getDatabase().getSnapshot(user, version);
@@ -194,9 +194,12 @@ public class UserDataCommand extends PluginCommand {
.ifPresent(executor::sendMessage); .ifPresent(executor::sendMessage);
return; return;
} }
this.dumpSnapshot(executor, user, data.get(), type);
}
// Dump the data // Dump a snapshot
final DataSnapshot.Packed userData = data.get(); private void dumpSnapshot(@NotNull CommandUser executor, @NotNull User user,
@NotNull DataSnapshot.Packed userData, @NotNull DumpType type) {
final UserDataDumper dumper = UserDataDumper.create(userData, user, plugin); final UserDataDumper dumper = UserDataDumper.create(userData, user, plugin);
try { try {
final String url = type == DumpType.WEB ? dumper.toWeb() : dumper.toFile(); final String url = type == DumpType.WEB ? dumper.toWeb() : dumper.toFile();
@@ -212,17 +215,11 @@ public class UserDataCommand extends PluginCommand {
@NotNull @NotNull
private CommandProvider view() { private CommandProvider view() {
return (sub) -> { return (sub) -> sub.addSyntax((ctx) -> {
sub.addSyntax((ctx) -> {
final User user = ctx.getArgument("username", User.class);
viewLatestSnapshot(user(sub, ctx), user);
}, user("username"));
sub.addSyntax((ctx) -> {
final User user = ctx.getArgument("username", User.class); final User user = ctx.getArgument("username", User.class);
final UUID version = ctx.getArgument("version", UUID.class); final UUID version = ctx.getArgument("version", UUID.class);
viewSnapshot(user(sub, ctx), user, version); viewSnapshot(user(sub, ctx), user, version);
}, user("username"), uuid("version")); }, user("username"), versionUuid());
};
} }
@NotNull @NotNull
@@ -246,7 +243,7 @@ public class UserDataCommand extends PluginCommand {
final User user = ctx.getArgument("username", User.class); final User user = ctx.getArgument("username", User.class);
final UUID version = ctx.getArgument("version", UUID.class); final UUID version = ctx.getArgument("version", UUID.class);
deleteSnapshot(user(sub, ctx), user, version); deleteSnapshot(user(sub, ctx), user, version);
}, user("username"), uuid("version")); }, user("username"), versionUuid());
} }
@NotNull @NotNull
@@ -263,7 +260,7 @@ public class UserDataCommand extends PluginCommand {
final User user = ctx.getArgument("username", User.class); final User user = ctx.getArgument("username", User.class);
final UUID version = ctx.getArgument("version", UUID.class); final UUID version = ctx.getArgument("version", UUID.class);
restoreSnapshot(user(sub, ctx), user, version); restoreSnapshot(user(sub, ctx), user, version);
}, user("username"), uuid("version")); }, user("username"), versionUuid());
} }
@NotNull @NotNull
@@ -272,17 +269,32 @@ public class UserDataCommand extends PluginCommand {
final User user = ctx.getArgument("username", User.class); final User user = ctx.getArgument("username", User.class);
final UUID version = ctx.getArgument("version", UUID.class); final UUID version = ctx.getArgument("version", UUID.class);
pinSnapshot(user(sub, ctx), user, version); pinSnapshot(user(sub, ctx), user, version);
}, user("username"), uuid("version")); }, user("username"), versionUuid());
} }
@NotNull @NotNull
private CommandProvider dump() { private CommandProvider dump() {
return (sub) -> sub.addSyntax((ctx) -> { return (sub) -> {
sub.addSyntax((ctx) -> {
final User user = ctx.getArgument("username", User.class);
final CommandUser executor = user(sub, ctx);
plugin.getRedisManager()
.getOnlineUserData(UUID.randomUUID(), user, DataSnapshot.SaveCause.DUMP_COMMAND)
.thenAccept((data) -> data
.or(() -> plugin.getDatabase().getLatestSnapshot(user))
.ifPresentOrElse(
(s) -> dumpSnapshot(executor, user, s, DumpType.WEB),
() -> plugin.getLocales().getLocale("error_no_data_to_display")
.ifPresent(executor::sendMessage)
));
}, user("username"));
sub.addSyntax((ctx) -> {
final User user = ctx.getArgument("username", User.class); final User user = ctx.getArgument("username", User.class);
final UUID version = ctx.getArgument("version", UUID.class); final UUID version = ctx.getArgument("version", UUID.class);
final DumpType type = ctx.getArgument("type", DumpType.class); final DumpType type = ctx.getArgument("type", DumpType.class);
dumpSnapshot(user(sub, ctx), user, version, type); dumpSnapshot(user(sub, ctx), user, version, type);
}, user("username"), uuid("version"), dumpType()); }, user("username"), versionUuid(), dumpType());
};
} }
private <S> ArgumentElement<S, DumpType> dumpType() { private <S> ArgumentElement<S, DumpType> dumpType() {

View File

@@ -887,6 +887,13 @@ public class DataSnapshot {
*/ */
public static final SaveCause SAVE_COMMAND = of("SAVE_COMMAND", true); public static final SaveCause SAVE_COMMAND = of("SAVE_COMMAND", true);
/**
* Indicates data was saved from executing the {@code /userdata dump} command
*
* @since 3.8
*/
public static final SaveCause DUMP_COMMAND = of("DUMP_COMMAND", true);
/** /**
* Indicates data was saved by an API call * Indicates data was saved by an API call
* *

View File

@@ -218,16 +218,17 @@ public class RedisManager extends JedisPubSub {
}); });
} }
public CompletableFuture<Optional<DataSnapshot.Packed>> getUserData(@NotNull UUID requestId, @NotNull User user) { public CompletableFuture<Optional<DataSnapshot.Packed>> getOnlineUserData(@NotNull UUID requestId, @NotNull User user,
@NotNull DataSnapshot.SaveCause saveCause) {
return plugin.getOnlineUser(user.getUuid()) return plugin.getOnlineUser(user.getUuid())
.map(online -> CompletableFuture.completedFuture( .map(online -> CompletableFuture.completedFuture(
Optional.of(online.createSnapshot(DataSnapshot.SaveCause.API))) Optional.of(online.createSnapshot(saveCause)))
) )
.orElse(this.requestData(requestId, user)); .orElse(this.getNetworkedUserData(requestId, user));
} }
// Request a user's dat x-server // Request a user's dat x-server
private CompletableFuture<Optional<DataSnapshot.Packed>> requestData(@NotNull UUID requestId, @NotNull User user) { private CompletableFuture<Optional<DataSnapshot.Packed>> getNetworkedUserData(@NotNull UUID requestId, @NotNull User user) {
final CompletableFuture<Optional<DataSnapshot.Packed>> future = new CompletableFuture<>(); final CompletableFuture<Optional<DataSnapshot.Packed>> future = new CompletableFuture<>();
pendingRequests.put(requestId, future); pendingRequests.put(requestId, future);
plugin.runAsync(() -> { plugin.runAsync(() -> {

View File

@@ -42,6 +42,7 @@ locales:
save_cause_death: 'death' save_cause_death: 'death'
save_cause_server_shutdown: 'server shutdown' save_cause_server_shutdown: 'server shutdown'
save_cause_save_command: 'save command' save_cause_save_command: 'save command'
save_cause_dump_command: 'dump command'
save_cause_inventory_command: 'inventory command' save_cause_inventory_command: 'inventory command'
save_cause_enderchest_command: 'enderchest command' save_cause_enderchest_command: 'enderchest command'
save_cause_backup_restore: 'backup restore' save_cause_backup_restore: 'backup restore'

View File

@@ -42,6 +42,7 @@ locales:
save_cause_death: 'Tod' save_cause_death: 'Tod'
save_cause_server_shutdown: 'server gestoppt' save_cause_server_shutdown: 'server gestoppt'
save_cause_save_command: 'save command' save_cause_save_command: 'save command'
save_cause_dump_command: 'dump command'
save_cause_inventory_command: 'inventar Befehl' save_cause_inventory_command: 'inventar Befehl'
save_cause_enderchest_command: 'enderchest Befehl' save_cause_enderchest_command: 'enderchest Befehl'
save_cause_backup_restore: 'backup wiederhergestellt' save_cause_backup_restore: 'backup wiederhergestellt'

View File

@@ -42,6 +42,7 @@ locales:
save_cause_death: 'death' save_cause_death: 'death'
save_cause_server_shutdown: 'server shutdown' save_cause_server_shutdown: 'server shutdown'
save_cause_save_command: 'save command' save_cause_save_command: 'save command'
save_cause_dump_command: 'dump command'
save_cause_inventory_command: 'inventory command' save_cause_inventory_command: 'inventory command'
save_cause_enderchest_command: 'enderchest command' save_cause_enderchest_command: 'enderchest command'
save_cause_backup_restore: 'backup restore' save_cause_backup_restore: 'backup restore'

View File

@@ -42,6 +42,7 @@ locales:
save_cause_death: 'death' save_cause_death: 'death'
save_cause_server_shutdown: 'server shutdown' save_cause_server_shutdown: 'server shutdown'
save_cause_save_command: 'save command' save_cause_save_command: 'save command'
save_cause_dump_command: 'dump command'
save_cause_inventory_command: 'inventory command' save_cause_inventory_command: 'inventory command'
save_cause_enderchest_command: 'enderchest command' save_cause_enderchest_command: 'enderchest command'
save_cause_backup_restore: 'backup restore' save_cause_backup_restore: 'backup restore'

View File

@@ -42,6 +42,7 @@ locales:
save_cause_death: 'mort' save_cause_death: 'mort'
save_cause_server_shutdown: 'arrêt du serveur' save_cause_server_shutdown: 'arrêt du serveur'
save_cause_save_command: 'save command' save_cause_save_command: 'save command'
save_cause_dump_command: 'dump command'
save_cause_inventory_command: 'commande d''inventaire' save_cause_inventory_command: 'commande d''inventaire'
save_cause_enderchest_command: 'commande du coffre de l''Ender' save_cause_enderchest_command: 'commande du coffre de l''Ender'
save_cause_backup_restore: 'restauration de sauvegarde' save_cause_backup_restore: 'restauration de sauvegarde'

View File

@@ -42,6 +42,7 @@ locales:
save_cause_death: 'kematian' save_cause_death: 'kematian'
save_cause_server_shutdown: 'pematian server' save_cause_server_shutdown: 'pematian server'
save_cause_save_command: 'save command' save_cause_save_command: 'save command'
save_cause_dump_command: 'dump command'
save_cause_inventory_command: 'perintah inventaris' save_cause_inventory_command: 'perintah inventaris'
save_cause_enderchest_command: 'perintah enderchest' save_cause_enderchest_command: 'perintah enderchest'
save_cause_backup_restore: 'pemulihan cadangan' save_cause_backup_restore: 'pemulihan cadangan'

View File

@@ -42,6 +42,7 @@ locales:
save_cause_death: 'death' save_cause_death: 'death'
save_cause_server_shutdown: 'server shutdown' save_cause_server_shutdown: 'server shutdown'
save_cause_save_command: 'save command' save_cause_save_command: 'save command'
save_cause_dump_command: 'dump command'
save_cause_inventory_command: 'inventory command' save_cause_inventory_command: 'inventory command'
save_cause_enderchest_command: 'enderchest command' save_cause_enderchest_command: 'enderchest command'
save_cause_backup_restore: 'backup restore' save_cause_backup_restore: 'backup restore'

View File

@@ -42,6 +42,7 @@ locales:
save_cause_death: 'death' save_cause_death: 'death'
save_cause_server_shutdown: 'server shutdown' save_cause_server_shutdown: 'server shutdown'
save_cause_save_command: 'save command' save_cause_save_command: 'save command'
save_cause_dump_command: 'dump command'
save_cause_inventory_command: 'inventory command' save_cause_inventory_command: 'inventory command'
save_cause_enderchest_command: 'enderchest command' save_cause_enderchest_command: 'enderchest command'
save_cause_backup_restore: 'backup restore' save_cause_backup_restore: 'backup restore'

View File

@@ -42,6 +42,7 @@ locales:
save_cause_death: 'death' save_cause_death: 'death'
save_cause_server_shutdown: 'server shutdown' save_cause_server_shutdown: 'server shutdown'
save_cause_save_command: 'save command' save_cause_save_command: 'save command'
save_cause_dump_command: 'dump command'
save_cause_inventory_command: 'inventory command' save_cause_inventory_command: 'inventory command'
save_cause_enderchest_command: 'enderchest command' save_cause_enderchest_command: 'enderchest command'
save_cause_backup_restore: 'backup restore' save_cause_backup_restore: 'backup restore'

View File

@@ -42,6 +42,7 @@ locales:
save_cause_death: 'death' save_cause_death: 'death'
save_cause_server_shutdown: 'server shutdown' save_cause_server_shutdown: 'server shutdown'
save_cause_save_command: 'save command' save_cause_save_command: 'save command'
save_cause_dump_command: 'dump command'
save_cause_inventory_command: 'inventory command' save_cause_inventory_command: 'inventory command'
save_cause_enderchest_command: 'enderchest command' save_cause_enderchest_command: 'enderchest command'
save_cause_backup_restore: 'backup restore' save_cause_backup_restore: 'backup restore'

View File

@@ -42,6 +42,7 @@ locales:
save_cause_death: 'death' save_cause_death: 'death'
save_cause_server_shutdown: 'server shutdown' save_cause_server_shutdown: 'server shutdown'
save_cause_save_command: 'save command' save_cause_save_command: 'save command'
save_cause_dump_command: 'dump command'
save_cause_inventory_command: 'inventory command' save_cause_inventory_command: 'inventory command'
save_cause_enderchest_command: 'enderchest command' save_cause_enderchest_command: 'enderchest command'
save_cause_backup_restore: 'backup restore' save_cause_backup_restore: 'backup restore'

View File

@@ -42,6 +42,7 @@ locales:
save_cause_death: 'смерть' save_cause_death: 'смерть'
save_cause_server_shutdown: 'отключение сервера' save_cause_server_shutdown: 'отключение сервера'
save_cause_save_command: 'save command' save_cause_save_command: 'save command'
save_cause_dump_command: 'dump command'
save_cause_inventory_command: 'команда inventory' save_cause_inventory_command: 'команда inventory'
save_cause_enderchest_command: 'команда enderchest' save_cause_enderchest_command: 'команда enderchest'
save_cause_backup_restore: 'восстановление из снимка' save_cause_backup_restore: 'восстановление из снимка'

View File

@@ -42,6 +42,7 @@ locales:
save_cause_death: 'ölüm' save_cause_death: 'ölüm'
save_cause_server_shutdown: 'sunucu kapatma' save_cause_server_shutdown: 'sunucu kapatma'
save_cause_save_command: 'save command' save_cause_save_command: 'save command'
save_cause_dump_command: 'dump command'
save_cause_inventory_command: 'envanter komutu' save_cause_inventory_command: 'envanter komutu'
save_cause_enderchest_command: 'ender sandığı komutu' save_cause_enderchest_command: 'ender sandığı komutu'
save_cause_backup_restore: 'yedek geri yükleme' save_cause_backup_restore: 'yedek geri yükleme'

View File

@@ -42,6 +42,7 @@ locales:
save_cause_death: 'death' save_cause_death: 'death'
save_cause_server_shutdown: 'server shutdown' save_cause_server_shutdown: 'server shutdown'
save_cause_save_command: 'save command' save_cause_save_command: 'save command'
save_cause_dump_command: 'dump command'
save_cause_inventory_command: 'inventory command' save_cause_inventory_command: 'inventory command'
save_cause_enderchest_command: 'enderchest command' save_cause_enderchest_command: 'enderchest command'
save_cause_backup_restore: 'backup restore' save_cause_backup_restore: 'backup restore'

View File

@@ -42,6 +42,7 @@ locales:
save_cause_death: '死亡' save_cause_death: '死亡'
save_cause_server_shutdown: '服务器关闭' save_cause_server_shutdown: '服务器关闭'
save_cause_save_command: 'save command' save_cause_save_command: 'save command'
save_cause_dump_command: 'dump command'
save_cause_inventory_command: '背包命令' save_cause_inventory_command: '背包命令'
save_cause_enderchest_command: '末影箱命令' save_cause_enderchest_command: '末影箱命令'
save_cause_backup_restore: '备份还原' save_cause_backup_restore: '备份还原'

View File

@@ -42,6 +42,7 @@ locales:
save_cause_death: '死亡' save_cause_death: '死亡'
save_cause_server_shutdown: '伺服器關閉' save_cause_server_shutdown: '伺服器關閉'
save_cause_save_command: 'save command' save_cause_save_command: 'save command'
save_cause_dump_command: 'dump command'
save_cause_inventory_command: '背包指令' save_cause_inventory_command: '背包指令'
save_cause_enderchest_command: '終界箱指令' save_cause_enderchest_command: '終界箱指令'
save_cause_backup_restore: '備份還原' save_cause_backup_restore: '備份還原'