diff --git a/pom.xml b/pom.xml
index 14b6dc3..07bb135 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
me.skymc
TabooLib
- 4.02
+ 4.03
UTF-8
diff --git a/src/main/java/com/ilummc/tlib/TLib.java b/src/main/java/com/ilummc/tlib/TLib.java
index a4643ee..9c64381 100644
--- a/src/main/java/com/ilummc/tlib/TLib.java
+++ b/src/main/java/com/ilummc/tlib/TLib.java
@@ -13,6 +13,7 @@ import com.ilummc.tlib.resources.TLocale;
import com.ilummc.tlib.resources.TLocaleLoader;
import com.ilummc.tlib.util.IO;
import me.skymc.taboolib.Main;
+import me.skymc.taboolib.fileutils.FileUtils;
import org.bukkit.Bukkit;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
@@ -49,7 +50,7 @@ public class TLib {
libsFolder.mkdirs();
}
try {
- String yamlText = new String(IO.readFully(TLib.class.getResourceAsStream("/lang/internal.yml")), Charset.forName("utf-8"));
+ String yamlText = new String(IO.readFully(FileUtils.getResource("lang/internal.yml")), Charset.forName("utf-8"));
internalLanguage = new YamlConfiguration();
internalLanguage.loadFromString(yamlText);
} catch (IOException | InvalidConfigurationException ignored) {
@@ -71,13 +72,14 @@ public class TLib {
TLocaleLoader.init();
PlaceholderHook.init();
TLocaleLoader.load(Main.getInst(), false);
- TDependencyInjector.inject(Main.getInst(), tLib);
+ }
+ public static void initPost() {
+ TDependencyInjector.inject(Main.getInst(), TLib.getTLib());
try {
Pool.init();
} catch (Throwable ignored) {
}
-
}
public static void unload() {
diff --git a/src/main/java/com/ilummc/tlib/dependency/TDependency.java b/src/main/java/com/ilummc/tlib/dependency/TDependency.java
index 193f115..2decabc 100644
--- a/src/main/java/com/ilummc/tlib/dependency/TDependency.java
+++ b/src/main/java/com/ilummc/tlib/dependency/TDependency.java
@@ -52,8 +52,8 @@ public class TDependency {
}
private static boolean downloadMaven(String url, String groupId, String artifactId, String version, File target, String dl) {
- if (Main.getInst().getConfig().getBoolean("OFFLINE-MODE")) {
- TLocale.Logger.warn("DEPENDENCY.OFFLINE-DEPENDENCY-WARN");
+ if (Main.isOfflineVersion()) {
+ TLocale.Logger.warn("DEPENDENCY.DOWNLOAD-OFFLINE");
return false;
}
AtomicBoolean failed = new AtomicBoolean(false);
diff --git a/src/main/java/com/ilummc/tlib/inject/TDependencyInjector.java b/src/main/java/com/ilummc/tlib/inject/TDependencyInjector.java
index def8e07..d8298a9 100644
--- a/src/main/java/com/ilummc/tlib/inject/TDependencyInjector.java
+++ b/src/main/java/com/ilummc/tlib/inject/TDependencyInjector.java
@@ -13,9 +13,23 @@ import org.bukkit.plugin.java.JavaPlugin;
import java.io.File;
import java.lang.reflect.Field;
+import java.util.HashMap;
public class TDependencyInjector {
+ public static Dependency[] getDependencies(Object o) {
+ Dependency[] dependencies = new Dependency[0];
+ Dependencies d = o.getClass().getAnnotation(Dependencies.class);
+ if (d != null) {
+ dependencies = d.value();
+ }
+ Dependency d2 = o.getClass().getAnnotation(Dependency.class);
+ if (d2 != null) {
+ dependencies = new Dependency[]{d2};
+ }
+ return dependencies;
+ }
+
public static void inject(Plugin plugin, Object o) {
TLocaleLoader.load(plugin, true);
injectDependencies(plugin, o);
@@ -135,17 +149,7 @@ public class TDependencyInjector {
}
private static void injectDependencies(Plugin plugin, Object o) {
- Dependency[] dependencies = new Dependency[0];
- {
- Dependencies d = o.getClass().getAnnotation(Dependencies.class);
- if (d != null) {
- dependencies = d.value();
- }
- Dependency d2 = o.getClass().getAnnotation(Dependency.class);
- if (d2 != null) {
- dependencies = new Dependency[]{d2};
- }
- }
+ Dependency[] dependencies = getDependencies(o);
if (dependencies.length != 0) {
TLocale.Logger.info("DEPENDENCY.LOADING-START", plugin.getName());
for (Dependency dependency : dependencies) {
@@ -167,5 +171,4 @@ public class TDependencyInjector {
TLocale.Logger.info("DEPENDENCY.LOAD-COMPLETE");
}
}
-
}
diff --git a/src/main/java/com/ilummc/tlib/resources/TLocaleLoader.java b/src/main/java/com/ilummc/tlib/resources/TLocaleLoader.java
index 31ddcad..c9f6bcb 100644
--- a/src/main/java/com/ilummc/tlib/resources/TLocaleLoader.java
+++ b/src/main/java/com/ilummc/tlib/resources/TLocaleLoader.java
@@ -10,6 +10,7 @@ import me.skymc.taboocode.TabooCodeLang;
import me.skymc.taboolib.Main;
import me.skymc.taboolib.TabooLib;
import me.skymc.taboolib.fileutils.ConfigUtils;
+import me.skymc.taboolib.fileutils.FileUtils;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.file.YamlConfiguration;
@@ -140,7 +141,7 @@ public class TLocaleLoader {
}
private static YamlConfiguration getLocaleAtStream(Plugin plugin, File localeFile) {
- InputStream localeInputSteam = plugin.getClass().getResourceAsStream("/lang/" + localeFile.getName());
+ InputStream localeInputSteam = FileUtils.getResource("lang/" + localeFile.getName());
try {
String yamlText = new String(IO.readFully(localeInputSteam), Charset.forName("utf-8"));
YamlConfiguration yaml = new YamlConfiguration();
diff --git a/src/main/java/me/skymc/taboolib/Main.java b/src/main/java/me/skymc/taboolib/Main.java
index 5eefd71..611e1d2 100644
--- a/src/main/java/me/skymc/taboolib/Main.java
+++ b/src/main/java/me/skymc/taboolib/Main.java
@@ -1,7 +1,8 @@
package me.skymc.taboolib;
import com.ilummc.tlib.TLib;
-import com.ilummc.tlib.inject.TConfigWatcher;
+import com.ilummc.tlib.annotations.Dependency;
+import com.ilummc.tlib.inject.TDependencyInjector;
import com.ilummc.tlib.resources.TLocale;
import me.skymc.taboolib.anvil.AnvilContainerAPI;
import me.skymc.taboolib.bstats.Metrics;
@@ -17,12 +18,12 @@ import me.skymc.taboolib.database.PlayerDataManager;
import me.skymc.taboolib.economy.EcoUtils;
import me.skymc.taboolib.entity.EntityUtils;
import me.skymc.taboolib.fileutils.ConfigUtils;
+import me.skymc.taboolib.fileutils.FileUtils;
import me.skymc.taboolib.inventory.ItemUtils;
import me.skymc.taboolib.inventory.speciaitem.SpecialItem;
import me.skymc.taboolib.javashell.JavaShell;
import me.skymc.taboolib.listener.*;
import me.skymc.taboolib.message.ChatCatcher;
-import me.skymc.taboolib.message.MsgUtils;
import me.skymc.taboolib.mysql.hikari.HikariHandler;
import me.skymc.taboolib.mysql.protect.MySQLConnection;
import me.skymc.taboolib.nms.item.DabItemUtils;
@@ -50,6 +51,8 @@ import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitRunnable;
import java.io.File;
+import java.io.InputStream;
+import java.net.InetAddress;
import java.util.Random;
/**
@@ -57,6 +60,14 @@ import java.util.Random;
*/
public class Main extends JavaPlugin implements Listener {
+ public Main() {
+ inst = this;
+ }
+
+ public enum StorageType {
+ LOCAL, SQL
+ }
+
private static Plugin inst;
private static net.milkbowl.vault.economy.Economy Economy;
@@ -65,7 +76,7 @@ public class Main extends JavaPlugin implements Listener {
private static File serverDataFolder;
- private static StorageType storageType;
+ private static StorageType storageType = StorageType.LOCAL;
private static boolean disable = false;
@@ -75,60 +86,10 @@ public class Main extends JavaPlugin implements Listener {
private static boolean started;
+ private static boolean isInternetOnline = false;
+
private FileConfiguration config = null;
- public static Plugin getInst() {
- return inst;
- }
-
- public static String getPrefix() {
- return "§8[§3§lTabooLib§8] §7";
- }
-
- public static net.milkbowl.vault.economy.Economy getEconomy() {
- return Economy;
- }
-
- public static void setEconomy(net.milkbowl.vault.economy.Economy economy) {
- Economy = economy;
- }
-
- public static File getPlayerDataFolder() {
- return playerDataFolder;
- }
-
- public static File getServerDataFolder() {
- return serverDataFolder;
- }
-
- public static StorageType getStorageType() {
- return storageType;
- }
-
- public static boolean isDisable() {
- return disable;
- }
-
- public static MySQLConnection getConnection() {
- return connection;
- }
-
- public static Language2 getExampleLanguage2() {
- return exampleLanguage2;
- }
-
- public static boolean isStarted() {
- return started;
- }
-
- public static Random getRandom() {
- return NumberUtils.getRandom();
- }
-
- public static String getTablePrefix() {
- return inst.getConfig().getString("MYSQL.PREFIX");
- }
-
@Override
public FileConfiguration getConfig() {
return config;
@@ -150,71 +111,31 @@ public class Main extends JavaPlugin implements Listener {
@Override
public void onLoad() {
- inst = this;
disable = false;
-
// 载入配置
saveDefaultConfig();
-
- // 加载依赖
+ // 载入牛逼玩意儿
TLib.init();
TLib.injectPluginManager();
-
- // 载入目录
+ // 网络检测
+ testInternet();
+ // 创建文件夹
setupDataFolder();
- // 注册配置
- DataUtils.addPluginData("TabooLibrary", null);
-
- // 启用数据库
- if (getConfig().getBoolean("MYSQL.ENABLE")) {
- // 连接数据库
- connection = new MySQLConnection(getConfig().getString("MYSQL.HOST"), getConfig().getString("MYSQL.USER"), getConfig().getString("MYSQL.POST"), getConfig().getString("MYSQL.PASSWORD"), getConfig().getString("MYSQL.DATABASE"), 30, this);
- // 连接成功
- if (connection.isConnection()) {
- // 创建表
- connection.createTable(getTablePrefix() + "_playerdata", "username", "configuration");
- connection.createTable(getTablePrefix() + "_plugindata", "name", "variable", "upgrade");
- connection.createTable(getTablePrefix() + "_serveruuid", "uuid", "hash");
-
- // 如果没有数据
- if (!connection.isExists(getTablePrefix() + "_serveruuid", "uuid", TabooLib.getServerUID())) {
- connection.intoValue(getTablePrefix() + "_serveruuid", TabooLib.getServerUID(), StringUtils.hashKeyForDisk(getDataFolder().getPath()));
- } else {
- String hash = connection.getValue(getTablePrefix() + "_serveruuid", "uuid", TabooLib.getServerUID(), "hash").toString();
- // 如果这个值和我的值不同
- if (!hash.equals(StringUtils.hashKeyForDisk(getDataFolder().getPath()))) {
- TLocale.Logger.error("NOTIFY.ERROR-SERVER-KEY");
- // 重新生成序列号
- TabooLib.resetServerUID();
- // 关服
- Bukkit.shutdown();
- }
- }
- } else {
- // 提示
- TLocale.Logger.error("NOTIFY.ERROR-CONNECTION-FAIL");
- // 关服
- Bukkit.shutdown();
- }
- // 储存方式
- storageType = StorageType.SQL;
- } else {
- // 储存方式
- storageType = StorageType.LOCAL;
- }
+ // 创建数据库
+ setupDatabase();
+ // 载入离线库文件
+ setupLibraries();
+ // 载入牛逼玩意儿
+ TLib.initPost();
}
@Override
public void onEnable() {
- // 注册指令
- getCommand("language2").setExecutor(new Language2Command());
- getCommand("taboolibrarymodule").setExecutor(new TLMCommands());
- getCommand("tabooliblocale").setExecutor(new TabooLibLocaleCommand());
- BaseMainCommand.createCommandExecutor("taboolib", new TabooLibMainCommand());
- BaseMainCommand.createCommandExecutor("taboolibplugin", new TabooLibPluginMainCommand());
-
+ // 注册命令
+ registerCommands();
// 注册监听
registerListener();
+
// 载入经济
EcoUtils.setupEconomy();
// 载入权限
@@ -243,6 +164,7 @@ public class Main extends JavaPlugin implements Listener {
// 文件保存
Bukkit.getScheduler().runTaskTimerAsynchronously(this, DataUtils::saveAllCaches, 20, 20 * 120);
Bukkit.getScheduler().runTaskTimerAsynchronously(this, () -> PlayerDataManager.saveAllCaches(true, false), 20, 20 * 60);
+
// 文件监控
TLib.getTLib().getConfigWatcher().addListener(new File(getDataFolder(), "config.yml"), null, obj -> {
reloadConfig();
@@ -254,9 +176,11 @@ public class Main extends JavaPlugin implements Listener {
@Override
public void run() {
+ // 载入 PlaceholderAPI 扩展
if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) {
new SupportPlaceholder(getInst(), "taboolib").hook();
}
+ // 载入 ProtocolLib 扩展
if (PacketUtils.isProtocolLibEnabled()) {
TagAPI.inst();
}
@@ -328,12 +252,29 @@ public class Main extends JavaPlugin implements Listener {
connection.closeConnection();
}
+ // 卸载牛逼玩意儿
TLib.unload();
// 关闭服务器
Bukkit.shutdown();
}
+ private void testInternet() {
+ try {
+ InetAddress inetAddress = InetAddress.getByName(getConfig().getString("TEST-URL", "aliyun.com"));
+ isInternetOnline = inetAddress.isReachable(10000);
+ } catch (Exception ignored) {
+ }
+ if (!isInternetOnline() && !isOfflineVersion() && !isLibrariesExists()) {
+ TLocale.Logger.error("TLIB.LOAD-FAIL-OFFLINE", getDescription().getVersion());
+ // 死锁
+ try {
+ Thread.sleep(Long.MAX_VALUE);
+ } catch (Exception ignored) {
+ }
+ }
+ }
+
private void setupDataFolder() {
playerDataFolder = new File(getConfig().getString("DATAURL.PLAYER-DATA"));
if (!playerDataFolder.exists()) {
@@ -345,6 +286,56 @@ public class Main extends JavaPlugin implements Listener {
}
}
+ private void setupLibraries() {
+ if (!isOfflineVersion()) {
+ return;
+ }
+ for (Dependency dependency : TDependencyInjector.getDependencies(TLib.getTLib())) {
+ if (dependency.type() == Dependency.Type.LIBRARY && dependency.maven().matches(".*:.*:.*")) {
+ String fileName = String.join("-", dependency.maven().split(":")) + ".jar";
+ File targetFile = FileUtils.file(TLib.getTLib().getLibsFolder(), fileName);
+ InputStream inputStream = FileUtils.getResource("libs/" + fileName);
+ if (!targetFile.exists() && inputStream != null) {
+ FileUtils.inputStreamToFile(inputStream, FileUtils.file(TLib.getTLib().getLibsFolder(), fileName));
+ }
+ }
+ }
+ }
+
+ private void setupDatabase() {
+ DataUtils.addPluginData("TabooLibrary", null);
+ if (getConfig().getBoolean("MYSQL.ENABLE")) {
+ connection = new MySQLConnection(getConfig().getString("MYSQL.HOST"), getConfig().getString("MYSQL.USER"), getConfig().getString("MYSQL.POST"), getConfig().getString("MYSQL.PASSWORD"), getConfig().getString("MYSQL.DATABASE"), 30, this);
+ if (connection.isConnection()) {
+ connection.createTable(getTablePrefix() + "_playerdata", "username", "configuration");
+ connection.createTable(getTablePrefix() + "_plugindata", "name", "variable", "upgrade");
+ connection.createTable(getTablePrefix() + "_serveruuid", "uuid", "hash");
+ if (!connection.isExists(getTablePrefix() + "_serveruuid", "uuid", TabooLib.getServerUID())) {
+ connection.intoValue(getTablePrefix() + "_serveruuid", TabooLib.getServerUID(), StringUtils.hashKeyForDisk(getDataFolder().getPath()));
+ } else {
+ String hash = connection.getValue(getTablePrefix() + "_serveruuid", "uuid", TabooLib.getServerUID(), "hash").toString();
+ if (!hash.equals(StringUtils.hashKeyForDisk(getDataFolder().getPath()))) {
+ TLocale.Logger.error("NOTIFY.ERROR-SERVER-KEY");
+ TabooLib.resetServerUID();
+ Bukkit.shutdown();
+ }
+ }
+ } else {
+ TLocale.Logger.error("NOTIFY.ERROR-CONNECTION-FAIL");
+ Bukkit.shutdown();
+ }
+ storageType = StorageType.SQL;
+ }
+ }
+
+ private void registerCommands() {
+ getCommand("language2").setExecutor(new Language2Command());
+ getCommand("taboolibrarymodule").setExecutor(new TLMCommands());
+ getCommand("tabooliblocale").setExecutor(new TabooLibLocaleCommand());
+ BaseMainCommand.createCommandExecutor("taboolib", new TabooLibMainCommand());
+ BaseMainCommand.createCommandExecutor("taboolibplugin", new TabooLibPluginMainCommand());
+ }
+
private void registerListener() {
getServer().getPluginManager().registerEvents(this, this);
getServer().getPluginManager().registerEvents(new ListenerPlayerCommand(), this);
@@ -368,7 +359,73 @@ public class Main extends JavaPlugin implements Listener {
}
}
- public enum StorageType {
- LOCAL, SQL
+ // *********************************
+ //
+ // Getter and Setter
+ //
+ // *********************************
+
+ public static Plugin getInst() {
+ return inst;
+ }
+
+ public static String getPrefix() {
+ return "§8[§3§lTabooLib§8] §7";
+ }
+
+ public static net.milkbowl.vault.economy.Economy getEconomy() {
+ return Economy;
+ }
+
+ public static void setEconomy(net.milkbowl.vault.economy.Economy economy) {
+ Economy = economy;
+ }
+
+ public static File getPlayerDataFolder() {
+ return playerDataFolder;
+ }
+
+ public static File getServerDataFolder() {
+ return serverDataFolder;
+ }
+
+ public static StorageType getStorageType() {
+ return storageType;
+ }
+
+ public static boolean isDisable() {
+ return disable;
+ }
+
+ public static MySQLConnection getConnection() {
+ return connection;
+ }
+
+ public static Language2 getExampleLanguage2() {
+ return exampleLanguage2;
+ }
+
+ public static boolean isStarted() {
+ return started;
+ }
+
+ public static Random getRandom() {
+ return NumberUtils.getRandom();
+ }
+
+ public static String getTablePrefix() {
+ return inst.getConfig().getString("MYSQL.PREFIX");
+ }
+
+ public static boolean isInternetOnline() {
+ return isInternetOnline;
+ }
+
+ public static boolean isOfflineVersion() {
+ return inst.getResource("libs") != null;
+ }
+
+ public static boolean isLibrariesExists() {
+ return TLib.getTLib().getLibsFolder().listFiles().length > 0;
}
}
diff --git a/src/main/java/me/skymc/taboolib/TabooLib.java b/src/main/java/me/skymc/taboolib/TabooLib.java
index beceeff..1e3c84c 100644
--- a/src/main/java/me/skymc/taboolib/TabooLib.java
+++ b/src/main/java/me/skymc/taboolib/TabooLib.java
@@ -1,5 +1,6 @@
package me.skymc.taboolib;
+import me.skymc.taboolib.other.NumberUtils;
import me.skymc.taboolib.playerdata.DataUtils;
import net.md_5.bungee.api.ChatColor;
import org.bukkit.Bukkit;
@@ -37,11 +38,7 @@ public class TabooLib {
}
public static double getPluginVersion() {
- try {
- return Double.valueOf(Main.getInst().getDescription().getVersion());
- } catch (Exception e) {
- return 0D;
- }
+ return NumberUtils.getDouble(Main.getInst().getDescription().getVersion());
}
public static String getVersion() {
diff --git a/src/main/java/me/skymc/taboolib/fileutils/FileUtils.java b/src/main/java/me/skymc/taboolib/fileutils/FileUtils.java
index 19d2587..a3040e4 100644
--- a/src/main/java/me/skymc/taboolib/fileutils/FileUtils.java
+++ b/src/main/java/me/skymc/taboolib/fileutils/FileUtils.java
@@ -1,6 +1,8 @@
package me.skymc.taboolib.fileutils;
import ch.njol.util.Closeable;
+import com.ilummc.tlib.util.IO;
+import me.skymc.taboolib.Main;
import org.apache.commons.io.IOUtils;
import java.io.*;
@@ -8,7 +10,9 @@ import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.nio.channels.FileChannel;
+import java.nio.charset.Charset;
import java.util.Objects;
+import java.util.logging.Level;
public class FileUtils {
@@ -43,6 +47,31 @@ public class FileUtils {
}
}
+ public static InputStream getResource(String filename) {
+ try {
+ URL url = Main.class.getClassLoader().getResource(filename);
+ if (url == null) {
+ return null;
+ } else {
+ URLConnection connection = url.openConnection();
+ connection.setUseCaches(false);
+ return connection.getInputStream();
+ }
+ } catch (IOException ignored) {
+ return null;
+ }
+ }
+
+ public static void inputStreamToFile(InputStream inputStream, File file) {
+ try {
+ String text = new String(IO.readFully(inputStream), Charset.forName("utf-8"));
+ FileWriter fileWriter = new FileWriter(FileUtils.createNewFile(file));
+ fileWriter.write(text);
+ fileWriter.close();
+ } catch (IOException ignored) {
+ }
+ }
+
/**
* 检测文件并创建
*
diff --git a/src/main/java/me/skymc/taboolib/mysql/builder/SQLColumn.java b/src/main/java/me/skymc/taboolib/mysql/builder/SQLColumn.java
index cf5da50..c209065 100644
--- a/src/main/java/me/skymc/taboolib/mysql/builder/SQLColumn.java
+++ b/src/main/java/me/skymc/taboolib/mysql/builder/SQLColumn.java
@@ -10,11 +10,6 @@ import java.util.Arrays;
*/
public class SQLColumn {
- public static void main(String[] args) {
- SQLColumn column2 = new SQLColumn(SQLColumnType.INT, "player_title", "无");
- System.out.println(column2.convertToCommand());
- }
-
/**
* 类型
*/
diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml
index 93de0ee..91a40b6 100644
--- a/src/main/resources/config.yml
+++ b/src/main/resources/config.yml
@@ -17,9 +17,8 @@ DATAURL:
# 启用后将收到来自其他插件的调试信息
DEBUG: false
-# 是否启用离线模式
-# 离线模式下将不会下载依赖
-OFFLINE-MODE: false
+# 网络连接测试地址
+TEST-URL: 'aliyun.com'
# 下载依赖时启用的线程数
DOWNLOAD-POOL-SIZE: 4
diff --git a/src/main/resources/lang/zh_CN.yml b/src/main/resources/lang/zh_CN.yml
index a236c96..87c8819 100644
--- a/src/main/resources/lang/zh_CN.yml
+++ b/src/main/resources/lang/zh_CN.yml
@@ -1,9 +1,18 @@
TLIB:
INJECTION-SUCCESS: '注入成功'
INJECTION-FAILED: '注入失败'
+ LOAD-FAIL-OFFLINE:
+ - '**********************************************'
+ - '** TabooLib-{0} 无法在您的服务器上使用'
+ - '**'
+ - '** 您的服务器尚未连接互联网导致本插件无法正常载入'
+ - '** 请使用离线版本或是手动下载依赖库文件'
+ - '**'
+ - '** 详情查阅: https://github.com/Bkm016/TabooLib'
+ - '**********************************************'
DEPENDENCY:
- OFFLINE-DEPENDENCY-WARN: '已启用离线模式, 将不会下载第三方依赖库'
+ DOWNLOAD-OFFLINE: '已启用离线模式, 将不会下载第三方依赖库'
DOWNLOAD-CONNECTED: ' 正在下载 {0} 大小 {1}'
DOWNLOAD-PROGRESS: ' 下载速度 {0} 进度 {1}'
DOWNLOAD-SUCCESS: ' 下载 {0} 完成'