更换至 Gradle

This commit is contained in:
IzzelAliz
2019-03-02 15:48:21 +08:00
parent b3233e4049
commit 57ac4e072c
311 changed files with 332 additions and 930 deletions

View File

@@ -0,0 +1,4 @@
package com.ilummc.eagletdl;
public class AlreadyStartException extends RuntimeException {
}

View File

@@ -0,0 +1,19 @@
package com.ilummc.eagletdl;
public class CompleteEvent {
private EagletTask task;
private boolean success;
CompleteEvent(EagletTask task, boolean success) {
this.task = task;
this.success = success;
}
public boolean isSuccess() {
return success;
}
public EagletTask getTask() {
return task;
}
}

View File

@@ -0,0 +1,27 @@
package com.ilummc.eagletdl;
public class ConnectedEvent {
private long contentLength;
private EagletTask task;
public ConnectedEvent(long length, EagletTask task) {
this.contentLength = length;
this.task = task;
}
/**
* Get the length of the download task.
* <p>
* If the length is -1, this task cannot be downloaded in multiple threads.
*
* @return length
*/
public long getContentLength() {
return contentLength;
}
public EagletTask getTask() {
return task;
}
}

View File

@@ -0,0 +1,4 @@
package com.ilummc.eagletdl;
public class DoNotSupportMultipleThreadException extends RuntimeException {
}

View File

@@ -0,0 +1,8 @@
package com.ilummc.eagletdl;
@FunctionalInterface
public interface EagletHandler<T> {
void handle(T event) ;
}

View File

@@ -0,0 +1,477 @@
package com.ilummc.eagletdl;
import java.io.File;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.Proxy;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
public class EagletTask {
private ReentrantLock lock = new ReentrantLock();
Map<String, String> httpHeader = new ConcurrentHashMap<>();
private URL url;
EagletHandler<ErrorEvent> onError = event -> event.getException().printStackTrace();
private EagletHandler<StartEvent> onStart;
private EagletHandler<CompleteEvent> onComplete;
private EagletHandler<ConnectedEvent> onConnected;
private EagletHandler<ProgressEvent> onProgress;
private Proxy proxy;
private String md5, sha1, sha256;
String requestMethod = "GET";
private int threadAmount = 1;
int connectionTimeout = 7000;
int readTimeout = 7000;
int maxRetry = 5;
private File dest;
private transient boolean running = false;
private transient long contentLength, maxBlockingTime = 7000;
private transient ExecutorService executorService;
private transient Thread monitor;
public EagletTask() {
}
/**
* Stop this task forcefully, and the target file will not be removed.
*/
public void stop() {
executorService.shutdownNow();
monitor.interrupt();
}
/**
* Start the download file
* <p>
* 开始下载文件
*/
public EagletTask start() {
// create thread pool for download
executorService = Executors.newFixedThreadPool(threadAmount);
// check if is already running
if (running) {
throw new AlreadyStartException();
}
// start the monitor thread
monitor = new Thread(() -> {
lock.lock();
// fire a new start event
if (onStart != null) {
onStart.handle(new StartEvent(this));
}
try {
// create the target file
if (!dest.exists()) {
dest.createNewFile();
}
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// set the connection properties
httpHeader.forEach(connection::addRequestProperty);
connection.setRequestMethod(requestMethod);
connection.setConnectTimeout(30000);
connection.setReadTimeout(30000);
connection.connect();
contentLength = connection.getContentLengthLong();
// fire a new connected event
// contains connection properties
if (onConnected != null) {
onConnected.handle(new ConnectedEvent(contentLength, this));
}
// if this is an unknown length task
if (contentLength == -1 || threadAmount == 1) {
// pass the connection instance to this new thread
SingleThreadDownload download = new SingleThreadDownload(connection, dest, this);
executorService.execute(download);
long last = 0;
do {
Thread.sleep(500);
// check the progress
long progress = download.getCurrentProgress();
// fire a new progress event
if (onProgress != null) {
onProgress.handle(new ProgressEvent(progress - last < 0 ? 0 : progress - last, this, ((double) progress) / Math.max((double) contentLength, 0D)));
}
last = progress;
// check complete
} while (last != contentLength && !download.isComplete());
// close the thread pool, DoNotSupportMultipleThreadExceptionrelease resources
executorService.shutdown();
// change the running flag to false
running = false;
} else {
List<SplitDownload> splitDownloads = new ArrayList<>();
// Assign download task length
long blockSize = contentLength / threadAmount;
for (int threadId = 0; threadId < threadAmount; threadId++) {
long startIndex = threadId * blockSize;
long endIndex = (threadId + 1) * blockSize - 1;
if (threadId == (threadAmount - 1)) {
endIndex = contentLength - 1;
}
SplitDownload download = new SplitDownload(url, startIndex, endIndex, dest, this);
// Start downloading
executorService.execute(download);
splitDownloads.add(download);
}
long last = 0;
do {
Thread.sleep(500);
long progress = 0;
// Collect download progress
for (SplitDownload splitDownload : splitDownloads) {
progress += splitDownload.getCurrentIndex() - splitDownload.startIndex;
// blocked then restart from current index
if (!splitDownload.isComplete() && System.currentTimeMillis() - splitDownload.getLastUpdateTime() > maxBlockingTime) {
splitDownload.setStartIndex(splitDownload.getCurrentIndex());
if (splitDownload.getRetry() <= maxRetry) {
executorService.execute(splitDownload);
} else {
throw new RetryFailedException(this);
}
}
}
// Fire a progress event
if (onProgress != null) {
onProgress.handle(new ProgressEvent(progress - last, this,
((double) progress) / ((double) contentLength)));
}
last = progress;
// check complete
} while (last < contentLength);
// close the thread pool, release resources
executorService.shutdown();
// change the running flag to false
running = false;
}
// check hash
if (md5 != null && !md5.equalsIgnoreCase(HashUtil.md5(dest))) {
throw new HashNotMatchException();
}
if (sha1 != null && !sha1.equalsIgnoreCase(HashUtil.sha1(dest))) {
throw new HashNotMatchException();
}
if (sha256 != null && !sha256.equalsIgnoreCase(HashUtil.sha256(dest))) {
throw new HashNotMatchException();
}
if (onComplete != null) {
onComplete.handle(new CompleteEvent(this, true));
}
} catch (Exception e) {
onError.handle(new ErrorEvent(e, this));
executorService.shutdown();
if (onComplete != null) {
onComplete.handle(new CompleteEvent(this, false));
}
} finally {
lock.unlock();
}
}, "EagletTaskMonitor");
monitor.start();
return this;
}
public EagletTask waitUntil() {
while (lock.tryLock()) {
lock.unlock();
}
lock.lock();
lock.unlock();
return this;
}
public EagletTask waitFor(long timeout, TimeUnit unit) {
while (lock.tryLock()) {
lock.unlock();
}
try {
lock.tryLock(timeout, unit);
} catch (InterruptedException e) {
e.printStackTrace();
}
return this;
}
public EagletTask maxRetry(int maxRetry) {
this.maxRetry = maxRetry;
return this;
}
/**
* Set the sha256 hash of the download file. Case is not sensitive.
* <p>
* If the hash check failed, an error event will be fired.
*
* @param sha256 file sha1
* @return task instance
*/
public EagletTask sha256(String sha256) {
this.sha256 = sha256;
return this;
}
/**
* Set the sha1 hash of the download file. Case is not sensitive.
* <p>
* If the hash check failed, an error event will be fired.
*
* @param sha1 file sha1
* @return task instance
*/
public EagletTask sha1(String sha1) {
this.sha1 = sha1;
return this;
}
/**
* Set the md5 hash of the download file. Case is not sensitive.
* <p>
* If the hash check failed, an error event will be fired.
*
* @param md5 file md5
* @return task instance
*/
public EagletTask md5(String md5) {
this.md5 = md5;
return this;
}
/**
* Set the max blocked time per download thread.
* <p>
* If the thread blocks exceeded the provided time, this thread will re-start the task.
*
* @param maxBlockingTime time
* @return task instance
*/
private EagletTask maxBlocking(long maxBlockingTime) {
this.maxBlockingTime = maxBlockingTime;
return this;
}
/**
* Set the progress handler
* <p>
* This handler will be called every 1000 milli seconds.
* <p>
* 设置处理进度的时间监听器。该监听器的 handle 方法每秒调用一次。
*
* @param onProgress handler
* @return task instance
*/
public EagletTask setOnProgress(EagletHandler<ProgressEvent> onProgress) {
this.onProgress = onProgress;
return this;
}
/**
* Set the download file
*
* @param file the file's absolute path
* @return task instance
*/
public EagletTask file(String file) {
this.dest = new File(file);
return this;
}
/**
* Set the download file
*
* @param file the file
* @return task instance
*/
public EagletTask file(File file) {
this.dest = file;
return this;
}
/**
* Set the connected handler
* <p>
* This will be called when the connection is established
* <p>
* Async call
*
* @param onConnected onConnected event handler
* @return task instance
*/
public EagletTask setOnConnected(EagletHandler<ConnectedEvent> onConnected) {
this.onConnected = onConnected;
return this;
}
/**
* Set the read timeout, default is 7000
*
* @param timeout timeout
* @return task instance
*/
public EagletTask readTimeout(int timeout) {
this.readTimeout = timeout;
return this;
}
/**
* Set the connection timeout, default is 7000
*
* @param timeout timeout
* @return task instance
*/
public EagletTask connectionTimeout(int timeout) {
this.connectionTimeout = timeout;
return this;
}
/**
* Set the request method, default is <code>GET</code>
*
* @param requestMethod the request method
* @return task instance
*/
public EagletTask requestMethod(String requestMethod) {
this.requestMethod = requestMethod;
return this;
}
/**
* Set the complete event handler
* <p>
* This handler will be called when everything is complete, and the downloaded file is available
* <p>
* Async call
*
* @param onComplete the handler
* @return task instance
*/
public EagletTask setOnComplete(EagletHandler<CompleteEvent> onComplete) {
this.onComplete = onComplete;
return this;
}
/**
* Set the start handler
* <p>
* This handler will be called when the <code>start</code> method is called
* <p>
* Async call
*
* @param onStart the handler
* @return task instance
*/
public EagletTask setOnStart(EagletHandler<StartEvent> onStart) {
this.onStart = onStart;
return this;
}
/**
* Set the network proxy
*
* @param proxy the proxy
* @return task instance
*/
public EagletTask proxy(Proxy proxy) {
this.proxy = proxy;
return this;
}
/**
* Set the error handler, default is to print the stack trace
* <p>
* This handler will be called when an exception is thrown
* <p>
* Async call
*
* @param onError the handler
* @return task instance
*/
public EagletTask setOnError(EagletHandler<ErrorEvent> onError) {
this.onError = onError;
return this;
}
/**
* Set how much thread should be used to download, default is 1
*
* @param i thread amount
* @return task instance
*/
public EagletTask setThreads(int i) {
if (i < 1) {
throw new RuntimeException("Thread amount cannot be zero or negative!");
}
threadAmount = i;
return this;
}
/**
* Set the download source
*
* @param url the url
* @return task instance
*/
public EagletTask url(URL url) {
this.url = url;
return this;
}
/**
* Set the download source
*
* @param url the url
* @return task instance
*/
public EagletTask url(String url) {
try {
this.url = new URL(url);
} catch (MalformedURLException e) {
onError.handle(new ErrorEvent(e, this));
}
return this;
}
/**
* Clear the http header field
*
* @return task instance
*/
public EagletTask clearHeaders() {
httpHeader.clear();
return this;
}
/**
* Set the header field of the http request
*
* @param key header key
* @param value header value
* @return builder instance
*/
public EagletTask header(String key, String value) {
httpHeader.put(key, value);
return this;
}
}

View File

@@ -0,0 +1,20 @@
package com.ilummc.eagletdl;
public class ErrorEvent {
private Throwable e;
private EagletTask task;
public ErrorEvent(Throwable e, EagletTask task) {
this.e = e;
this.task = task;
}
public EagletTask getTask() {
return task;
}
public Throwable getException() {
return e;
}
}

View File

@@ -0,0 +1,4 @@
package com.ilummc.eagletdl;
public class HashNotMatchException extends RuntimeException {
}

View File

@@ -0,0 +1,63 @@
package com.ilummc.eagletdl;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class HashUtil {
public static String sha256(File file) {
try {
FileInputStream fis = new FileInputStream(file);
MessageDigest md = MessageDigest.getInstance("SHA256");
byte[] buffer = new byte[1024];
int length = -1;
while ((length = fis.read(buffer, 0, 1024)) != -1) {
md.update(buffer, 0, length);
}
BigInteger bigInt = new BigInteger(1, md.digest());
return bigInt.toString(16);
} catch (NoSuchAlgorithmException | IOException e) {
e.printStackTrace();
}
return null;
}
public static String sha1(File file) {
try {
FileInputStream fis = new FileInputStream(file);
MessageDigest md = MessageDigest.getInstance("SHA1");
byte[] buffer = new byte[1024];
int length = -1;
while ((length = fis.read(buffer, 0, 1024)) != -1) {
md.update(buffer, 0, length);
}
BigInteger bigInt = new BigInteger(1, md.digest());
return bigInt.toString(16);
} catch (NoSuchAlgorithmException | IOException e) {
e.printStackTrace();
}
return null;
}
public static String md5(File file) {
try {
FileInputStream fis = new FileInputStream(file);
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] buffer = new byte[1024];
int length = -1;
while ((length = fis.read(buffer, 0, 1024)) != -1) {
md.update(buffer, 0, length);
}
BigInteger bigInt = new BigInteger(1, md.digest());
return bigInt.toString(16);
} catch (NoSuchAlgorithmException | IOException e) {
e.printStackTrace();
}
return null;
}
}

View File

@@ -0,0 +1,53 @@
package com.ilummc.eagletdl;
import java.text.DecimalFormat;
public class ProgressEvent {
private long speed;
private EagletTask task;
private double percentage;
ProgressEvent(long speed, EagletTask task, double percentage) {
this.speed = speed;
this.task = task;
this.percentage = percentage;
}
public EagletTask getTask() {
return task;
}
public long getSpeed() {
return speed;
}
public double getPercentage() {
return percentage;
}
public String getPercentageFormatted() {
return formatDouble(percentage * 100D) + " %";
}
/**
* Get the speed with format like <code>X.00 MiB</code>, <code>Y.50 GiB</code>, etc.
*
* @return formatted speed string
*/
public String getSpeedFormatted() {
return format(getSpeed());
}
private static String formatDouble(double d) {
return new DecimalFormat("0.00").format(d);
}
public static String format(long l) {
if (l < 1024) return l + " B";
if (l < 1024 * 1024) return formatDouble((double) l / 1024D) + " KiB";
if (l < 1024 * 1024 * 1024) return formatDouble((double) l / (1024D * 1024D)) + " MiB";
if (l < 1024 * 1024 * 1024 * 1024L) return formatDouble((double) l / (1024D * 1024D * 1024)) + " GiB";
return "";
}
}

View File

@@ -0,0 +1,14 @@
package com.ilummc.eagletdl;
public class RetryFailedException extends RuntimeException {
private EagletTask task;
RetryFailedException(EagletTask task) {
this.task = task;
}
public EagletTask getTask() {
return task;
}
}

View File

@@ -0,0 +1,49 @@
package com.ilummc.eagletdl;
import java.io.*;
import java.net.HttpURLConnection;
class SingleThreadDownload implements Runnable {
private HttpURLConnection connection;
private File target;
private EagletTask task;
private transient long currentProgress = 0, lastUpdateTime = System.currentTimeMillis();
private transient boolean complete = false;
SingleThreadDownload(HttpURLConnection connection, File target, EagletTask task) {
this.connection = connection;
this.target = target;
this.task = task;
}
long getLastUpdateTime() {
return lastUpdateTime;
}
long getCurrentProgress() {
return currentProgress;
}
public boolean isComplete() {
return complete;
}
@Override
public void run() {
byte[] buf = new byte[1024];
int len = 0;
try (BufferedInputStream stream = new BufferedInputStream(connection.getInputStream()); BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream(target))) {
while ((len = stream.read(buf)) > 0) {
outputStream.write(buf, 0, len);
currentProgress += len;
lastUpdateTime = System.currentTimeMillis();
}
} catch (IOException e) {
task.onError.handle(new ErrorEvent(e, task));
}
complete = true;
}
}

View File

@@ -0,0 +1,92 @@
package com.ilummc.eagletdl;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
class SplitDownload implements Runnable {
private URL url;
long startIndex, endIndex;
private File target;
private EagletTask task;
private transient long currentIndex, lastUpdateTime = System.currentTimeMillis(), tmpStart;
private transient int retry = 0;
private transient boolean complete;
SplitDownload(URL url, long startIndex, long endIndex, File dest, EagletTask task) {
this.url = url;
tmpStart = this.startIndex = this.currentIndex = startIndex;
this.endIndex = endIndex;
target = dest;
this.task = task;
}
void setStartIndex(long index) {
this.tmpStart = index;
}
long getLastUpdateTime() {
return lastUpdateTime;
}
long getCurrentIndex() {
return currentIndex;
}
int getRetry() {
return retry;
}
boolean isComplete() {
return complete || currentIndex == endIndex + 1;
}
@Override
public void run() {
try {
complete = false;
currentIndex = tmpStart;
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// set the connection properties
task.httpHeader.forEach(connection::addRequestProperty);
connection.setRequestMethod(task.requestMethod);
connection.setConnectTimeout(task.connectionTimeout);
connection.setReadTimeout(task.readTimeout);
// set the download range
connection.setRequestProperty("Range", "bytes=" + tmpStart + "-" + endIndex);
connection.connect();
// if response code not equals 206, it means that the server do not support multi thread downloading
if (connection.getResponseCode() == 206) {
RandomAccessFile file = new RandomAccessFile(target, "rwd");
file.seek(tmpStart);
byte[] buf = new byte[1024];
int len;
try (BufferedInputStream stream = new BufferedInputStream(connection.getInputStream())) {
while ((len = stream.read(buf)) > 0) {
file.write(buf, 0, len);
lastUpdateTime = System.currentTimeMillis();
currentIndex += len;
// some mysterious error occurred while downloading
if (currentIndex >= endIndex + 2) {
currentIndex = tmpStart;
lastUpdateTime = 0;
retry++;
return;
}
}
complete = true;
}
file.close();
} else {
throw new DoNotSupportMultipleThreadException();
}
} catch (Exception e) {
task.onError.handle(new ErrorEvent(e, task));
retry++;
}
}
}

View File

@@ -0,0 +1,14 @@
package com.ilummc.eagletdl;
public class StartEvent {
private EagletTask task;
StartEvent(EagletTask task) {
this.task = task;
}
public EagletTask getTask() {
return task;
}
}

View File

@@ -0,0 +1,114 @@
package com.ilummc.tlib;
import com.ilummc.tlib.annotations.TConfig;
import com.ilummc.tlib.bean.Property;
import org.bukkit.Bukkit;
import org.bukkit.plugin.java.JavaPlugin;
import java.lang.management.GarbageCollectorMXBean;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.util.concurrent.TimeUnit;
@TConfig(name = "cfg.yml", charset = "GBK")
public class ExampleMain extends JavaPlugin {
private Property<Boolean> update = Property.of(false);
public static void main(String[] args) {
MemoryMXBean bean = ManagementFactory.getMemoryMXBean();
System.out.println(bean.getHeapMemoryUsage().toString());
System.out.println(bean.getNonHeapMemoryUsage().toString());
for (int i = 0; i < 10; i++) {
for (GarbageCollectorMXBean mxBean : ManagementFactory.getGarbageCollectorMXBeans()) {
System.out.println(mxBean.getName());
System.out.println(mxBean.getCollectionCount());
System.out.println(mxBean.getCollectionTime());
for (String s : mxBean.getMemoryPoolNames()) {
System.out.println(s);
}
System.out.println(mxBean.getObjectName().toString());
}
System.gc();
}
for (String s : ManagementFactory.getRuntimeMXBean().getInputArguments()) {
System.out.println(s);
}
}
@Override
public void onEnable() {
update.addListener(((oldVal, newVal) -> {
Bukkit.getLogger().info("配置项 enableUpdate 的值由 " + oldVal + " 变为了 " + newVal);
if (newVal) {
Updater.start();
} else {
Updater.stop();
}
}));
}
private static class Updater {
public static void start() {
}
public static void stop() {
}
}
private static class CD {
final long start, period;
final TimeUnit unit;
final Runnable onStart, onFinish, onTimer;
CD(long start, long period, TimeUnit unit, Runnable onStart, Runnable onFinish, Runnable onTimer) {
this.start = start;
this.period = period;
this.unit = unit;
this.onStart = onStart;
this.onFinish = onFinish;
this.onTimer = onTimer;
}
public static void main(String[] args) {
CD.builder().setOnStart(() -> {
}).setOnFinish(() -> {
}).setOnTimer(1000, TimeUnit.MILLISECONDS, () -> {
}).build();
}
public static CdBuilder builder() {
return new CdBuilder();
}
private static class CdBuilder {
private long start, period;
private TimeUnit unit;
private Runnable onStart, onFinish, onTimer;
public CdBuilder setOnStart(Runnable runnable) {
this.onStart = runnable;
return this;
}
public CdBuilder setOnFinish(Runnable runnable) {
this.onFinish = runnable;
return this;
}
public CdBuilder setOnTimer(long period, TimeUnit timeUnit, Runnable runnable) {
this.period = period;
this.unit = timeUnit;
this.onTimer = runnable;
return this;
}
public CD build() {
return new CD(start, period, unit, onStart, onFinish, onTimer);
}
}
}
}

View File

@@ -0,0 +1,137 @@
package com.ilummc.tlib;
import com.ilummc.tlib.annotations.Dependency;
import com.ilummc.tlib.compat.PlaceholderHook;
import com.ilummc.tlib.config.TLibConfig;
import com.ilummc.tlib.db.Pool;
import com.ilummc.tlib.inject.TConfigWatcher;
import com.ilummc.tlib.inject.TDependencyInjector;
import com.ilummc.tlib.inject.TPluginManager;
import com.ilummc.tlib.logger.TLogger;
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.TabooLib;
import me.skymc.taboolib.fileutils.FileUtils;
import me.skymc.taboolib.plugin.PluginUtils;
import org.bukkit.Bukkit;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.nio.charset.Charset;
import java.util.Arrays;
@Dependency(type = Dependency.Type.LIBRARY, maven = "com.zaxxer:HikariCP:3.1.0")
@Dependency(type = Dependency.Type.LIBRARY, maven = "org.slf4j:slf4j-api:1.7.25")
@Dependency(type = Dependency.Type.LIBRARY, maven = "org.javalite:activejdbc:2.0")
@Dependency(type = Dependency.Type.LIBRARY, maven = "org.javalite:javalite-common:2.0")
@Dependency(type = Dependency.Type.LIBRARY, maven = "org.javalite:app-config:2.0")
@Dependency(type = Dependency.Type.LIBRARY, maven = "org.codehaus.jackson:jackson-mapper-asl:1.9.13")
@Dependency(type = Dependency.Type.LIBRARY, maven = "org.codehaus.jackson:jackson-core-asl:1.9.13")
@Dependency(type = Dependency.Type.LIBRARY, maven = "jaxen:jaxen:1.1.6")
@Dependency(type = Dependency.Type.LIBRARY, maven = "dom4j:dom4j:1.6.1")
@Dependency(type = Dependency.Type.LIBRARY, maven = "xml-apis:xml-apis:1.0.b2")
@Dependency(type = Dependency.Type.LIBRARY, maven = "org.ehcache:ehcache:3.5.2")
@Dependency(type = Dependency.Type.LIBRARY, maven = "com.h2database:h2:1.4.197")
public class TLib {
private static TLib tLib;
private static YamlConfiguration internalLanguage;
private TLogger logger = new TLogger("§8[§3§lTabooLib§8][§r{1}§8] §f{2}", Main.getInst(), TLogger.FINE);
private TLibConfig config;
private TConfigWatcher configWatcher = new TConfigWatcher();
private File libsFolder;
private TLib() {
libsFolder = new File(Main.getInst().getDataFolder(), "/libs");
if (!libsFolder.exists()) {
libsFolder.mkdirs();
}
try {
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) {
}
}
public static void init() {
tLib = new TLib();
TLocaleLoader.init();
PlaceholderHook.init();
TLocaleLoader.load(Main.getInst(), false);
}
public static void initPost() {
TDependencyInjector.inject(Main.getInst(), TLib.getTLib());
try {
Pool.init();
} catch (Throwable ignored) {
}
}
public static void unload() {
try {
Pool.unload();
} catch (Throwable ignored) {
}
tLib.getConfigWatcher().unregisterAll();
TDependencyInjector.eject(Main.getInst(), tLib);
}
public static void injectPluginManager() {
if (!tLib.isInjectEnabled() || tLib.isBlackListPluginExists()) {
TLocale.Logger.fatal("TLIB.INJECTION-DISABLED");
Arrays.stream(Bukkit.getPluginManager().getPlugins()).filter(plugin -> plugin != Main.getInst()).forEach(plugin -> TDependencyInjector.inject(plugin, plugin));
return;
}
try {
Field field = Bukkit.getServer().getClass().getDeclaredField("pluginManager");
field.setAccessible(true);
field.set(Bukkit.getServer(), new TPluginManager());
TLocale.Logger.info("TLIB.INJECTION-SUCCESS");
} catch (NoSuchFieldException | IllegalAccessException | IllegalArgumentException ignored) {
TLocale.Logger.error("TLIB.INJECTION-FAILED");
Arrays.stream(Bukkit.getPluginManager().getPlugins()).filter(plugin -> !TabooLib.isTabooLib(plugin)).forEach(plugin -> TDependencyInjector.inject(plugin, plugin));
}
}
public static TLib getTLib() {
return tLib;
}
public static YamlConfiguration getInternalLanguage() {
return internalLanguage;
}
public TLogger getLogger() {
return logger;
}
public TLibConfig getConfig() {
return config;
}
public TConfigWatcher getConfigWatcher() {
return configWatcher;
}
public File getLibsFolder() {
return libsFolder;
}
public boolean isInjectEnabled() {
return Main.getInst().getConfig().getBoolean("PLUGIN-INJECTOR.ENABLE", true);
}
public boolean isBlackListPluginExists() {
return Main.getInst().getConfig().getStringList("PLUGIN-INJECTOR.DISABLE-ON-PLUGIN-EXISTS").stream().anyMatch(PluginUtils::isPluginExists);
}
}

View File

@@ -0,0 +1,14 @@
package com.ilummc.tlib.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Dependencies {
Dependency[] value();
}

View File

@@ -0,0 +1,24 @@
package com.ilummc.tlib.annotations;
import com.ilummc.tlib.dependency.TDependency;
import java.lang.annotation.*;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Dependencies.class)
public @interface Dependency {
enum Type {PLUGIN, LIBRARY}
Type type();
String plugin() default "";
String maven() default "";
String mavenRepo() default TDependency.MAVEN_REPO;
String url() default "";
}

View File

@@ -0,0 +1,16 @@
package com.ilummc.tlib.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Logger {
String value() default "[{0}|{1}§f] {2}";
int level() default com.ilummc.tlib.logger.TLogger.INFO;
}

View File

@@ -0,0 +1,13 @@
package com.ilummc.tlib.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PluginInstance {
String value();
}

View File

@@ -0,0 +1,29 @@
package com.ilummc.tlib.annotations;
import com.ilummc.tlib.util.Ref;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Modifier;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TConfig {
String name() default "config.yml";
boolean fromJar() default false;
boolean saveOnExit() default false;
boolean readOnly() default true;
String charset() default "UTF-8";
boolean listenChanges() default false;
int excludeModifiers() default Modifier.STATIC | Modifier.TRANSIENT | Ref.ACC_SYNTHETIC | Ref.ACC_BRIDGE;
}

View File

@@ -0,0 +1,11 @@
package com.ilummc.tlib.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TLocalePlugin {
}

View File

@@ -0,0 +1,17 @@
package com.ilummc.tlib.annotations.clr;
import java.lang.annotation.*;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(CommandHandlers.class)
public @interface CommandHandler {
/**
* Name of the command
*
* @return Name of the command
*/
String value();
}

View File

@@ -0,0 +1,14 @@
package com.ilummc.tlib.annotations.clr;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface CommandHandlers {
CommandHandler[] value();
}

View File

@@ -0,0 +1,14 @@
package com.ilummc.tlib.annotations.clr;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Sub {
String value();
}

View File

@@ -0,0 +1,11 @@
package com.ilummc.tlib.annotations.db;
public @interface Database {
boolean sharedPool() default true;
int poolSize() default 8;
Class<?> configClass();
}

View File

@@ -0,0 +1,4 @@
package com.ilummc.tlib.annotations.db;
public @interface DatabasePassword {
}

View File

@@ -0,0 +1,4 @@
package com.ilummc.tlib.annotations.db;
public @interface DatabaseType {
}

View File

@@ -0,0 +1,4 @@
package com.ilummc.tlib.annotations.db;
public @interface DatabaseUrl {
}

View File

@@ -0,0 +1,4 @@
package com.ilummc.tlib.annotations.db;
public @interface DatabaseUser {
}

View File

@@ -0,0 +1,14 @@
package com.ilummc.tlib.annotations.db;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLTable {
String value();
}

View File

@@ -0,0 +1,43 @@
package com.ilummc.tlib.bean;
import java.util.ArrayList;
import java.util.List;
import java.util.function.BiConsumer;
public class Property<T> {
private Property(T value) {
this.value = value;
}
private List<BiConsumer<T, T>> consumers;
private T value;
public void set(T value) {
if (value != this.value) {
if (consumers != null) {
for (BiConsumer<T, T> consumer : consumers) {
consumer.accept(this.value, value);
}
}
this.value = value;
}
}
public T get() {
return value;
}
public void addListener(BiConsumer<T, T> consumer) {
if (consumers == null) {
consumers = new ArrayList<>();
}
consumers.add(consumer);
}
public static <T> Property<T> of(T value) {
return new Property<>(value);
}
}

View File

@@ -0,0 +1,16 @@
package com.ilummc.tlib.bean;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import java.lang.reflect.Type;
public class PropertyTypeAdaptor implements JsonDeserializer<Property> {
@Override
public Property deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext context) throws JsonParseException {
return null;
}
}

View File

@@ -0,0 +1,180 @@
package com.ilummc.tlib.bungee.api;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;
/**
* Simplistic enumeration of all supported color values for chat.
* @author md_5
*/
public enum ChatColor {
/**
* Represents black.
*/
BLACK('0', "black"),
/**
* Represents dark blue.
*/
DARK_BLUE('1', "dark_blue"),
/**
* Represents dark green.
*/
DARK_GREEN('2', "dark_green"),
/**
* Represents dark blue (aqua).
*/
DARK_AQUA('3', "dark_aqua"),
/**
* Represents dark red.
*/
DARK_RED('4', "dark_red"),
/**
* Represents dark purple.
*/
DARK_PURPLE('5', "dark_purple"),
/**
* Represents gold.
*/
GOLD('6', "gold"),
/**
* Represents gray.
*/
GRAY('7', "gray"),
/**
* Represents dark gray.
*/
DARK_GRAY('8', "dark_gray"),
/**
* Represents blue.
*/
BLUE('9', "blue"),
/**
* Represents green.
*/
GREEN('a', "green"),
/**
* Represents aqua.
*/
AQUA('b', "aqua"),
/**
* Represents red.
*/
RED('c', "red"),
/**
* Represents light purple.
*/
LIGHT_PURPLE('d', "light_purple"),
/**
* Represents yellow.
*/
YELLOW('e', "yellow"),
/**
* Represents white.
*/
WHITE('f', "white"),
/**
* Represents magical characters that change around randomly.
*/
MAGIC('k', "obfuscated"),
/**
* Makes the text bold.
*/
BOLD('l', "bold"),
/**
* Makes a line appear through the text.
*/
STRIKETHROUGH('m', "strikethrough"),
/**
* Makes the text appear underlined.
*/
UNDERLINE('n', "underline"),
/**
* Makes the text italic.
*/
ITALIC('o', "italic"),
/**
* Resets all previous chat colors or formats.
*/
RESET('r', "reset");
/**
* The special character which prefixes all chat colour codes. Use this if
* you need to dynamically convert colour codes from your custom format.
*/
public static final char COLOR_CHAR = '\u00A7';
public static final String ALL_CODES = "0123456789AaBbCcDdEeFfKkLlMmNnOoRr";
/**
* Pattern to remove all colour codes.
*/
public static final Pattern STRIP_COLOR_PATTERN = Pattern.compile("(?i)" + String.valueOf(COLOR_CHAR) + "[0-9A-FK-OR]");
/**
* Colour instances keyed by their active character.
*/
private static final Map<Character, ChatColor> BY_CHAR = new HashMap<Character, ChatColor>();
/**
* The code appended to {@link #COLOR_CHAR} to make usable colour.
*/
private final char code;
/**
* This colour's colour char prefixed by the {@link #COLOR_CHAR}.
*/
private final String toString;
private final String name;
public String getName() {
return name;
}
static {
for (ChatColor colour : values()) {
BY_CHAR.put(colour.code, colour);
}
}
ChatColor(char code, String name) {
this.code = code;
this.name = name;
this.toString = new String(new char[]{COLOR_CHAR, code});
}
@Override
public String toString() {
return toString;
}
/**
* Strips the given message of all color codes
*
* @param input String to strip of color
* @return A copy of the input string, without any coloring
*/
public static String stripColor(final String input) {
if (input == null) {
return null;
}
return STRIP_COLOR_PATTERN.matcher(input).replaceAll("");
}
public static String translateAlternateColorCodes(char altColorChar, String textToTranslate) {
char[] b = textToTranslate.toCharArray();
for (int i = 0; i < b.length - 1; i++) {
if (b[i] == altColorChar && ALL_CODES.indexOf(b[i + 1]) > -1) {
b[i] = ChatColor.COLOR_CHAR;
b[i + 1] = Character.toLowerCase(b[i + 1]);
}
}
return new String(b);
}
/**
* Get the colour represented by the specified code.
*
* @param code the code to search for
* @return the mapped colour, or null if non exists
*/
public static ChatColor getByChar(char code) {
return BY_CHAR.get(code);
}
}

View File

@@ -0,0 +1,12 @@
package com.ilummc.tlib.bungee.api;
/**
* Represents the position on the screen where a message will appear.
* @author md_5
*/
public enum ChatMessageType {
CHAT,
SYSTEM,
ACTION_BAR
}

View File

@@ -0,0 +1,493 @@
package com.ilummc.tlib.bungee.api.chat;
import com.ilummc.tlib.bungee.api.ChatColor;
import com.ilummc.tlib.bungee.api.chat.ComponentBuilder.FormatRetention;
import java.util.ArrayList;
import java.util.List;
/**
* @author md_5
*/
public abstract class BaseComponent {
BaseComponent parent;
/**
* The color of this component and any child components (unless overridden)
*/
private ChatColor color;
/**
* Whether this component and any child components (unless overridden) is
* bold
*/
private Boolean bold;
/**
* Whether this component and any child components (unless overridden) is
* italic
*/
private Boolean italic;
/**
* Whether this component and any child components (unless overridden) is
* underlined
*/
private Boolean underlined;
/**
* Whether this component and any child components (unless overridden) is
* strikethrough
*/
private Boolean strikethrough;
/**
* Whether this component and any child components (unless overridden) is
* obfuscated
*/
private Boolean obfuscated;
/**
* The text to insert into the chat when this component (and child
* components) are clicked while pressing the shift key
*/
private String insertion;
/**
* Appended components that inherit this component's formatting and events
*/
private List<BaseComponent> extra;
/**
* The action to perform when this component (and child components) are
* clicked
*/
private ClickEvent clickEvent;
/**
* The action to perform when this component (and child components) are
* hovered over
*/
private HoverEvent hoverEvent;
public String getInsertion() {
return insertion;
}
public List<BaseComponent> getExtra() {
return extra;
}
public ClickEvent getClickEvent() {
return clickEvent;
}
public HoverEvent getHoverEvent() {
return hoverEvent;
}
public void setParent(BaseComponent parent) {
this.parent = parent;
}
public void setColor(ChatColor color) {
this.color = color;
}
public void setBold(Boolean bold) {
this.bold = bold;
}
public void setItalic(Boolean italic) {
this.italic = italic;
}
public void setUnderlined(Boolean underlined) {
this.underlined = underlined;
}
public void setStrikethrough(Boolean strikethrough) {
this.strikethrough = strikethrough;
}
public void setObfuscated(Boolean obfuscated) {
this.obfuscated = obfuscated;
}
public void setInsertion(String insertion) {
this.insertion = insertion;
}
public void setClickEvent(ClickEvent clickEvent) {
this.clickEvent = clickEvent;
}
public void setHoverEvent(HoverEvent hoverEvent) {
this.hoverEvent = hoverEvent;
}
@Override
public String toString() {
return "parent=" + "BaseComponent{" + parent + ", color=" + color + ", bold=" + bold + ", italic=" + italic + ", underlined=" + underlined + ", strikethrough=" + strikethrough + ", obfuscated=" + obfuscated + ", insertion='" + insertion + '\'' + ", extra=" + extra + ", clickEvent=" + clickEvent + ", hoverEvent=" + hoverEvent + '}';
}
BaseComponent() {
}
BaseComponent(BaseComponent old) {
copyFormatting(old, FormatRetention.ALL, true);
if (old.getExtra() != null) {
for (BaseComponent extra : old.getExtra()) {
addExtra(extra.duplicate());
}
}
}
/**
* Copies the events and formatting of a BaseComponent. Already set
* formatting will be replaced.
*
* @param component the component to copy from
*/
public void copyFormatting(BaseComponent component) {
copyFormatting(component, FormatRetention.ALL, true);
}
/**
* Copies the events and formatting of a BaseComponent.
*
* @param component the component to copy from
* @param replace if already set formatting should be replaced by the new
* component
*/
public void copyFormatting(BaseComponent component, boolean replace) {
copyFormatting(component, FormatRetention.ALL, replace);
}
/**
* Copies the specified formatting of a BaseComponent.
*
* @param component the component to copy from
* @param retention the formatting to copy
* @param replace if already set formatting should be replaced by the new
* component
*/
public void copyFormatting(BaseComponent component, FormatRetention retention, boolean replace) {
if (retention == FormatRetention.EVENTS || retention == FormatRetention.ALL) {
if (replace || clickEvent == null) {
setClickEvent(component.getClickEvent());
}
if (replace || hoverEvent == null) {
setHoverEvent(component.getHoverEvent());
}
}
if (retention == FormatRetention.FORMATTING || retention == FormatRetention.ALL) {
if (replace || color == null) {
setColor(component.getColorRaw());
}
if (replace || bold == null) {
setBold(component.isBoldRaw());
}
if (replace || italic == null) {
setItalic(component.isItalicRaw());
}
if (replace || underlined == null) {
setUnderlined(component.isUnderlinedRaw());
}
if (replace || strikethrough == null) {
setStrikethrough(component.isStrikethroughRaw());
}
if (replace || obfuscated == null) {
setObfuscated(component.isObfuscatedRaw());
}
if (replace || insertion == null) {
setInsertion(component.getInsertion());
}
}
}
/**
* Retains only the specified formatting.
*
* @param retention the formatting to retain
*/
public void retain(FormatRetention retention) {
if (retention == FormatRetention.FORMATTING || retention == FormatRetention.NONE) {
setClickEvent(null);
setHoverEvent(null);
}
if (retention == FormatRetention.EVENTS || retention == FormatRetention.NONE) {
setColor(null);
setBold(null);
setItalic(null);
setUnderlined(null);
setStrikethrough(null);
setObfuscated(null);
setInsertion(null);
}
}
/**
* Clones the BaseComponent and returns the clone.
*
* @return The duplicate of this BaseComponent
*/
public abstract BaseComponent duplicate();
/**
* Clones the BaseComponent without formatting and returns the clone.
*
* @return The duplicate of this BaseComponent
* @deprecated API use discouraged, use traditional duplicate
*/
@Deprecated
public BaseComponent duplicateWithoutFormatting() {
BaseComponent component = duplicate();
component.retain(FormatRetention.NONE);
return component;
}
/**
* Converts the components to a string that uses the old formatting codes
* ({@link ChatColor#COLOR_CHAR}
*
* @param components the components to convert
* @return the string in the old format
*/
public static String toLegacyText(BaseComponent... components) {
StringBuilder builder = new StringBuilder();
for (BaseComponent msg : components) {
builder.append(msg.toLegacyText());
}
return builder.toString();
}
/**
* Converts the components into a string without any formatting
*
* @param components the components to convert
* @return the string as plain text
*/
public static String toPlainText(BaseComponent... components) {
StringBuilder builder = new StringBuilder();
for (BaseComponent msg : components) {
builder.append(msg.toPlainText());
}
return builder.toString();
}
/**
* Returns the color of this component. This uses the parent's color if this
* component doesn't have one. {@link ChatColor#WHITE}
* is returned if no color is found.
*
* @return the color of this component
*/
public ChatColor getColor() {
if (color == null) {
if (parent == null) {
return ChatColor.WHITE;
}
return parent.getColor();
}
return color;
}
/**
* Returns the color of this component without checking the parents color.
* May return null
*
* @return the color of this component
*/
public ChatColor getColorRaw() {
return color;
}
/**
* Returns whether this component is bold. This uses the parent's setting if
* this component hasn't been set. false is returned if none of the parent
* chain has been set.
*
* @return whether the component is bold
*/
public boolean isBold() {
if (bold == null) {
return parent != null && parent.isBold();
}
return bold;
}
/**
* Returns whether this component is bold without checking the parents
* setting. May return null
*
* @return whether the component is bold
*/
public Boolean isBoldRaw() {
return bold;
}
/**
* Returns whether this component is italic. This uses the parent's setting
* if this component hasn't been set. false is returned if none of the
* parent chain has been set.
*
* @return whether the component is italic
*/
public boolean isItalic() {
if (italic == null) {
return parent != null && parent.isItalic();
}
return italic;
}
/**
* Returns whether this component is italic without checking the parents
* setting. May return null
*
* @return whether the component is italic
*/
public Boolean isItalicRaw() {
return italic;
}
/**
* Returns whether this component is underlined. This uses the parent's
* setting if this component hasn't been set. false is returned if none of
* the parent chain has been set.
*
* @return whether the component is underlined
*/
public boolean isUnderlined() {
if (underlined == null) {
return parent != null && parent.isUnderlined();
}
return underlined;
}
/**
* Returns whether this component is underlined without checking the parents
* setting. May return null
*
* @return whether the component is underlined
*/
public Boolean isUnderlinedRaw() {
return underlined;
}
/**
* Returns whether this component is strikethrough. This uses the parent's
* setting if this component hasn't been set. false is returned if none of
* the parent chain has been set.
*
* @return whether the component is strikethrough
*/
public boolean isStrikethrough() {
if (strikethrough == null) {
return parent != null && parent.isStrikethrough();
}
return strikethrough;
}
/**
* Returns whether this component is strikethrough without checking the
* parents setting. May return null
*
* @return whether the component is strikethrough
*/
public Boolean isStrikethroughRaw() {
return strikethrough;
}
/**
* Returns whether this component is obfuscated. This uses the parent's
* setting if this component hasn't been set. false is returned if none of
* the parent chain has been set.
*
* @return whether the component is obfuscated
*/
public boolean isObfuscated() {
if (obfuscated == null) {
return parent != null && parent.isObfuscated();
}
return obfuscated;
}
/**
* Returns whether this component is obfuscated without checking the parents
* setting. May return null
*
* @return whether the component is obfuscated
*/
public Boolean isObfuscatedRaw() {
return obfuscated;
}
public void setExtra(List<BaseComponent> components) {
components.forEach(component -> component.parent = this);
extra = components;
}
/**
* Appends a text element to the component. The text will inherit this
* component's formatting
*
* @param text the text to append
*/
public void addExtra(String text) {
addExtra(new TextComponent(text));
}
/**
* Appends a component to the component. The text will inherit this
* component's formatting
*
* @param component the component to append
*/
public void addExtra(BaseComponent component) {
if (extra == null) {
extra = new ArrayList<>();
}
component.parent = this;
extra.add(component);
}
/**
* Returns whether the component has any formatting or events applied to it
*
* @return Whether any formatting or events are applied
*/
public boolean hasFormatting() {
return color != null || italic != null || bold != null || underlined != null || strikethrough != null || obfuscated != null || insertion != null || hoverEvent != null || clickEvent != null;
}
/**
* Converts the component into a string without any formatting
*
* @return the string as plain text
*/
public String toPlainText() {
StringBuilder builder = new StringBuilder();
toPlainText(builder);
return builder.toString();
}
void toPlainText(StringBuilder builder) {
if (extra != null) {
extra.forEach(e -> e.toPlainText(builder));
}
}
/**
* Converts the component to a string that uses the old formatting codes
* ({@link ChatColor#COLOR_CHAR}
*
* @return the string in the old format
*/
public String toLegacyText() {
StringBuilder builder = new StringBuilder();
toLegacyText(builder);
return builder.toString();
}
void toLegacyText(StringBuilder builder) {
if (extra != null) {
extra.forEach(e -> e.toLegacyText(builder));
}
}
}

View File

@@ -0,0 +1,61 @@
package com.ilummc.tlib.bungee.api.chat;
/**
* @author md_5
*/
public final class ClickEvent {
/**
* The type of action to perform on click
*/
private final Action action;
/**
* Depends on action
*
* @see Action
*/
private final String value;
public ClickEvent(Action action, String value) {
this.action = action;
this.value = value;
}
public Action getAction() {
return action;
}
public String getValue() {
return value;
}
public enum Action {
/**
* Open a url at the path given by
* {@link ClickEvent#value}
*/
OPEN_URL,
/**
* Open a file at the path given by
* {@link ClickEvent#value}
*/
OPEN_FILE,
/**
* Run the command given by
* {@link ClickEvent#value}
*/
RUN_COMMAND,
/**
* Inserts the string given by
* {@link ClickEvent#value} into the players
* text box
*/
SUGGEST_COMMAND,
/**
* Change to the page number given by
* {@link ClickEvent#value} in a book
*/
CHANGE_PAGE
}
}

View File

@@ -0,0 +1,311 @@
package com.ilummc.tlib.bungee.api.chat;
import com.google.common.base.Preconditions;
import com.ilummc.tlib.bungee.api.ChatColor;
import java.util.ArrayList;
import java.util.List;
/**
* <p>
* ComponentBuilder simplifies creating basic messages by allowing the use of a
* chainable builder.
* </p>
* <pre>
* new ComponentBuilder("Hello ").color(ChatColor.RED).
* append("World").color(ChatColor.BLUE). append("!").bold(true).create();
* </pre>
* <p>
* All methods (excluding {@link #append(String)} and {@link #create()} work on
* the last part appended to the builder, so in the example above "Hello " would
* be {@link ChatColor#RED} and "World" would be
* {@link ChatColor#BLUE} but "!" would be bold and
* {@link ChatColor#BLUE} because append copies the previous
* part's formatting
* </p>
*
* @author md_5
*/
public final class ComponentBuilder {
private BaseComponent current;
private final List<BaseComponent> parts = new ArrayList<>();
/**
* Creates a ComponentBuilder from the other given ComponentBuilder to clone
* it.
*
* @param original the original for the new ComponentBuilder.
*/
public ComponentBuilder(ComponentBuilder original) {
current = original.current.duplicate();
original.parts.stream().map(BaseComponent::duplicate).forEach(parts::add);
}
/**
* Creates a ComponentBuilder with the given text as the first part.
*
* @param text the first text element
*/
public ComponentBuilder(String text) {
current = new TextComponent(text);
}
/**
* Creates a ComponentBuilder with the given component as the first part.
*
* @param component the first component element
*/
public ComponentBuilder(BaseComponent component) {
current = component.duplicate();
}
/**
* Appends a component to the builder and makes it the current target for
* formatting. The component will have all the formatting from previous
* part.
*
* @param component the component to append
* @return this ComponentBuilder for chaining
*/
public ComponentBuilder append(BaseComponent component) {
return append(component, FormatRetention.ALL);
}
/**
* Appends a component to the builder and makes it the current target for
* formatting. You can specify the amount of formatting retained from
* previous part.
*
* @param component the component to append
* @param retention the formatting to retain
* @return this ComponentBuilder for chaining
*/
public ComponentBuilder append(BaseComponent component, FormatRetention retention) {
parts.add(current);
BaseComponent previous = current;
current = component.duplicate();
current.copyFormatting(previous, retention, false);
return this;
}
/**
* Appends the components to the builder and makes the last element the
* current target for formatting. The components will have all the
* formatting from previous part.
*
* @param components the components to append
* @return this ComponentBuilder for chaining
*/
public ComponentBuilder append(BaseComponent[] components) {
return append(components, FormatRetention.ALL);
}
/**
* Appends the components to the builder and makes the last element the
* current target for formatting. You can specify the amount of formatting
* retained from previous part.
*
* @param components the components to append
* @param retention the formatting to retain
* @return this ComponentBuilder for chaining
*/
public ComponentBuilder append(BaseComponent[] components, FormatRetention retention) {
Preconditions.checkArgument(components.length != 0, "No components to append");
BaseComponent previous = current;
for (BaseComponent component : components) {
parts.add(current);
current = component.duplicate();
current.copyFormatting(previous, retention, false);
}
return this;
}
/**
* Appends the text to the builder and makes it the current target for
* formatting. The text will have all the formatting from previous part.
*
* @param text the text to append
* @return this ComponentBuilder for chaining
*/
public ComponentBuilder append(String text) {
return append(text, FormatRetention.ALL);
}
/**
* Appends the text to the builder and makes it the current target for
* formatting. You can specify the amount of formatting retained from
* previous part.
*
* @param text the text to append
* @param retention the formatting to retain
* @return this ComponentBuilder for chaining
*/
public ComponentBuilder append(String text, FormatRetention retention) {
parts.add(current);
BaseComponent old = current;
current = new TextComponent(text);
current.copyFormatting(old, retention, false);
return this;
}
/**
* Sets the color of the current part.
*
* @param color the new color
* @return this ComponentBuilder for chaining
*/
public ComponentBuilder color(ChatColor color) {
current.setColor(color);
return this;
}
/**
* Sets whether the current part is bold.
*
* @param bold whether this part is bold
* @return this ComponentBuilder for chaining
*/
public ComponentBuilder bold(boolean bold) {
current.setBold(bold);
return this;
}
/**
* Sets whether the current part is italic.
*
* @param italic whether this part is italic
* @return this ComponentBuilder for chaining
*/
public ComponentBuilder italic(boolean italic) {
current.setItalic(italic);
return this;
}
/**
* Sets whether the current part is underlined.
*
* @param underlined whether this part is underlined
* @return this ComponentBuilder for chaining
*/
public ComponentBuilder underlined(boolean underlined) {
current.setUnderlined(underlined);
return this;
}
/**
* Sets whether the current part is strikethrough.
*
* @param strikethrough whether this part is strikethrough
* @return this ComponentBuilder for chaining
*/
public ComponentBuilder strikethrough(boolean strikethrough) {
current.setStrikethrough(strikethrough);
return this;
}
/**
* Sets whether the current part is obfuscated.
*
* @param obfuscated whether this part is obfuscated
* @return this ComponentBuilder for chaining
*/
public ComponentBuilder obfuscated(boolean obfuscated) {
current.setObfuscated(obfuscated);
return this;
}
/**
* Sets the insertion text for the current part.
*
* @param insertion the insertion text
* @return this ComponentBuilder for chaining
*/
public ComponentBuilder insertion(String insertion) {
current.setInsertion(insertion);
return this;
}
/**
* Sets the click event for the current part.
*
* @param clickEvent the click event
* @return this ComponentBuilder for chaining
*/
public ComponentBuilder event(ClickEvent clickEvent) {
current.setClickEvent(clickEvent);
return this;
}
/**
* Sets the hover event for the current part.
*
* @param hoverEvent the hover event
* @return this ComponentBuilder for chaining
*/
public ComponentBuilder event(HoverEvent hoverEvent) {
current.setHoverEvent(hoverEvent);
return this;
}
/**
* Sets the current part back to normal settings. Only text is kept.
*
* @return this ComponentBuilder for chaining
*/
public ComponentBuilder reset() {
return retain(FormatRetention.NONE);
}
/**
* Retains only the specified formatting. Text is not modified.
*
* @param retention the formatting to retain
* @return this ComponentBuilder for chaining
*/
public ComponentBuilder retain(FormatRetention retention) {
current.retain(retention);
return this;
}
/**
* Returns the components needed to display the message created by this
* builder.
*
* @return the created components
*/
public BaseComponent[] create() {
BaseComponent[] result = parts.toArray(new BaseComponent[parts.size() + 1]);
result[parts.size()] = current;
return result;
}
public enum FormatRetention {
/**
* Specify that we do not want to retain anything from the previous
* component.
*/
NONE,
/**
* Specify that we want the formatting retained from the previous
* component.
*/
FORMATTING,
/**
* Specify that we want the events retained from the previous component.
*/
EVENTS,
/**
* Specify that we want to retain everything from the previous
* component.
*/
ALL
}
}

View File

@@ -0,0 +1,38 @@
package com.ilummc.tlib.bungee.api.chat;
import java.util.Arrays;
/**
* @author md_5
*/
public final class HoverEvent {
private final Action action;
private final BaseComponent[] value;
public HoverEvent(Action action, BaseComponent[] value) {
this.action = action;
this.value = value;
}
public Action getAction() {
return action;
}
public BaseComponent[] getValue() {
return value;
}
@Override
public String toString() {
return "action=" + "HoverEvent{" + action + ", value=" + Arrays.toString(value) + '}';
}
public enum Action {
SHOW_TEXT,
SHOW_ACHIEVEMENT,
SHOW_ITEM,
SHOW_ENTITY
}
}

View File

@@ -0,0 +1,184 @@
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.ilummc.tlib.bungee.api.chat;
import com.ilummc.tlib.bungee.api.ChatColor;
import java.beans.ConstructorProperties;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author md_5
*/
public class TextComponent extends BaseComponent {
private static final Pattern url = Pattern.compile("^(?:(https?)://)?([-\\w_\\.]{2,}\\.[a-z]{2,4})(/\\S*)?$");
private String text;
public static BaseComponent[] fromLegacyText(String message) {
ArrayList<BaseComponent> components = new ArrayList();
StringBuilder builder = new StringBuilder();
TextComponent component = new TextComponent();
Matcher matcher = url.matcher(message);
for(int i = 0; i < message.length(); ++i) {
char c = message.charAt(i);
TextComponent old;
if (c == 167) {
++i;
c = message.charAt(i);
if (c >= 'A' && c <= 'Z') {
c = (char)(c + 32);
}
ChatColor format = ChatColor.getByChar(c);
if (format != null) {
if (builder.length() > 0) {
old = component;
component = new TextComponent(component);
old.setText(builder.toString());
builder = new StringBuilder();
components.add(old);
}
switch(format) {
case BOLD:
component.setBold(true);
break;
case ITALIC:
component.setItalic(true);
break;
case UNDERLINE:
component.setUnderlined(true);
break;
case STRIKETHROUGH:
component.setStrikethrough(true);
break;
case MAGIC:
component.setObfuscated(true);
break;
case RESET:
format = ChatColor.WHITE;
default:
component = new TextComponent();
component.setColor(format);
break;
}
}
} else {
int pos = message.indexOf(32, i);
if (pos == -1) {
pos = message.length();
}
if (matcher.region(i, pos).find()) {
if (builder.length() > 0) {
old = component;
component = new TextComponent(component);
old.setText(builder.toString());
builder = new StringBuilder();
components.add(old);
}
old = component;
component = new TextComponent(component);
String urlString = message.substring(i, pos);
component.setText(urlString);
component.setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, urlString.startsWith("http") ? urlString : "http://" + urlString));
components.add(component);
i += pos - i - 1;
component = old;
} else {
builder.append(c);
}
}
}
if (builder.length() > 0) {
component.setText(builder.toString());
components.add(component);
}
if (components.isEmpty()) {
components.add(new TextComponent(""));
}
return components.toArray(new BaseComponent[0]);
}
public TextComponent() {
this.text = "";
}
public TextComponent(TextComponent textComponent) {
super(textComponent);
this.setText(textComponent.getText());
}
public TextComponent(BaseComponent... extras) {
this.setText("");
this.setExtra(new ArrayList(Arrays.asList(extras)));
}
@Override
public BaseComponent duplicate() {
return new TextComponent(this);
}
@Override
protected void toPlainText(StringBuilder builder) {
builder.append(this.text);
super.toPlainText(builder);
}
@Override
protected void toLegacyText(StringBuilder builder) {
builder.append(this.getColor());
if (this.isBold()) {
builder.append(ChatColor.BOLD);
}
if (this.isItalic()) {
builder.append(ChatColor.ITALIC);
}
if (this.isUnderlined()) {
builder.append(ChatColor.UNDERLINE);
}
if (this.isStrikethrough()) {
builder.append(ChatColor.STRIKETHROUGH);
}
if (this.isObfuscated()) {
builder.append(ChatColor.MAGIC);
}
builder.append(this.text);
super.toLegacyText(builder);
}
@Override
public String toString() {
return String.format("TextComponent{text=%s, %s}", this.text, super.toString());
}
public String getText() {
return this.text;
}
public void setText(String text) {
this.text = text;
}
@ConstructorProperties({"text"})
public TextComponent(String text) {
this.text = text;
}
}

View File

@@ -0,0 +1,242 @@
package com.ilummc.tlib.bungee.api.chat;
import com.ilummc.tlib.bungee.api.ChatColor;
import java.util.ArrayList;
import java.util.List;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
/**
* @author md_5
*/
public final class TranslatableComponent extends BaseComponent {
private final ResourceBundle locales = ResourceBundle.getBundle("mojang-translations/en_US");
private final Pattern format = Pattern.compile("%(?:(\\d+)\\$)?([A-Za-z%]|$)");
/**
* The key into the Minecraft locale files to use for the translation. The
* text depends on the client's locale setting. The console is always en_US
*/
private String translate;
/**
* The components to substitute into the translation
*/
private List<BaseComponent> with;
public ResourceBundle getLocales() {
return locales;
}
public Pattern getFormat() {
return format;
}
public String getTranslate() {
return translate;
}
public void setTranslate(String translate) {
this.translate = translate;
}
public List<BaseComponent> getWith() {
return with;
}
public TranslatableComponent() {
}
/**
* Creates a translatable component from the original to clone it.
*
* @param original the original for the new translatable component.
*/
public TranslatableComponent(TranslatableComponent original) {
super(original);
setTranslate(original.getTranslate());
if (original.getWith() != null) {
setWith(original.getWith().stream().map(BaseComponent::duplicate).collect(Collectors.toList()));
}
}
/**
* Creates a translatable component with the passed substitutions
*
* @param translate the translation key
* @param with the {@link java.lang.String}s and
* {@link BaseComponent}s to use into the
* translation
* @see #translate
* @see #setWith(java.util.List)
*/
public TranslatableComponent(String translate, Object... with) {
setTranslate(translate);
if (with != null && with.length != 0) {
List<BaseComponent> temp = new ArrayList<>();
for (Object w : with) {
if (w instanceof String) {
temp.add(new TextComponent((String) w));
} else {
temp.add((BaseComponent) w);
}
}
setWith(temp);
}
}
/**
* Creates a duplicate of this TranslatableComponent.
*
* @return the duplicate of this TranslatableComponent.
*/
@Override
public BaseComponent duplicate() {
return new TranslatableComponent(this);
}
@Override
public String toString() {
return "locales=" + "TranslatableComponent{" + locales + ", format=" + format + ", translate='" + translate + '\'' + ", with=" + with + '}';
}
/**
* Sets the translation substitutions to be used in this component. Removes
* any previously set substitutions
*
* @param components the components to substitute
*/
public void setWith(List<BaseComponent> components) {
components.forEach(component -> component.parent = this);
with = components;
}
/**
* Adds a text substitution to the component. The text will inherit this
* component's formatting
*
* @param text the text to substitute
*/
public void addWith(String text) {
addWith(new TextComponent(text));
}
/**
* Adds a component substitution to the component. The text will inherit
* this component's formatting
*
* @param component the component to substitute
*/
public void addWith(BaseComponent component) {
if (with == null) {
with = new ArrayList<>();
}
component.parent = this;
with.add(component);
}
@Override
protected void toPlainText(StringBuilder builder) {
String trans;
try {
trans = locales.getString(translate);
} catch (MissingResourceException ex) {
trans = translate;
}
Matcher matcher = format.matcher(trans);
int position = 0;
int i = 0;
while (matcher.find(position)) {
int pos = matcher.start();
if (pos != position) {
builder.append(trans, position, pos);
}
position = matcher.end();
String formatCode = matcher.group(2);
switch (formatCode.charAt(0)) {
case 's':
case 'd':
String withIndex = matcher.group(1);
with.get(withIndex != null ? Integer.parseInt(withIndex) - 1 : i++).toPlainText(builder);
break;
case '%':
builder.append('%');
break;
default:
break;
}
}
if (trans.length() != position) {
builder.append(trans, position, trans.length());
}
super.toPlainText(builder);
}
@Override
protected void toLegacyText(StringBuilder builder) {
String trans;
try {
trans = locales.getString(translate);
} catch (MissingResourceException e) {
trans = translate;
}
Matcher matcher = format.matcher(trans);
int position = 0;
int i = 0;
while (matcher.find(position)) {
int pos = matcher.start();
if (pos != position) {
addFormat(builder);
builder.append(trans, position, pos);
}
position = matcher.end();
String formatCode = matcher.group(2);
switch (formatCode.charAt(0)) {
case 's':
case 'd':
String withIndex = matcher.group(1);
with.get(withIndex != null ? Integer.parseInt(withIndex) - 1 : i++).toLegacyText(builder);
break;
case '%':
addFormat(builder);
builder.append('%');
break;
default:
break;
}
}
if (trans.length() != position) {
addFormat(builder);
builder.append(trans, position, trans.length());
}
super.toLegacyText(builder);
}
private void addFormat(StringBuilder builder) {
builder.append(getColor());
if (isBold()) {
builder.append(ChatColor.BOLD);
}
if (isItalic()) {
builder.append(ChatColor.ITALIC);
}
if (isUnderlined()) {
builder.append(ChatColor.UNDERLINE);
}
if (isStrikethrough()) {
builder.append(ChatColor.STRIKETHROUGH);
}
if (isObfuscated()) {
builder.append(ChatColor.MAGIC);
}
}
}

View File

@@ -0,0 +1,121 @@
package com.ilummc.tlib.bungee.chat;
import com.google.common.base.Preconditions;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonObject;
import com.google.gson.JsonSerializationContext;
import com.ilummc.tlib.bungee.api.ChatColor;
import com.ilummc.tlib.bungee.api.chat.BaseComponent;
import com.ilummc.tlib.bungee.api.chat.ClickEvent;
import com.ilummc.tlib.bungee.api.chat.HoverEvent;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Locale;
/**
* @author md_5
*/
public class BaseComponentSerializer {
protected void deserialize(JsonObject object, BaseComponent component, JsonDeserializationContext context) {
if (object.has("color")) {
component.setColor(ChatColor.valueOf(object.get("color").getAsString().toUpperCase(Locale.ROOT)));
}
if (object.has("bold")) {
component.setBold(object.get("bold").getAsBoolean());
}
if (object.has("italic")) {
component.setItalic(object.get("italic").getAsBoolean());
}
if (object.has("underlined")) {
component.setUnderlined(object.get("underlined").getAsBoolean());
}
if (object.has("strikethrough")) {
component.setStrikethrough(object.get("strikethrough").getAsBoolean());
}
if (object.has("obfuscated")) {
component.setObfuscated(object.get("obfuscated").getAsBoolean());
}
if (object.has("insertion")) {
component.setInsertion(object.get("insertion").getAsString());
}
if (object.has("extra")) {
component.setExtra(Arrays.asList(context.<BaseComponent[]>deserialize(object.get("extra"), BaseComponent[].class)));
}
//Events
if (object.has("clickEvent")) {
JsonObject event = object.getAsJsonObject("clickEvent");
component.setClickEvent(new ClickEvent(
ClickEvent.Action.valueOf(event.get("action").getAsString().toUpperCase(Locale.ROOT)),
event.get("value").getAsString()));
}
if (object.has("hoverEvent")) {
JsonObject event = object.getAsJsonObject("hoverEvent");
BaseComponent[] res;
if (event.get("value").isJsonArray()) {
res = context.deserialize(event.get("value"), BaseComponent[].class);
} else {
res = new BaseComponent[]{context.deserialize(event.get("value"), BaseComponent.class)};
}
component.setHoverEvent(new HoverEvent(HoverEvent.Action.valueOf(event.get("action").getAsString().toUpperCase(Locale.ROOT)), res));
}
}
protected void serialize(JsonObject object, BaseComponent component, JsonSerializationContext context) {
boolean first = false;
if (ComponentSerializer.serializedComponents.get() == null) {
first = true;
ComponentSerializer.serializedComponents.set(new HashSet<>());
}
try {
Preconditions.checkArgument(!ComponentSerializer.serializedComponents.get().contains(component), "Component loop");
ComponentSerializer.serializedComponents.get().add(component);
if (component.getColorRaw() != null) {
object.addProperty("color", component.getColorRaw().getName());
}
if (component.isBoldRaw() != null) {
object.addProperty("bold", component.isBoldRaw());
}
if (component.isItalicRaw() != null) {
object.addProperty("italic", component.isItalicRaw());
}
if (component.isUnderlinedRaw() != null) {
object.addProperty("underlined", component.isUnderlinedRaw());
}
if (component.isStrikethroughRaw() != null) {
object.addProperty("strikethrough", component.isStrikethroughRaw());
}
if (component.isObfuscatedRaw() != null) {
object.addProperty("obfuscated", component.isObfuscatedRaw());
}
if (component.getInsertion() != null) {
object.addProperty("insertion", component.getInsertion());
}
if (component.getExtra() != null) {
object.add("extra", context.serialize(component.getExtra()));
}
//Events
if (component.getClickEvent() != null) {
JsonObject clickEvent = new JsonObject();
clickEvent.addProperty("action", component.getClickEvent().getAction().toString().toLowerCase(Locale.ROOT));
clickEvent.addProperty("value", component.getClickEvent().getValue());
object.add("clickEvent", clickEvent);
}
if (component.getHoverEvent() != null) {
JsonObject hoverEvent = new JsonObject();
hoverEvent.addProperty("action", component.getHoverEvent().getAction().toString().toLowerCase(Locale.ROOT));
hoverEvent.add("value", context.serialize(component.getHoverEvent().getValue()));
object.add("hoverEvent", hoverEvent);
}
} finally {
ComponentSerializer.serializedComponents.get().remove(component);
if (first) {
ComponentSerializer.serializedComponents.set(null);
}
}
}
}

View File

@@ -0,0 +1,59 @@
package com.ilummc.tlib.bungee.chat;
import com.google.gson.*;
import com.ilummc.tlib.bungee.api.chat.BaseComponent;
import com.ilummc.tlib.bungee.api.chat.TextComponent;
import com.ilummc.tlib.bungee.api.chat.TranslatableComponent;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.HashSet;
/**
* @author md_5
*/
public class ComponentSerializer implements JsonDeserializer<BaseComponent> {
private final static JsonParser JSON_PARSER = new JsonParser();
private final static Gson gson = new GsonBuilder().
registerTypeAdapter(BaseComponent.class, new ComponentSerializer()).
registerTypeAdapter(TextComponent.class, new TextComponentSerializer()).
registerTypeAdapter(TranslatableComponent.class, new TranslatableComponentSerializer()).
create();
public final static ThreadLocal<HashSet<BaseComponent>> serializedComponents = new ThreadLocal<>();
public static BaseComponent[] parse(String json) {
JsonElement jsonElement = JSON_PARSER.parse(json);
if (jsonElement.isJsonArray()) {
return gson.fromJson(jsonElement, BaseComponent[].class);
} else {
return new BaseComponent[]{gson.fromJson(jsonElement, BaseComponent.class)};
}
}
public static String toString(BaseComponent component) {
return gson.toJson(component);
}
public static String toString(BaseComponent... components) {
if (components.length == 1) {
return gson.toJson(components[0]);
} else {
return gson.toJson(new TextComponent(components));
}
}
@Override
public BaseComponent deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
if (json.isJsonPrimitive()) {
return new TextComponent(json.getAsString());
}
JsonObject object = json.getAsJsonObject();
if (object.has("translate")) {
return context.deserialize(json, TranslatableComponent.class);
}
return context.deserialize(json, TextComponent.class);
}
}

View File

@@ -0,0 +1,42 @@
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.ilummc.tlib.bungee.chat;
import com.google.gson.*;
import com.ilummc.tlib.bungee.api.chat.BaseComponent;
import com.ilummc.tlib.bungee.api.chat.TextComponent;
import java.lang.reflect.Type;
import java.util.List;
/**
* @author md_5
*/
public class TextComponentSerializer extends BaseComponentSerializer implements JsonSerializer<TextComponent>, JsonDeserializer<TextComponent> {
public TextComponentSerializer() {
}
@Override
public TextComponent deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
TextComponent component = new TextComponent();
JsonObject object = json.getAsJsonObject();
this.deserialize(object, component, context);
component.setText(object.get("text").getAsString());
return component;
}
@Override
public JsonElement serialize(TextComponent src, Type typeOfSrc, JsonSerializationContext context) {
List<BaseComponent> extra = src.getExtra();
JsonObject object = new JsonObject();
if (src.hasFormatting() || extra != null && !extra.isEmpty()) {
this.serialize(object, src, context);
}
object.addProperty("text", src.getText());
return object;
}
}

View File

@@ -0,0 +1,46 @@
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.ilummc.tlib.bungee.chat;
import com.google.gson.*;
import com.ilummc.tlib.bungee.api.chat.BaseComponent;
import com.ilummc.tlib.bungee.api.chat.TranslatableComponent;
import java.lang.reflect.Type;
import java.util.Arrays;
/**
* @author md_5
*/
public class TranslatableComponentSerializer extends BaseComponentSerializer implements JsonSerializer<TranslatableComponent>, JsonDeserializer<TranslatableComponent> {
public TranslatableComponentSerializer() {
}
@Override
public TranslatableComponent deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
TranslatableComponent component = new TranslatableComponent();
JsonObject object = json.getAsJsonObject();
this.deserialize(object, component, context);
component.setTranslate(object.get("translate").getAsString());
if (object.has("with")) {
component.setWith(Arrays.asList((BaseComponent[]) context.deserialize(object.get("with"), BaseComponent[].class)));
}
return component;
}
@Override
public JsonElement serialize(TranslatableComponent src, Type typeOfSrc, JsonSerializationContext context) {
JsonObject object = new JsonObject();
this.serialize(object, src, context);
object.addProperty("translate", src.getTranslate());
if (src.getWith() != null) {
object.add("with", context.serialize(src.getWith()));
}
return object;
}
}

View File

@@ -0,0 +1,7 @@
package com.ilummc.tlib.clr;
public class CommandLineResolver {
}

View File

@@ -0,0 +1,42 @@
package com.ilummc.tlib.compat;
import me.clip.placeholderapi.PlaceholderAPI;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public abstract class PlaceholderHook {
private static PlaceholderHook impl;
public static void init() {
if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) {
impl = new PlaceholderImpl();
} else {
impl = new AbstractImpl();
}
}
public static String replace(CommandSender sender, String text) {
return sender instanceof Player ? impl.replace(((Player) sender), text) : text;
}
abstract String replace(Player player, String text);
private static class PlaceholderImpl extends PlaceholderHook {
@Override
String replace(Player player, String text) {
return PlaceholderAPI.setPlaceholders(player, text);
}
}
private static class AbstractImpl extends PlaceholderHook {
@Override
String replace(Player player, String text) {
return text;
}
}
}

View File

@@ -0,0 +1,59 @@
package com.ilummc.tlib.config;
import com.ilummc.tlib.annotations.TConfig;
import java.util.HashMap;
import java.util.Map;
/**
* @author sky
* @since 2018-04-22 14:31:11
*/
@TConfig(name = "tlib.yml")
public class TLibConfig {
private String dataSourceClassName;
private String jdbcUrl = "jdbc:h2:file:~/plugins/TabooLib/h2";
private String driverClassName;
private String username = "";
private String password = "";
private int maximumPoolSize = 4;
private Map<String, Object> settings = new HashMap<String, Object>() {{
put("cachePrepStmts", true);
put("useServerPrepStmts", true);
}};
public String getDataSourceClassName() {
return dataSourceClassName;
}
public String getJdbcUrl() {
return jdbcUrl;
}
public String getDriverClassName() {
return driverClassName;
}
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
public int getMaximumPoolSize() {
return maximumPoolSize;
}
public Map<String, Object> getSettings() {
return settings;
}
}

View File

@@ -0,0 +1,63 @@
package com.ilummc.tlib.db;
import com.ilummc.tlib.TLib;
import com.ilummc.tlib.resources.TLocale;
import org.javalite.activejdbc.Base;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
public final class Pool extends ThreadPoolExecutor {
private static final AtomicInteger number = new AtomicInteger(1);
private static final Pool singleton = new Pool();
private final TLibDataSource dataSource;
private Pool() {
super(TLib.getTLib().getConfig().getMaximumPoolSize(),
TLib.getTLib().getConfig().getMaximumPoolSize(),
0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
try {
dataSource = new TLibDataSource();
this.setThreadFactory(r -> new Thread(() -> {
Base.open(dataSource.getDataSource());
r.run();
}, "TabooLib-DbPool-" + number.getAndIncrement()));
prestartAllCoreThreads();
TLocale.sendToConsole("DATABASE.CONNECTION-ESTABLISHED", dataSource.getDataSource().getConnection().getMetaData().getDatabaseProductName(),
String.valueOf(TLib.getTLib().getConfig().getMaximumPoolSize()));
} catch (Exception e) {
TLocale.sendToConsole("DATABASE.CONNECTION-ERROR", e.toString());
throw new RuntimeException();
}
}
public static void run(Runnable runnable) {
instance().execute(runnable);
}
public static void init() {
}
public static void unload() {
instance().dataSource.disconnect();
instance().shutdown();
}
public static Pool instance() {
return singleton;
}
@Override
protected void afterExecute(Runnable r, Throwable t) {
if (t != null) {
Base.close();
}
}
}

View File

@@ -0,0 +1,35 @@
package com.ilummc.tlib.db;
import com.ilummc.tlib.TLib;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.javalite.activejdbc.Base;
import javax.sql.DataSource;
import java.util.Properties;
public class TLibDataSource {
private final HikariDataSource dataSource;
TLibDataSource() {
Properties properties = new Properties();
properties.put("jdbcUrl", TLib.getTLib().getConfig().getJdbcUrl());
properties.put("username", TLib.getTLib().getConfig().getUsername());
properties.put("password", TLib.getTLib().getConfig().getPassword());
properties.put("dataSourceClassName", TLib.getTLib().getConfig().getDataSourceClassName());
properties.put("driverClassName", TLib.getTLib().getConfig().getDriverClassName());
TLib.getTLib().getConfig().getSettings().forEach((k, v) -> properties.put("dataSource." + k, v));
dataSource = new HikariDataSource(new HikariConfig(properties));
Base.open(dataSource);
}
public DataSource getDataSource() {
return dataSource;
}
public void disconnect() {
Base.close();
}
}

View File

@@ -0,0 +1,80 @@
package com.ilummc.tlib.dependency;
import com.ilummc.eagletdl.EagletTask;
import com.ilummc.eagletdl.ProgressEvent;
import com.ilummc.tlib.resources.TLocale;
import me.skymc.taboolib.Main;
import java.io.File;
import java.util.concurrent.atomic.AtomicBoolean;
public class TDependency {
// 阿里 http://maven.aliyun.com/nexus/content/groups/public
// Maven Central
public static final String MAVEN_REPO = "http://repo1.maven.org/maven2";
/**
* 请求一个插件作为依赖,这个插件将会在所有已经添加的 Jenkins 仓库、Maven 仓库寻找
* <p>
* 阻塞线程进行下载/加载
*
* @param args 插件名称,下载地址(可选)
* @return 是否成功加载了依赖
*/
public static boolean requestPlugin(String... args) {
return false;
}
/**
* 请求一个库作为依赖,这个库将会在 Maven Central、oss.sonatype 以及自定义的 Maven 仓库寻找
* <p>
* 阻塞线程进行下载/加载
*
* @param type 依赖名,格式为 groupId:artifactId:version
* @return 是否成功加载库,如果加载成功,插件将可以任意调用使用的类
*/
public static boolean requestLib(String type, String repo, String url) {
if (type.matches(".*:.*:.*")) {
String[] arr = type.split(":");
File file = new File(Main.getInst().getDataFolder(), "/libs/" + String.join("-", arr) + ".jar");
if (file.exists()) {
TDependencyLoader.addToPath(Main.getInst(), file);
return true;
} else {
if (downloadMaven(repo, arr[0], arr[1], arr[2], file, url)) {
TDependencyLoader.addToPath(Main.getInst(), file);
return true;
} else {
return false;
}
}
}
return false;
}
private static boolean downloadMaven(String url, String groupId, String artifactId, String version, File target, String dl) {
if (Main.isOfflineVersion()) {
TLocale.Logger.warn("DEPENDENCY.DOWNLOAD-OFFLINE");
return false;
}
AtomicBoolean failed = new AtomicBoolean(false);
String link = dl.length() == 0 ? url + "/" + groupId.replace('.', '/') + "/" + artifactId + "/" + version + "/" + artifactId + "-" + version + ".jar" : dl;
new EagletTask()
.url(link)
.file(target)
.setThreads(1)
.setOnError(event -> event.getException().printStackTrace())
.setOnConnected(event -> TLocale.Logger.info("DEPENDENCY.DOWNLOAD-CONNECTED", String.join(":", new String[] {groupId, artifactId, version}), ProgressEvent.format(event.getContentLength())))
.setOnProgress(event -> TLocale.Logger.info("DEPENDENCY.DOWNLOAD-PROGRESS", event.getSpeedFormatted(), event.getPercentageFormatted()))
.setOnComplete(event -> {
if (event.isSuccess()) {
TLocale.Logger.info("DEPENDENCY.DOWNLOAD-SUCCESS", String.join(":", new String[] {groupId, artifactId, version}));
} else {
failed.set(true);
TLocale.Logger.error("DEPENDENCY.DOWNLOAD-FAILED", String.join(":", new String[] {groupId, artifactId, version}), link, target.getName());
}
}).start().waitUntil();
return !failed.get();
}
}

View File

@@ -0,0 +1,32 @@
package com.ilummc.tlib.dependency;
import org.bukkit.plugin.Plugin;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
public class TDependencyLoader {
public static synchronized void addToPath(Plugin plugin, URL url) {
try {
Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
method.setAccessible(true);
method.invoke(plugin.getClass().getClassLoader(), url);
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
public static synchronized void addToPath(Plugin plugin, File file) {
try {
addToPath(plugin, file.toURI().toURL());
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1,102 @@
package com.ilummc.tlib.filter;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.ilummc.tlib.filter.impl.FilterConfiguration;
import com.ilummc.tlib.filter.impl.FilterInvalidPluginLoader;
import me.skymc.taboolib.TabooLib;
import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.logging.Filter;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
/**
* @author Bkm016
* @since 2018-04-22
*/
public class TLoggerFilter implements Filter {
private Filter filter;
private Logger logger;
private static List<TLoggerFilterHandler> handlers = Lists.newLinkedList();
private static Map<String, TLoggerFilter> pluginFilter = Maps.newHashMap();
private static TLoggerFilter globalFilter;
private static String playerConnectionName;
static {
handlers.add(new FilterConfiguration());
handlers.add(new FilterInvalidPluginLoader());
// handlers.add(new FilterExceptionMirror());
}
public static void preInit() {
inject(new TLoggerFilter(), Bukkit.getLogger());
inject(new TLoggerFilter(), TabooLib.instance().getLogger());
try {
playerConnectionName = Class.forName("net.minecraft.server." + TabooLib.getVersion() + ".PlayerConnection").getName();
} catch (Exception ignored) {
}
}
public static void postInit() {
Arrays.stream(Bukkit.getPluginManager().getPlugins()).filter(TabooLib::isDependTabooLib).forEach(plugin -> inject(new TLoggerFilter(), plugin.getLogger()));
}
public static void inject0() {
inject(new TLoggerFilter(), Logger.getLogger(playerConnectionName));
}
public static void inject(TLoggerFilter filter, Logger logger) {
if (!(logger.getFilter() instanceof TLoggerFilter)) {
try {
filter.filter = logger.getFilter();
filter.logger = logger;
logger.setFilter(filter);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void eject(Plugin plugin) {
try {
if (plugin.getLogger().getFilter() instanceof TLoggerFilter) {
((TLoggerFilter) plugin.getLogger().getFilter()).filter = null;
((TLoggerFilter) plugin.getLogger().getFilter()).logger = null;
plugin.getLogger().setFilter(null);
}
} catch (Throwable t) {
t.printStackTrace();
}
}
public static TLoggerFilter getGlobalFilter() {
return globalFilter;
}
public static Map<String, TLoggerFilter> getPluginFilter() {
return pluginFilter;
}
public static List<TLoggerFilterHandler> getHandlers() {
return handlers;
}
public Filter getFilter() {
return filter;
}
public Logger getLogger() {
return logger;
}
@Override
public boolean isLoggable(LogRecord e) {
return handlers.stream().allMatch(filter -> filter.isLoggable(e)) && (filter == null || filter.isLoggable(e));
}
}

View File

@@ -0,0 +1,13 @@
package com.ilummc.tlib.filter;
import java.util.logging.LogRecord;
/**
* @Author 坏黑
* @Since 2018-11-29 11:42
*/
public abstract class TLoggerFilterHandler {
abstract public boolean isLoggable(LogRecord e);
}

View File

@@ -0,0 +1,28 @@
package com.ilummc.tlib.filter.impl;
import com.ilummc.tlib.filter.TLoggerFilterHandler;
import java.util.Arrays;
import java.util.logging.LogRecord;
/**
* @Author 坏黑
* @Since 2018-11-29 11:47
*/
public class FilterConfiguration extends TLoggerFilterHandler {
@Override
public boolean isLoggable(LogRecord e) {
if (String.valueOf(e.getMessage()).contains("Cannot load configuration from stream")) {
StackTraceElement[] elements = Thread.currentThread().getStackTrace();
for (StackTraceElement element : elements) {
if (element.getClassName().contains("ConfigUtils")) {
// Bukkit 拦截异常?我再扔一个
System.out.println(Arrays.asList(e.getParameters()));
}
}
return false;
}
return true;
}
}

View File

@@ -0,0 +1,119 @@
package com.ilummc.tlib.filter.impl;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.ilummc.tlib.filter.TLoggerFilterHandler;
import com.ilummc.tlib.resources.TLocale;
import me.skymc.taboolib.Main;
import me.skymc.taboolib.TabooLib;
import org.bukkit.command.CommandException;
import org.bukkit.event.EventException;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.LogRecord;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @Author 坏黑
* @Since 2018-11-29 11:42
*/
public class FilterExceptionMirror extends TLoggerFilterHandler {
interface ArgumentsCallback {
String[] run();
}
private static Pattern patternEvent = Pattern.compile("Could not pass event (.+?) to (.+?)");
private static Pattern patternCommand = Pattern.compile("Unhandled exception executing command '(.+?)' in plugin (.+?)");
/**
* 判断是否为调度器异常
*/
public boolean isScheduleException(LogRecord log) {
return String.valueOf(log.getMessage()).contains("generated an exception");
}
/**
* 是否为可捕捉异常
*/
public boolean isValidException(Throwable throwable) {
return throwable.getCause() != null && throwable.getCause().getStackTrace() != null && throwable.getCause().getStackTrace().length > 0;
}
/**
* 向控制台打印捕捉到的异常
*
* @param stackTraceElements 堆栈
* @param message 信息类型
* @param args 信息参数
* @return 是否成功捕捉并打印
*/
public boolean printException(AtomicReference<Plugin> plugin, StackTraceElement[] stackTraceElements, String message, ArgumentsCallback args) {
Set<Plugin> plugins = Sets.newHashSet();
List<StackTraceElement> stackTraces = Lists.newLinkedList();
for (StackTraceElement stack : stackTraceElements) {
try {
plugins.add(JavaPlugin.getProvidingPlugin(Class.forName(stack.getClassName())));
stackTraces.add(stack);
} catch (Exception ignored) {
}
}
if (!plugins.isEmpty() && plugins.stream().allMatch(p -> TabooLib.isTabooLib(p) || TabooLib.isDependTabooLib(p))) {
plugin.set(plugins.iterator().next());
TLocale.Logger.error("TFILTER.EXCEPTION-MIRROR." + message + ".HEAD", args.run());
for (int i = 0; i < stackTraces.size(); i++) {
StackTraceElement stack = stackTraces.get(i);
TLocale.Logger.error("TFILTER.EXCEPTION-MIRROR." + message + ".STACK-TRACE", String.valueOf(i), stack.toString());
}
return true;
}
return false;
}
@Override
public boolean isLoggable(LogRecord e) {
if (!Main.getInst().getConfig().getBoolean("EXCEPTION-MIRROR", true) || e.getThrown() == null) {
return true;
}
// 是否为调度器异常
if (isScheduleException(e)) {
long time = System.currentTimeMillis();
AtomicReference<Plugin> plugin = new AtomicReference<>();
return !printException(plugin, e.getThrown().getStackTrace(), "SCHEDULE", () -> new String[] {plugin.get().getName(), String.valueOf(System.currentTimeMillis() - time), e.getThrown().getClass().getSimpleName(), String.valueOf(e.getThrown().getMessage())});
}
// 是否为其他可捕捉异常
else if (isValidException(e.getThrown())) {
// 事件异常
if (e.getThrown() instanceof EventException) {
Matcher matcher = patternEvent.matcher(e.getMessage());
if (matcher.find()) {
long time = System.currentTimeMillis();
AtomicReference<Plugin> plugin = new AtomicReference<>();
return !printException(plugin, e.getThrown().getCause().getStackTrace(), "EVENT", () -> new String[] {plugin.get().getName(), String.valueOf(System.currentTimeMillis() - time), matcher.group(1), e.getThrown().getCause().getClass().getSimpleName(), String.valueOf(e.getThrown().getCause().getMessage())});
}
}
// 命令异常
else if (e.getThrown() instanceof CommandException) {
Matcher matcher = patternCommand.matcher(e.getThrown().getMessage());
if (matcher.find()) {
long time = System.currentTimeMillis();
AtomicReference<Plugin> plugin = new AtomicReference<>();
return !printException(plugin, e.getThrown().getCause().getStackTrace(), "COMMAND", () -> new String[] {plugin.get().getName(), String.valueOf(System.currentTimeMillis() - time), matcher.group(1), e.getThrown().getCause().getClass().getSimpleName(), String.valueOf(e.getThrown().getCause().getMessage())});
}
}
// 其他异常
else {
long time = System.currentTimeMillis();
AtomicReference<Plugin> plugin = new AtomicReference<>();
return !printException(plugin, e.getThrown().getCause().getStackTrace(), "OTHER", () -> new String[] {plugin.get().getName(), String.valueOf(System.currentTimeMillis() - time), e.getThrown().getCause().getClass().getSimpleName(), String.valueOf(e.getThrown().getCause().getMessage())});
}
}
return true;
}
}

View File

@@ -0,0 +1,18 @@
package com.ilummc.tlib.filter.impl;
import com.ilummc.tlib.filter.TLoggerFilterHandler;
import java.util.logging.LogRecord;
/**
* @Author 坏黑
* @Since 2018-11-29 11:47
*/
public class FilterInvalidPluginLoader extends TLoggerFilterHandler {
@Override
public boolean isLoggable(LogRecord e) {
// 屏蔽插件加载器注入导致的警告信息
return !String.valueOf(e.getMessage()).contains("Enabled plugin with unregistered PluginClassLoader");
}
}

View File

@@ -0,0 +1,143 @@
package com.ilummc.tlib.inject;
import com.google.common.io.Files;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.ilummc.tlib.annotations.TConfig;
import com.ilummc.tlib.resources.TLocale;
import me.skymc.taboolib.fileutils.ConfigUtils;
import org.apache.commons.lang3.Validate;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.plugin.Plugin;
import org.yaml.snakeyaml.DumperOptions;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
public class TConfigInjector {
public static void fixUnicode(YamlConfiguration configuration) {
try {
Field field = YamlConfiguration.class.getDeclaredField("yamlOptions");
field.setAccessible(true);
field.set(configuration, NoUnicodeDumperOption.INSTANCE);
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
}
private static final class NoUnicodeDumperOption extends DumperOptions {
private static final NoUnicodeDumperOption INSTANCE = new NoUnicodeDumperOption();
@Override
public void setAllowUnicode(boolean allowUnicode) {
super.setAllowUnicode(false);
}
@Override
public boolean isAllowUnicode() {
return false;
}
@Override
public void setLineBreak(LineBreak lineBreak) {
super.setLineBreak(LineBreak.getPlatformLineBreak());
}
}
public static Object loadConfig(Plugin plugin, Class<?> clazz) {
try {
TConfig config = clazz.getAnnotation(TConfig.class);
Validate.notNull(config);
File file = new File(plugin.getDataFolder(), config.name());
if (!file.exists()) {
if (config.fromJar()) {
plugin.saveResource(config.name(), true);
} else {
saveConfig(plugin, clazz.newInstance());
}
}
Object obj = unserialize(plugin, clazz);
if (config.readOnly()) {
saveConfig(plugin, obj);
}
return obj;
} catch (NullPointerException e) {
TLocale.Logger.warn("CONFIG.LOAD-FAIL-NO-ANNOTATION", plugin.toString(), clazz.getSimpleName());
} catch (Exception e) {
TLocale.Logger.warn("CONFIG.LOAD-FAIL", plugin.toString(), clazz.getSimpleName());
}
return null;
}
public static void reloadConfig(Plugin plugin, Object object) {
try {
TConfig config = object.getClass().getAnnotation(TConfig.class);
Validate.notNull(config);
File file = new File(plugin.getDataFolder(), config.name());
Map<String, Object> map = ConfigUtils.confToMap(ConfigUtils.loadYaml(plugin, file));
Object obj = ConfigUtils.mapToObj(map, object);
if (config.readOnly()) {
saveConfig(plugin, obj);
}
} catch (NullPointerException e) {
TLocale.Logger.warn("CONFIG.LOAD-FAIL-NO-ANNOTATION", plugin.toString(), object.getClass().getSimpleName());
} catch (Exception e) {
TLocale.Logger.warn("CONFIG.LOAD-FAIL", plugin.toString(), object.getClass().getSimpleName());
}
}
public static Object unserialize(Plugin plugin, Class<?> clazz) {
try {
TConfig config = clazz.getAnnotation(TConfig.class);
Validate.notNull(config);
return ConfigUtils.confToObj(
ConfigUtils.mapToConf(
ConfigUtils.yamlToMap(
Files.toString(new File(plugin.getDataFolder(), config.name()), Charset.forName(config.charset())))), clazz);
} catch (NullPointerException e) {
TLocale.Logger.warn("CONFIG.LOAD-FAIL-NO-FILE", plugin.toString(), clazz.getSimpleName());
return null;
} catch (Exception e) {
try {
return clazz.newInstance();
} catch (InstantiationException | IllegalAccessException e1) {
TLocale.Logger.warn("CONFIG.LOAD-FAIL", plugin.toString(), clazz.getSimpleName());
return null;
}
}
}
public static Map<String, Object> serialize(Plugin plugin, Object object) {
try {
TConfig config = object.getClass().getAnnotation(TConfig.class);
Validate.notNull(config);
return ConfigUtils.objToMap(ConfigUtils.objToConf(object).getValues(false), config.excludeModifiers());
} catch (NullPointerException e) {
TLocale.Logger.warn("CONFIG.SAVE-FAIL-NO-ANNOTATION", plugin.toString(), object.getClass().getSimpleName());
} catch (Exception e) {
TLocale.Logger.warn("CONFIG.SAVE-FAIL", plugin.toString(), object.getClass().getSimpleName());
}
return null;
}
public static void saveConfig(Plugin plugin, Object object) throws IOException, NullPointerException {
TConfig config = object.getClass().getAnnotation(TConfig.class);
Validate.notNull(config);
Gson gson = new GsonBuilder().disableHtmlEscaping().create();
Map map = gson.fromJson(gson.toJson(object), HashMap.class);
YamlConfiguration configuration = (YamlConfiguration) ConfigUtils.mapToConf(map);
File target = new File(plugin.getDataFolder(), config.name());
if (!target.exists()) {
target.createNewFile();
}
byte[] arr = configuration.saveToString().getBytes(config.charset());
Files.write(arr, target);
}
}

View File

@@ -0,0 +1,87 @@
package com.ilummc.tlib.inject;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.apache.commons.lang3.tuple.Triple;
import java.io.File;
import java.io.IOException;
import java.nio.file.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
/**
* @author lzzelAliz
*/
public class TConfigWatcher {
private final ScheduledExecutorService service = Executors.newScheduledThreadPool(1, new BasicThreadFactory.Builder().namingPattern("TConfigWatcherService-%d").build());
private final Map<WatchService, Triple<File, Object, Consumer<Object>>> map = new HashMap<>();
public TConfigWatcher() {
service.scheduleAtFixedRate(() -> {
synchronized (map) {
map.forEach((service, triple) -> {
WatchKey key;
while ((key = service.poll()) != null) {
for (WatchEvent<?> watchEvent : key.pollEvents()) {
if (triple.getLeft().getName().equals(Objects.toString(watchEvent.context()))) {
triple.getRight().accept(triple.getMiddle());
}
}
key.reset();
}
});
}
}, 1000, 100, TimeUnit.MILLISECONDS);
}
public void addSimpleListener(File file, Runnable runnable) {
addListener(file, null, obj -> runnable.run());
}
public void addOnListen(File file, Object obj, Consumer<Object> consumer) {
try {
WatchService service = FileSystems.getDefault().newWatchService();
file.getParentFile().toPath().register(service, StandardWatchEventKinds.ENTRY_MODIFY);
map.putIfAbsent(service, Triple.of(file, obj, consumer));
} catch (IOException e) {
e.printStackTrace();
}
}
@SuppressWarnings("unchecked")
public <T> void addListener(File file, T obj, Consumer<T> consumer) {
addOnListen(file, obj, (Consumer<Object>) consumer);
}
public void removeListener(File file) {
synchronized (map) {
map.entrySet().removeIf(entry -> {
if (entry.getValue().getLeft().equals(file)) {
try {
entry.getKey().close();
} catch (IOException ignored) {
}
return true;
}
return false;
});
}
}
public void unregisterAll() {
service.shutdown();
map.forEach((service, pair) -> {
try {
service.close();
} catch (IOException e) {
e.printStackTrace();
}
});
}
}

View File

@@ -0,0 +1,188 @@
package com.ilummc.tlib.inject;
import com.ilummc.tlib.TLib;
import com.ilummc.tlib.annotations.*;
import com.ilummc.tlib.dependency.TDependency;
import com.ilummc.tlib.resources.TLocale;
import com.ilummc.tlib.resources.TLocaleLoader;
import com.ilummc.tlib.util.Ref;
import me.skymc.taboolib.TabooLib;
import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin;
import java.io.File;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
/**
* @author Izzel_Aliz
*/
public class TDependencyInjector {
private static List<String> injected = new ArrayList<>();
static void injectOnEnable(Plugin plugin) {
inject(plugin, plugin);
}
static void ejectOnDisable(Plugin plugin) {
eject(plugin, plugin);
}
public static boolean injected(Plugin plugin) {
return injected.contains(plugin.getName());
}
public static void inject(Plugin plugin, Object o) {
if (!injected.contains(plugin.getName())) {
injected.add(plugin.getName());
TLocaleLoader.load(plugin, true);
injectDependencies(plugin, o);
injectLogger(plugin, o);
injectConfig(plugin, o);
injectPluginInstance(plugin, o);
}
}
public static void eject(Plugin plugin, Object o) {
try {
injected.remove(plugin.getName());
ejectConfig(plugin, o);
} catch (Throwable ignored) {
}
}
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;
}
private static void ejectConfig(Plugin plugin, Object o) {
for (Field field : Ref.getDeclaredFields(o.getClass())) {
TConfig config;
if ((config = field.getType().getAnnotation(TConfig.class)) != null && config.saveOnExit()) {
try {
field.setAccessible(true);
TConfigInjector.saveConfig(plugin, field.get(o));
TLocale.Logger.info("CONFIG.SAVE-SUCCESS", plugin.toString(), config.name());
} catch (Exception e) {
TLocale.Logger.warn("CONFIG.SAVE-FAIL", plugin.toString(), config.name());
e.printStackTrace();
}
}
}
}
private static void injectConfig(Plugin plugin, Object o) {
for (Field field : Ref.getDeclaredFields(o.getClass())) {
try {
TConfig config;
if ((config = field.getType().getAnnotation(TConfig.class)) != null) {
field.setAccessible(true);
Object obj = TConfigInjector.loadConfig(plugin, field.getType());
if (obj != null) {
TLocale.Logger.info("CONFIG.LOAD-SUCCESS", plugin.toString(), config.name());
field.set(o, obj);
if (config.listenChanges()) {
TLocale.Logger.info("CONFIG.LISTEN-START", plugin.toString(), config.name());
TLib.getTLib().getConfigWatcher().addOnListen(
new File(plugin.getDataFolder(), config.name()),
obj,
object -> {
try {
TConfigInjector.reloadConfig(plugin, object);
TLocale.Logger.info("CONFIG.RELOAD-SUCCESS", plugin.toString(), config.name());
} catch (Exception ignored) {
TLocale.Logger.warn("CONFIG.RELOAD-FAIL", plugin.toString(), config.name());
}
}
);
}
}
}
} catch (Exception ignored) {
}
}
}
private static void injectLogger(Plugin plugin, Object o) {
for (Field field : Ref.getDeclaredFields(o.getClass())) {
try {
Logger logger;
if ((logger = field.getAnnotation(Logger.class)) != null) {
field.getType().asSubclass(com.ilummc.tlib.logger.TLogger.class);
com.ilummc.tlib.logger.TLogger tLogger = new com.ilummc.tlib.logger.TLogger(logger.value(), plugin, logger.level());
if (!field.isAccessible()) {
field.setAccessible(true);
}
field.set(o, tLogger);
TLoggerManager.setDefaultLogger(plugin, tLogger);
}
} catch (Exception ignored2) {
}
}
}
private static void injectPluginInstance(Plugin plugin, Object o) {
for (Field field : Ref.getDeclaredFields(o.getClass())) {
try {
PluginInstance instance;
if ((instance = field.getAnnotation(PluginInstance.class)) != null) {
if (!field.isAccessible()) {
field.setAccessible(true);
}
field.getType().asSubclass(JavaPlugin.class);
Plugin pl;
if ((pl = Bukkit.getPluginManager().getPlugin(instance.value())) == null) {
if (!TDependency.requestPlugin(instance.value())) {
TLocale.Logger.warn("PLUGIN-AUTOLOAD-FAIL", plugin.getName(), instance.value());
return;
} else {
pl = Bukkit.getPluginManager().getPlugin(instance.value());
}
}
if (pl != null) {
field.set(o, pl);
}
}
} catch (Exception ignored) {
}
}
}
private static void injectDependencies(Plugin plugin, Object o) {
Dependency[] dependencies = getDependencies(o);
if (dependencies.length != 0) {
TLocale.Logger.info("DEPENDENCY.LOADING-START", plugin.getName());
for (Dependency dependency : dependencies) {
if (dependency.type() == Dependency.Type.PLUGIN) {
if (TDependency.requestPlugin(dependency.plugin())) {
TabooLib.debug(" Loaded " + dependency.plugin() + " (" + plugin.getName() + ")");
// TLocale.Logger.info("DEPENDENCY.PLUGIN-LOAD-SUCCESS", plugin.getName(), dependency.plugin());
} else {
TLocale.Logger.warn("DEPENDENCY.PLUGIN-LOAD-FAIL", plugin.getName(), dependency.plugin());
}
}
if (dependency.type() == Dependency.Type.LIBRARY) {
if (TDependency.requestLib(dependency.maven(), dependency.mavenRepo(), dependency.url())) {
TabooLib.debug(" Loaded " + String.join(":", dependency.maven()) + " (" + plugin.getName() + ")");
// TLocale.Logger.info("DEPENDENCY.LIBRARY-LOAD-SUCCESS", plugin.getName(), String.join(":", dependency.maven()));
} else {
TLocale.Logger.warn("DEPENDENCY.LIBRARY-LOAD-FAIL", plugin.getName(), String.join(":", dependency.maven()));
}
}
}
TLocale.Logger.info("DEPENDENCY.LOAD-COMPLETE");
}
}
}

View File

@@ -0,0 +1,25 @@
package com.ilummc.tlib.inject;
import com.ilummc.tlib.logger.TLogger;
import org.bukkit.plugin.Plugin;
import java.util.HashMap;
import java.util.Map;
public class TLoggerManager {
private static final Map<Plugin, TLogger> map = new HashMap<>();
public static void setDefaultLogger(Plugin plugin, TLogger logger) {
map.put(plugin, logger);
}
public static TLogger getLogger(Plugin plugin) {
TLogger logger = map.get(plugin);
if (logger == null) {
logger = TLogger.getUnformatted(plugin);
map.put(plugin, logger);
}
return logger;
}
}

View File

@@ -0,0 +1,231 @@
package com.ilummc.tlib.inject;
import com.ilummc.tlib.resources.TLocale;
import me.skymc.taboolib.Main;
import org.bukkit.Bukkit;
import org.bukkit.Server;
import org.bukkit.command.SimpleCommandMap;
import org.bukkit.event.Event;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.permissions.Permissible;
import org.bukkit.permissions.Permission;
import org.bukkit.plugin.*;
import java.io.File;
import java.lang.reflect.Field;
import java.util.*;
import java.util.regex.Pattern;
@SuppressWarnings("unused")
public class TPluginManager implements PluginManager {
private static TPluginManager singleton;
private final PluginManager instance;
private final Main main = (Main) Main.getInst();
private static File updateDirectory = null;
private Server server;
private Map<Pattern, PluginLoader> fileAssociations = new HashMap<>();
private List<Plugin> plugins = new ArrayList<>();
private Map<String, Plugin> lookupNames = new HashMap<>();
private SimpleCommandMap commandMap;
private Map<String, Permission> permissions = new HashMap<>();
private Map<Boolean, Set<Permission>> defaultPerms = new LinkedHashMap<>();
private Map<String, Map<Permissible, Boolean>> permSubs = new HashMap<>();
private Map<Boolean, Map<Permissible, Boolean>> defSubs = new HashMap<>();
private boolean useTimings = false;
private List<Plugin> delayedDisable = new ArrayList<>();
public static void delayDisable(Plugin plugin) {
if (!singleton.delayedDisable.contains(plugin)) {
singleton.delayedDisable.add(plugin);
}
}
public TPluginManager() {
instance = Bukkit.getPluginManager();
// clone all Field in SimplePluginManager
cloneField("updateDirectory");
cloneField("server");
cloneField("fileAssociations");
cloneField("plugins");
cloneField("lookupNames");
cloneField("commandMap");
cloneField("permissions");
cloneField("defaultPerms");
cloneField("permSubs");
cloneField("defSubs");
cloneField("useTimings");
singleton = this;
}
private void cloneField(String bukkitName) {
try {
Field bukkitField = instance.getClass().getDeclaredField(bukkitName);
Field thisFiled = this.getClass().getDeclaredField(bukkitName);
if (bukkitField == null || thisFiled == null) {
TLocale.Logger.warn("MISC.FIELD-COPY-FAILED", bukkitName);
return;
}
bukkitField.setAccessible(true);
thisFiled.setAccessible(true);
thisFiled.set(this, bukkitField.get(instance));
} catch (Exception e) {
TLocale.Logger.error("MISC.FIELD-COPY-ERROR", bukkitName, e.toString());
}
}
@Override
public void registerInterface(Class<? extends PluginLoader> aClass) throws IllegalArgumentException {
instance.registerInterface(aClass);
}
@Override
public Plugin getPlugin(String s) {
return instance.getPlugin(s);
}
@Override
public Plugin[] getPlugins() {
return instance.getPlugins();
}
@Override
public boolean isPluginEnabled(String s) {
return instance.isPluginEnabled(s);
}
@Override
public boolean isPluginEnabled(Plugin plugin) {
return instance.isPluginEnabled(plugin);
}
@Override
public Plugin loadPlugin(File file) throws InvalidPluginException, InvalidDescriptionException, UnknownDependencyException {
return instance.loadPlugin(file);
}
@Override
public Plugin[] loadPlugins(File file) {
return instance.loadPlugins(file);
}
@Override
public void disablePlugins() {
for (Plugin plugin : getPlugins()) {
if (plugin != main && !delayedDisable.contains(plugin)) {
disablePlugin(plugin);
}
}
Collections.reverse(delayedDisable);
delayedDisable.forEach(singleton::disablePlugin);
disablePlugin(main);
}
@Override
public void clearPlugins() {
instance.clearPlugins();
}
@Override
public void callEvent(Event event) throws IllegalStateException {
instance.callEvent(event);
}
@Override
public void registerEvents(Listener listener, Plugin plugin) {
instance.registerEvents(listener, plugin);
}
@Override
public void registerEvent(Class<? extends Event> aClass, Listener listener, EventPriority eventPriority, EventExecutor eventExecutor, Plugin plugin) {
instance.registerEvent(aClass, listener, eventPriority, eventExecutor, plugin);
}
@Override
public void registerEvent(Class<? extends Event> aClass, Listener listener, EventPriority eventPriority, EventExecutor eventExecutor, Plugin plugin, boolean b) {
instance.registerEvent(aClass, listener, eventPriority, eventExecutor, plugin, b);
}
@Override
public void enablePlugin(Plugin plugin) {
TDependencyInjector.injectOnEnable(plugin);
instance.enablePlugin(plugin);
}
@Override
public void disablePlugin(Plugin plugin) {
TDependencyInjector.ejectOnDisable(plugin);
instance.disablePlugin(plugin);
}
@Override
public Permission getPermission(String s) {
return instance.getPermission(s);
}
@Override
public void addPermission(Permission permission) {
instance.addPermission(permission);
}
@Override
public void removePermission(Permission permission) {
instance.removePermission(permission);
}
@Override
public void removePermission(String s) {
instance.removePermission(s);
}
@Override
public Set<Permission> getDefaultPermissions(boolean b) {
return instance.getDefaultPermissions(b);
}
@Override
public void recalculatePermissionDefaults(Permission permission) {
instance.recalculatePermissionDefaults(permission);
}
@Override
public void subscribeToPermission(String s, Permissible permissible) {
instance.subscribeToPermission(s, permissible);
}
@Override
public void unsubscribeFromPermission(String s, Permissible permissible) {
instance.unsubscribeFromPermission(s, permissible);
}
@Override
public Set<Permissible> getPermissionSubscriptions(String s) {
return instance.getPermissionSubscriptions(s);
}
@Override
public void subscribeToDefaultPerms(boolean b, Permissible permissible) {
instance.subscribeToDefaultPerms(b, permissible);
}
@Override
public void unsubscribeFromDefaultPerms(boolean b, Permissible permissible) {
instance.unsubscribeFromDefaultPerms(b, permissible);
}
@Override
public Set<Permissible> getDefaultPermSubscriptions(boolean b) {
return instance.getDefaultPermSubscriptions(b);
}
@Override
public Set<Permission> getPermissions() {
return instance.getPermissions();
}
@Override
public boolean useTimings() {
return instance.useTimings();
}
}

View File

@@ -0,0 +1,130 @@
package com.ilummc.tlib.logger;
import com.ilummc.tlib.resources.TLocale;
import com.ilummc.tlib.util.Strings;
import me.skymc.taboolib.Main;
import me.skymc.taboolib.TabooLib;
import net.md_5.bungee.BungeeCord;
import net.md_5.bungee.api.chat.TextComponent;
import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;
public class TLogger {
public static final int VERBOSE = 0, FINEST = 1, FINE = 2, INFO = 3, WARN = 4, ERROR = 5, FATAL = 6;
private static TLogger globalLogger = new TLogger("§8[§3§lTabooLib§8][§r{1}§8] §f{2}", Main.getInst(), TLogger.FINE);
private final String pattern;
private String name;
private int level;
public static TLogger getGlobalLogger() {
return globalLogger;
}
public String getPattern() {
return pattern;
}
public String getName() {
return name;
}
public int getLevel() {
return level;
}
public void setLevel(int level) {
this.level = level;
}
public TLogger(String pattern, Plugin plugin, int level) {
this.pattern = pattern;
this.name = plugin.getName();
this.level = level;
}
public TLogger(String pattern, String name, int level) {
this.pattern = pattern;
this.name = name;
this.level = level;
}
public void verbose(String msg) {
if (level <= VERBOSE) {
if (TabooLib.isSpigot()) {
Bukkit.getConsoleSender().sendMessage(Strings.replaceWithOrder(pattern, name, "§f全部", TLocale.Translate.setColored(msg)));
} else {
BungeeCord.getInstance().getConsole().sendMessage(TextComponent.fromLegacyText(Strings.replaceWithOrder(pattern, name, "§f全部", TLocale.Translate.setColored(msg))));
}
}
}
public void finest(String msg) {
if (level <= FINEST) {
if (TabooLib.isSpigot()) {
Bukkit.getConsoleSender().sendMessage(Strings.replaceWithOrder(pattern, name, "§e良好", TLocale.Translate.setColored(msg)));
} else {
BungeeCord.getInstance().getConsole().sendMessage(TextComponent.fromLegacyText(Strings.replaceWithOrder(pattern, name, "§e良好", TLocale.Translate.setColored(msg))));
}
}
}
public void fine(String msg) {
if (level <= FINE) {
if (TabooLib.isSpigot()) {
Bukkit.getConsoleSender().sendMessage(Strings.replaceWithOrder(pattern, name, "§a正常", TLocale.Translate.setColored(msg)));
} else {
BungeeCord.getInstance().getConsole().sendMessage(TextComponent.fromLegacyText(Strings.replaceWithOrder(pattern, name, "§a正常", TLocale.Translate.setColored(msg))));
}
}
}
public void info(String msg) {
if (level <= INFO) {
if (TabooLib.isSpigot()) {
Bukkit.getConsoleSender().sendMessage(Strings.replaceWithOrder(pattern, name, "§b信息", TLocale.Translate.setColored(msg)));
} else {
BungeeCord.getInstance().getConsole().sendMessage(TextComponent.fromLegacyText(Strings.replaceWithOrder(pattern, name, "§b信息", TLocale.Translate.setColored(msg))));
}
}
}
public void warn(String msg) {
if (level <= WARN) {
if (TabooLib.isSpigot()) {
Bukkit.getConsoleSender().sendMessage(Strings.replaceWithOrder(pattern, name, "§6警告", "§6" + TLocale.Translate.setColored(msg)));
} else {
BungeeCord.getInstance().getConsole().sendMessage(TextComponent.fromLegacyText(Strings.replaceWithOrder(pattern, name, "§6警告", "§6" + TLocale.Translate.setColored(msg))));
}
}
}
public void error(String msg) {
if (level <= ERROR) {
if (TabooLib.isSpigot()) {
Bukkit.getConsoleSender().sendMessage(Strings.replaceWithOrder(pattern, name, "§c错误", "§c" + TLocale.Translate.setColored(msg)));
} else {
BungeeCord.getInstance().getConsole().sendMessage(TextComponent.fromLegacyText(Strings.replaceWithOrder(pattern, name, "§c错误", "§c" + TLocale.Translate.setColored(msg))));
}
}
}
public void fatal(String msg) {
if (level <= FATAL) {
if (TabooLib.isSpigot()) {
Bukkit.getConsoleSender().sendMessage(Strings.replaceWithOrder(pattern, name, "§4致命错误", "§4" + TLocale.Translate.setColored(msg)));
} else {
BungeeCord.getInstance().getConsole().sendMessage(TextComponent.fromLegacyText(Strings.replaceWithOrder(pattern, name, "§4致命错误", "§4" + TLocale.Translate.setColored(msg))));
}
}
}
public static TLogger getUnformatted(Plugin plugin) {
return new TLogger("§8[§3§l{0}§8][§r{1}§8] §f{2}", plugin, TLogger.FINE);
}
public static TLogger getUnformatted(String name) {
return new TLogger("§8[§3§l{0}§8][§r{1}§8] §f{2}", name, TLogger.FINE);
}
}

View File

@@ -0,0 +1,47 @@
package com.ilummc.tlib.nms;
import com.ilummc.tlib.util.asm.AsmClassTransformer;
import me.skymc.taboolib.TabooLib;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
public abstract class ActionBar {
private static ActionBar instance;
static {
if (TabooLib.getVerint() > 11100) {
instance = (ActionBar) AsmClassTransformer.builder().from(Impl_1_12.class).fromVersion("v1_12_R1")
.toVersion(Bukkit.getServer().getClass().getName().split("\\.")[3]).build().transform();
} else {
instance = (ActionBar) AsmClassTransformer.builder().from(Impl_1_8.class).fromVersion("v1_8_R3")
.toVersion(Bukkit.getServer().getClass().getName().split("\\.")[3]).build().transform();
}
}
public static void sendActionBar(Player player, String text) {
instance.send(player, text);
}
public abstract void send(Player player, String text);
public static class Impl_1_8 extends ActionBar {
@Override
public void send(Player player, String text) {
net.minecraft.server.v1_8_R3.ChatComponentText component = new net.minecraft.server.v1_8_R3.ChatComponentText(text);
net.minecraft.server.v1_8_R3.PacketPlayOutChat packet = new net.minecraft.server.v1_8_R3.PacketPlayOutChat(component, (byte) 2);
((org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer) player).getHandle().playerConnection.sendPacket(packet);
}
}
public static class Impl_1_12 extends ActionBar {
@Override
public void send(Player player, String text) {
net.minecraft.server.v1_12_R1.ChatComponentText component = new net.minecraft.server.v1_12_R1.ChatComponentText(text);
net.minecraft.server.v1_12_R1.PacketPlayOutChat packet = new net.minecraft.server.v1_12_R1.PacketPlayOutChat(component, net.minecraft.server.v1_12_R1.ChatMessageType.a((byte) 2));
((org.bukkit.craftbukkit.v1_12_R1.entity.CraftPlayer) player).getHandle().playerConnection.sendPacket(packet);
}
}
}

View File

@@ -0,0 +1,161 @@
package com.ilummc.tlib.resources;
import com.ilummc.tlib.TLib;
import com.ilummc.tlib.bungee.api.ChatColor;
import com.ilummc.tlib.bungee.api.chat.TextComponent;
import com.ilummc.tlib.bungee.chat.ComponentSerializer;
import com.ilummc.tlib.inject.TLoggerManager;
import com.ilummc.tlib.util.Ref;
import com.ilummc.tlib.util.Strings;
import me.clip.placeholderapi.PlaceholderAPI;
import me.skymc.taboolib.Main;
import me.skymc.taboolib.common.nms.NMSHandler;
import me.skymc.taboolib.json.tellraw.TellrawCreator;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
/**
* @author IzzelAliz
*/
public class TLocale {
private TLocale() {
throw new AssertionError();
}
static String asString(String path, Class<?> callerClass, String... args) {
return TLocaleLoader.asString(Ref.getCallerPlugin(callerClass), path, args);
}
static List<String> asStringList(String path, Class<?> callerClass, String... args) {
return TLocaleLoader.asStringList(Ref.getCallerPlugin(callerClass), path, args);
}
private static void sendTo(String path, CommandSender sender, String[] args, Class<?> callerClass) {
TLocaleLoader.sendTo(Ref.getCallerPlugin(callerClass), path, sender, args);
}
public static void sendToConsole(String path, String... args) {
Ref.getCallerClass(3).ifPresent(clazz -> sendTo(path, Bukkit.getConsoleSender(), args, clazz));
}
public static void sendTo(CommandSender sender, String path, String... args) {
Ref.getCallerClass(3).ifPresent(clazz -> sendTo(path, sender, args, clazz));
}
public static void sendTo(String path, CommandSender sender, String... args) {
Ref.getCallerClass(3).ifPresent(clazz -> sendTo(path, sender, args, clazz));
}
public static String asString(String path, String... args) {
try {
return asString(path, Ref.getCallerClass(3).orElse(Main.class), args);
} catch (Exception e) {
TLib.getTLib().getLogger().error(Strings.replaceWithOrder(TLib.getInternalLanguage().getString("FETCH-LOCALE-ERROR"), path));
TLib.getTLib().getLogger().error(Strings.replaceWithOrder(TLib.getInternalLanguage().getString("LOCALE-ERROR-REASON"), e.getMessage()));
return "§4<" + path + "§4>";
}
}
public static List<String> asStringList(String path, String... args) {
try {
return asStringList(path, Ref.getCallerClass(3).orElse(Main.class), args);
} catch (Exception e) {
TLib.getTLib().getLogger().error(Strings.replaceWithOrder(TLib.getInternalLanguage().getString("LOCALE-ERROR-REASON"), e.getMessage()));
return Collections.singletonList("§4<" + path + "§4>");
}
}
public static void reload() {
Ref.getCallerClass(3).ifPresent(clazz -> TLocaleLoader.load(Ref.getCallerPlugin(clazz), false));
}
public static final class Tellraw extends TLocale {
public static void send(CommandSender sender, String rawMessage) {
if (sender instanceof Player) {
TellrawCreator.getAbstractTellraw().sendRawMessage((Player) sender, rawMessage);
} else {
sender.sendMessage(TextComponent.toLegacyText(ComponentSerializer.parse(rawMessage)));
}
}
}
public static final class Display extends TLocale {
public static void sendTitle(Player player, String title, String subTitle) {
sendTitle(player, title, subTitle, 10, 20, 10);
}
public static void sendTitle(Player player, String title, String subTitle, int fadein, int stay, int fadeout) {
NMSHandler.getHandler().sendTitle(player, title, fadein, stay, fadeout, subTitle, fadein, stay, fadeout);
}
public static void sendActionBar(Player player, String text) {
NMSHandler.getHandler().sendActionBar(player, text);
}
}
public static final class Translate extends TLocale {
public static boolean isPlaceholderUseDefault() {
return Main.getInst().getConfig().getBoolean("LOCALE.USE_PAPI", false);
}
public static boolean isPlaceholderPluginEnabled() {
return Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null && Bukkit.getPluginManager().getPlugin("PlaceholderAPI").isEnabled();
}
public static String setColored(String args) {
return ChatColor.translateAlternateColorCodes('&', args);
}
public static List<String> setColored(List<String> args) {
return args.stream().map(var -> ChatColor.translateAlternateColorCodes('&', var)).collect(Collectors.toList());
}
public static String setPlaceholders(CommandSender sender, String args) {
return isPlaceholderPluginEnabled() ? sender instanceof Player ? PlaceholderAPI.setPlaceholders((Player) sender, args) : args : args;
}
public static List<String> setPlaceholders(CommandSender sender, List<String> args) {
return isPlaceholderPluginEnabled() ? sender instanceof Player ? PlaceholderAPI.setPlaceholders((Player) sender, args) : args : args;
}
}
public static final class Logger extends TLocale {
public static void info(String path, String... args) {
Ref.getCallerClass(3).ifPresent(clazz -> asStringList(path, clazz, args).forEach(locale -> TLoggerManager.getLogger(Ref.getCallerPlugin(clazz)).info(locale)));
}
public static void warn(String path, String... args) {
Ref.getCallerClass(3).ifPresent(clazz -> asStringList(path, clazz, args).forEach(locale -> TLoggerManager.getLogger(Ref.getCallerPlugin(clazz)).warn(locale)));
}
public static void error(String path, String... args) {
Ref.getCallerClass(3).ifPresent(clazz -> asStringList(path, clazz, args).forEach(locale -> TLoggerManager.getLogger(Ref.getCallerPlugin(clazz)).error(locale)));
}
public static void fatal(String path, String... args) {
Ref.getCallerClass(3).ifPresent(clazz -> asStringList(path, clazz, args).forEach(locale -> TLoggerManager.getLogger(Ref.getCallerPlugin(clazz)).fatal(locale)));
}
public static void fine(String path, String... args) {
Ref.getCallerClass(3).ifPresent(clazz -> asStringList(path, clazz, args).forEach(locale -> TLoggerManager.getLogger(Ref.getCallerPlugin(clazz)).fine(locale)));
}
public static void finest(String path, String... args) {
Ref.getCallerClass(3).ifPresent(clazz -> asStringList(path, clazz, args).forEach(locale -> TLoggerManager.getLogger(Ref.getCallerPlugin(clazz)).finest(locale)));
}
public static void verbose(String path, String... args) {
Ref.getCallerClass(3).ifPresent(clazz -> asStringList(path, clazz, args).forEach(locale -> TLoggerManager.getLogger(Ref.getCallerPlugin(clazz)).verbose(locale)));
}
}
}

View File

@@ -0,0 +1,115 @@
package com.ilummc.tlib.resources;
import com.google.common.collect.ImmutableList;
import com.ilummc.tlib.TLib;
import com.ilummc.tlib.resources.type.TLocaleText;
import com.ilummc.tlib.util.Strings;
import me.skymc.taboolib.TabooLib;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.plugin.Plugin;
import javax.annotation.concurrent.ThreadSafe;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
@ThreadSafe
@SuppressWarnings("rawtypes")
class TLocaleInstance {
private final Map<String, List<TLocaleSerialize>> map = new HashMap<>();
private final Plugin plugin;
private final AtomicInteger latestUpdateNodes = new AtomicInteger();
TLocaleInstance(Plugin plugin) {
this.plugin = plugin;
}
@Override
public String toString() {
return map.toString();
}
public int size() {
return map.size();
}
public Map<String, List<TLocaleSerialize>> getMap() {
return map;
}
public Plugin getPlugin() {
return plugin;
}
public AtomicInteger getLatestUpdateNodes() {
return latestUpdateNodes;
}
public void sendTo(String path, CommandSender sender, String... args) {
try {
map.getOrDefault(path, ImmutableList.of(TLocaleSerialize.getEmpty(path))).forEach(tSender -> {
if (Bukkit.isPrimaryThread() || "true".equals(System.getProperty("tlib.forceAsync"))) {
tSender.sendTo(sender, args);
} else {
Bukkit.getScheduler().runTask(plugin, () -> tSender.sendTo(sender, args));
}
});
} catch (Exception | Error e) {
TLib.getTLib().getLogger().error(Strings.replaceWithOrder(TLib.getInternalLanguage().getString("SEND-LOCALE-ERROR"), path));
TLib.getTLib().getLogger().error(Strings.replaceWithOrder(TLib.getInternalLanguage().getString("LOCALE-ERROR-REASON"), e.toString()));
}
}
public String asString(String path, String... args) {
return map.getOrDefault(path, ImmutableList.of(TLocaleSerialize.getEmpty(path))).get(0).asString(args);
}
public List<String> asStringList(String path, String... args) {
return map.getOrDefault(path, ImmutableList.of(TLocaleSerialize.getEmpty(path))).get(0).asStringList(args);
}
private static boolean isListString(List list) {
for (Object o : list) {
if (!(o instanceof String)) {
return false;
}
}
return true;
}
public void load(YamlConfiguration configuration) {
load(configuration, false);
}
public void load(YamlConfiguration configuration, boolean cleanup) {
int originNodes = map.size();
int updateNodes = 0;
if (cleanup) {
map.clear();
}
for (String s : configuration.getKeys(true)) {
boolean updated = false;
Object value = configuration.get(s);
if (value instanceof TLocaleSerialize) {
updated = map.put(s, Collections.singletonList((TLocaleSerialize) value)) != null;
} else if (value instanceof List && !((List) value).isEmpty()) {
if (isListString((List) value)) {
updated = map.put(s, Collections.singletonList(TLocaleText.of(value))) != null;
} else {
updated = map.put(s, ((List<?>) value).stream().map(o -> o instanceof TLocaleSerialize ? (TLocaleSerialize) o : TLocaleText.of(String.valueOf(o))).collect(Collectors.toList())) != null;
}
} else if (!(value instanceof ConfigurationSection)) {
String str = String.valueOf(value);
updated = map.put(s, Collections.singletonList(str.length() == 0 ? TLocaleSerialize.getEmpty() : TLocaleText.of(str))) != null;
}
if (updated) {
updateNodes++;
}
}
latestUpdateNodes.set(originNodes - updateNodes);
}
}

View File

@@ -0,0 +1,169 @@
package com.ilummc.tlib.resources;
import com.ilummc.tlib.TLib;
import com.ilummc.tlib.annotations.TLocalePlugin;
import com.ilummc.tlib.logger.TLogger;
import com.ilummc.tlib.resources.type.*;
import com.ilummc.tlib.util.IO;
import com.ilummc.tlib.util.Strings;
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;
import org.bukkit.configuration.serialization.ConfigurationSerialization;
import org.bukkit.plugin.Plugin;
import java.io.File;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public class TLocaleLoader {
private static final Map<String, TLocaleInstance> map = new ConcurrentHashMap<>();
public static void init() {
ConfigurationSerialization.registerClass(TLocaleText.class, "TEXT");
ConfigurationSerialization.registerClass(TLocaleJson.class, "JSON");
ConfigurationSerialization.registerClass(TLocaleBook.class, "BOOK");
ConfigurationSerialization.registerClass(TLocaleSound.class, "SOUND");
ConfigurationSerialization.registerClass(TLocaleTitle.class, "TITLE");
ConfigurationSerialization.registerClass(TLocaleBossBar.class, "BAR");
ConfigurationSerialization.registerClass(TLocaleActionBar.class, "ACTION");
}
public static void sendTo(Plugin plugin, String path, CommandSender sender, String... args) {
TabooLib.debug(plugin, "TLocaleLoader.sendTo: " + plugin + ", path: " + path + ", sender: " + sender + ", args: " + Arrays.asList(args));
if (Bukkit.isPrimaryThread()) {
Optional.ofNullable(map.get(plugin.getName())).ifPresent(localeInstance -> localeInstance.sendTo(path, sender, args));
} else {
synchronized (TLocaleLoader.class) {
Optional.ofNullable(map.get(plugin.getName())).ifPresent(localeInstance -> localeInstance.sendTo(path, sender, args));
}
}
}
public static String asString(Plugin plugin, String path, String... args) {
TabooLib.debug(plugin, "TLocaleLoader.asString: " + plugin.getName() + ", path: " + path + ", args: " + Arrays.asList(args));
TLocaleInstance tLocaleInstance = map.get(plugin.getName());
if (tLocaleInstance != null) {
return tLocaleInstance.asString(path, args);
} else {
return "";
}
}
public static List<String> asStringList(Plugin plugin, String path, String... args) {
TabooLib.debug(plugin, "TLocaleLoader.asStringList: " + plugin + ", path: " + path + ", args: " + Arrays.asList(args));
TLocaleInstance tLocaleInstance = map.get(plugin.getName());
if (tLocaleInstance != null) {
return tLocaleInstance.asStringList(path, args);
} else {
return Collections.emptyList();
}
}
/**
* 载入语言文件
*
* @param plugin 载入插件
* @param isCover 是否覆盖
*/
public static void load(Plugin plugin, boolean isCover) {
try {
if (isLoadLocale(plugin, isCover)) {
// 获取文件
File localeFile = getLocaleFile(plugin);
if (localeFile == null) {
return;
}
// 加载文件
infoLogger("TRY-LOADING-LANG", plugin.getName(), localeFile.getName());
YamlConfiguration localeConfiguration = ConfigUtils.loadYaml(plugin, localeFile);
YamlConfiguration localeConfigurationAtStream = getLocaleAtStream(plugin, localeFile);
// 载入配置
loadPluginLocale(plugin, localeFile, localeConfiguration, localeConfigurationAtStream);
// 注册监听
TLib.getTLib().getConfigWatcher().removeListener(localeFile);
TLib.getTLib().getConfigWatcher().addListener(localeFile, null, obj -> {
infoLogger("RELOADING-LANG", plugin.getName());
loadPluginLocale(plugin, localeFile, ConfigUtils.loadYaml(plugin, localeFile), getLocaleAtStream(plugin, localeFile));
});
}
} catch (Exception e) {
errorLogger("ERROR-LOADING-LANG", plugin.getName(), e.toString() + "\n" + e.getStackTrace()[0].toString());
}
}
public static boolean isLocaleLoaded(Plugin plugin) {
return map.containsKey(plugin.getName());
}
public static boolean isDependWithTabooLib(Plugin plugin) {
return plugin.getClass().getAnnotation(TLocalePlugin.class) != null || plugin.getDescription().getDepend().contains(Main.getInst().getName()) || plugin.getDescription().getSoftDepend().contains(Main.getInst().getName());
}
public static List<String> getLocalePriority() {
return Main.getInst().getConfig().contains("LOCALE.PRIORITY") ? Main.getInst().getConfig().getStringList("LOCALE.PRIORITY") : Collections.singletonList("zh_CN");
}
private static boolean isLoadLocale(Plugin plugin, boolean isCover) {
return (isCover || !isLocaleLoaded(plugin)) && (plugin.equals(Main.getInst()) || isDependWithTabooLib(plugin));
}
private static void infoLogger(String path, String... args) {
TLogger.getGlobalLogger().info(Strings.replaceWithOrder(TLib.getInternalLanguage().getString(path), args));
}
private static void errorLogger(String path, String... args) {
TLogger.getGlobalLogger().error(Strings.replaceWithOrder(TLib.getInternalLanguage().getString(path), args));
}
private static File getLocaleFile(Plugin plugin) {
releaseLocales(plugin);
return getLocalePriority().stream().map(localeName -> new File(plugin.getDataFolder(), "lang/" + localeName + ".yml")).filter(File::exists).findFirst().orElse(null);
}
private static void releaseLocales(Plugin plugin) {
getLocalePriority().stream().filter(localeName -> !new File(plugin.getDataFolder(), "lang/" + localeName + ".yml").exists() && plugin.getResource("lang/" + localeName + ".yml") != null).forEach(localeName -> plugin.saveResource("lang/" + localeName + ".yml", true));
}
private static TLocaleInstance getLocaleInstance(Plugin plugin) {
TLocaleInstance instance = new TLocaleInstance(plugin);
map.put(plugin.getName(), instance);
return instance;
}
private static YamlConfiguration getLocaleAtStream(Plugin plugin, File localeFile) {
InputStream localeInputSteam = FileUtils.getResource(plugin, "lang/" + localeFile.getName());
try {
String yamlText = new String(IO.readFully(localeInputSteam), Charset.forName("utf-8"));
YamlConfiguration yaml = new YamlConfiguration();
yaml.loadFromString(yamlText);
return yaml;
} catch (Exception ignored) {
return null;
}
}
private static void loadPluginLocale(Plugin plugin, File localeFile, YamlConfiguration localeConfiguration, YamlConfiguration localeConfigurationAtStream) {
TLocaleInstance localeInstance = getLocaleInstance(plugin);
if (localeConfigurationAtStream != null) {
localeInstance.load(localeConfigurationAtStream);
}
localeInstance.load(localeConfiguration);
if (localeInstance.getLatestUpdateNodes().get() <= 0) {
infoLogger("SUCCESS-LOADING-LANG-NORMAL", plugin.getName(), localeFile.getName().split("\\.")[0], String.valueOf(localeInstance.size()));
} else {
infoLogger("SUCCESS-LOADING-LANG-UPDATE", plugin.getName(), localeFile.getName().split("\\.")[0], String.valueOf(localeInstance.size()), String.valueOf(localeInstance.getLatestUpdateNodes().get()));
}
}
}

View File

@@ -0,0 +1,37 @@
package com.ilummc.tlib.resources;
import org.bukkit.command.CommandSender;
import java.util.List;
/**
* @Author sky
* @Since 2018-05-12 13:58
*/
public interface TLocaleSender {
/**
* 发送信息
*
* @param sender 发送目标
* @param args 参数
*/
void sendTo(CommandSender sender, String... args);
/**
* 获取文本
*
* @param args 参数
* @return 文本
*/
String asString(String... args);
/**
* 获取文本集合
*
* @param args 参数
* @return 文本集合
*/
List<String> asStringList(String... args);
}

View File

@@ -0,0 +1,84 @@
package com.ilummc.tlib.resources;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.serialization.ConfigurationSerializable;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* @Author sky
* @Since 2018-05-12 14:01
*/
public abstract class TLocaleSerialize implements TLocaleSender, ConfigurationSerializable {
public static boolean isPlaceholderEnabled(Map<String, Object> map) {
Object placeholderObject = map.getOrDefault("papi", TLocale.Translate.isPlaceholderUseDefault());
return placeholderObject instanceof Boolean ? (boolean) placeholderObject : placeholderObject instanceof String && "true".equals(placeholderObject);
}
public static String getStringOrDefault(Map<String, Object> map, String path, String def) {
Object var = map.getOrDefault(path, def);
return var instanceof String ? (String) var : def;
}
public static Integer getIntegerOrDefault(Map<String, Object> map, String path, Integer def) {
Object var = map.getOrDefault(path, def);
return var instanceof Integer ? (Integer) var : def;
}
public static Double getDoubleOrDefault(Map<String, Object> map, String path, Double def) {
Object var = map.getOrDefault(path, def);
return var instanceof Double ? (Double) var : def;
}
static TLocaleSerialize getEmpty() {
return new TLocaleSerialize() {
@Override
public void sendTo(CommandSender sender, String... args) {
}
@Override
public Map<String, Object> serialize() {
return null;
}
};
}
static TLocaleSerialize getEmpty(String path) {
return new TLocaleSerialize() {
@Override
public Map<String, Object> serialize() {
return null;
}
@Override
public void sendTo(CommandSender sender, String... args) {
sender.sendMessage("§8<" + path + "§8>");
}
@Override
public String asString(String... args) {
return "§8<" + path + "§8>";
}
@Override
public List<String> asStringList(String... args) {
return Collections.singletonList("§4<" + path + "§4>");
}
};
}
@Override
public String asString(String... args) {
return "";
}
@Override
public List<String> asStringList(String... args) {
return Collections.emptyList();
}
}

View File

@@ -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.resources.TLocale;
import com.ilummc.tlib.resources.TLocaleSerialize;
import com.ilummc.tlib.util.Strings;
import me.skymc.taboolib.display.ActionUtils;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
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 extends TLocaleSerialize {
private final String text;
private final boolean papi;
private TLocaleActionBar(String text, boolean papi) {
this.text = text;
this.papi = papi;
}
public static TLocaleActionBar valueOf(Map<String, Object> map) {
String text = ChatColor.translateAlternateColorCodes('&', String.valueOf(map.getOrDefault("text", "Empty Action bar message.")));
return new TLocaleActionBar(text, isPlaceholderEnabled(map));
}
@Override
public void sendTo(CommandSender sender, String... args) {
if (sender instanceof Player) {
TLocale.Display.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;
}
}

View File

@@ -0,0 +1,95 @@
package com.ilummc.tlib.resources.type;
import com.google.common.collect.Maps;
import com.ilummc.tlib.bungee.chat.ComponentSerializer;
import com.ilummc.tlib.resources.TLocale;
import com.ilummc.tlib.resources.TLocaleSerialize;
import com.ilummc.tlib.util.Strings;
import me.skymc.taboolib.Main;
import me.skymc.taboolib.bookformatter.BookFormatter;
import me.skymc.taboolib.bookformatter.builder.BookBuilder;
import me.skymc.taboolib.json.tellraw.TellrawJson;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.serialization.SerializableAs;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitRunnable;
import javax.annotation.concurrent.ThreadSafe;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* @Author sky
* @Since 2018-05-27 0:05
*/
@ThreadSafe
@SerializableAs("BOOK")
public class TLocaleBook extends TLocaleSerialize {
/*
BookTest:
- ==: BOOK
pages:
0:
- '第一页内容'
- '[ <变量1@page-1> ]'
1:
- '第二页内容'
- '[ <变量2@page-2> ]'
args:
page-1:
hover: '展示内容1'
command: '/say %player_name% NB1'
page-2:
hover: '展示内容2'
suggest: '/say %player_name% NB2'
*/
private final List<TellrawJson> pages;
private final Map<String, Object> map;
private final boolean papi;
public TLocaleBook(List<TellrawJson> pages, Map<String, Object> map, boolean papi) {
this.pages = pages;
this.map = map;
this.papi = papi;
}
@Override
public Map<String, Object> serialize() {
return Maps.newHashMap(map);
}
@Override
public void sendTo(CommandSender sender, String... args) {
if (!(sender instanceof Player)) {
return;
}
new BukkitRunnable() {
@Override
public void run() {
BookBuilder bookBuilder = BookFormatter.writtenBook();
pages.stream().map(jsonPage -> format(jsonPage, sender, args)).map(ComponentSerializer::parse).forEach(bookBuilder::addPages);
new BukkitRunnable() {
@Override
public void run() {
BookFormatter.forceOpen((Player) sender, bookBuilder.build());
}
}.runTask(Main.getInst());
}
}.runTaskAsynchronously(Main.getInst());
}
private String format(TellrawJson jsonPage, CommandSender sender, String[] args) {
return papi ? TLocale.Translate.setPlaceholders(sender, Strings.replaceWithOrder(jsonPage.toRawMessage(), args)) : Strings.replaceWithOrder(jsonPage.toRawMessage(), args);
}
public static TLocaleBook valueOf(Map<String, Object> map) {
Map<String, Object> pages = map.containsKey("pages") ? (Map<String, Object>) map.get("pages") : new HashMap<>();
Map<String, Object> section = map.containsKey("args") ? (Map<String, Object>) map.get("args") : new HashMap<>();
List<TellrawJson> pageJsonList = pages.values().stream().map(page -> TLocaleJson.formatJson(section, page, TellrawJson.create())).collect(Collectors.toList());
return new TLocaleBook(pageJsonList, map, isPlaceholderEnabled(map));
}
}

View File

@@ -0,0 +1,95 @@
package com.ilummc.tlib.resources.type;
import com.ilummc.tlib.resources.TLocale;
import com.ilummc.tlib.resources.TLocaleSerialize;
import com.ilummc.tlib.util.Strings;
import me.skymc.taboolib.other.NumberUtils;
import net.md_5.bungee.api.chat.TextComponent;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.serialization.SerializableAs;
import org.bukkit.entity.Player;
import org.inventivetalent.bossbar.BossBar;
import org.inventivetalent.bossbar.BossBarAPI;
import javax.annotation.concurrent.ThreadSafe;
import java.util.Map;
/**
* @Author sky
* @Since 2018-05-27 18:52
*/
@ThreadSafe
@SerializableAs("BAR")
public class TLocaleBossBar extends TLocaleSerialize {
/*
BossBar:
- ==: BAR
text: 'BossBar 血条公告'
color: BLUE
style: NOTCHED_20
progress: 1.0
timeout: 20
timeout-interval: 2
*/
private final String text;
private final BossBarAPI.Color color;
private final BossBarAPI.Style style;
private final float progress;
private final int timeout;
private final int timeoutInterval;
private final boolean papi;
public TLocaleBossBar(String text, BossBarAPI.Color color, BossBarAPI.Style style, float progress, int timeout, int timeoutInterval, boolean papi) {
this.text = text;
this.color = color;
this.style = style;
this.progress = progress;
this.timeout = timeout;
this.timeoutInterval = timeoutInterval;
this.papi = papi;
}
@Override
public void sendTo(CommandSender sender, String... args) {
if (Bukkit.getPluginManager().getPlugin("BossBarAPI") == null) {
TLocale.Logger.error("LOCALE.BAR-PLUGIN-NOT-FOUND");
return;
}
if (sender instanceof Player) {
TextComponent textComponent = new TextComponent(papi ? TLocale.Translate.setPlaceholders(sender, Strings.replaceWithOrder(text, args)) : TLocale.Translate.setColored(Strings.replaceWithOrder(text, args)));
BossBar bossBar = BossBarAPI.addBar((Player) sender, textComponent, color, style, progress, timeout, timeoutInterval);
} else {
sender.sendMessage(text);
}
}
@Override
public Map<String, Object> serialize() {
return null;
}
public static TLocaleBossBar valueOf(Map<String, Object> map) {
return new TLocaleBossBar(map.getOrDefault("text", "§4* Invalid Text*").toString(), getColor(String.valueOf(map.get("color"))), getStyle(String.valueOf(map.get("style"))), (float) NumberUtils.getDouble(String.valueOf(map.getOrDefault("progress", 1))), NumberUtils.getInteger(String.valueOf(map.getOrDefault("timeout", 20))), NumberUtils.getInteger(String.valueOf(map.getOrDefault("timeout-interval", 2))), isPlaceholderEnabled(map));
}
private static BossBarAPI.Color getColor(String color) {
try {
return BossBarAPI.Color.valueOf(color);
} catch (Exception e) {
TLocale.Logger.error("LOCALE.BAR-STYLE-IDENTIFICATION-FAILED", e.toString());
return BossBarAPI.Color.WHITE;
}
}
private static BossBarAPI.Style getStyle(String style) {
try {
return BossBarAPI.Style.valueOf(style);
} catch (Exception e) {
TLocale.Logger.error("LOCALE.BAR-COLOR-IDENTIFICATION-FAILED", e.toString());
return BossBarAPI.Style.NOTCHED_20;
}
}
}

View File

@@ -0,0 +1,227 @@
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.bungee.api.chat.*;
import com.ilummc.tlib.bungee.chat.ComponentSerializer;
import com.ilummc.tlib.compat.PlaceholderHook;
import com.ilummc.tlib.resources.TLocale;
import com.ilummc.tlib.resources.TLocaleSerialize;
import com.ilummc.tlib.util.Strings;
import me.skymc.taboolib.inventory.ItemUtils;
import me.skymc.taboolib.json.tellraw.TellrawJson;
import me.skymc.taboolib.other.NumberUtils;
import me.skymc.taboolib.string.VariableFormatter;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.serialization.SerializableAs;
import javax.annotation.concurrent.ThreadSafe;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@ThreadSafe
@SerializableAs("JSON")
public class TLocaleJson extends TLocaleSerialize {
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) {
List<String> textList = getTextList(map.getOrDefault("text", "Empty Node"));
// 分析 args 并替换
Object argsObj = map.get("args");
if (argsObj instanceof Map) {
Map<String, Object> section = new HashMap<>(((Map<?, ?>) argsObj).size());
// valueOf(k) 是因为这个键可能加载为一个 Integer 导致 contains(String) 返回 false
((Map<?, ?>) argsObj).forEach((k, v) -> section.put(String.valueOf(k), v));
List<BaseComponent[]> collect = textList.stream().map(s -> {
int index = 0;
String[] template = pattern.split(s);
Matcher matcher = pattern.matcher(s);
// 有可能开头和结尾是替换文本,所以做个特判
List<BaseComponent> builder = template.length > index ? new ArrayList<>(Arrays.asList(TextComponent.fromLegacyText(template[index++]))) : new ArrayList<>();
while (matcher.find()) {
String replace = matcher.group();
// 假的 <@>
if (replace.length() <= 2) {
continue;
}
// 真的 <@xxx>
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];
// 如果 args 有这个 xxx
if (section.containsKey(node)) {
Map<String, Object> arg = (Map<String, Object>) section.get(node);
text = TLocale.Translate.setColored(String.valueOf(arg.getOrDefault("text", text)));
// 可能有很多个 BaseComponent于是为每个 component 单独设置各种事件
BaseComponent[] component = TextComponent.fromLegacyText(text);
arg.forEach((key, value) -> {
if (key.equalsIgnoreCase("suggest")) {
Arrays.stream(component).forEach(baseComponent -> baseComponent.setClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, String.valueOf(value))));
} else if (key.equalsIgnoreCase("command") || "commands".equalsIgnoreCase(key)) {
Arrays.stream(component).forEach(baseComponent -> baseComponent.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, String.valueOf(value))));
} else if (key.equalsIgnoreCase("hover")) {
Arrays.stream(component).forEach(baseComponent -> baseComponent.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new ComponentBuilder(TLocale.Translate.setColored(String.valueOf(value))).create())));
}
});
// 添加到原来的 list 里面
builder.addAll(Arrays.asList(component));
} else {
// 这个参数节点并没有找到,于是随便放点字符串进去
builder.addAll(Arrays.asList(TextComponent.fromLegacyText(text)));
TLib.getTLib().getLogger().warn(Strings.replaceWithOrder(TLib.getInternalLanguage().getString("MISSING-ARGUMENT"), node));
}
// 有可能一开头就是 <@xxx>,然后 split 出来就少了一些,于是直接加上
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, isPlaceholderEnabled(map), map);
}
return new TLocaleJson(textList.stream().map(TextComponent::fromLegacyText).collect(Collectors.toList()), isPlaceholderEnabled(map), map);
}
private static List<String> getTextList(Object textObj) {
if (textObj instanceof List) {
return ((List<?>) textObj).stream().map(Object::toString).map(TLocale.Translate::setColored).collect(Collectors.toList());
} else if (textObj instanceof String) {
return Lists.newArrayList(TLocale.Translate.setColored((String) textObj));
} else {
return Collections.emptyList();
}
}
@Override
public void sendTo(CommandSender sender, String... args) {
components.forEach(comp -> sendRawMessage(sender, replace(comp, sender, args)));
}
@Override
public String asString(String... args) {
return components.toString();
}
@Override
public Map<String, Object> serialize() {
return Maps.newHashMap(map);
}
private void sendRawMessage(CommandSender sender, BaseComponent[] components) {
TLocale.Tellraw.send(sender, ComponentSerializer.toString(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) {
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 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;
}
public static TellrawJson formatJson(Map<String, Object> section, Object textObject, TellrawJson pageJson) {
List<String> textList = textObject instanceof List ? (List<String>) textObject : Collections.singletonList(String.valueOf(textObject));
// 遍历本页文本
for (int i = 0; i < textList.size(); i++) {
// 捕捉变量
for (VariableFormatter.Variable variable : new VariableFormatter(TLocale.Translate.setColored(textList.get(i)), pattern).find().getVariableList()) {
// 如果是变量
if (variable.isVariable()) {
String[] split = variable.getText().split("@");
// @ 前面的字符串
String text = split.length > 1 ? split[0] : "§4* Invalid Text *";
// @ 后面的节点名
String node = split.length > 1 ? split[1] : null;
// 处理变量
formatNode(section, pageJson, text, node);
} else {
pageJson.append(variable.getText());
}
}
if (i + 1 < textList.size()) {
pageJson.newLine();
}
}
return pageJson;
}
private static void formatNode(Map<String, Object> section, TellrawJson pageJson, String text, String node) {
if (section.containsKey(node)) {
try {
Map<String, Object> args = (Map<String, Object>) section.get(node);
// 文本
pageJson.append(args.getOrDefault("text", text).toString());
// 功能
if (args.containsKey("item")) {
pageJson.hoverItem(ItemUtils.getCacheItem(args.get("item").toString()));
}
if (args.containsKey("hover")) {
pageJson.hoverText(args.get("hover").toString());
}
if (args.containsKey("suggest")) {
pageJson.clickSuggest(args.get("suggest").toString());
}
if (args.containsKey("command")) {
pageJson.clickCommand(args.get("command").toString());
}
if (args.containsKey("page")) {
pageJson.clickChangePage(NumberUtils.getInteger(args.get("page").toString()));
}
if (args.containsKey("url")) {
pageJson.clickOpenURL(args.get("url").toString());
}
} catch (Exception e) {
TLocale.Logger.error("LOCALE.BOOK-ARGUMENTS-IDENTIFICATION-FAILED", e.toString());
}
} else {
pageJson.append("§4* Invalid Argument *");
}
}
}

View File

@@ -0,0 +1,68 @@
package com.ilummc.tlib.resources.type;
import com.google.common.collect.Maps;
import com.ilummc.tlib.resources.TLocaleSerialize;
import me.skymc.taboolib.sound.SoundPack;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.serialization.SerializableAs;
import org.bukkit.entity.Player;
import javax.annotation.concurrent.Immutable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* @Author sky
* @Since 2018-05-06 14:35
*/
@Immutable
@SerializableAs("ACTION")
public class TLocaleSound extends TLocaleSerialize {
private final List<SoundPack> soundPacks;
public TLocaleSound(List<SoundPack> soundPacks) {
this.soundPacks = soundPacks;
}
public static TLocaleSound valueOf(Map<String, Object> map) {
List<SoundPack> soundPacks = new ArrayList<>();
Object sounds = map.containsKey("sounds") ? map.get("sounds") : map.getOrDefault("sound", "");
if (sounds instanceof List) {
soundPacks = ((List<String>) sounds).stream().map(SoundPack::new).collect(Collectors.toList());
} else {
soundPacks.add(new SoundPack(sounds.toString()));
}
return new TLocaleSound(soundPacks);
}
@Override
public void sendTo(CommandSender sender, String... args) {
if (sender instanceof Player) {
soundPacks.forEach(x -> x.play((Player) sender));
}
}
@Override
public String asString(String... args) {
return toString();
}
@Override
public String toString() {
return "soundPacks=" + "TLocaleSound{" + soundPacks + '}';
}
@Override
public Map<String, Object> serialize() {
Map<String, Object> map = Maps.newHashMap();
if (soundPacks.size() == 1) {
map.put("sounds", soundPacks.get(0).toString());
} else if (soundPacks.size() > 1) {
map.put("sounds", soundPacks.stream().map(SoundPack::toString).collect(Collectors.toList()));
}
return map;
}
}

View File

@@ -0,0 +1,107 @@
package com.ilummc.tlib.resources.type;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.ilummc.tlib.compat.PlaceholderHook;
import com.ilummc.tlib.resources.TLocale;
import com.ilummc.tlib.resources.TLocaleSerialize;
import com.ilummc.tlib.util.Strings;
import me.skymc.taboolib.Main;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.serialization.SerializableAs;
import javax.annotation.concurrent.Immutable;
import java.util.*;
import java.util.stream.Collectors;
@Immutable
@SerializableAs("TEXT")
@SuppressWarnings({"unchecked", "rawtypes"})
public class TLocaleText extends TLocaleSerialize {
private final Object text;
private final boolean usePlaceholder;
private TLocaleText(Object text, boolean usePlaceholder) {
this.usePlaceholder = usePlaceholder;
if (text instanceof String) {
this.text = text;
} else if (text instanceof List) {
this.text = ImmutableList.copyOf(((List) text));
} else {
throw new IllegalArgumentException("Param 'text' can only be an instance of String or List<String>");
}
}
public static TLocaleText of(String s) {
return new TLocaleText(TLocale.Translate.setColored(s), TLocale.Translate.isPlaceholderUseDefault());
}
public static TLocaleText of(Object o) {
return o instanceof String ? of(((String) o)) : new TLocaleText(o, false);
}
public static TLocaleText valueOf(Map<String, Object> map) {
if (map.containsKey("text")) {
Object object = map.get("text");
if (object instanceof String[]) {
return new TLocaleText(Arrays.stream(((String[]) object)).collect(Collectors.toList()), isPlaceholderEnabled(map));
} else {
return new TLocaleText(Objects.toString(object), isPlaceholderEnabled(map));
}
}
return new TLocaleText("§cError chat message loaded.", TLocale.Translate.isPlaceholderUseDefault());
}
@Override
public void sendTo(CommandSender sender, String... args) {
if (text instanceof String) {
sender.sendMessage(replaceText(sender, Strings.replaceWithOrder((String) text, args)));
} else if (text instanceof List) {
((List) text).forEach(s -> sender.sendMessage(replaceText(sender, Strings.replaceWithOrder(String.valueOf(s), args))));
}
}
@Override
public String asString(String... args) {
return Strings.replaceWithOrder(TLocale.Translate.setColored(objectToString(text)), args);
}
@Override
public List<String> asStringList(String... args) {
if (text instanceof List) {
return ((List<String>) text).stream().map(x -> Strings.replaceWithOrder(TLocale.Translate.setColored(x), args)).collect(Collectors.toList());
} else {
return Collections.singletonList(asString(args));
}
}
@Override
public String toString() {
if (text instanceof String[]) {
return Arrays.toString((String[]) text);
} else {
return text.toString();
}
}
@Override
public Map<String, Object> serialize() {
return usePlaceholder ? Maps.newHashMap(ImmutableMap.of("text", text, "papi", true)) : Maps.newHashMap(ImmutableMap.of("text", text));
}
private String replaceText(CommandSender sender, String args) {
return usePlaceholder ? TLocale.Translate.setPlaceholders(sender, args) : TLocale.Translate.setColored(args);
}
private String objectToString(Object text) {
if (text instanceof String) {
return ((String) text);
} else {
StringJoiner joiner = new StringJoiner("\n");
((List<String>) text).forEach(joiner::add);
return joiner.toString();
}
}
}

View File

@@ -0,0 +1,86 @@
package com.ilummc.tlib.resources.type;
import com.google.common.collect.Maps;
import com.ilummc.tlib.resources.TLocale;
import com.ilummc.tlib.resources.TLocaleSerialize;
import com.ilummc.tlib.util.Strings;
import me.skymc.taboolib.display.TitleUtils;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.serialization.SerializableAs;
import org.bukkit.entity.Player;
import javax.annotation.concurrent.Immutable;
import java.util.HashMap;
import java.util.Map;
/**
* @author Bkm016
* @since 2018-04-22
*/
@Immutable
@SerializableAs("TITLE")
public class TLocaleTitle extends TLocaleSerialize {
private final String title;
private final String subtitle;
private final int fadein;
private final int fadeout;
private final int stay;
private boolean usePlaceholder;
private TLocaleTitle(String title, String subString, int fadein, int fadeout, int stay, boolean usePlaceholder) {
this.title = title;
this.subtitle = subString;
this.fadein = fadein;
this.fadeout = fadeout;
this.stay = stay;
this.usePlaceholder = usePlaceholder;
}
public static TLocaleTitle valueOf(Map<String, Object> map) {
TLocaleTitle title;
try {
title = new TLocaleTitle(getStringOrDefault(map, "title", ""), getStringOrDefault(map, "subtitle", ""), getIntegerOrDefault(map, "fadein", 10), getIntegerOrDefault(map, "fadeout", 10), getIntegerOrDefault(map, "stay", 10), isPlaceholderEnabled(map));
} catch (Exception e) {
title = new TLocaleTitle("Empty Title message.", e.getMessage(), 10, 20, 10, false);
}
return title;
}
@Override
public void sendTo(CommandSender sender, String... args) {
if (sender instanceof Player) {
TLocale.Display.sendTitle((Player) sender, replaceText(sender, Strings.replaceWithOrder(title, args)), replaceText(sender, Strings.replaceWithOrder(subtitle, args)), fadein, stay, fadeout);
} else {
TLocale.Logger.error("LOCALE.TITLE-SEND-TO-NON-PLAYER", asString(args));
}
}
@Override
public String asString(String... args) {
return Strings.replaceWithOrder(Strings.replaceWithOrder("TITLE: [title: ''{0}'', subtitle: ''{1}'', fadeIn: {2}, fadeOut: {3}]", title, subtitle, fadein, fadeout), args);
}
@Override
public String toString() {
return asString();
}
@Override
public Map<String, Object> serialize() {
HashMap<String, Object> map = Maps.newHashMap();
map.put("papi", usePlaceholder);
map.put("title", title);
map.put("subtitle", subtitle);
map.put("fadein", fadein);
map.put("fadeout", fadeout);
map.put("stay", stay);
return map;
}
private String replaceText(CommandSender sender, String text, String... args) {
return usePlaceholder ? TLocale.Translate.setPlaceholders(sender, text) : TLocale.Translate.setColored(text);
}
}

View File

@@ -0,0 +1,18 @@
package com.ilummc.tlib.util;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
public class IO {
public static byte[] readFully(InputStream inputStream) throws IOException {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
byte[] buf = new byte[1024];
int len = 0;
while ((len = inputStream.read(buf)) > 0) {
stream.write(buf, 0, len);
}
return stream.toByteArray();
}
}

View File

@@ -0,0 +1,157 @@
package com.ilummc.tlib.util;
import com.google.gson.annotations.SerializedName;
import com.ilummc.tlib.TLib;
import com.ilummc.tlib.util.asm.AsmAnalyser;
import me.skymc.taboolib.Main;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import sun.reflect.Reflection;
import javax.annotation.concurrent.ThreadSafe;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
@ThreadSafe
public class Ref {
private static final Map<String, List<Field>> cachedFields = new ConcurrentHashMap<>();
public static final int ACC_BRIDGE = 0x0040;
public static final int ACC_SYNTHETIC = 0x1000;
public static List<Field> getDeclaredFields(Class<?> clazz) {
return getDeclaredFields(clazz, 0, true);
}
public static List<Field> getDeclaredFields(String clazz, int excludeModifiers, boolean cache) {
try {
return getDeclaredFields(Class.forName(clazz), excludeModifiers, cache);
} catch (ClassNotFoundException e) {
return Collections.emptyList();
}
}
public static List<Field> getDeclaredFields(Class<?> clazz, int excludeModifiers, boolean cache) {
try {
// 特殊判断
if (clazz == TLib.class) {
return Arrays.asList(clazz.getDeclaredFields());
}
List<Field> fields;
if ((fields = cachedFields.get(clazz.getName())) != null) {
return fields;
}
ClassReader classReader = new ClassReader(clazz.getResourceAsStream("/" + clazz.getName().replace('.', '/') + ".class"));
AsmAnalyser analyser = new AsmAnalyser(new ClassWriter(ClassWriter.COMPUTE_MAXS), excludeModifiers);
classReader.accept(analyser, ClassReader.SKIP_DEBUG);
fields = analyser.getFields().stream().map(name -> {
try {
return clazz.getDeclaredField(name);
} catch (Throwable ignored) {
return null;
}
}).filter(Objects::nonNull).collect(Collectors.toList());
if (cache) {
cachedFields.putIfAbsent(clazz.getName(), fields);
}
return fields;
} catch (Exception | Error e) {
try {
List<Field> list = Arrays.stream(clazz.getDeclaredFields())
.filter(field -> (field.getModifiers() & excludeModifiers) == 0).collect(Collectors.toList());
cachedFields.putIfAbsent(clazz.getName(), list);
return list;
} catch (Error err) {
return Collections.emptyList();
}
}
}
public static Optional<Class<?>> getCallerClass(int depth) {
return Optional.ofNullable(CallerClass.impl.getCallerClass(depth + 1));
}
public static Class<?> getCallerClassNotOptional(int depth) {
return CallerClass.impl.getCallerClass(depth);
}
public static String getSerializedName(Field field) {
return field.isAnnotationPresent(SerializedName.class) ? field.getAnnotation(SerializedName.class).value() : field.getName();
}
public static Optional<Field> getFieldBySerializedName(Class<?> clazz, String name) {
for (Field field : Ref.getDeclaredFields(clazz, 0, false)) {
if (field.isAnnotationPresent(SerializedName.class)) {
if (field.getAnnotation(SerializedName.class).value().equals(name)) {
return Optional.of(field);
} else if (field.getName().equals(name)) {
return Optional.of(field);
}
}
}
return Optional.empty();
}
public static Plugin getCallerPlugin(Class<?> callerClass) {
try {
return JavaPlugin.getProvidingPlugin(callerClass);
} catch (Exception ignored) {
try {
ClassLoader loader = callerClass.getClassLoader();
Field pluginF = loader.getClass().getDeclaredField("plugin");
pluginF.setAccessible(true);
Object o = pluginF.get(loader);
return (JavaPlugin) o;
} catch (Exception e) {
return Main.getInst();
}
}
}
private static abstract class CallerClass {
private static CallerClass impl;
static {
try {
Class.forName("sun.reflect.Reflection");
impl = new ReflectionImpl();
} catch (ClassNotFoundException e) {
impl = new StackTraceImpl();
}
}
abstract Class<?> getCallerClass(int i);
private static class ReflectionImpl extends CallerClass {
@SuppressWarnings({"deprecation", "restriction"})
@Override
Class<?> getCallerClass(int i) {
return Reflection.getCallerClass(i);
}
}
private static class StackTraceImpl extends CallerClass {
@Override
Class<?> getCallerClass(int i) {
StackTraceElement[] elements = Thread.currentThread().getStackTrace();
try {
return Class.forName(elements[i].getClassName());
} catch (ClassNotFoundException e) {
return null;
}
}
}
}
}

View File

@@ -0,0 +1,48 @@
package com.ilummc.tlib.util;
public class Strings {
public static boolean isBlank(String var) {
return var == null || var.trim().isEmpty();
}
public static boolean isEmpty(CharSequence var) {
return var == null || var.length() == 0;
}
/**
* 优化过的 String#replace比默认快了大概 5 倍
*
* @param template 模板替换文件
* @param args 替换的参数
* @return 替换好的字符串
*/
public static String replaceWithOrder(String template, Object... args) {
if (args.length == 0 || template.length() == 0) {
return template;
}
char[] arr = template.toCharArray();
StringBuilder stringBuilder = new StringBuilder(template.length());
for (int i = 0; i < arr.length; i++) {
if (arr[i] == '{' && Character.isDigit(arr[Math.min(i + 1, arr.length - 1)])
&& arr[Math.min(i + 1, arr.length - 1)] - '0' < args.length
&& arr[Math.min(i + 2, arr.length - 1)] == '}') {
stringBuilder.append(args[arr[i + 1] - '0']);
i += 2;
} else {
stringBuilder.append(arr[i]);
}
}
return stringBuilder.toString();
}
// *********************************
//
// Deprecated
//
// *********************************
public static String replaceWithOrder(String template, String... args) {
return replaceWithOrder(template, (Object[]) args);
}
}

View File

@@ -0,0 +1,32 @@
package com.ilummc.tlib.util.asm;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.Opcodes;
import java.util.ArrayList;
import java.util.List;
public class AsmAnalyser extends ClassVisitor implements Opcodes {
private final List<String> fields = new ArrayList<>();
private final int excludeModifier;
public AsmAnalyser(ClassVisitor classVisitor, int excludeModifiers) {
super(Opcodes.ASM6, classVisitor);
this.excludeModifier = excludeModifiers;
}
@Override
public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) {
if ((access & excludeModifier) == 0) {
fields.add(name);
}
return super.visitField(access, name, descriptor, signature, value);
}
public List<String> getFields() {
return fields;
}
}

View File

@@ -0,0 +1,21 @@
package com.ilummc.tlib.util.asm;
public class AsmClassLoader extends ClassLoader {
private static final class AsmClassLoaderHolder {
private static AsmClassLoader instance = new AsmClassLoader();
}
public static AsmClassLoader getInstance() {
return new AsmClassLoader();
}
private AsmClassLoader() {
super(AsmClassLoader.class.getClassLoader());
}
public static Class<?> createNewClass(String name, byte[] arr) {
return getInstance().defineClass(name, arr, 0, arr.length, AsmClassLoader.class.getProtectionDomain());
}
}

View File

@@ -0,0 +1,162 @@
package com.ilummc.tlib.util.asm;
import org.bukkit.Bukkit;
import org.objectweb.asm.*;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;
public class AsmClassTransformer extends ClassVisitor implements Opcodes {
private final Class<?> from;
private final String fromVer;
private final String toVer;
private final ClassWriter writer;
private String newClassName;
private String prevName;
private AsmClassTransformer(Class<?> from, String fromVer, String toVer, ClassWriter classWriter) {
super(Opcodes.ASM5, classWriter);
this.writer = classWriter;
this.from = from;
this.fromVer = fromVer;
this.toVer = toVer;
}
public Object transform() {
try {
ClassReader classReader = new ClassReader(from.getResourceAsStream("/" + from.getName().replace('.', '/') + ".class"));
newClassName = from.getName() + "_TabooLibRemap_" + this.hashCode() + "_" + toVer;
prevName = from.getName().replace('.', '/');
classReader.accept(this, ClassReader.SKIP_DEBUG);
Class<?> clazz = AsmClassLoader.createNewClass(newClassName, writer.toByteArray());
Field field = from.getClassLoader().getClass().getDeclaredField("classes");
field.setAccessible(true);
((Map<String, Class<?>>) field.get(from.getClassLoader())).put(newClassName, clazz);
Constructor<?> constructor = clazz.getDeclaredConstructor();
constructor.setAccessible(true);
return constructor.newInstance();
} catch (IOException | NoSuchFieldException | IllegalAccessException | InstantiationException | NoSuchMethodException | InvocationTargetException e) {
e.printStackTrace();
return null;
}
}
public static Builder builder() {
return new Builder().toVersion(Bukkit.getServer().getClass().getName().split("\\.")[3]);
}
public static Builder builder(String ver) {
return new Builder().toVersion(ver);
}
@Override
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
MethodVisitor visitor = super.visitMethod(access, name, replace(descriptor), replace(signature), replace(exceptions));
return new AsmMethodTransformer(visitor);
}
@Override
public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) {
return super.visitField(access, name, replace(descriptor), replace(signature), value);
}
@Override
public void visitInnerClass(String name, String outerName, String innerName, int access) {
super.visitInnerClass(replace(name), outerName, replace(name).substring(outerName.length() + 1), access);
}
@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 String replace(String text) {
if (text != null) {
return text
.replace("net/minecraft/server/" + fromVer, "net/minecraft/server/" + toVer)
.replace("org/bukkit/craftbukkit/" + fromVer, "org/bukkit/craftbukkit/" + toVer)
.replace(prevName, newClassName.replace('.', '/'));
} else {
return null;
}
}
private String[] replace(String[] text) {
if (text != null) {
for (int i = 0; i < text.length; i++) {
text[i] = replace(text[i]);
}
return text;
} else {
return null;
}
}
private class AsmMethodTransformer extends MethodVisitor {
AsmMethodTransformer(MethodVisitor visitor) {
super(Opcodes.ASM5, visitor);
}
@Override
public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) {
super.visitMethodInsn(opcode, replace(owner), name, replace(descriptor), isInterface);
}
@Override
public void visitLdcInsn(Object value) {
if (value instanceof String) {
super.visitLdcInsn(replace((String) value));
} else {
super.visitLdcInsn(value);
}
}
@Override
public void visitTypeInsn(int opcode, String type) {
super.visitTypeInsn(opcode, replace(type));
}
@Override
public void visitFieldInsn(int opcode, String owner, String name, String descriptor) {
super.visitFieldInsn(opcode, replace(owner), name, replace(descriptor));
}
@Override
public void visitLocalVariable(String name, String descriptor, String signature, Label start, Label end, int index) {
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));
}
}
}

View File

@@ -1,4 +1,4 @@
package com.ilummc.tlib.scala
package com.ilummc.tlibscala
import org.bukkit.plugin.Plugin

View File

@@ -1,6 +1,6 @@
package com.ilummc.tlib.scala
package com.ilummc.tlibscala
import com.ilummc.tlib.scala.Prelude._
import Prelude._
import org.bukkit.Material
import org.bukkit.event.player.PlayerJoinEvent
import org.bukkit.event.{EventHandler, Listener}

View File

@@ -1,6 +1,6 @@
package com.ilummc.tlib.scala
package com.ilummc.tlibscala
import com.ilummc.tlib.scala.runtime.{RichLocation, RichOfflinePlayer, RichPlayer, RichVector}
import com.ilummc.tlibscala.runtime.{RichLocation, RichOfflinePlayer, RichPlayer, RichVector}
import org.bukkit.entity.Player
import org.bukkit.util.Vector
import org.bukkit.{Location, OfflinePlayer, World, util}

View File

@@ -1,4 +1,4 @@
package com.ilummc.tlib.scala
package com.ilummc.tlibscala
import com.ilummc.tlib.resources.TLocale.Logger
import org.bukkit.Bukkit

View File

@@ -1,8 +1,8 @@
package com.ilummc.tlib.scala
package com.ilummc.tlibscala
import org.bukkit.scheduler.BukkitRunnable
private[scala] class ScalaTaskExecutor(task: => Any) extends BukkitRunnable {
private[tlibscala] class ScalaTaskExecutor(task: => Any) extends BukkitRunnable {
override def run(): Unit = {
try task catch {

View File

@@ -1,4 +1,4 @@
package com.ilummc.tlib.scala
package com.ilummc.tlibscala
import org.bukkit.plugin.Plugin

View File

@@ -1,4 +1,4 @@
package com.ilummc.tlib.scala.runtime
package com.ilummc.tlibscala.runtime
import org.bukkit.Location

View File

@@ -1,4 +1,4 @@
package com.ilummc.tlib.scala.runtime
package com.ilummc.tlibscala.runtime
import me.skymc.taboolib.Main
import me.skymc.taboolib.economy.EcoUtils

View File

@@ -1,4 +1,4 @@
package com.ilummc.tlib.scala.runtime
package com.ilummc.tlibscala.runtime
import com.ilummc.tlib.resources.TLocale
import me.skymc.taboolib.anvil.AnvilContainerAPI

View File

@@ -1,4 +1,4 @@
package com.ilummc.tlib.scala.runtime
package com.ilummc.tlibscala.runtime
import org.bukkit.util.Vector

View File

@@ -0,0 +1,283 @@
package me.skymc.taboolib;
import com.ilummc.tlib.TLib;
import com.ilummc.tlib.filter.TLoggerFilter;
import com.ilummc.tlib.resources.TLocale;
import com.ilummc.tlib.util.IO;
import com.ilummc.tlib.util.Strings;
import me.skymc.taboolib.database.GlobalDataManager;
import me.skymc.taboolib.database.PlayerDataManager;
import me.skymc.taboolib.fileutils.ConfigUtils;
import me.skymc.taboolib.fileutils.FileUtils;
import me.skymc.taboolib.listener.TListenerHandler;
import me.skymc.taboolib.mysql.hikari.HikariHandler;
import me.skymc.taboolib.mysql.protect.MySQLConnection;
import me.skymc.taboolib.other.NumberUtils;
import me.skymc.taboolib.playerdata.DataUtils;
import me.skymc.taboolib.socket.TabooLibClient;
import me.skymc.taboolib.socket.TabooLibServer;
import me.skymc.taboolib.string.language2.Language2;
import me.skymc.taboolib.update.UpdateTask;
import net.milkbowl.vault.economy.Economy;
import org.bukkit.Bukkit;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitRunnable;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.Random;
/**
* @author sky
*/
public class Main extends JavaPlugin {
public Main() {
inst = this;
}
public enum StorageType {
LOCAL, SQL
}
private static Plugin inst;
private static Economy economy;
private static File playerDataFolder;
private static File serverDataFolder;
private static StorageType storageType = StorageType.LOCAL;
private static Language2 exampleLanguage2;
private static boolean disable = false;
private static boolean started = false;
private static boolean isInternetOnline = false;
private FileConfiguration config = null;
@Override
public FileConfiguration getConfig() {
return config;
}
@Override
public void saveDefaultConfig() {
reloadConfig();
}
@Override
public void reloadConfig() {
File file = new File(getDataFolder(), "config.yml");
if (!file.exists()) {
saveResource("config.yml", true);
}
config = ConfigUtils.load(this, file);
}
@Override
public void onLoad() {
disable = false;
// 载入配置文件
saveDefaultConfig();
// 载入日志过滤
TLoggerFilter.preInit();
// 载入扩展
TabooLibLoader.setupAddons();
// 载入牛逼东西
TLib.init();
TLib.injectPluginManager();
// 载入插件设置
TabooLibLoader.setup();
// 载入大饼
TLib.initPost();
}
@Override
public void onEnable() {
// 载入日志过滤
TLoggerFilter.postInit();
// 注册插件配置
TabooLibLoader.register();
// 启动数据库储存方法
if (getStorageType() == StorageType.SQL) {
GlobalDataManager.SQLMethod.startSQLMethod();
}
// 载入完成
TLocale.Logger.info("NOTIFY.SUCCESS-LOADED", getDescription().getAuthors().toString(), getDescription().getVersion(), String.valueOf(TabooLib.getVersion()));
// 文件保存
Bukkit.getScheduler().runTaskTimerAsynchronously(this, DataUtils::saveAllCaches, 20, 20 * 120);
Bukkit.getScheduler().runTaskTimerAsynchronously(this, () -> PlayerDataManager.saveAllCaches(true, false), 20, 20 * 60);
// 文件监控
TLib.getTLib().getConfigWatcher().addSimpleListener(new File(getDataFolder(), "config.yml"), () -> {
reloadConfig();
TLocale.Logger.info("CONFIG.RELOAD-SUCCESS", inst.getName(), "config.yml");
});
// 插件联动
new BukkitRunnable() {
@Override
public void run() {
// 面子工程
if (!TabooLib.isSilent()) {
InputStream inputStream = FileUtils.getResource("motd.txt");
try {
String text = new String(IO.readFully(inputStream), Charset.forName("utf-8"));
if (text != null) {
Arrays.stream(text.split("\n")).forEach(line -> Bukkit.getConsoleSender().sendMessage(Strings.replaceWithOrder(line, getDescription().getVersion())));
}
} catch (IOException ignored) {
}
}
// 本地通讯网络终端
if (getConfig().getBoolean("SERVER")) {
TabooLibServer.main(new String[0]);
}
// 本地通讯网络
TabooLibClient.init();
}
}.runTask(this);
// 启动
started = true;
// 载入语言文件
exampleLanguage2 = new Language2("Language2", this);
// 更新检测
if (!TabooLib.isSilent()) {
new UpdateTask();
}
}
@Override
public void onDisable() {
disable = true;
// 如果插件尚未启动完成
if (!started) {
TLocale.Logger.error("NOTIFY.FAIL-DISABLE");
return;
}
// 注销插件
TabooLibLoader.unregister();
// 保存数据
Bukkit.getOnlinePlayers().forEach(x -> DataUtils.saveOnline(x.getName()));
// 结束线程
Bukkit.getScheduler().cancelTasks(this);
// 保存插件数据
DataUtils.saveAllCaches();
// 保存玩家数据
PlayerDataManager.saveAllPlayers(false, true);
// 注销连接池
HikariHandler.closeDataSourceForce();
// 注销监听器
TListenerHandler.cancelListeners();
// 结束数据库储存方法
if (getStorageType() == StorageType.SQL) {
GlobalDataManager.SQLMethod.cancelSQLMethod();
}
// 清理数据
if (getStorageType() == StorageType.LOCAL && getConfig().getBoolean("DELETE-DATA")) {
getPlayerDataFolder().delete();
}
// 清理数据
if (getStorageType() == StorageType.SQL && getConfig().getBoolean("DELETE-VARIABLE")) {
GlobalDataManager.clearInvalidVariables();
}
// 提示信息
TLocale.Logger.info("NOTIFY.SUCCESS-DISABLE");
// 卸载牛逼玩意儿
TLib.unload();
// 关闭服务器
Bukkit.shutdown();
}
// *********************************
//
// 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(Economy economy) {
Main.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 null;
}
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;
}
// *********************************
//
// Private Setter
//
// *********************************
static void setIsInternetOnline(boolean isInternetOnline) {
Main.isInternetOnline = isInternetOnline;
}
static void setPlayerDataFolder(File playerDataFolder) {
Main.playerDataFolder = playerDataFolder;
}
static void setServerDataFolder(File serverDataFolder) {
Main.serverDataFolder = serverDataFolder;
}
static void setStorageType(StorageType storageType) {
Main.storageType = storageType;
}
}

View File

@@ -0,0 +1,167 @@
package me.skymc.taboolib;
import me.skymc.taboolib.common.nms.NMSHandler;
import me.skymc.taboolib.other.NumberUtils;
import me.skymc.taboolib.playerdata.DataUtils;
import net.md_5.bungee.api.ChatColor;
import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;
import java.util.Arrays;
import java.util.UUID;
/**
* @author sky
*/
public class TabooLib {
private static boolean spigot = false;
private static boolean silent = false;
static {
try {
// 判断是否为独立客户端运行,不是判断 Bukkit 与 Spigot
Class.forName("org.bukkit.Bukkit");
spigot = true;
} catch (Exception ignored) {
}
}
/**
* 获取主类对象,因 Main 名称容易造成混淆所以转移至此
*/
public static Main instance() {
return (Main) Main.getInst();
}
/**
* 插件是否为 TabooLib沙雕方法
*/
public static boolean isTabooLib(Plugin plugin) {
return plugin.equals(instance()) || plugin.getName().equals("TabooLib");
}
/**
* 插件是否依赖于 TabooLib依赖或软兼容
*/
public static boolean isDependTabooLib(Plugin plugin) {
return plugin.getDescription().getDepend().contains("TabooLib") || plugin.getDescription().getSoftDepend().contains("TabooLib");
}
/**
* 是否为 Spigot 核心,因 TabooLib 可在 BungeeCord 上运行所以添加此方法
*/
public static boolean isSpigot() {
return spigot;
}
/**
* 是否为静默模式
*/
public static boolean isSilent() {
return silent;
}
/**
* 设置静默模式,启用后将关闭部分提示
*/
public static void setSilent(boolean silent) {
TabooLib.silent = silent;
}
/**
* 获取 TabooLib 插件版本
*/
public static double getPluginVersion() {
return NumberUtils.getDouble(Main.getInst().getDescription().getVersion());
}
/**
* 获取服务端版本
*/
public static String getVersion() {
return Bukkit.getServer().getClass().getName().split("\\.")[3];
}
/**
* 获取服务端版本数字
*/
public static int getVersionNumber() {
return getVerint();
}
/**
* 重置服务器序列号
*/
public static void resetServerUID() {
DataUtils.getPluginData("TabooLibrary", null).set("serverUID", UUID.randomUUID().toString());
}
/**
* 是否为调试模式
*/
public static boolean isDebug() {
return DataUtils.getPluginData("TabooLibrary", instance()).getBoolean("debug");
}
/**
* 切换调试模式
*/
public static void setDebug(boolean debug) {
DataUtils.getPluginData("TabooLibrary", instance()).set("debug", debug);
}
/**
* 发送调试信息
*/
public static void debug(String... args) {
debug(instance(), args);
}
/**
* 发送调试信息
*/
public static void debug(Plugin plugin, String... args) {
if (TabooLib.isDebug()) {
Arrays.stream(args).forEach(var -> Bukkit.getConsoleSender().sendMessage(ChatColor.DARK_RED + "[TabooLib - DEBUG][" + plugin.getName() + "] " + ChatColor.RED + var));
}
}
/**
* 获取服务器序列号
*/
public static String getServerUID() {
if (!DataUtils.getPluginData("TabooLibrary", null).contains("serverUID")) {
DataUtils.getPluginData("TabooLibrary", null).set("serverUID", UUID.randomUUID().toString());
}
return DataUtils.getPluginData("TabooLibrary", null).getString("serverUID");
}
/**
* 获取服务器 TPS
*/
public static double[] getTPS() {
return NMSHandler.getHandler().getTPS();
}
@Deprecated
public static int getVerint() {
String version = getVersion();
if (version.startsWith("v1_7")) {
return 10700;
} else if (version.startsWith("v1_8")) {
return 10800;
} else if (version.startsWith("v1_9")) {
return 10900;
} else if (version.startsWith("v1_10")) {
return 11000;
} else if (version.startsWith("v1_11")) {
return 11100;
} else if (version.startsWith("v1_12")) {
return 11200;
} else if (version.startsWith("v1_13")) {
return 11300;
}
return 0;
}
}

View File

@@ -0,0 +1,128 @@
package me.skymc.taboolib;
import com.ilummc.tlib.resources.TLocale;
import me.skymc.taboolib.mysql.builder.SQLColumn;
import me.skymc.taboolib.mysql.builder.SQLColumnType;
import me.skymc.taboolib.mysql.builder.SQLHost;
import me.skymc.taboolib.mysql.builder.SQLTable;
import me.skymc.taboolib.mysql.hikari.HikariHandler;
import me.skymc.taboolib.string.StringUtils;
import org.bukkit.Bukkit;
import javax.sql.DataSource;
import java.util.HashMap;
/**
* @Author sky
* @Since 2018-08-23 17:15
*/
public class TabooLibDatabase {
private static SQLHost host;
private static DataSource dataSource;
private static HashMap<String, SQLTable> tables = new HashMap<>();
static void init() {
if (Main.getStorageType() != Main.StorageType.SQL) {
return;
}
// 数据库地址
host = new SQLHost(
// 地址
Main.getInst().getConfig().getString("MYSQL.HOST"),
// 用户
Main.getInst().getConfig().getString("MYSQL.USER"),
// 端口
Main.getInst().getConfig().getString("MYSQL.POST"),
// 密码
Main.getInst().getConfig().getString("MYSQL.PASSWORD"),
// 数据库
Main.getInst().getConfig().getString("MYSQL.DATABASE"), TabooLib.instance());
// 连接数据库
try {
dataSource = HikariHandler.createDataSource(host);
} catch (Exception ignored) {
TLocale.Logger.error("NOTIFY.ERROR-CONNECTION-FAIL");
return;
}
// 创建各项数据表
createTableWithPlayerData();
createTableWithPluginData();
createTableWithServerUUID();
}
/**
* 创建玩家数据表
*/
static void createTableWithPlayerData() {
SQLTable table = new SQLTable(Main.getTablePrefix() + "_playerdata", SQLColumn.PRIMARY_KEY_ID, new SQLColumn(SQLColumnType.TEXT, "username"), new SQLColumn(SQLColumnType.TEXT, "configuration"));
table.executeUpdate(table.createQuery()).dataSource(dataSource).run();
tables.put("playerdata", table);
}
/**
* 创建插件数据表
*/
static void createTableWithPluginData() {
SQLTable table = new SQLTable(Main.getTablePrefix() + "_plugindata", SQLColumn.PRIMARY_KEY_ID, new SQLColumn(SQLColumnType.TEXT, "name"), new SQLColumn(SQLColumnType.TEXT, "variable"), new SQLColumn(SQLColumnType.TEXT, "upgrade"));
table.executeUpdate(table.createQuery()).dataSource(dataSource).run();
tables.put("plugindata", table);
}
/**
* 创建服务器数据表
*/
static void createTableWithServerUUID() {
SQLTable table = new SQLTable(Main.getTablePrefix() + "_serveruuid", SQLColumn.PRIMARY_KEY_ID, new SQLColumn(SQLColumnType.TEXT, "uuid"), new SQLColumn(SQLColumnType.TEXT, "hash"));
table.executeUpdate(table.createQuery()).dataSource(dataSource).run();
tables.put("serveruuid", table);
// 获取当前服务器信息
String hash = getServerHash(TabooLib.getServerUID());
if (hash == null) {
// 写入序列号
table.executeUpdate("insert into " + table.getTableName() + " values(null, ?, ?)")
.dataSource(dataSource)
.statement(s -> {
s.setString(1, TabooLib.getServerUID());
s.setString(2, StringUtils.hashKeyForDisk(Main.getInst().getDataFolder().getPath()));
}).run();
} else if (!hash.equals(StringUtils.hashKeyForDisk(Main.getInst().getDataFolder().getPath()))) {
TLocale.Logger.error("NOTIFY.ERROR-SERVER-KEY");
TabooLib.resetServerUID();
Bukkit.shutdown();
}
}
/**
* 获取服务器序列号对应的目录哈希值
*
* @param uuid 服务器序列号
* @return 目录哈希值
*/
public static String getServerHash(String uuid) {
SQLTable table = tables.get("serveruuid");
return table.executeQuery("select * from " + table.getTableName() + " where uuid = ?")
.dataSource(dataSource)
.statement(s -> s.setString(1, uuid))
.resultNext(r -> r.getString("hash"))
.run(null, "");
}
// *********************************
//
// Getter and Setter
//
// *********************************
public static SQLHost getHost() {
return host;
}
public static HashMap<String, SQLTable> getTables() {
return tables;
}
public static DataSource getDataSource() {
return dataSource;
}
}

View File

@@ -0,0 +1,300 @@
package me.skymc.taboolib;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.ilummc.tlib.TLib;
import com.ilummc.tlib.annotations.Dependency;
import com.ilummc.tlib.dependency.TDependencyLoader;
import com.ilummc.tlib.inject.TDependencyInjector;
import com.ilummc.tlib.resources.TLocale;
import me.skymc.taboolib.bstats.Metrics;
import me.skymc.taboolib.deprecated.TabooLibDeprecated;
import me.skymc.taboolib.events.TPluginEnableEvent;
import me.skymc.taboolib.fileutils.FileUtils;
import me.skymc.taboolib.listener.TListener;
import me.skymc.taboolib.listener.TListenerHandler;
import me.skymc.taboolib.methods.ReflectionUtils;
import me.skymc.taboolib.playerdata.DataUtils;
import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.server.PluginDisableEvent;
import org.bukkit.plugin.Plugin;
import java.io.File;
import java.io.InputStream;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.net.InetAddress;
import java.util.*;
/**
* @Author sky
* @Since 2018-08-23 17:04
*/
@TListener
public class TabooLibLoader implements Listener {
/*
关于 TabooLib 各项自动化接口的执行顺序
[ENABLING]
第一阶段:运行 @TInjectInstance Inject
第二阶段(先后):实例化 @TListener -> 实例化 @Instantiable
第三阶段(并行):运行 @TFunction & 运行 @TInject
[ENABLED]
第三阶段:注册 @TListener
*/
static TabooLibDeprecated tabooLibDeprecated;
static Map<String, List<Class>> pluginClasses = Maps.newHashMap();
static List<Loader> loaders = Lists.newArrayList();
static List<Runnable> tasks = Lists.newArrayList();
static boolean started;
static void setup() {
testInternet();
setupDataFolder();
setupDatabase();
setupLibraries();
}
static void register() {
setupClasses();
preLoadClasses();
registerListener();
registerMetrics();
postLoadClasses();
try {
tabooLibDeprecated = new TabooLibDeprecated();
} catch (Exception e) {
e.printStackTrace();
}
Bukkit.getScheduler().runTask(TabooLib.instance(), () -> {
for (Runnable task : tasks) {
try {
task.run();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
static void unregister() {
unloadClasses();
try {
tabooLibDeprecated.unregister();
} catch (Exception e) {
e.printStackTrace();
}
}
public static TabooLibDeprecated getTabooLibDeprecated() {
return tabooLibDeprecated;
}
public static Optional<List<Class>> getPluginClasses(Plugin plugin) {
return Optional.ofNullable(pluginClasses.get(plugin.getName()));
}
public static List<Class> getPluginClassSafely(Plugin plugin) {
List<Class> classes = pluginClasses.get(plugin.getName());
return classes == null ? new ArrayList<>() : new ArrayList<>(classes);
}
public static void runTaskOnEnabled(Runnable runnable) {
if (Main.isStarted()) {
Bukkit.getScheduler().runTask(TabooLib.instance(), () -> {
try {
runnable.run();
} catch (Throwable t) {
t.printStackTrace();
}
});
} else {
tasks.add(runnable);
}
}
static boolean isLoader(Class pluginClass) {
return !Loader.class.equals(pluginClass) && Loader.class.isAssignableFrom(pluginClass);
}
static void preLoadClasses() {
pluginClasses.forEach((key, classes) -> classes.forEach(pluginClass -> preLoadClass(Bukkit.getPluginManager().getPlugin(key), pluginClass)));
}
static void postLoadClasses() {
pluginClasses.forEach((key, classes) -> classes.forEach(pluginClass -> postLoadClass(Bukkit.getPluginManager().getPlugin(key), pluginClass)));
}
static void unloadClasses() {
pluginClasses.forEach((key, classes) -> classes.forEach(pluginClass -> unloadClass(Bukkit.getPluginManager().getPlugin(key), pluginClass)));
}
static void registerListener() {
TListenerHandler.setupListeners();
Bukkit.getScheduler().runTask(TabooLib.instance(), TListenerHandler::registerListeners);
}
static void registerMetrics() {
Metrics metrics = new Metrics(TabooLib.instance());
metrics.addCustomChart(new Metrics.SingleLineChart("plugins_using_taboolib", () -> Math.toIntExact(Arrays.stream(Bukkit.getPluginManager().getPlugins()).filter(plugin -> plugin.getDescription().getDepend().contains("TabooLib")).count())));
}
static void setupDataFolder() {
Main.setPlayerDataFolder(FileUtils.folder(Main.getInst().getConfig().getString("DATAURL.PLAYER-DATA")));
Main.setServerDataFolder(FileUtils.folder(Main.getInst().getConfig().getString("DATAURL.SERVER-DATA")));
}
static void setupDatabase() {
DataUtils.addPluginData("TabooLibrary", null);
Main.setStorageType(Main.getInst().getConfig().getBoolean("MYSQL.ENABLE") ? Main.StorageType.SQL : Main.StorageType.LOCAL);
TabooLibDatabase.init();
}
static void setupAddons() {
TabooLib.instance().saveResource("Addons/TabooLibDeprecated", true);
// 傻逼 Gradle 的 shadow 插件会将所有 jar 排除
// https://github.com/johnrengelman/shadow/issues/276
new File(TabooLib.instance().getDataFolder(), "Addons/TabooLibDeprecated").renameTo(new File(TabooLib.instance().getDataFolder(), "Addons/TabooLibDeprecated.jar"));
File file = new File(TabooLib.instance().getDataFolder(), "Addons");
if (file.exists()) {
Arrays.stream(file.listFiles()).forEach(listFile -> TDependencyLoader.addToPath(TabooLib.instance(), listFile));
}
}
static void setupLibraries() {
if (Main.isOfflineVersion()) {
Arrays.stream(TDependencyInjector.getDependencies(TLib.getTLib())).filter(dependency -> dependency.type() == Dependency.Type.LIBRARY && dependency.maven().matches(".*:.*:.*")).map(dependency -> String.join("-", dependency.maven().split(":")) + ".jar").forEach(fileName -> {
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));
}
});
}
}
static void testInternet() {
try {
InetAddress inetAddress = InetAddress.getByName(Main.getInst().getConfig().getString("TEST-URL", "aliyun.com"));
Main.setIsInternetOnline(inetAddress.isReachable(10000));
} catch (Exception ignored) {
}
if (!Main.isInternetOnline() && !Main.isOfflineVersion() && !Main.isLibrariesExists()) {
TLocale.Logger.error("TLIB.LOAD-FAIL-OFFLINE", Main.getInst().getDescription().getVersion());
for (; ; ) {
// 停止主线程
}
}
}
static void setupClasses(Plugin plugin) {
if (TabooLib.isTabooLib(plugin) || TabooLib.isDependTabooLib(plugin)) {
try {
long time = System.currentTimeMillis();
List<Class> classes;
IgnoreClasses annotation = plugin.getClass().getAnnotation(IgnoreClasses.class);
if (annotation != null) {
classes = FileUtils.getClasses(plugin, annotation.value());
} else {
classes = FileUtils.getClasses(plugin);
}
TabooLib.debug("Saved " + classes.size() + " classes (" + plugin.getName() + ") (" + (System.currentTimeMillis() - time) + "ms)");
pluginClasses.put(plugin.getName(), classes);
} catch (Exception ignored) {
}
}
}
static void setupClasses() {
Arrays.stream(Bukkit.getPluginManager().getPlugins()).forEach(TabooLibLoader::setupClasses);
pluginClasses.get("TabooLib").stream().filter(TabooLibLoader::isLoader).forEach(pluginClass -> {
try {
loaders.add((Loader) ReflectionUtils.instantiateObject(pluginClass));
} catch (Exception e) {
e.printStackTrace();
}
loaders.sort(Comparator.comparingInt(Loader::priority));
});
}
static void preLoadClass(Plugin plugin, Class<?> loadClass) {
loaders.forEach(loader -> {
try {
loader.preLoad(plugin, loadClass);
} catch (NoClassDefFoundError ignore) {
} catch (Throwable e) {
e.printStackTrace();
}
});
}
static void postLoadClass(Plugin plugin, Class<?> loadClass) {
loaders.forEach(loader -> {
try {
loader.postLoad(plugin, loadClass);
} catch (NoClassDefFoundError ignore) {
} catch (Throwable e) {
e.printStackTrace();
}
});
}
static void unloadClass(Plugin plugin, Class<?> loadClass) {
loaders.forEach(loader -> {
try {
loader.unload(plugin, loadClass);
} catch (NoClassDefFoundError ignore) {
} catch (Throwable e) {
e.printStackTrace();
}
});
}
@EventHandler(priority = EventPriority.LOWEST)
public void onEnablePre(TPluginEnableEvent e) {
setupClasses(e.getPlugin());
Optional.ofNullable(pluginClasses.get(e.getPlugin().getName())).ifPresent(classes -> classes.forEach(pluginClass -> preLoadClass(e.getPlugin(), pluginClass)));
}
@EventHandler
public void onEnablePost(TPluginEnableEvent e) {
Optional.ofNullable(pluginClasses.get(e.getPlugin().getName())).ifPresent(classes -> classes.forEach(pluginClass -> postLoadClass(e.getPlugin(), pluginClass)));
}
@EventHandler(priority = EventPriority.MONITOR)
public void onDisable(PluginDisableEvent e) {
Optional.ofNullable(pluginClasses.remove(e.getPlugin().getName())).ifPresent(classes -> classes.forEach(pluginClass -> unloadClass(e.getPlugin(), pluginClass)));
}
public interface Loader {
default void preLoad(Plugin plugin, Class<?> loadClass) {
}
default void postLoad(Plugin plugin, Class<?> loadClass) {
}
default void unload(Plugin plugin, Class<?> cancelClass) {
}
default int priority() {
return 0;
}
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface IgnoreClasses {
String[] value();
}
}

View File

@@ -0,0 +1,29 @@
package me.skymc.taboolib.anvil;
import org.bukkit.entity.Player;
/**
* @Author sky
* @Since 2018-09-08 15:47
*/
public class AnvilContainer extends net.minecraft.server.v1_12_R1.ContainerAnvil {
public AnvilContainer(net.minecraft.server.v1_12_R1.EntityHuman player) {
super(player.inventory, player.world, new net.minecraft.server.v1_12_R1.BlockPosition(0, 0, 0), player);
}
@Override
public boolean a(net.minecraft.server.v1_12_R1.EntityHuman player) {
return true;
}
public static void openAnvil(Player p) {
net.minecraft.server.v1_12_R1.EntityPlayer player = ((org.bukkit.craftbukkit.v1_12_R1.entity.CraftPlayer) p).getHandle();
AnvilContainer container = new AnvilContainer(player);
int c = player.nextContainerCounter();
player.playerConnection.sendPacket(new net.minecraft.server.v1_12_R1.PacketPlayOutOpenWindow(c, "minecraft:anvil", new net.minecraft.server.v1_12_R1.ChatMessage("Repairing"), 0));
player.activeContainer = container;
player.activeContainer.windowId = c;
player.activeContainer.addSlotListener(player);
}
}

View File

@@ -0,0 +1,44 @@
package me.skymc.taboolib.anvil;
import com.ilummc.tlib.util.asm.AsmClassLoader;
import me.skymc.taboolib.TabooLib;
import me.skymc.taboolib.common.loader.Instantiable;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
/**
* @author sky
*/
@Instantiable("AnvilContainerAPI")
public class AnvilContainerAPI implements Listener {
private static Class<?> impl;
public AnvilContainerAPI() {
try {
impl = AsmClassLoader.createNewClass("me.skymc.taboolib.anvil.AnvilContainer", AnvilContainerGenerator.generate());
Bukkit.getPluginManager().registerEvents(this, TabooLib.instance());
} catch (Exception e) {
e.printStackTrace();
}
}
public static void openAnvil(Player player) {
try {
impl.getMethod("openAnvil", Player.class).invoke(impl, player);
} catch (Exception e) {
e.printStackTrace();
}
}
@EventHandler
public void example(PlayerCommandPreprocessEvent e) {
if (e.getMessage().equalsIgnoreCase("/anvilExample") && e.getPlayer().hasPermission("taboolib.admin")) {
e.setCancelled(true);
openAnvil(e.getPlayer());
}
}
}

View File

@@ -0,0 +1,142 @@
package me.skymc.taboolib.anvil;
import me.skymc.taboolib.TabooLib;
import org.objectweb.asm.*;
/**
* @author idea
*/
public class AnvilContainerGenerator {
public static byte[] generate() {
String version = TabooLib.getVersion();
ClassWriter cw = new ClassWriter(0);
FieldVisitor fv;
MethodVisitor mv;
AnnotationVisitor av0;
cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER, "me/skymc/taboolib/anvil/AnvilContainer", null, "net/minecraft/server/" + version + "/ContainerAnvil", null);
cw.visitSource("AnvilContainer.java", null);
{
mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "(Lnet/minecraft/server/" + version + "/EntityHuman;)V", null, null);
mv.visitCode();
Label l0 = new Label();
mv.visitLabel(l0);
mv.visitLineNumber(12, l0);
mv.visitVarInsn(Opcodes.ALOAD, 0);
mv.visitVarInsn(Opcodes.ALOAD, 1);
mv.visitFieldInsn(Opcodes.GETFIELD, "net/minecraft/server/" + version + "/EntityHuman", "inventory", "Lnet/minecraft/server/" + version + "/PlayerInventory;");
mv.visitVarInsn(Opcodes.ALOAD, 1);
mv.visitFieldInsn(Opcodes.GETFIELD, "net/minecraft/server/" + version + "/EntityHuman", "world", "Lnet/minecraft/server/" + version + "/World;");
mv.visitTypeInsn(Opcodes.NEW, "net/minecraft/server/" + version + "/BlockPosition");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "net/minecraft/server/" + version + "/BlockPosition", "<init>", "(III)V", false);
mv.visitVarInsn(Opcodes.ALOAD, 1);
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "net/minecraft/server/" + version + "/ContainerAnvil", "<init>", "(Lnet/minecraft/server/" + version + "/PlayerInventory;Lnet/minecraft/server/" + version + "/World;Lnet/minecraft/server/" + version + "/BlockPosition;Lnet/minecraft/server/" + version + "/EntityHuman;)V", false);
Label l1 = new Label();
mv.visitLabel(l1);
mv.visitLineNumber(13, l1);
mv.visitInsn(Opcodes.RETURN);
Label l2 = new Label();
mv.visitLabel(l2);
mv.visitLocalVariable("this", "Lme/skymc/taboolib/anvil/AnvilContainer;", null, l0, l2, 0);
mv.visitLocalVariable("player", "Lnet/minecraft/server/" + version + "/EntityHuman;", null, l0, l2, 1);
mv.visitMaxs(8, 2);
mv.visitEnd();
}
{
mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "a", "(Lnet/minecraft/server/" + version + "/EntityHuman;)Z", null, null);
mv.visitCode();
Label l0 = new Label();
mv.visitLabel(l0);
mv.visitLineNumber(17, l0);
mv.visitInsn(Opcodes.ICONST_1);
mv.visitInsn(Opcodes.IRETURN);
Label l1 = new Label();
mv.visitLabel(l1);
mv.visitLocalVariable("this", "Lme/skymc/taboolib/anvil/AnvilContainer;", null, l0, l1, 0);
mv.visitLocalVariable("player", "Lnet/minecraft/server/" + version + "/EntityHuman;", null, l0, l1, 1);
mv.visitMaxs(1, 2);
mv.visitEnd();
}
{
mv = cw.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "openAnvil", "(Lorg/bukkit/entity/Player;)V", null, null);
mv.visitCode();
Label l0 = new Label();
mv.visitLabel(l0);
mv.visitLineNumber(21, l0);
mv.visitVarInsn(Opcodes.ALOAD, 0);
mv.visitTypeInsn(Opcodes.CHECKCAST, "org/bukkit/craftbukkit/" + version + "/entity/CraftPlayer");
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "org/bukkit/craftbukkit/" + version + "/entity/CraftPlayer", "getHandle", "()Lnet/minecraft/server/" + version + "/EntityPlayer;", false);
mv.visitVarInsn(Opcodes.ASTORE, 1);
Label l1 = new Label();
mv.visitLabel(l1);
mv.visitLineNumber(22, l1);
mv.visitTypeInsn(Opcodes.NEW, "me/skymc/taboolib/anvil/AnvilContainer");
mv.visitInsn(Opcodes.DUP);
mv.visitVarInsn(Opcodes.ALOAD, 1);
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "me/skymc/taboolib/anvil/AnvilContainer", "<init>", "(Lnet/minecraft/server/" + version + "/EntityHuman;)V", false);
mv.visitVarInsn(Opcodes.ASTORE, 2);
Label l2 = new Label();
mv.visitLabel(l2);
mv.visitLineNumber(23, l2);
mv.visitVarInsn(Opcodes.ALOAD, 1);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "net/minecraft/server/" + version + "/EntityPlayer", "nextContainerCounter", "()I", false);
mv.visitVarInsn(Opcodes.ISTORE, 3);
Label l3 = new Label();
mv.visitLabel(l3);
mv.visitLineNumber(24, l3);
mv.visitVarInsn(Opcodes.ALOAD, 1);
mv.visitFieldInsn(Opcodes.GETFIELD, "net/minecraft/server/" + version + "/EntityPlayer", "playerConnection", "Lnet/minecraft/server/" + version + "/PlayerConnection;");
mv.visitTypeInsn(Opcodes.NEW, "net/minecraft/server/" + version + "/PacketPlayOutOpenWindow");
mv.visitInsn(Opcodes.DUP);
mv.visitVarInsn(Opcodes.ILOAD, 3);
mv.visitLdcInsn("minecraft:anvil");
mv.visitTypeInsn(Opcodes.NEW, "net/minecraft/server/" + version + "/ChatMessage");
mv.visitInsn(Opcodes.DUP);
mv.visitLdcInsn("Repairing");
mv.visitInsn(Opcodes.ICONST_0);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "net/minecraft/server/" + version + "/ChatMessage", "<init>", "(Ljava/lang/String;[Ljava/lang/Object;)V", false);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "net/minecraft/server/" + version + "/PacketPlayOutOpenWindow", "<init>", "(ILjava/lang/String;Lnet/minecraft/server/" + version + "/IChatBaseComponent;I)V", false);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "net/minecraft/server/" + version + "/PlayerConnection", "sendPacket", "(Lnet/minecraft/server/" + version + "/Packet;)V", false);
Label l4 = new Label();
mv.visitLabel(l4);
mv.visitLineNumber(25, l4);
mv.visitVarInsn(Opcodes.ALOAD, 1);
mv.visitVarInsn(Opcodes.ALOAD, 2);
mv.visitFieldInsn(Opcodes.PUTFIELD, "net/minecraft/server/" + version + "/EntityPlayer", "activeContainer", "Lnet/minecraft/server/" + version + "/Container;");
Label l5 = new Label();
mv.visitLabel(l5);
mv.visitLineNumber(26, l5);
mv.visitVarInsn(Opcodes.ALOAD, 1);
mv.visitFieldInsn(Opcodes.GETFIELD, "net/minecraft/server/" + version + "/EntityPlayer", "activeContainer", "Lnet/minecraft/server/" + version + "/Container;");
mv.visitVarInsn(Opcodes.ILOAD, 3);
mv.visitFieldInsn(Opcodes.PUTFIELD, "net/minecraft/server/" + version + "/Container", "windowId", "I");
Label l6 = new Label();
mv.visitLabel(l6);
mv.visitLineNumber(27, l6);
mv.visitVarInsn(Opcodes.ALOAD, 1);
mv.visitFieldInsn(Opcodes.GETFIELD, "net/minecraft/server/" + version + "/EntityPlayer", "activeContainer", "Lnet/minecraft/server/" + version + "/Container;");
mv.visitVarInsn(Opcodes.ALOAD, 1);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "net/minecraft/server/" + version + "/Container", "addSlotListener", "(Lnet/minecraft/server/" + version + "/ICrafting;)V", false);
Label l7 = new Label();
mv.visitLabel(l7);
mv.visitLineNumber(28, l7);
mv.visitInsn(Opcodes.RETURN);
Label l8 = new Label();
mv.visitLabel(l8);
mv.visitLocalVariable("p", "Lorg/bukkit/entity/Player;", null, l0, l8, 0);
mv.visitLocalVariable("player", "Lnet/minecraft/server/" + version + "/EntityPlayer;", null, l1, l8, 1);
mv.visitLocalVariable("container", "Lme/skymc/taboolib/anvil/AnvilContainer;", null, l2, l8, 2);
mv.visitLocalVariable("c", "I", null, l3, l8, 3);
mv.visitMaxs(9, 4);
mv.visitEnd();
}
cw.visitEnd();
return cw.toByteArray();
}
}

View File

@@ -0,0 +1,63 @@
package me.skymc.taboolib.bookformatter;
import org.bukkit.Achievement;
import java.util.HashMap;
import static org.bukkit.Achievement.*;
public final class BookAchievement {
private static final HashMap<Achievement, String> achievements = new HashMap<>();
static {
achievements.put(OPEN_INVENTORY, "openInventory");
achievements.put(MINE_WOOD, "mineWood");
achievements.put(BUILD_WORKBENCH, "buildWorkBench");
achievements.put(BUILD_PICKAXE, "buildPickaxe");
achievements.put(BUILD_FURNACE, "buildFurnace");
achievements.put(ACQUIRE_IRON, "aquireIron");
achievements.put(BUILD_HOE, "buildHoe");
achievements.put(MAKE_BREAD, "makeBread");
achievements.put(BAKE_CAKE, "bakeCake");
achievements.put(BUILD_BETTER_PICKAXE, "buildBetterPickaxe");
achievements.put(COOK_FISH, "cookFish");
achievements.put(ON_A_RAIL, "onARail");
achievements.put(BUILD_SWORD, "buildSword");
achievements.put(KILL_ENEMY, "killEnemy");
achievements.put(KILL_COW, "killCow");
achievements.put(FLY_PIG, "flyPig");
achievements.put(SNIPE_SKELETON, "snipeSkeleton");
achievements.put(GET_DIAMONDS, "diamonds");
achievements.put(NETHER_PORTAL, "portal");
achievements.put(GHAST_RETURN, "ghast");
achievements.put(GET_BLAZE_ROD, "blazerod");
achievements.put(BREW_POTION, "potion");
achievements.put(END_PORTAL, "thEnd");
achievements.put(THE_END, "theEnd2");
achievements.put(ENCHANTMENTS, "enchantments");
achievements.put(OVERKILL, "overkill");
achievements.put(BOOKCASE, "bookacase");
achievements.put(EXPLORE_ALL_BIOMES, "exploreAllBiomes");
achievements.put(SPAWN_WITHER, "spawnWither");
achievements.put(KILL_WITHER, "killWither");
achievements.put(FULL_BEACON, "fullBeacon");
achievements.put(BREED_COW, "breedCow");
achievements.put(DIAMONDS_TO_YOU, "diamondsToYou");
achievements.put(OVERPOWERED, "overpowered");
}
private BookAchievement() {
}
/**
* Gets the json id from the bukkit achievement passed as argument
*
* @param achievement the achievement
* @return the achievement's id or null if not found
*/
public static String toId(Achievement achievement) {
return achievements.get(achievement);
}
}

Some files were not shown because too many files have changed in this diff Show More