Commit a2ff8c84 authored by KingRainbow44's avatar KingRainbow44
Browse files

Merge `development` into `plugin-auth`

parents 3adf0d44 a751e71d
package emu.grasscutter.server.packet.send;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.WidgetGadgetAllDataNotifyOuterClass.WidgetGadgetAllDataNotify;
public class PacketWidgetGadgetAllDataNotify extends BasePacket {
public PacketWidgetGadgetAllDataNotify() {
super(PacketOpcodes.AllWidgetDataNotify);
WidgetGadgetAllDataNotify proto = WidgetGadgetAllDataNotify.newBuilder().build();
this.setData(proto);
}
}
package emu.grasscutter.server.packet.send;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.WidgetGadgetDataNotifyOuterClass;
import emu.grasscutter.net.proto.WidgetGadgetDataOuterClass;
import java.io.IOException;
import java.util.List;
public class PacketWidgetGadgetDataNotify extends BasePacket {
public PacketWidgetGadgetDataNotify(int gadgetId, List<Integer> gadgetEntityIdList) throws IOException {
super(PacketOpcodes.WidgetGadgetDataNotify);
WidgetGadgetDataNotifyOuterClass.WidgetGadgetDataNotify proto = WidgetGadgetDataNotifyOuterClass.WidgetGadgetDataNotify.newBuilder()
.setWidgetGadgetData(
WidgetGadgetDataOuterClass.WidgetGadgetData.newBuilder()
.setGadgetId(gadgetId)
.addAllGadgetEntityIdList(gadgetEntityIdList)
.build()
)
.build();
this.setData(proto);
}
}
package emu.grasscutter.server.packet.send;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.WidgetSlotChangeNotifyOuterClass;
import emu.grasscutter.net.proto.WidgetSlotDataOuterClass;
import emu.grasscutter.net.proto.WidgetSlotOpOuterClass;
public class PacketWidgetSlotChangeNotify extends BasePacket {
public PacketWidgetSlotChangeNotify(WidgetSlotChangeNotifyOuterClass.WidgetSlotChangeNotify proto) {
super(PacketOpcodes.WidgetSlotChangeNotify);
this.setData(proto);
}
public PacketWidgetSlotChangeNotify(WidgetSlotOpOuterClass.WidgetSlotOp op) {
super(PacketOpcodes.WidgetSlotChangeNotify);
WidgetSlotChangeNotifyOuterClass.WidgetSlotChangeNotify proto = WidgetSlotChangeNotifyOuterClass.WidgetSlotChangeNotify.newBuilder()
.setOp(op)
.setSlot(
WidgetSlotDataOuterClass.WidgetSlotData.newBuilder()
.setIsActive(true)
.build()
)
.build();
this.setData(proto);
}
public PacketWidgetSlotChangeNotify(int materialId) {
super(PacketOpcodes.WidgetSlotChangeNotify);
WidgetSlotChangeNotifyOuterClass.WidgetSlotChangeNotify proto = WidgetSlotChangeNotifyOuterClass.WidgetSlotChangeNotify.newBuilder()
.setSlot(
WidgetSlotDataOuterClass.WidgetSlotData.newBuilder()
.setIsActive(true)
.setMaterialId(materialId)
.build()
)
.build();
this.setData(proto);
}
}
...@@ -19,9 +19,11 @@ import emu.grasscutter.command.Command; ...@@ -19,9 +19,11 @@ import emu.grasscutter.command.Command;
import emu.grasscutter.command.CommandMap; import emu.grasscutter.command.CommandMap;
import emu.grasscutter.data.GameData; import emu.grasscutter.data.GameData;
import emu.grasscutter.data.ResourceLoader; import emu.grasscutter.data.ResourceLoader;
import emu.grasscutter.data.custom.MainQuestData;
import emu.grasscutter.data.def.AvatarData; import emu.grasscutter.data.def.AvatarData;
import emu.grasscutter.data.def.ItemData; import emu.grasscutter.data.def.ItemData;
import emu.grasscutter.data.def.MonsterData; import emu.grasscutter.data.def.MonsterData;
import emu.grasscutter.data.def.QuestData;
import emu.grasscutter.data.def.SceneData; import emu.grasscutter.data.def.SceneData;
import emu.grasscutter.utils.Utils; import emu.grasscutter.utils.Utils;
...@@ -88,7 +90,7 @@ public final class Tools { ...@@ -88,7 +90,7 @@ public final class Tools {
final class ToolsWithLanguageOption { final class ToolsWithLanguageOption {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public static void createGmHandbook(String language) throws Exception { public static void createGmHandbook(String language) throws Exception {
ResourceLoader.loadResources(); ResourceLoader.loadAll();
Map<Long, String> map; Map<Long, String> map;
try (InputStreamReader fileReader = new InputStreamReader(new FileInputStream(Utils.toFilePath(RESOURCE("TextMap/TextMap"+language+".json"))), StandardCharsets.UTF_8)) { try (InputStreamReader fileReader = new InputStreamReader(new FileInputStream(Utils.toFilePath(RESOURCE("TextMap/TextMap"+language+".json"))), StandardCharsets.UTF_8)) {
...@@ -150,6 +152,18 @@ final class ToolsWithLanguageOption { ...@@ -150,6 +152,18 @@ final class ToolsWithLanguageOption {
writer.println(); writer.println();
writer.println("// Quests");
list = new ArrayList<>(GameData.getQuestDataMap().keySet());
Collections.sort(list);
for (Integer id : list) {
QuestData data = GameData.getQuestDataMap().get(id);
MainQuestData mainQuest = GameData.getMainQuestDataMap().get(data.getMainId());
writer.println(data.getId() + " : " + map.get(mainQuest.getTitleTextMapHash()) + " - " + map.get(data.getDescTextMapHash()));
}
writer.println();
writer.println("// Monsters"); writer.println("// Monsters");
list = new ArrayList<>(GameData.getMonsterDataMap().keySet()); list = new ArrayList<>(GameData.getMonsterDataMap().keySet());
Collections.sort(list); Collections.sort(list);
......
...@@ -11,14 +11,18 @@ import static emu.grasscutter.Configuration.*; ...@@ -11,14 +11,18 @@ import static emu.grasscutter.Configuration.*;
public final class Crypto { public final class Crypto {
private static final SecureRandom secureRandom = new SecureRandom(); private static final SecureRandom secureRandom = new SecureRandom();
public static final long ENCRYPT_SEED = Long.parseUnsignedLong("11468049314633205968");
public static byte[] ENCRYPT_SEED_BUFFER = new byte[0];
public static byte[] DISPATCH_KEY; public static byte[] DISPATCH_KEY;
public static byte[] DISPATCH_SEED;
public static byte[] ENCRYPT_KEY; public static byte[] ENCRYPT_KEY;
public static long ENCRYPT_SEED = Long.parseUnsignedLong("11468049314633205968");
public static byte[] ENCRYPT_SEED_BUFFER = new byte[0];
public static void loadKeys() { public static void loadKeys() {
DISPATCH_KEY = FileUtils.read(KEYS_FOLDER + "/dispatchKey.bin"); DISPATCH_KEY = FileUtils.read(KEYS_FOLDER + "/dispatchKey.bin");
DISPATCH_SEED = FileUtils.read(KEYS_FOLDER + "/dispatchSeed.bin");
ENCRYPT_KEY = FileUtils.read(KEYS_FOLDER + "/secretKey.bin"); ENCRYPT_KEY = FileUtils.read(KEYS_FOLDER + "/secretKey.bin");
ENCRYPT_SEED_BUFFER = FileUtils.read(KEYS_FOLDER + "/secretKeyBuffer.bin"); ENCRYPT_SEED_BUFFER = FileUtils.read(KEYS_FOLDER + "/secretKeyBuffer.bin");
} }
...@@ -55,6 +59,6 @@ public final class Crypto { ...@@ -55,6 +59,6 @@ public final class Crypto {
public static byte[] createSessionKey(int length) { public static byte[] createSessionKey(int length) {
byte[] bytes = new byte[length]; byte[] bytes = new byte[length];
secureRandom.nextBytes(bytes); secureRandom.nextBytes(bytes);
return bytes; return bytes;
} }
} }
...@@ -160,7 +160,9 @@ public final class Language { ...@@ -160,7 +160,9 @@ public final class Language {
JsonObject object = this.languageData; JsonObject object = this.languageData;
int index = 0; int index = 0;
String result = "This value does not exist. Please report this to the Discord: " + key; String valueNotFoundPattern = "This value does not exist. Please report this to the Discord: ";
String result = valueNotFoundPattern + key;
boolean isValueFound = false;
while (true) { while (true) {
if(index == keys.length) break; if(index == keys.length) break;
...@@ -171,10 +173,18 @@ public final class Language { ...@@ -171,10 +173,18 @@ public final class Language {
if(element.isJsonObject()) if(element.isJsonObject())
object = element.getAsJsonObject(); object = element.getAsJsonObject();
else { else {
isValueFound = true;
result = element.getAsString(); break; result = element.getAsString(); break;
} }
} else break; } else break;
} }
if (!isValueFound && !languageCode.equals("en-US")) {
var englishValue = Grasscutter.getLanguage("en-US").get(key);
if (!englishValue.contains(valueNotFoundPattern)) {
result += "\nhere is english version:\n" + englishValue;
}
}
this.cachedTranslations.put(key, result); return result; this.cachedTranslations.put(key, result); return result;
} }
......
...@@ -12,6 +12,8 @@ import emu.grasscutter.Grasscutter; ...@@ -12,6 +12,8 @@ import emu.grasscutter.Grasscutter;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil; import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList;
import org.slf4j.Logger; import org.slf4j.Logger;
...@@ -304,14 +306,79 @@ public final class Utils { ...@@ -304,14 +306,79 @@ public final class Utils {
return map; return map;
} }
/**
* Performs a linear interpolation using a table of fixed points to create an effective piecewise f(x) = y function.
* @param x
* @param xyArray Array of points in [[x0,y0], ... [xN, yN]] format
* @return f(x) = y
*/
public static int lerp(int x, int[][] xyArray) {
try {
if (x <= xyArray[0][0]){ // Clamp to first point
return xyArray[0][1];
} else if (x >= xyArray[xyArray.length-1][0]) { // Clamp to last point
return xyArray[xyArray.length-1][1];
}
// At this point we're guaranteed to have two lerp points, and pity be somewhere between them.
for (int i=0; i < xyArray.length-1; i++) {
if (x == xyArray[i+1][0]) {
return xyArray[i+1][1];
}
if (x < xyArray[i+1][0]) {
// We are between [i] and [i+1], interpolation time!
// Using floats would be slightly cleaner but we can just as easily use ints if we're careful with order of operations.
int position = x - xyArray[i][0];
int fullDist = xyArray[i+1][0] - xyArray[i][0];
int prevValue = xyArray[i][1];
int fullDelta = xyArray[i+1][1] - prevValue;
return prevValue + ( (position * fullDelta) / fullDist );
}
}
} catch (IndexOutOfBoundsException e) {
Grasscutter.getLogger().error("Malformed lerp point array. Must be of form [[x0, y0], ..., [xN, yN]].");
}
return 0;
}
/**
* Checks if an int is in an int[]
* @param key int to look for
* @param array int[] to look in
* @return key in array
*/
public static boolean intInArray(int key, int[] array) {
for (int i : array) {
if (i == key) {
return true;
}
}
return false;
}
/**
* Return a copy of minuend without any elements found in subtrahend.
* @param minuend The array we want elements from
* @param subtrahend The array whose elements we don't want
* @return The array with only the elements we want, in the order that minuend had them
*/
public static int[] setSubtract(int[] minuend, int[] subtrahend) {
IntList temp = new IntArrayList();
for (int i : minuend) {
if (!intInArray(i, subtrahend)) {
temp.add(i);
}
}
return temp.toIntArray();
}
/** /**
* Gets the language code from a given locale. * Gets the language code from a given locale.
* @param locale A locale. * @param locale A locale.
* @return A string in the format of 'XX-XX'. * @return A string in the format of 'XX-XX'.
*/ */
public static String getLanguageCode(Locale locale) { public static String getLanguageCode(Locale locale) {
return String.format("%s-%s", locale.getLanguage(), locale.getCountry()); return String.format("%s-%s", locale.getLanguage(), locale.getCountry());
} }
/** /**
* Base64 encodes a given byte array. * Base64 encodes a given byte array.
......
...@@ -16,6 +16,9 @@ ...@@ -16,6 +16,9 @@
"no_keystore_error": "[Dispatch] No SSL cert found! Falling back to HTTP server.", "no_keystore_error": "[Dispatch] No SSL cert found! Falling back to HTTP server.",
"default_password": "[Dispatch] The default keystore password was loaded successfully. Please consider setting the password to 123456 in config.json." "default_password": "[Dispatch] The default keystore password was loaded successfully. Please consider setting the password to 123456 in config.json."
}, },
"authentication": {
"default_unable_to_verify": "[Authentication] Something called the verifyUser method which is unavailable in the default authentication handler"
},
"no_commands_error": "Commands are not supported in dispatch only mode.", "no_commands_error": "Commands are not supported in dispatch only mode.",
"unhandled_request_error": "[Dispatch] Potential unhandled %s request: %s", "unhandled_request_error": "[Dispatch] Potential unhandled %s request: %s",
"account": { "account": {
...@@ -46,7 +49,8 @@ ...@@ -46,7 +49,8 @@
"run_mode_error": "Invalid server run mode: %s.", "run_mode_error": "Invalid server run mode: %s.",
"run_mode_help": "Server run mode must be 'HYBRID', 'DISPATCH_ONLY', or 'GAME_ONLY'. Unable to start Grasscutter...", "run_mode_help": "Server run mode must be 'HYBRID', 'DISPATCH_ONLY', or 'GAME_ONLY'. Unable to start Grasscutter...",
"create_resources": "Creating resources folder...", "create_resources": "Creating resources folder...",
"resources_error": "Place a copy of 'BinOutput' and 'ExcelBinOutput' in the resources folder." "resources_error": "Place a copy of 'BinOutput' and 'ExcelBinOutput' in the resources folder.",
"version": "Grasscutter version: %s-%s"
} }
}, },
"commands": { "commands": {
...@@ -173,6 +177,10 @@ ...@@ -173,6 +177,10 @@
"success": "All characters have been healed.", "success": "All characters have been healed.",
"description": "Heal all characters in your current team." "description": "Heal all characters in your current team."
}, },
"join": {
"usage": "Usage: join [AvatarIDs] such as\"join 10000038 10000039\"",
"description": "force join avatar into your team"
},
"kick": { "kick": {
"player_kick_player": "Player [%s:%s] has kicked player [%s:%s]", "player_kick_player": "Player [%s:%s] has kicked player [%s:%s]",
"server_kick_player": "Kicking player [%s:%s]", "server_kick_player": "Kicking player [%s:%s]",
...@@ -212,11 +220,24 @@ ...@@ -212,11 +220,24 @@
"success": "Coordinates: %s, %s, %s\nScene id: %s", "success": "Coordinates: %s, %s, %s\nScene id: %s",
"description": "Get coordinates." "description": "Get coordinates."
}, },
"quest": {
"description": "Add or finish quests",
"usage": "quest <add|finish> [quest id]",
"added": "Quest %s added",
"finished": "Finished quest %s",
"not_found": "Quest not found",
"invalid_id": "Invalid quest id"
},
"reload": { "reload": {
"reload_start": "Reloading config.", "reload_start": "Reloading config.",
"reload_done": "Reload complete.", "reload_done": "Reload complete.",
"description": "Reload server config" "description": "Reload server config"
}, },
"remove": {
"usage": "Usage: remove [indexOfYourTeams] index start from 1",
"invalid_index": "index start from 1",
"description": "force remove avatar into your team"
},
"resetConst": { "resetConst": {
"reset_all": "Reset all avatars' constellations.", "reset_all": "Reset all avatars' constellations.",
"success": "Constellations for %s have been reset. Please relog to see changes.", "success": "Constellations for %s have been reset. Please relog to see changes.",
...@@ -349,5 +370,14 @@ ...@@ -349,5 +370,14 @@
"resetshop": { "resetshop": {
"description": "reset shop" "description": "reset shop"
} }
},
"gacha": {
"details": {
"title": "Banner Details",
"available_five_stars": "Available 5-star Items",
"available_four_stars": "Available 4-star Items",
"available_three_stars": "Available 3-star Items",
"template_missing": "data/gacha_details.html is missing."
}
} }
} }
...@@ -45,7 +45,8 @@ ...@@ -45,7 +45,8 @@
"run_mode_error": "Błędny tryb pracy serwera: %s.", "run_mode_error": "Błędny tryb pracy serwera: %s.",
"run_mode_help": "Tryb pracy serwera musi być ustawiony na 'HYBRID', 'DISPATCH_ONLY', lub 'GAME_ONLY'. Nie można wystartować Grasscutter...", "run_mode_help": "Tryb pracy serwera musi być ustawiony na 'HYBRID', 'DISPATCH_ONLY', lub 'GAME_ONLY'. Nie można wystartować Grasscutter...",
"create_resources": "Tworzenie folderu resources...", "create_resources": "Tworzenie folderu resources...",
"resources_error": "Umieść kopię 'BinOutput' i 'ExcelBinOutput' w folderze resources." "resources_error": "Umieść kopię 'BinOutput' i 'ExcelBinOutput' w folderze resources.",
"version": "Grasscutter versión: %s-%s"
} }
}, },
"commands": { "commands": {
...@@ -301,5 +302,14 @@ ...@@ -301,5 +302,14 @@
"resetshop": { "resetshop": {
"description": "zresetuj sklep" "description": "zresetuj sklep"
} }
},
"gacha": {
"details": {
"title": "Banner Details",
"available_five_stars": "Available 5-star Items",
"available_four_stars": "Available 4-star Items",
"available_three_stars": "Available 3-star Items",
"template_missing": "data/gacha_details.html is missing."
}
} }
} }
\ No newline at end of file
...@@ -16,11 +16,14 @@ ...@@ -16,11 +16,14 @@
"no_keystore_error": "[Dispatch] 未找到 SSL 证书!已降级到 HTTP 模式", "no_keystore_error": "[Dispatch] 未找到 SSL 证书!已降级到 HTTP 模式",
"default_password": "[Dispatch] 成功加载 keystore 默认密码。请考虑将 config.json 的默认密码设置为 123456" "default_password": "[Dispatch] 成功加载 keystore 默认密码。请考虑将 config.json 的默认密码设置为 123456"
}, },
"authentication": {
"default_unable_to_verify": "[Authentication] 称为 verifyUser 的方法在默认验证程序中不可用"
},
"no_commands_error": "此命令不适用于 Dispatch-only 模式", "no_commands_error": "此命令不适用于 Dispatch-only 模式",
"unhandled_request_error": "[Dispatch] 潜在的未处理请求:%s %s", "unhandled_request_error": "[Dispatch] 潜在的未处理请求:%s %s",
"account": { "account": {
"login_attempt": "[Dispatch] 客户端 %s 正在尝试登录", "login_attempt": "[Dispatch] 客户端 %s 正在尝试登录",
"login_success": "[Dispatch] 客户端 %s 已登录,UID为 %s", "login_success": "[Dispatch] 客户端 %s 已登录,UID 为 %s",
"login_token_attempt": "[Dispatch] 客户端 %s 正在尝试使用 token 登录", "login_token_attempt": "[Dispatch] 客户端 %s 正在尝试使用 token 登录",
"login_token_error": "[Dispatch] 客户端 %s 使用 token 登录失败", "login_token_error": "[Dispatch] 客户端 %s 使用 token 登录失败",
"login_token_success": "[Dispatch] 客户端 %s 已通过 token 登录,UID 为 %s", "login_token_success": "[Dispatch] 客户端 %s 已通过 token 登录,UID 为 %s",
...@@ -45,7 +48,8 @@ ...@@ -45,7 +48,8 @@
"run_mode_error": "无效的服务器运行模式:%s。", "run_mode_error": "无效的服务器运行模式:%s。",
"run_mode_help": "服务器运行模式必须为 HYBRID、DISPATCH_ONLY 或 GAME_ONLY。Grasscutter 启动失败...", "run_mode_help": "服务器运行模式必须为 HYBRID、DISPATCH_ONLY 或 GAME_ONLY。Grasscutter 启动失败...",
"create_resources": "正在创建 resources 目录...", "create_resources": "正在创建 resources 目录...",
"resources_error": "请将 BinOutput 和 ExcelBinOutput 复制到 resources 目录。" "resources_error": "请将 BinOutput 和 ExcelBinOutput 复制到 resources 目录。",
"version": "Grasscutter 版本: %s-%s"
} }
}, },
"commands": { "commands": {
...@@ -55,7 +59,7 @@ ...@@ -55,7 +59,7 @@
"permission_error": "哼哼哼!你没有执行此命令的权限!请联系服务器管理员解决!", "permission_error": "哼哼哼!你没有执行此命令的权限!请联系服务器管理员解决!",
"console_execute_error": "此命令只能在服务器控制台执行呐~", "console_execute_error": "此命令只能在服务器控制台执行呐~",
"player_execute_error": "此命令只能在游戏内执行哦~", "player_execute_error": "此命令只能在游戏内执行哦~",
"command_exist_error": "这条命令……好像找不到呢?", "command_exist_error": "这条命令...好像找不到呢?",
"no_description_specified": "没有指定说明", "no_description_specified": "没有指定说明",
"invalid": { "invalid": {
"amount": "无效的数量。", "amount": "无效的数量。",
...@@ -80,7 +84,7 @@ ...@@ -80,7 +84,7 @@
"player_exist_offline_error": "玩家不存在或已离线。", "player_exist_offline_error": "玩家不存在或已离线。",
"argument_error": "无效的参数。", "argument_error": "无效的参数。",
"clear_target": "目标已清除。", "clear_target": "目标已清除。",
"set_target": "随后的的命令都会以@%s为预设。", "set_target": "随后的的命令都会以 @%s 为预设。",
"need_target": "此命令需要一个目标 UID。添加 <@UID> 参数或使用 /target @UID 来指定默认目标。" "need_target": "此命令需要一个目标 UID。添加 <@UID> 参数或使用 /target @UID 来指定默认目标。"
}, },
"status": { "status": {
...@@ -96,20 +100,20 @@ ...@@ -96,20 +100,20 @@
"create": "已创建账号,UID 为 %s。", "create": "已创建账号,UID 为 %s。",
"delete": "账号已删除。", "delete": "账号已删除。",
"no_account": "账号不存在。", "no_account": "账号不存在。",
"command_usage": "用法:account <create|delete> <用户名> [uid]", "command_usage": "用法:account <create|delete> <用户名> [UID]",
"description": "创建或删除账号" "description": "创建或删除账号"
}, },
"broadcast": { "broadcast": {
"command_usage": "用法:broadcast <消息>", "command_usage": "用法:broadcast <消息>",
"message_sent": "公告已发送。", "message_sent": "公告已发送。",
"description": "向所有玩家发送公告" "description": "向所有玩家发送公告"
}, },
"changescene": { "changescene": {
"usage": "用法:changescene <场景ID>", "usage": "用法:changescene <场景ID>",
"already_in_scene": "你已经在这个场景中了。", "already_in_scene": "你已经在这个场景中了。",
"success": "已切换至场景 %s。", "success": "已切换至场景 %s。",
"exists_error": "此场景不存在。", "exists_error": "此场景不存在。",
"description": "切换指定场景" "description": "切换指定场景"
}, },
"clear": { "clear": {
"command_usage": "用法:clear <all|wp|art|mat>\nall: 所有, wp: 武器, art: 圣遗物, mat: 材料", "command_usage": "用法:clear <all|wp|art|mat>\nall: 所有, wp: 武器, art: 圣遗物, mat: 材料",
...@@ -120,83 +124,87 @@ ...@@ -120,83 +124,87 @@
"displays": "已清空 %s 的屏幕。", "displays": "已清空 %s 的屏幕。",
"virtuals": "已清除 %s 的所有货币和经验值。", "virtuals": "已清除 %s 的所有货币和经验值。",
"everything": "已清除 %s 的所有物品。", "everything": "已清除 %s 的所有物品。",
"description": "从你的背包中删除所有未装备且已解锁的物品,包括稀有物品" "description": "从你的背包中删除所有未装备且已解锁的物品,包括稀有物品"
}, },
"coop": { "coop": {
"usage": "用法:coop <玩家ID> <目标玩家ID>", "usage": "用法:coop <玩家ID> <目标玩家ID>",
"success": "已强制传送 %s 到 %s 的世界", "success": "已强制传送 %s 到 %s 的世界",
"description": "强制传送指定用户到他人的世界" "description": "强制传送指定用户到他人的世界"
}, },
"enter_dungeon": { "enter_dungeon": {
"usage": "用法:enterdungeon <秘境ID>", "usage": "用法:enterdungeon <秘境ID>",
"changed": "已进入秘境 %s", "changed": "已进入秘境 %s",
"not_found_error": "此秘境不存在。", "not_found_error": "此秘境不存在。",
"in_dungeon_error": "你已经在秘境中了。", "in_dungeon_error": "你已经在秘境中了。",
"description": "进入指定秘境" "description": "进入指定秘境"
}, },
"giveAll": { "giveAll": {
"usage": "用法:giveall [玩家] [数量]", "usage": "用法:giveall [玩家] [数量]",
"started": "正在给予全部物品...", "started": "正在给予全部物品...",
"success": "已给予 %s 全部物品。", "success": "已给予 %s 全部物品。",
"invalid_amount_or_playerId": "无效的数量/玩家ID。", "invalid_amount_or_playerId": "无效的数量/玩家ID。",
"description": "给予所有物品" "description": "给予所有物品"
}, },
"giveArtifact": { "giveArtifact": {
"usage": "用法:giveart|gart [玩家] <圣遗物ID> <主词条ID> [<副词条ID>[,<强化次数>]]... [等级]", "usage": "用法:giveart|gart [玩家] <圣遗物ID> <主词条ID> [<副词条ID>[,<强化次数>]]... [等级]",
"id_error": "无效的圣遗物ID。", "id_error": "无效的圣遗物ID。",
"success": "已将 %s 给予 %s。", "success": "已将 %s 给予 %s。",
"description": "给予指定圣遗物" "description": "给予指定圣遗物"
}, },
"giveChar": { "giveChar": {
"usage": "用法:givechar <玩家> <角色ID|角色名> [数量]", "usage": "用法:givechar <玩家> <角色ID|角色名> [数量]",
"given": "已将角色 %s (等级 %s) 给与 %s。", "given": "已将角色 %s [等级 %s] 给与 %s。",
"invalid_avatar_id": "无效的角色ID。", "invalid_avatar_id": "无效的角色ID。",
"invalid_avatar_level": "无效的角色等级。", "invalid_avatar_level": "无效的角色等级。",
"invalid_avatar_or_player_id": "无效的角色ID/玩家ID。", "invalid_avatar_or_player_id": "无效的角色ID/玩家ID。",
"description": "给予指定角色" "description": "给予指定角色"
}, },
"give": { "give": {
"usage": "用法:give <玩家> <物品ID|物品名> [数量] [等级] [精炼等级]", "usage": "用法:give <玩家> <物品ID|物品名> [数量] [等级] [精炼等级]",
"refinement_only_applicable_weapons": "只有武器可以设置精炼等级。", "refinement_only_applicable_weapons": "只有武器可以设置精炼等级。",
"refinement_must_between_1_and_5": "精炼等级必须在 1 到 5 之间。", "refinement_must_between_1_and_5": "精炼等级必须在 1 到 5 之间。",
"given": "已将 %s 个 %s 给予 %s。", "given": "已将 %s 个 %s 给予 %s。",
"given_with_level_and_refinement": "已将 %s (等级 %s, 精炼 %s) %s 个给予 %s", "given_with_level_and_refinement": "已将 %s [等级 %s, 精炼 %s] %s 个给予 %s",
"given_level": "已将 %s (等级 %s) %s 个给予 %s", "given_level": "已将 %s [等级 %s] %s 个给予 %s",
"description": "给予指定物品" "description": "给予指定物品"
}, },
"godmode": { "godmode": {
"success": "%s 的无敌模式已被设置为 %s。", "success": "上帝模式已设为 %s。[用户:%s]",
"description": "防止你受到伤害" "description": "防止你受到伤害"
}, },
"heal": { "heal": {
"success": "已经治疗所有角色。", "success": "已治疗所有角色。",
"description": "治疗当前队伍的角色。" "description": "治疗当前队伍的角色"
},
"join": {
"usage": "用法:join <角色IDs> 例如\"join 10000038 10000039\"空格分开",
"description": "强制将角色加入到当前队伍中"
}, },
"kick": { "kick": {
"player_kick_player": "玩家 [%s:%s] 已将 [%s:%s] 踢出", "player_kick_player": "玩家 [%s:%s] 已将 [%s:%s] 踢出",
"server_kick_player": "正在踢出玩家 [%s:%s]", "server_kick_player": "正在踢出玩家 [%s:%s]...",
"description": "从服务器内踢出指定玩家" "description": "从服务器内踢出指定玩家"
}, },
"kill": { "kill": {
"usage": "用法:killall [玩家UID] [场景ID]", "usage": "用法:killall [玩家UID] [场景ID]",
"scene_not_found_in_player_world": "未在玩家世界中找到此场景", "scene_not_found_in_player_world": "未在玩家世界中找到此场景",
"kill_monsters_in_scene": "已杀死场景 %s 中的 %s 个怪物。", "kill_monsters_in_scene": "已杀死场景 %s 中的 %s 个怪物。",
"description": "杀死所有怪物" "description": "杀死所有怪物"
}, },
"killCharacter": { "killCharacter": {
"usage": "用法:/killcharacter [玩家ID]", "usage": "用法:/killcharacter [玩家ID]",
"success": "已杀死 %s 当前角色。", "success": "已杀死 %s 当前角色。",
"description": "杀死当前角色" "description": "杀死当前角色"
}, },
"language": { "language": {
"current_language": "当前语言是: %s", "current_language": "当前语言是: %s",
"language_changed": "语言切换至: %s", "language_changed": "语言切换至: %s",
"language_not_found": "目前服务端没有这种语言: %s", "language_not_found": "目前服务端没有这种语言: %s",
"description": "显示或切换当前语言" "description": "显示或切换当前语言"
}, },
"list": { "list": {
"success": "目前在线人数:%s", "success": "目前在线人数:%s",
"description": "查看所有玩家" "description": "查看所有玩家"
}, },
"permission": { "permission": {
"usage": "用法:permission <add|remove> <用户名> <权限>", "usage": "用法:permission <add|remove> <用户名> <权限>",
...@@ -205,25 +213,38 @@ ...@@ -205,25 +213,38 @@
"remove": "权限已移除。", "remove": "权限已移除。",
"not_have_error": "此玩家未拥有权限!", "not_have_error": "此玩家未拥有权限!",
"account_error": "账号不存在。", "account_error": "账号不存在。",
"description": "添加或移除指定玩家的权限" "description": "添加或移除指定玩家的权限"
}, },
"position": { "position": {
"success": "坐标:%s, %s, %s\n场景ID:%s", "success": "坐标:%s, %s, %s\n场景ID:%s",
"description": "获取所在位置。" "description": "获取所在位置"
},
"quest": {
"description": "添加或完成任务",
"usage": "quest <add|finish> [任务ID]",
"added": "已添加任务 %s",
"finished": "已完成任务 %s",
"not_found": "未找到任务",
"invalid_id": "无效的任务ID"
}, },
"reload": { "reload": {
"reload_start": "正在重载配置文件和数据。", "reload_start": "正在重载配置文件和数据。",
"reload_done": "重载完成。", "reload_done": "重载完成。",
"description": "重载配置文件和数据。" "description": "重载配置文件和数据"
},
"remove": {
"usage": "用法: remove [indexOfYourTeams] 从1开始",
"invalid_index": "下标从1开始",
"description": "强制移除队内角色"
}, },
"resetConst": { "resetConst": {
"reset_all": "重置所有角色的命座。", "reset_all": "重置所有角色的命座。",
"success": "已重置 %s 的命座,重新登录后生效。", "success": "已重置 %s 的命座,重新登录后生效。",
"description": "重置当前角色的命之座,执行命令后需重新登录以生效" "description": "重置当前角色的命之座,执行命令后需重新登录以生效"
}, },
"resetShopLimit": { "resetShopLimit": {
"usage": "用法:/resetshop <玩家ID>", "usage": "用法:/resetshop <玩家ID>",
"description": "重置所选玩家的商店刷新时间" "description": "重置所选玩家的商店刷新时间"
}, },
"sendMail": { "sendMail": {
"usage": "用法:give [玩家] <物品ID|物品名称> [数量]", "usage": "用法:give [玩家] <物品ID|物品名称> [数量]",
...@@ -246,19 +267,19 @@ ...@@ -246,19 +267,19 @@
"sender": "<发件人>", "sender": "<发件人>",
"arguments": "<物品ID|物品名称|finish> [数量] [等级]", "arguments": "<物品ID|物品名称|finish> [数量] [等级]",
"error": "错误:无效的编写阶段 %s。需要 StackTrace 请查看服务器控制台。", "error": "错误:无效的编写阶段 %s。需要 StackTrace 请查看服务器控制台。",
"description": "向指定用户发送邮件。此命令的用法可根据附加的参数而变化" "description": "向指定用户发送邮件。此命令的用法可根据附加的参数而变化"
}, },
"sendMessage": { "sendMessage": {
"usage": "用法:sendmessage <玩家> <消息>", "usage": "用法:sendmessage <玩家> <消息>",
"success": "消息已发送。", "success": "消息已发送。",
"description": "向指定玩家发送消息" "description": "向指定玩家发送消息"
}, },
"setFetterLevel": { "setFetterLevel": {
"usage": "用法:setfetterlevel <好感度等级>", "usage": "用法:setfetterlevel <好感度等级>",
"range_error": "好感度等级必须在 0 到 10 之间。", "range_error": "好感度等级必须在 0 到 10 之间。",
"success": "好感度已设为 %s 级", "success": "好感度已设为 %s 级",
"level_error": "无效的好感度等级。", "level_error": "无效的好感度等级。",
"description": "设置当前角色的好感度等级" "description": "设置当前角色的好感度等级"
}, },
"setStats": { "setStats": {
"usage_console": "用法:setstats|stats @<UID> <属性> <数值>", "usage_console": "用法:setstats|stats @<UID> <属性> <数值>",
...@@ -268,29 +289,29 @@ ...@@ -268,29 +289,29 @@
"uid_error": "无效的UID。", "uid_error": "无效的UID。",
"player_error": "玩家不存在或已离线。", "player_error": "玩家不存在或已离线。",
"set_self": "%s 已设为 %s。", "set_self": "%s 已设为 %s。",
"set_for_uid": "%s (来自 %s) 设置为 %s。", "set_for_uid": "%s [来自 %s] 已设为 %s。",
"set_max_hp": "最大生命值已设为 %s。", "set_max_hp": "最大生命值已设为 %s。",
"description": "设置当前角色的属性" "description": "设置当前角色的属性"
}, },
"setWorldLevel": { "setWorldLevel": {
"usage": "用法:setworldlevel <等级>", "usage": "用法:setworldlevel <等级>",
"value_error": "世界等级必须设置在0-8之间。", "value_error": "世界等级必须设置在0-8之间。",
"success": "已将世界等级设为 %s。", "success": "世界等级设为 %s。",
"invalid_world_level": "无效的世界等级。", "invalid_world_level": "无效的世界等级。",
"description": "设置世界等级,执行命令后需重新登录以生效" "description": "设置世界等级,执行命令后需重新登录以生效"
}, },
"spawn": { "spawn": {
"usage": "用法:spawn <实体ID> [数量] [等级(仅怪物)]", "usage": "用法:spawn <实体ID> [数量] [等级(仅怪物)]",
"success": "已生成 %s 个 %s。", "success": "已生成 %s 个 %s。",
"description": "在你附近生成一个生物" "description": "在你附近生成一个生物"
}, },
"stop": { "stop": {
"success": "正在关闭服务器...", "success": "正在关闭服务器...",
"description": "停止服务器" "description": "停止服务器"
}, },
"talent": { "talent": {
"usage_1": "设置天赋等级:/talent set <天赋ID> <数值>", "usage_1": "设置天赋等级:/talent set <天赋ID> <数值>",
"usage_2": "另一种设置天赋等级的方法:/talent <n (普) | e (元素战技) | q (元素爆发)> <数值>", "usage_2": "另一种设置天赋等级的方法:/talent <n (普通攻击) | e (元素战技) | q (元素爆发)> <数值>",
"usage_3": "获取天赋ID:/talent getid", "usage_3": "获取天赋ID:/talent getid",
"lower_16": "无效的天赋等级,天赋等级应小于等于15。", "lower_16": "无效的天赋等级,天赋等级应小于等于15。",
"set_id": "将天赋等级设为 %s。", "set_id": "将天赋等级设为 %s。",
...@@ -303,20 +324,20 @@ ...@@ -303,20 +324,20 @@
"normal_attack_id": "普通攻击的 ID 为 %s。", "normal_attack_id": "普通攻击的 ID 为 %s。",
"e_skill_id": "元素战技ID %s。", "e_skill_id": "元素战技ID %s。",
"q_skill_id": "元素爆发ID %s。", "q_skill_id": "元素爆发ID %s。",
"description": "设置当前角色的天赋等级" "description": "设置当前角色的天赋等级"
}, },
"teleportAll": { "teleportAll": {
"success": "已将所有玩家传送到你的位置", "success": "已将所有玩家传送到你的位置",
"error": "你只能在多人游戏状态下执行此命令。", "error": "你只能在多人游戏状态下执行此命令。",
"description": "将你世界中的所有玩家传送到你所在的位置" "description": "将你世界中的所有玩家传送到你所在的位置"
}, },
"teleport": { "teleport": {
"usage_server": "用法:/tp @<玩家ID> <x> <y> <z> [场景ID]", "usage_server": "用法:/tp @<玩家ID> <x> <y> <z> [场景ID]",
"usage": "用法:/tp [@<玩家ID>] <x> <y> <z> [场景ID]", "usage": "用法:/tp [@<玩家ID>] <x> <y> <z> [场景ID]",
"specify_player_id": "你必须指定一个玩家ID。", "specify_player_id": "你必须指定一个玩家ID。",
"invalid_position": "无效的位置。", "invalid_position": "无效的位置。",
"success": "传送 %s 到坐标 %s,%s,%s,场景为 %s", "success": "传送 %s 到坐标 %s,%s,%s,场景为 %s",
"description": "改变指定玩家的位置" "description": "改变指定玩家的位置"
}, },
"tower": { "tower": {
"unlock_done": "深境回廊的所有层已全部解锁。" "unlock_done": "深境回廊的所有层已全部解锁。"
...@@ -325,28 +346,37 @@ ...@@ -325,28 +346,37 @@
"usage": "用法:weather <天气ID> [气候ID]", "usage": "用法:weather <天气ID> [气候ID]",
"success": "已更改天气为 %s,气候为 %s。", "success": "已更改天气为 %s,气候为 %s。",
"invalid_id": "无效的天气ID。", "invalid_id": "无效的天气ID。",
"description": "更改天气" "description": "更改天气"
}, },
"drop": { "drop": {
"command_usage": "用法:drop <物品ID|物品名称> [数量]", "command_usage": "用法:drop <物品ID|物品名称> [数量]",
"success": "已丢下 %s 个 %s。", "success": "已丢下 %s 个 %s。",
"description": "在你附近丢下一个物品" "description": "在你附近丢下一个物品"
}, },
"help": { "help": {
"usage": "用法:", "usage": "用法:",
"aliases": "别名:", "aliases": "别名:",
"available_commands": "可用命令:", "available_commands": "可用命令:",
"description": "发送帮助信息或显示指定命令的信息" "description": "发送帮助信息或显示指定命令的信息"
}, },
"restart": { "restart": {
"description": "重新启动服务器" "description": "重新启动服务器"
}, },
"unlocktower": { "unlocktower": {
"success": "解锁完成。", "success": "解锁完成。",
"description": "解锁深境螺旋的所有层" "description": "解锁深境螺旋的所有层"
}, },
"resetshop": { "resetshop": {
"description": "重置商店刷新时间。" "description": "重置商店刷新时间"
}
},
"gacha": {
"details": {
"title": "祈愿详情",
"available_five_stars": "可获得的5星物品",
"available_four_stars": "可获得的4星物品",
"available_three_stars": "可获得的3星物品",
"template_missing": "缺失文件:data/gacha_details.html"
} }
} }
} }
...@@ -16,6 +16,9 @@ ...@@ -16,6 +16,9 @@
"no_keystore_error": "[Dispatch] 未找到 SSL 憑證!已後降到 HTTP 伺服器。", "no_keystore_error": "[Dispatch] 未找到 SSL 憑證!已後降到 HTTP 伺服器。",
"default_password": "[Dispatch] 默認的 keystore 密碼加載成功。請考慮將 config.json 的憑證密碼設定成 123456。" "default_password": "[Dispatch] 默認的 keystore 密碼加載成功。請考慮將 config.json 的憑證密碼設定成 123456。"
}, },
"authentication": {
"default_unable_to_verify": "[驗證系統] 稱為 verifyUser 方法的東西在默認身份驗證程序中不可用。"
},
"no_commands_error": "此指令不適用於Dispatch-only模式。", "no_commands_error": "此指令不適用於Dispatch-only模式。",
"unhandled_request_error": "[Dispatch] 潛在的未處理請求 %s 請求:%s", "unhandled_request_error": "[Dispatch] 潛在的未處理請求 %s 請求:%s",
"account": { "account": {
...@@ -45,7 +48,8 @@ ...@@ -45,7 +48,8 @@
"run_mode_error": "無效的伺服器運行模式: %s。", "run_mode_error": "無效的伺服器運行模式: %s。",
"run_mode_help": "伺服器運行模式必須為 HYBRID 或者 DISPATCH_ONLY 或者 GAME_ONLY。Grasscutter 啟動失敗...", "run_mode_help": "伺服器運行模式必須為 HYBRID 或者 DISPATCH_ONLY 或者 GAME_ONLY。Grasscutter 啟動失敗...",
"create_resources": "正在建立 resources 資料夾...", "create_resources": "正在建立 resources 資料夾...",
"resources_error": "請將 BinOutput 和 ExcelBinOutput 複製到 resources 資料夾。" "resources_error": "請將 BinOutput 和 ExcelBinOutput 複製到 resources 資料夾。",
"version": "Grasscutter版本: %s-%s"
} }
}, },
"commands": { "commands": {
...@@ -56,6 +60,7 @@ ...@@ -56,6 +60,7 @@
"console_execute_error": "此指令只能在伺服器的命令提示字元執行。", "console_execute_error": "此指令只能在伺服器的命令提示字元執行。",
"player_execute_error": "請在遊戲裡使用這條指令。", "player_execute_error": "請在遊戲裡使用這條指令。",
"command_exist_error": "找不到指令。", "command_exist_error": "找不到指令。",
"no_description_specified": "没有指定說明。",
"invalid": { "invalid": {
"amount": "無效的數量。", "amount": "無效的數量。",
"artifactId": "無效的聖遺物ID。", "artifactId": "無效的聖遺物ID。",
...@@ -95,17 +100,20 @@ ...@@ -95,17 +100,20 @@
"create": "已建立帳號,UID 為 %s 。", "create": "已建立帳號,UID 為 %s 。",
"delete": "帳號已刪除。", "delete": "帳號已刪除。",
"no_account": "帳號不存在。", "no_account": "帳號不存在。",
"command_usage": "用法:account <create|delete> <username> [uid]" "command_usage": "用法:account <create|delete> <username> [uid]",
"description": "建立或刪除帳號。"
}, },
"broadcast": { "broadcast": {
"command_usage": "用法:broadcast <message>", "command_usage": "用法:broadcast <message>",
"message_sent": "公告已發送。" "message_sent": "公告已發送。",
"description": "向所有玩家發送公告。"
}, },
"changescene": { "changescene": {
"usage": "用法:changescene <scene id>", "usage": "用法:changescene <scene id>",
"already_in_scene": "你已經在這個場景中了。", "already_in_scene": "你已經在這個場景中了。",
"success": "已切換至場景 %s.", "success": "已切換至場景 %s.",
"exists_error": "此場景不存在。" "exists_error": "此場景不存在。",
"description": "切換指定場景。"
}, },
"clear": { "clear": {
"command_usage": "用法: clear <all|wp|art|mat>", "command_usage": "用法: clear <all|wp|art|mat>",
...@@ -115,35 +123,41 @@ ...@@ -115,35 +123,41 @@
"furniture": "已將 %s 的塵歌壺家具清空。", "furniture": "已將 %s 的塵歌壺家具清空。",
"displays": "已清除 %s 的顯示。", "displays": "已清除 %s 的顯示。",
"virtuals": "已將 %s 的所有貨幣和經驗值清空。", "virtuals": "已將 %s 的所有貨幣和經驗值清空。",
"everything": "已將 %s 的所有物品清空。" "everything": "已將 %s 的所有物品清空。",
"description": "從你的背包中刪除所有未裝備且未上鎖的物品,包括稀有物品。"
}, },
"coop": { "coop": {
"usage": "用法:coop <playerId> <target playerId>", "usage": "用法:coop <playerId> <target playerId>",
"success": "召喚了 %s 到 %s 的世界。" "success": "召喚了 %s 到 %s 的世界。",
"description": "強制傳送指定用戶到他人的世界。"
}, },
"enter_dungeon": { "enter_dungeon": {
"usage": "用法:enterdungeon <dungeon id>", "usage": "用法:enterdungeon <dungeon id>",
"changed": "已進入副本 %s", "changed": "已進入祕境 %s",
"not_found_error": "此副本不存在。", "not_found_error": "此祕境不存在。",
"in_dungeon_error": "你已經在祕境中了。" "in_dungeon_error": "你已經在祕境中了。",
"description": "進入指定祕境。"
}, },
"giveAll": { "giveAll": {
"usage": "用法:giveall [player] [amount]", "usage": "用法:giveall [player] [amount]",
"started": "正在賦予全部物品...", "started": "正在賦予全部物品...",
"success": "已賦予全部物品。", "success": "已賦予全部物品。",
"invalid_amount_or_playerId": "無效的數量/玩家ID。" "invalid_amount_or_playerId": "無效的數量/玩家ID。",
"description": "賦予所有物品。"
}, },
"giveArtifact": { "giveArtifact": {
"usage": "用法:giveart|gart [player] <artifactId> <mainPropId> [<appendPropId>[,<times>]]... [level]", "usage": "用法:giveart|gart [player] <artifactId> <mainPropId> [<appendPropId>[,<times>]]... [level]",
"id_error": "無效的聖遺物ID。", "id_error": "無效的聖遺物ID。",
"success": "已把 %s 給予 %s。" "success": "已把 %s 給予 %s。",
"description": "給予指定聖遺物。"
}, },
"giveChar": { "giveChar": {
"usage": "用法:givechar <player> <itemId|itemName> [amount]", "usage": "用法:givechar <player> <itemId|itemName> [amount]",
"given": "已將 %s 等級 %s 給予 %s。", "given": "已將 %s 等級 %s 給予 %s。",
"invalid_avatar_id": "無效的角色ID。", "invalid_avatar_id": "無效的角色ID。",
"invalid_avatar_level": "無效的角色等級。.", "invalid_avatar_level": "無效的角色等級。.",
"invalid_avatar_or_player_id": "無效的角色ID/玩家ID。" "invalid_avatar_or_player_id": "無效的角色ID/玩家ID。",
"description": "給予指定角色。"
}, },
"give": { "give": {
"usage": "用法:give <player> <itemId|itemName> [amount] [level]", "usage": "用法:give <player> <itemId|itemName> [amount] [level]",
...@@ -151,29 +165,42 @@ ...@@ -151,29 +165,42 @@
"refinement_must_between_1_and_5": "精煉度必需在 1 到 5 之間。", "refinement_must_between_1_and_5": "精煉度必需在 1 到 5 之間。",
"given": "已經將 %s 個 %s 給予 %s。", "given": "已經將 %s 個 %s 給予 %s。",
"given_with_level_and_refinement": "已將 %s [等級%s, 精煉%s] %s個給予 %s", "given_with_level_and_refinement": "已將 %s [等級%s, 精煉%s] %s個給予 %s",
"given_level": "已將 %s 等級 %s %s 個給予 %s" "given_level": "已將 %s 等級 %s %s 個給予 %s",
"description": "給予指定物品。"
}, },
"godmode": { "godmode": {
"success": "上帝模式設定為 %s 。 [用戶:%s]" "success": "上帝模式設定為 %s 。 [用戶:%s]",
"description": "防止你受到傷害。"
}, },
"heal": { "heal": {
"success": "所有角色已被治療。" "success": "所有角色已被治療。",
"description": "治療當前隊伍的角色。"
}, },
"kick": { "kick": {
"player_kick_player": "玩家 [%s:%s] 已把 [%s:%s] 踢出", "player_kick_player": "玩家 [%s:%s] 已把 [%s:%s] 踢出",
"server_kick_player": "正在踢出玩家 [%s:%s]" "server_kick_player": "正在踢出玩家 [%s:%s]",
"description": "從伺服器內踢出指定玩家。"
}, },
"kill": { "kill": {
"usage": "用法:killall [playerUid] [sceneId]", "usage": "用法:killall [playerUid] [sceneId]",
"scene_not_found_in_player_world": "未在玩家世界中找到此場景", "scene_not_found_in_player_world": "未在玩家世界中找到此場景",
"kill_monsters_in_scene": "已殺死 %s 個怪物。 [場景ID: %s]" "kill_monsters_in_scene": "已殺死 %s 個怪物。 [場景ID: %s]",
"description": "殺死所有怪物。"
}, },
"killCharacter": { "killCharacter": {
"usage": "用法:/killcharacter [playerId]", "usage": "用法:/killcharacter [playerId]",
"success": "已殺死 %s 目前的場上角色。" "success": "已殺死 %s 目前的場上角色。",
"description": "殺死玩家目前使用的場上角色。"
},
"language": {
"current_language": "當前語言是: %s",
"language_changed": "語言切換至: %s",
"language_not_found": "目前客戶端沒有這種語言: %s",
"description": "顯示或切換當前語言。"
}, },
"list": { "list": {
"success": "目前總線上人數:%s" "success": "目前總線上人數:%s" ,
"description": "查看所有在線玩家"
}, },
"permission": { "permission": {
"usage": "用法:permission <add|remove> <username> <permission>", "usage": "用法:permission <add|remove> <username> <permission>",
...@@ -181,21 +208,39 @@ ...@@ -181,21 +208,39 @@
"has_error": "此玩家已擁有權限!", "has_error": "此玩家已擁有權限!",
"remove": "權限已移除。", "remove": "權限已移除。",
"not_have_error": "此玩家未擁有權限!", "not_have_error": "此玩家未擁有權限!",
"account_error": "The account cannot be found." "account_error": "帳號不存在。",
"description": "指派或移除指定玩家的權限。"
}, },
"position": { "position": {
"success": "坐標:%s, %s, %s\n場景ID:%s" "success": "座標:%s, %s, %s\n場景ID:%s",
"description": "獲取目前所在位置的座標。"
},
"quest": {
"description": "添加或完成任務",
"usage": "quest <add|finish> [任務ID]",
"added": "已添加任務 %s",
"finished": "已完成任務 %s",
"not_found": "未找到任務",
"invalid_id": "無效的任務ID"
}, },
"reload": { "reload": {
"reload_start": "正在重新加載設定檔。", "reload_start": "正在重新加載設定檔。",
"reload_done": "重新加載已完成。" "reload_done": "重新加載已完成。",
"description": "重新加載設定檔和數據。"
},
"remove": {
"usage": "用法: remove [indexOfYourTeams] 从1开始",
"invalid_index": "下標從1開始",
"description": "强制移除對内角色"
}, },
"resetConst": { "resetConst": {
"reset_all": "重設所有角色的命座。", "reset_all": "重設所有角色的命座。",
"success": "已重設 %s 的命座,重新登入後將會生效。" "success": "已重設 %s 的命座,重新登入後將會生效。",
"description": "重置當前角色的命之座,重新登入後將會生效。"
}, },
"resetShopLimit": { "resetShopLimit": {
"usage": "用法:/resetshop <player id>" "usage": "用法:/resetshop <player id>",
"description": "重置所選玩家的商店刷新時間。"
}, },
"sendMail": { "sendMail": {
"usage": "用法:give [player] <itemId|itemName> [amount]", "usage": "用法:give [player] <itemId|itemName> [amount]",
...@@ -217,17 +262,20 @@ ...@@ -217,17 +262,20 @@
"message": "<正文>", "message": "<正文>",
"sender": "<寄件者>", "sender": "<寄件者>",
"arguments": "<itemId|itemName|finish> [數量] [等級]", "arguments": "<itemId|itemName|finish> [數量] [等級]",
"error": "錯誤:無效的編寫階段 %s。需要 stacktrace 請查看伺服器命令提示字元。" "error": "錯誤:無效的編寫階段 %s。需要 stacktrace 請查看伺服器命令提示字元。",
"description": "向指定用戶發送郵件。此指令的用法可根據附加的參數而改變。"
}, },
"sendMessage": { "sendMessage": {
"usage": "用法:sendmessage <player> <message>", "usage": "用法:sendmessage <player> <message>",
"success": "訊息已發送。" "success": "訊息已發送。",
"description": "向指定玩家發送訊息。"
}, },
"setFetterLevel": { "setFetterLevel": {
"usage": "用法:setfetterlevel <level>", "usage": "用法:setfetterlevel <level>",
"range_error": "好感度必須在 0 到 10 之間。", "range_error": "好感度必須在 0 到 10 之間。",
"success": "好感等級已設定為 %s", "success": "好感等級已設定為 %s",
"level_error": "無效的好感度。" "level_error": "無效的好感度。",
"description": "設定當前角色的好感度等級。"
}, },
"setStats": { "setStats": {
"usage_console": "用法:setstats|stats @<UID> <stat> <value>", "usage_console": "用法:setstats|stats @<UID> <stat> <value>",
...@@ -238,68 +286,93 @@ ...@@ -238,68 +286,93 @@
"player_error": "玩家不存在或已離線。", "player_error": "玩家不存在或已離線。",
"set_self": "%s 已經設為 %s。", "set_self": "%s 已經設為 %s。",
"set_for_uid": "%s 的使用者 %s 更改為 %s。", "set_for_uid": "%s 的使用者 %s 更改為 %s。",
"set_max_hp": "最大生命值更改為 %s。" "set_max_hp": "最大生命值更改為 %s。",
"description": "設定當前角色的數據類型。"
}, },
"setWorldLevel": { "setWorldLevel": {
"usage": "用法:setworldlevel <level>", "usage": "用法:setworldlevel <level>",
"value_error": "世界等級必須設定在0-8之間。", "value_error": "世界等級必須設定在0-8之間。",
"success": "已將世界等級設為%s。", "success": "已將世界等級設為%s。",
"invalid_world_level": "無效的世界等級。" "invalid_world_level": "無效的世界等級。",
"description": "設定世界等級,執行指令後需重新登入後才會生效。"
}, },
"spawn": { "spawn": {
"usage": "用法:spawn <entityId> [amount] [level(僅限怪物)]", "usage": "用法:spawn <entityId> [amount] [level(僅限怪物)]",
"success": "已生成 %s 個 %s。" "success": "已生成 %s 個 %s。",
"description": "在你附近生成一個實體動物。"
}, },
"stop": { "stop": {
"success": "正在關閉伺服器..." "success": "正在關閉伺服器...",
"description": "以正常的方式關閉伺服器。"
}, },
"talent": { "talent": {
"usage_1": "設定天賦等級:/talent set <talentID> <value>", "usage_1": "設定天賦等級:/talent set <talentID> <value>",
"usage_2": "另一種設定天賦等級的指令使用方法:/talent <n or e or q> <value>", "usage_2": "另一種設定天賦等級的指令使用方法:/talent <n or e or q> <value>",
"usage_3": "獲取天賦ID指令用法:/talent getid", "usage_3": "獲取天賦ID指令用法:/talent getid",
"lower_16": "無效的技能等級,技能等級應低於 16。", "lower_16": "無效的天賦等級,技能等級應低於 16。",
"set_id": "將天賦等級設為%s。", "set_id": "將天賦等級設為%s。",
"set_atk": "將普通攻擊等級設為 %s。", "set_atk": "將普通攻擊等級設為 %s。",
"set_e": "設定天賦E等級至 %s。", "set_e": "設定元素戰技的天賦等級至 %s。",
"set_q": "設定天賦Q等級至 %s。", "set_q": "設定元素爆發的天賦等級至 %s。",
"invalid_skill_id": "無效的技能ID。", "invalid_skill_id": "無效的技能ID。",
"set_this": "將天賦等級設為 %s。", "set_this": "將天賦等級設為 %s。",
"invalid_level": "無效的天賦等級。", "invalid_level": "無效的天賦等級。",
"normal_attack_id": "普通攻擊的 ID 為 %s。", "normal_attack_id": "普通攻擊的 ID 為 %s。",
"e_skill_id": "E技能ID %s。", "e_skill_id": "元素戰技技能ID %s。",
"q_skill_id": "Q技能ID %s。" "q_skill_id": "元素爆發技能ID %s。",
"description": "設定當前角色的天賦等級"
}, },
"teleportAll": { "teleportAll": {
"success": "召喚了所有玩家到你的位置上。", "success": "召喚了所有玩家到你的位置上。",
"error": "此指令僅可在多人遊戲下可用。" "error": "此指令僅可在多人遊戲下可用。",
"description": "將你世界裡的所有玩家傳送到你目前的所在位置。"
}, },
"teleport": { "teleport": {
"usage_server": "用法:/tp @<player id> <x> <y> <z> [scene id]", "usage_server": "用法:/tp @<player id> <x> <y> <z> [scene id]",
"usage": "用法:/tp [@<player id>] <x> <y> <z> [scene id]", "usage": "用法:/tp [@<player id>] <x> <y> <z> [scene id]",
"specify_player_id": "你必須指定一個玩家ID。", "specify_player_id": "你必須指定一個玩家ID。",
"invalid_position": "無效的位置。", "invalid_position": "無效的座標。",
"success": "傳送 %s 到坐標 %s,%s,%s ,場景為 %s" "success": "傳送 %s 到座標 %s,%s,%s ,場景為 %s 。",
"description": "將玩家的位置傳送到你所指定的座標。"
},
"tower": {
"unlock_done": "解鎖所有級別的深境螺旋已全部解鎖。"
}, },
"weather": { "weather": {
"usage": "用法:weather <weatherId> [climateId]", "usage": "用法:weather <weatherId> [climateId]",
"success": "已將當前天氣設定為 %s ,氣候則為 %s 。", "success": "已將當前天氣設定為 %s ,氣候則為 %s 。",
"invalid_id": "無效的ID。" "invalid_id": "無效的ID。",
"description": "更改目前的天氣。"
}, },
"drop": { "drop": {
"command_usage": "用法:drop <itemId|itemName> [amount]", "command_usage": "用法:drop <itemId|itemName> [amount]",
"success": "已將 %s x %s 丟在附近。" "success": "已將 %s x %s 丟在附近。",
"description": "在你附近丟下一個物品。"
}, },
"help": { "help": {
"usage": "用法:", "usage": "用法:",
"aliases": "別名:", "aliases": "別名:",
"description": "發送幫助信息或顯示特定命令的信息",
"available_commands": "可用指令:" "available_commands": "可用指令:"
}, },
"restart": {
"description": "重新啟動伺服器。"
},
"unlocktower": { "unlocktower": {
"success": "解鎖完成。", "success": "解鎖完成。",
"description": "解鎖所有級別的深境螺旋" "description": "解鎖所有級別的深境螺旋"
}, },
"resetshop": { "resetshop": {
"description": "重置商店時間" "description": "重置商店刷新時間。"
}
},
"gacha": {
"details": {
"title": "祈願詳情",
"available_five_stars": "可獲得的5星物品",
"available_four_stars": "可獲得的4星物品",
"available_three_stars": "可獲得的3星物品",
"template_missing": "data/gacha_details.html 不存在。"
} }
} }
} }
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment