船新两个 Sendable Json 和 ActionBar
This commit is contained in:
parent
da8890b30a
commit
19b4bd9a6b
@ -17,7 +17,6 @@ public abstract class ActionBar {
|
||||
instance = (ActionBar) AsmClassTransformer.builder().from(Impl_1_8.class).fromVersion("v1_8_R3")
|
||||
.toVersion(Bukkit.getServer().getClass().getName().split("\\.")[3]).build().transform();
|
||||
}
|
||||
System.out.println(instance.getClass());
|
||||
}
|
||||
|
||||
public static void sendActionBar(Player player, String text) {
|
||||
|
@ -37,9 +37,10 @@ class TLocaleInstance {
|
||||
Bukkit.getScheduler().runTask(plugin, () -> sendable.sendTo(sender, args));
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
} catch (Exception | Error e) {
|
||||
TLib.getTLib().getLogger().error(Strings.replaceWithOrder(TLib.getTLib().getInternalLang().getString("SEND-LOCALE-ERROR"), path));
|
||||
TLib.getTLib().getLogger().error(Strings.replaceWithOrder(TLib.getTLib().getInternalLang().getString("LOCALE-ERROR-REASON"), e.getMessage()));
|
||||
TLib.getTLib().getLogger().error(Strings.replaceWithOrder(TLib.getTLib().getInternalLang().getString("LOCALE-ERROR-REASON"), e.toString()));
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
package com.ilummc.tlib.resources;
|
||||
|
||||
import com.ilummc.tlib.TLib;
|
||||
import com.ilummc.tlib.resources.type.TLocaleActionBar;
|
||||
import com.ilummc.tlib.resources.type.TLocaleJson;
|
||||
import com.ilummc.tlib.resources.type.TLocaleText;
|
||||
import com.ilummc.tlib.resources.type.TLocaleTitle;
|
||||
import com.ilummc.tlib.util.Strings;
|
||||
@ -39,6 +41,8 @@ public class TLocaleLoader {
|
||||
public static void init() {
|
||||
ConfigurationSerialization.registerClass(TLocaleText.class, "TEXT");
|
||||
ConfigurationSerialization.registerClass(TLocaleTitle.class, "TITLE");
|
||||
ConfigurationSerialization.registerClass(TLocaleJson.class, "JSON");
|
||||
ConfigurationSerialization.registerClass(TLocaleActionBar.class, "ACTION");
|
||||
}
|
||||
|
||||
public static void load(Plugin plugin, boolean ignoreLoaded) {
|
||||
|
@ -0,0 +1,61 @@
|
||||
package com.ilummc.tlib.resources.type;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.ilummc.tlib.compat.PlaceholderHook;
|
||||
import com.ilummc.tlib.nms.ActionBar;
|
||||
import com.ilummc.tlib.resources.TLocaleSendable;
|
||||
import com.ilummc.tlib.util.Strings;
|
||||
import me.skymc.taboolib.Main;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.configuration.serialization.ConfigurationSerializable;
|
||||
import org.bukkit.configuration.serialization.SerializableAs;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
import java.util.Map;
|
||||
|
||||
@Immutable
|
||||
@SerializableAs("ACTION")
|
||||
public class TLocaleActionBar implements TLocaleSendable, ConfigurationSerializable {
|
||||
|
||||
private final String text;
|
||||
|
||||
private final boolean papi;
|
||||
|
||||
public TLocaleActionBar(String text, boolean papi) {
|
||||
this.text = text;
|
||||
this.papi = papi;
|
||||
}
|
||||
|
||||
public static TLocaleActionBar valueOf(Map<String, Object> map) {
|
||||
String text = String.valueOf(map.getOrDefault("text", "Empty Action bar message."));
|
||||
boolean papi = (boolean) map.getOrDefault("papi", Main.getInst().getConfig().getBoolean("LOCALE.USE_PAPI", false));
|
||||
return new TLocaleActionBar(text, papi);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendTo(CommandSender sender, String... args) {
|
||||
if (sender instanceof Player)
|
||||
ActionBar.sendActionBar(((Player) sender), replace(sender, text, args));
|
||||
}
|
||||
|
||||
private String replace(CommandSender sender, String text, String[] args) {
|
||||
String s = Strings.replaceWithOrder(text, args);
|
||||
return papi ? PlaceholderHook.replace(sender, s) : s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String asString(String... args) {
|
||||
return "ActionBar: [" + text + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> serialize() {
|
||||
Map<String, Object> map = Maps.newHashMap();
|
||||
map.put("text", text);
|
||||
if (papi)
|
||||
map.put("papi", true);
|
||||
return map;
|
||||
}
|
||||
|
||||
}
|
153
src/main/java/com/ilummc/tlib/resources/type/TLocaleJson.java
Normal file
153
src/main/java/com/ilummc/tlib/resources/type/TLocaleJson.java
Normal file
@ -0,0 +1,153 @@
|
||||
package com.ilummc.tlib.resources.type;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.ilummc.tlib.TLib;
|
||||
import com.ilummc.tlib.compat.PlaceholderHook;
|
||||
import com.ilummc.tlib.resources.TLocaleSendable;
|
||||
import com.ilummc.tlib.util.Strings;
|
||||
import me.skymc.taboolib.Main;
|
||||
import net.md_5.bungee.api.chat.*;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.configuration.serialization.ConfigurationSerializable;
|
||||
import org.bukkit.configuration.serialization.SerializableAs;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import javax.annotation.concurrent.ThreadSafe;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ThreadSafe
|
||||
@SerializableAs("JSON")
|
||||
public class TLocaleJson implements TLocaleSendable, ConfigurationSerializable {
|
||||
|
||||
private static final Pattern pattern = Pattern.compile("<([^<>]*)?@([^<>]*)>");
|
||||
private final List<BaseComponent[]> components;
|
||||
private final boolean papi;
|
||||
private final Map<String, Object> map;
|
||||
|
||||
private TLocaleJson(List<BaseComponent[]> components, boolean papi, Map<String, Object> map) {
|
||||
this.components = ImmutableList.copyOf(components);
|
||||
this.papi = papi;
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
public static TLocaleJson valueOf(Map<String, Object> map) {
|
||||
Object textObj = map.getOrDefault("text", "Empty Node");
|
||||
List<String> textList = textObj instanceof String ? Lists.newArrayList(((String) textObj)) :
|
||||
(textObj instanceof List && !((List) textObj).isEmpty()) ?
|
||||
((List<?>) textObj).stream().map(Object::toString).collect(Collectors.toList()) : Lists.newArrayList(String.valueOf(textObj));
|
||||
boolean papi = (boolean) map.getOrDefault("papi", Main.getInst().getConfig().getBoolean("LOCALE.USE_PAPI", false));
|
||||
Object argsObj = map.get("args");
|
||||
if (argsObj instanceof Map) {
|
||||
Map<?, ?> section = ((Map<?, ?>) argsObj);
|
||||
List<BaseComponent[]> collect = textList.stream().map(s -> {
|
||||
String[] template = pattern.split(s);
|
||||
int index = 0;
|
||||
Matcher matcher = pattern.matcher(s);
|
||||
List<BaseComponent> builder;
|
||||
if (template.length > index) {
|
||||
builder = new ArrayList<>(Arrays.asList(TextComponent.fromLegacyText(template[index++])));
|
||||
} else builder = new ArrayList<>();
|
||||
while (matcher.find()) {
|
||||
String replace = matcher.group();
|
||||
if (replace.length() <= 2) continue;
|
||||
replace = replace.substring(1, replace.length() - 1);
|
||||
String[] split = replace.split("@");
|
||||
String text = split.length > 1 ? split[0] : "";
|
||||
String node = split.length > 1 ? split[1] : split[0];
|
||||
if (section.containsKey(node)) {
|
||||
Map<String, Object> arg = (Map<String, Object>) section.get(node);
|
||||
text = (String) arg.getOrDefault("text", text);
|
||||
BaseComponent[] component = TextComponent.fromLegacyText(text);
|
||||
arg.forEach((key, value) -> {
|
||||
switch (key) {
|
||||
case "suggest":
|
||||
for (BaseComponent baseComponent : component) {
|
||||
baseComponent.setClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, String.valueOf(value)));
|
||||
}
|
||||
break;
|
||||
case "command":
|
||||
for (BaseComponent baseComponent : component) {
|
||||
baseComponent.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, String.valueOf(value)));
|
||||
}
|
||||
break;
|
||||
case "hover":
|
||||
for (BaseComponent baseComponent : component) {
|
||||
baseComponent.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new ComponentBuilder(String.valueOf(value)).create()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
builder.addAll(Arrays.asList(component));
|
||||
} else {
|
||||
builder.addAll(Arrays.asList(TextComponent.fromLegacyText(text)));
|
||||
TLib.getTLib().getLogger().warn(Strings.replaceWithOrder(TLib.getTLib().getInternalLang().getString("MISSING-ARGUMENT"), node));
|
||||
}
|
||||
if (index < template.length) {
|
||||
builder.addAll(Arrays.asList(TextComponent.fromLegacyText(template[index++])));
|
||||
}
|
||||
}
|
||||
return builder.toArray(new BaseComponent[0]);
|
||||
}).collect(Collectors.toList());
|
||||
return new TLocaleJson(collect, papi, map);
|
||||
}
|
||||
return new TLocaleJson(textList.stream().map(TextComponent::fromLegacyText).collect(Collectors.toList()), papi, map);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendTo(CommandSender sender, String... args) {
|
||||
if (sender instanceof Player)
|
||||
components.forEach(comp -> ((Player) sender).spigot().sendMessage(replace(comp, sender, args)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String asString(String... args) {
|
||||
return components.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> serialize() {
|
||||
return Maps.newHashMap(map);
|
||||
}
|
||||
|
||||
private BaseComponent[] replace(BaseComponent[] component, CommandSender sender, String... args) {
|
||||
BaseComponent[] components = new BaseComponent[component.length];
|
||||
for (int i = 0; i < components.length; i++) {
|
||||
components[i] = replace(component[i].duplicate(), sender, args);
|
||||
}
|
||||
return components;
|
||||
}
|
||||
|
||||
private List<BaseComponent> replace(List<BaseComponent> component, CommandSender sender, String... args) {
|
||||
return component.stream().map(c -> replace(c, sender, args)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private BaseComponent replace(BaseComponent component, CommandSender sender, String... args) {
|
||||
if (component.getClickEvent() != null) {
|
||||
ClickEvent clickEvent = new ClickEvent(component.getClickEvent().getAction(), replace(sender, component.getClickEvent().getValue(), args));
|
||||
component.setClickEvent(clickEvent);
|
||||
}
|
||||
if (component.getHoverEvent() != null) {
|
||||
HoverEvent hoverEvent = new HoverEvent(component.getHoverEvent().getAction(), replace(component.getHoverEvent().getValue(), sender, args));
|
||||
component.setHoverEvent(hoverEvent);
|
||||
}
|
||||
if (component.getExtra() != null)
|
||||
component.setExtra(replace(component.getExtra(), sender, args));
|
||||
if (component instanceof TextComponent) {
|
||||
((TextComponent) component).setText(replace(sender, ((TextComponent) component).getText(), args));
|
||||
}
|
||||
return component;
|
||||
}
|
||||
|
||||
private String replace(CommandSender sender, String text, String[] args) {
|
||||
String s = Strings.replaceWithOrder(text, args);
|
||||
return papi ? PlaceholderHook.replace(sender, s) : s;
|
||||
}
|
||||
}
|
@ -1,11 +1,11 @@
|
||||
package com.ilummc.tlib.resources.type;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.ilummc.tlib.TLib;
|
||||
import com.ilummc.tlib.compat.PlaceholderHook;
|
||||
import com.ilummc.tlib.resources.TLocale;
|
||||
import com.ilummc.tlib.resources.TLocaleSendable;
|
||||
import com.ilummc.tlib.util.Strings;
|
||||
import me.skymc.taboolib.Main;
|
||||
import me.skymc.taboolib.display.TitleUtils;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
@ -52,7 +52,7 @@ public class TLocaleTitle implements TLocaleSendable, ConfigurationSerializable
|
||||
(int) map.getOrDefault("fadein", 10),
|
||||
(int) map.getOrDefault("fadeout", 10),
|
||||
(int) map.getOrDefault("stay", 20),
|
||||
(boolean) map.getOrDefault("papi", TLib.getTLib().getConfig().isEnablePlaceholderHookByDefault()));
|
||||
(boolean) map.getOrDefault("papi", Main.getInst().getConfig().getBoolean("LOCALE.USE_PAPI", false)));
|
||||
} catch (Exception e) {
|
||||
title = new TLocaleTitle("§4Load failed!", "§c" + e.getMessage(), 10, 20, 10, false);
|
||||
}
|
||||
|
@ -28,10 +28,6 @@ public class AsmClassTransformer extends ClassVisitor implements Opcodes {
|
||||
this.toVer = toVer;
|
||||
}
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder().toVersion(Bukkit.getServer().getClass().getName().split("\\.")[3]);
|
||||
}
|
||||
|
||||
public Object transform() {
|
||||
try {
|
||||
ClassReader classReader = new ClassReader(from.getResourceAsStream("/" + from.getName().replace('.', '/') + ".class"));
|
||||
@ -51,10 +47,8 @@ public class AsmClassTransformer extends ClassVisitor implements Opcodes {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
|
||||
super.visit(version, access, newClassName.replace('.', '/'), replace(signature),
|
||||
prevName, replace(interfaces));
|
||||
public static Builder builder() {
|
||||
return new Builder().toVersion(Bukkit.getServer().getClass().getName().split("\\.")[3]);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -90,31 +84,10 @@ public class AsmClassTransformer extends ClassVisitor implements Opcodes {
|
||||
} else return null;
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
|
||||
private Class<?> from;
|
||||
|
||||
private String fromVersion, toVersion;
|
||||
|
||||
public Builder from(Class<?> clazz) {
|
||||
this.from = clazz;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder fromVersion(String ver) {
|
||||
fromVersion = ver;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder toVersion(String ver) {
|
||||
toVersion = ver;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AsmClassTransformer build() {
|
||||
return new AsmClassTransformer(from, fromVersion, toVersion, new ClassWriter(ClassWriter.COMPUTE_MAXS));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
|
||||
super.visit(version, access, newClassName.replace('.', '/'), replace(signature),
|
||||
replace(superName), replace(interfaces));
|
||||
}
|
||||
|
||||
private class AsmMethodTransformer extends MethodVisitor {
|
||||
@ -150,4 +123,31 @@ public class AsmClassTransformer extends ClassVisitor implements Opcodes {
|
||||
super.visitLocalVariable(name, replace(descriptor), replace(signature), start, end, index);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
|
||||
private Class<?> from;
|
||||
|
||||
private String fromVersion, toVersion;
|
||||
|
||||
public Builder from(Class<?> clazz) {
|
||||
this.from = clazz;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder fromVersion(String ver) {
|
||||
fromVersion = ver;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder toVersion(String ver) {
|
||||
toVersion = ver;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AsmClassTransformer build() {
|
||||
return new AsmClassTransformer(from, fromVersion, toVersion, new ClassWriter(ClassWriter.COMPUTE_MAXS));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,10 @@
|
||||
package me.skymc.taboolib.javashell;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.HashMap;
|
||||
|
||||
import com.ilummc.tlib.dependency.TDependencyLoader;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import me.skymc.taboolib.Main;
|
||||
import me.skymc.taboolib.message.MsgUtils;
|
||||
import org.apache.commons.lang.ArrayUtils;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.event.HandlerList;
|
||||
@ -13,11 +12,11 @@ import org.bukkit.event.Listener;
|
||||
import org.bukkit.plugin.RegisteredListener;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import me.skymc.taboolib.Main;
|
||||
import me.skymc.taboolib.javashell.utils.JarUtils;
|
||||
import me.skymc.taboolib.message.MsgUtils;
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class JavaShell {
|
||||
|
||||
@ -118,8 +117,7 @@ public class JavaShell {
|
||||
if (disableMethod != null) {
|
||||
disableMethod.invoke(clazz.newInstance());
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
} catch (Exception e) {
|
||||
//
|
||||
}
|
||||
}
|
||||
@ -137,8 +135,7 @@ public class JavaShell {
|
||||
}
|
||||
MsgUtils.send("已为脚本 &f" + shell + " &7注销监听器");
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
} catch (Exception e) {
|
||||
//
|
||||
}
|
||||
}
|
||||
@ -148,8 +145,7 @@ public class JavaShell {
|
||||
|
||||
try {
|
||||
Class.forName("com.sun.tools.javac.main.Main");
|
||||
}
|
||||
catch (Exception e) {
|
||||
} catch (Exception e) {
|
||||
MsgUtils.warn("&4JavaShell &c工具的必要依赖 &4com.sun.tools.jar &c丢失, 无法载入!");
|
||||
return false;
|
||||
}
|
||||
@ -171,7 +167,7 @@ public class JavaShell {
|
||||
if (code == 0) {
|
||||
MsgUtils.send("&f" + shell + "&7 载入成功");
|
||||
try {
|
||||
URL[] urls = { cacheFolder.toURI().toURL() };
|
||||
URL[] urls = {cacheFolder.toURI().toURL()};
|
||||
URLClassLoader sysloader = new URLClassLoader(urls, Main.class.getClassLoader());
|
||||
Class<?> clazz = sysloader.loadClass(shell);
|
||||
shells.put(shell, clazz);
|
||||
@ -182,13 +178,11 @@ public class JavaShell {
|
||||
Bukkit.getPluginManager().registerEvents((Listener) clazz.newInstance(), Main.getInst());
|
||||
MsgUtils.send("已为脚本 &f" + shell + " &7注册监听器");
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
} catch (Exception e) {
|
||||
//
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
MsgUtils.send("&4" + shell + "&c 载入失败");
|
||||
return false;
|
||||
}
|
||||
@ -197,7 +191,7 @@ public class JavaShell {
|
||||
private static void loadLibrary() {
|
||||
for (File jar : libFolder.listFiles()) {
|
||||
try {
|
||||
JarUtils.addClassPath(JarUtils.getJarUrl(jar));
|
||||
TDependencyLoader.addToPath(Main.getInst(), jar);
|
||||
MsgUtils.send("成功载入 &f" + jar.getName() + " &7到运行库");
|
||||
} catch (Exception e) {
|
||||
//
|
||||
|
@ -1,12 +1,9 @@
|
||||
package me.skymc.taboolib.javashell.utils;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import me.skymc.taboolib.message.MsgUtils;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
@ -15,10 +12,6 @@ import java.util.Enumeration;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import me.skymc.taboolib.message.MsgUtils;
|
||||
|
||||
public class JarUtils {
|
||||
|
||||
public static boolean extractFromJar(final String fileName, final String dest) throws IOException {
|
||||
@ -65,6 +58,7 @@ public class JarUtils {
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static URL getJarUrl(final File file) throws IOException {
|
||||
return new URL("jar:" + file.toURI().toURL().toExternalForm() + "!/");
|
||||
}
|
||||
@ -88,6 +82,7 @@ public class JarUtils {
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static void addClassPath(final URL url) {
|
||||
final URLClassLoader sysloader = (URLClassLoader) Bukkit.class.getClassLoader();
|
||||
final Class<URLClassLoader> sysclass = URLClassLoader.class;
|
||||
|
@ -6,3 +6,4 @@ RELOADING-LANG: '正在重新载入 {0} 插件的语言文件'
|
||||
FETCH-LOCALE-ERROR: '语言文件获取失败:{0}'
|
||||
SEND-LOCALE-ERROR: '语言文件发送失败:{0}'
|
||||
LOCALE-ERROR-REASON: '原因:{0}'
|
||||
MISSING-ARGUMENT: '语言文本含有没有找到的参数 {0}'
|
Loading…
Reference in New Issue
Block a user