1
0
mirror of https://e.coding.net/circlecloud/TellRaw.git synced 2024-12-25 07:08:51 +00:00

首次提交...

Signed-off-by: 502647092 <jtb1@163.com>
This commit is contained in:
502647092 2016-01-13 13:31:39 +08:00
commit 5d5bf4edd3
17 changed files with 2693 additions and 0 deletions

16
.classpath Normal file
View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src/main/java"/>
<classpathentry kind="src" path="src/main/resources"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>

41
.gitignore vendored Normal file
View File

@ -0,0 +1,41 @@
# Eclipse stuff
/.settings
# netbeans
/nbproject
# we use maven!
/build.xml
# maven
/target
/repo
# vim
.*.sw[a-p]
# various other potential build files
/build
/bin
/dist
/manifest.mf
/world
# Mac filesystem dust
*.DS_Store
# intellij
*.iml
*.ipr
*.iws
.idea/
# Project Stuff
/src/main/resources/Soulbound
# Other Libraries
*.jar
# Atlassian Stuff
/atlassian-ide-plugin.xml

23
.project Normal file
View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>TellRaw</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

64
pom.xml Normal file
View File

@ -0,0 +1,64 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.citycraft</groupId>
<artifactId>TellRaw</artifactId>
<version>1.0</version>
<name>TellRaw</name>
<build>
<finalName>${project.name}</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<env.BUILD_NUMBER>Debug</env.BUILD_NUMBER>
<env.GIT_ID>Debug</env.GIT_ID>
<jenkins.url>http://ci.citycraft.cn:8080</jenkins.url>
</properties>
<repositories>
<repository>
<id>spigot-repo</id>
<url>https://hub.spigotmc.org/nexus/content/groups/public/</url>
</repository>
<repository>
<id>citycraft-repo</id>
<url>${jenkins.url}/plugin/repository/everything/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<type>jar</type>
<version>1.8.8-R0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.comphenix.protocol</groupId>
<artifactId>ProtocolLib</artifactId>
<version>3.6.5-SNAPSHOT</version>
<scope>system</scope>
<systemPath>${project.basedir}/lib/ProtocolLib-3.6.5-SNAPSHOT.jar</systemPath>
</dependency>
<dependency>
<groupId>cn.citycraft</groupId>
<artifactId>GsonAgent</artifactId>
<type>jar</type>
<version>1.0</version>
</dependency>
</dependencies>
</project>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,64 @@
package cn.citycraft.TellRaw;
import java.io.File;
import java.io.IOException;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.configuration.file.YamlConfiguration;
/**
* PluginHelper 通用配置文件类
*
* @author
*/
public class PluginHelperConfig {
public static YamlConfiguration a;
public static File configfile = new File(Bukkit.getUpdateFolderFile().getParentFile(), "PluginHelper" + File.separatorChar + "config.yml");
static {
try {
if (!configfile.exists()) {
configfile.createNewFile();
}
a = YamlConfiguration.loadConfiguration(configfile);
initFile(a);
} catch (final IOException e) {
a = new YamlConfiguration();
try {
initFile(a);
} catch (final IOException e1) {
}
}
}
public static YamlConfiguration getConfig() {
try {
return YamlConfiguration.loadConfiguration(configfile);
} catch (final Exception e) {
return a;
}
}
public static String getGUID() {
return a.getString("guid");
}
private static void initFile(final YamlConfiguration config) throws IOException {
if (config.getString("guid") == null) {
config.options().header("数据中心 http://yum.citycraft.cn 收集的数据仅用于统计插件使用情况").copyDefaults(true);
config.set("guid", UUID.randomUUID().toString());
config.set("debug", false);
config.save(configfile);
}
if (!config.contains("YumAccount")) {
config.set("YumAccount.username", "Username Not Set");
config.set("YumAccount.password", "Password NotSet");
config.save(configfile);
}
if (!config.contains("TellrawManualHandle")) {
config.set("TellrawManualHandle", false);
config.save(configfile);
}
}
}

View File

@ -0,0 +1,117 @@
package cn.citycraft.TellRaw.common;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Collection;
import org.apache.commons.lang.Validate;
/**
* Represents a wrapper around an array class of an arbitrary reference type,
* which properly implements "value" hash code and equality functions.
* <p>
* This class is intended for use as a key to a map.
* </p>
*
* @author Glen Husman
* @param <E>
* The type of elements in the array.
* @see Arrays
*/
public final class ArrayWrapper<E> {
private E[] _array;
/**
* Creates an array wrapper with some elements.
*
* @param elements
* The elements of the array.
*/
@SafeVarargs
public ArrayWrapper(final E... elements) {
setArray(elements);
}
/**
* Converts an iterable element collection to an array of elements.
* The iteration order of the specified object will be used as the array
* element order.
*
* @param list
* The iterable of objects which will be converted to an array.
* @param c
* The type of the elements of the array.
* @return An array of elements in the specified iterable.
*/
@SuppressWarnings("unchecked")
public static <T> T[] toArray(final Iterable<? extends T> list, final Class<T> c) {
int size = -1;
if (list instanceof Collection<?>) {
@SuppressWarnings("rawtypes")
final Collection coll = (Collection) list;
size = coll.size();
}
if (size < 0) {
size = 0;
// Ugly hack: Count it ourselves
for (@SuppressWarnings("unused")
final T element : list) {
size++;
}
}
final T[] result = (T[]) Array.newInstance(c, size);
int i = 0;
for (final T element : list) { // Assumes iteration order is consistent
result[i++] = element; // Assign array element at index THEN increment counter
}
return result;
}
/**
* Determines if this object has a value equivalent to another object.
*
* @see Arrays#equals(Object[], Object[])
*/
@SuppressWarnings("rawtypes")
@Override
public boolean equals(final Object other) {
if (!(other instanceof ArrayWrapper)) {
return false;
}
return Arrays.equals(_array, ((ArrayWrapper) other)._array);
}
/**
* Retrieves a reference to the wrapped array instance.
*
* @return The array wrapped by this instance.
*/
public E[] getArray() {
return _array;
}
/**
* Gets the hash code represented by this objects value.
*
* @see Arrays#hashCode(Object[])
* @return This object's hash code.
*/
@Override
public int hashCode() {
return Arrays.hashCode(_array);
}
/**
* Set this wrapper to wrap a new array instance.
*
* @param array
* The new wrapped array.
*/
public void setArray(final E[] array) {
Validate.notNull(array, "The array must not be null.");
_array = array;
}
}

View File

@ -0,0 +1,22 @@
package cn.citycraft.TellRaw.common;
import java.io.IOException;
import cn.citycraft.GsonAgent.api.stream.JsonWriter;
/**
* Represents an object that can be serialized to a JSON writer instance.
*/
public interface JsonRepresentedObject {
/**
* Writes the JSON representation of this object to the specified writer.
*
* @param writer
* The JSON writer which will receive the object.
* @throws IOException
* If an error occurs writing to the stream.
*/
public void writeJson(JsonWriter writer) throws IOException;
}

View File

@ -0,0 +1,50 @@
package cn.citycraft.TellRaw.common;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import org.bukkit.configuration.serialization.ConfigurationSerializable;
import cn.citycraft.GsonAgent.api.stream.JsonWriter;
/**
* Represents a JSON string value.
* Writes by this object will not write name values nor begin/end objects in the
* JSON stream.
* All writes merely write the represented string value.
*/
public final class JsonString implements JsonRepresentedObject, ConfigurationSerializable {
private final String _value;
public JsonString(final CharSequence value) {
_value = value == null ? null : value.toString();
}
public static JsonString deserialize(final Map<String, Object> map) {
return new JsonString(map.get("stringValue").toString());
}
public String getValue() {
return _value;
}
@Override
public Map<String, Object> serialize() {
final HashMap<String, Object> theSingleValue = new HashMap<String, Object>();
theSingleValue.put("stringValue", _value);
return theSingleValue;
}
@Override
public String toString() {
return _value;
}
@Override
public void writeJson(final JsonWriter writer) throws IOException {
writer.value(getValue());
}
}

View File

@ -0,0 +1,159 @@
package cn.citycraft.TellRaw.common;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.configuration.serialization.ConfigurationSerializable;
import org.bukkit.configuration.serialization.ConfigurationSerialization;
import com.google.common.collect.BiMap;
import com.google.common.collect.ImmutableBiMap;
import cn.citycraft.GsonAgent.api.stream.JsonWriter;
import cn.citycraft.TellRaw.internal.FancyMessageInternal;
/**
* Internal class: Represents a component of a JSON-serializable
* {@link FancyMessageInternal}.
*/
public final class MessagePart implements JsonRepresentedObject, ConfigurationSerializable, Cloneable {
public static final BiMap<ChatColor, String> stylesToNames;
static {
final ImmutableBiMap.Builder<ChatColor, String> builder = ImmutableBiMap.builder();
for (final ChatColor style : ChatColor.values()) {
if (!style.isFormat()) {
continue;
}
String styleName;
switch (style) {
case MAGIC:
styleName = "obfuscated";
break;
case UNDERLINE:
styleName = "underlined";
break;
default:
styleName = style.name().toLowerCase();
break;
}
builder.put(style, styleName);
}
stylesToNames = builder.build();
}
static {
ConfigurationSerialization.registerClass(MessagePart.class);
}
public String clickActionData = null;
public String clickActionName = null;
public ChatColor color = ChatColor.WHITE;
public JsonRepresentedObject hoverActionData = null;
public String hoverActionName = null;
public String insertionData = null;
public ArrayList<ChatColor> styles = new ArrayList<ChatColor>();
public TextualComponent text = null;
public ArrayList<JsonRepresentedObject> translationReplacements = new ArrayList<JsonRepresentedObject>();
public MessagePart() {
this.text = null;
}
public MessagePart(final TextualComponent text) {
this.text = text;
}
@SuppressWarnings("unchecked")
public static MessagePart deserialize(final Map<String, Object> serialized) {
final MessagePart part = new MessagePart((TextualComponent) serialized.get("text"));
part.styles = (ArrayList<ChatColor>) serialized.get("styles");
part.color = ChatColor.getByChar(serialized.get("color").toString());
part.hoverActionName = (String) serialized.get("hoverActionName");
part.hoverActionData = (JsonRepresentedObject) serialized.get("hoverActionData");
part.clickActionName = (String) serialized.get("clickActionName");
part.clickActionData = (String) serialized.get("clickActionData");
part.insertionData = (String) serialized.get("insertion");
part.translationReplacements = (ArrayList<JsonRepresentedObject>) serialized.get("translationReplacements");
return part;
}
@Override
@SuppressWarnings("unchecked")
public MessagePart clone() throws CloneNotSupportedException {
final MessagePart obj = (MessagePart) super.clone();
obj.styles = (ArrayList<ChatColor>) styles.clone();
if (hoverActionData instanceof JsonString) {
obj.hoverActionData = new JsonString(((JsonString) hoverActionData).getValue());
} else if (hoverActionData instanceof FancyMessageInternal) {
obj.hoverActionData = ((FancyMessageInternal) hoverActionData).clone();
}
obj.translationReplacements = (ArrayList<JsonRepresentedObject>) translationReplacements.clone();
return obj;
}
public boolean hasText() {
return text != null;
}
@Override
public Map<String, Object> serialize() {
final HashMap<String, Object> map = new HashMap<String, Object>();
map.put("text", text);
map.put("styles", styles);
map.put("color", color.getChar());
map.put("hoverActionName", hoverActionName);
map.put("hoverActionData", hoverActionData);
map.put("clickActionName", clickActionName);
map.put("clickActionData", clickActionData);
map.put("insertion", insertionData);
map.put("translationReplacements", translationReplacements);
return map;
}
@Override
public void writeJson(final JsonWriter json) {
try {
json.beginObject();
text.writeJson(json);
json.name("color").value(color.name().toLowerCase());
for (final ChatColor style : styles) {
json.name(stylesToNames.get(style)).value(true);
}
if (clickActionName != null && clickActionData != null) {
json.name("clickEvent").beginObject().name("action").value(clickActionName).name("value").value(clickActionData).endObject();
}
if (hoverActionName != null && hoverActionData != null) {
json.name("hoverEvent").beginObject().name("action").value(hoverActionName).name("value");
hoverActionData.writeJson(json);
json.endObject();
}
if (insertionData != null) {
json.name("insertion").value(insertionData);
}
if (translationReplacements.size() > 0 && text != null && TextualComponent.isTranslatableText(text)) {
json.name("with").beginArray();
for (final JsonRepresentedObject obj : translationReplacements) {
obj.writeJson(json);
}
json.endArray();
}
json.endObject();
} catch (final IOException e) {
Bukkit.getLogger().log(Level.WARNING, "A problem occured during writing of JSON string", e);
}
}
}

View File

@ -0,0 +1,300 @@
package cn.citycraft.TellRaw.common;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.bukkit.Bukkit;
/**
* A class containing static utility methods and caches which are intended as
* reflective conveniences.
* Unless otherwise noted, upon failure methods will return {@code null}.
*/
public final class Reflection {
private static final Map<Class<?>, Map<String, Field>> _loadedFields = new HashMap<Class<?>, Map<String, Field>>();
/**
* Contains loaded methods in a cache.
* The map maps [types to maps of [method names to maps of [parameter types
* to method instances]]].
*/
private static final Map<Class<?>, Map<String, Map<ArrayWrapper<Class<?>>, Method>>> _loadedMethods = new HashMap<Class<?>, Map<String, Map<ArrayWrapper<Class<?>>, Method>>>();
/**
* Stores loaded classes from the {@code net.minecraft.server} package.
*/
private static final Map<String, Class<?>> _loadedNMSClasses = new HashMap<String, Class<?>>();
/**
* Stores loaded classes from the {@code org.bukkit.craftbukkit} package
* (and subpackages).
*/
private static final Map<String, Class<?>> _loadedOBCClasses = new HashMap<String, Class<?>>();
private static String _versionString;
private Reflection() {
}
@SuppressWarnings("rawtypes")
public static List<Field> getDeclaredFieldByType(final Class source, final Class type) {
final List<Field> list = new ArrayList<>();
for (final Field field : source.getDeclaredFields()) {
if (field.getType() == type) {
field.setAccessible(true);
list.add(field);
}
}
return list;
}
/**
* Retrieves a {@link Field} instance declared by the specified class with
* the specified name.
* Java access modifiers are ignored during this retrieval. No guarantee is
* made as to whether the field
* returned will be an instance or static field.
* <p>
* A global caching mechanism within this class is used to store fields.
* Combined with synchronization, this guarantees that no field will be
* reflectively looked up twice.
* </p>
* <p>
* If a field is deemed suitable for return,
* {@link Field#setAccessible(boolean) setAccessible} will be invoked with
* an argument of {@code true} before it is returned. This ensures that
* callers do not have to check or worry about Java access modifiers when
* dealing with the returned instance.
* </p>
*
* @param clazz
* The class which contains the field to retrieve.
* @param name
* The declared name of the field in the class.
* @return A field object with the specified name declared by the specified
* class.
* @throws Exception
* @see Class#getDeclaredField(String)
*/
public synchronized static Field getField(final Class<?> clazz, final String name) throws Exception {
Map<String, Field> loaded;
if (!_loadedFields.containsKey(clazz)) {
loaded = new HashMap<String, Field>();
_loadedFields.put(clazz, loaded);
} else {
loaded = _loadedFields.get(clazz);
}
if (loaded.containsKey(name)) {
// If the field is loaded (or cached as not existing), return the
// relevant value, which might be null
return loaded.get(name);
}
try {
final Field field = clazz.getDeclaredField(name);
field.setAccessible(true);
loaded.put(name, field);
return field;
} catch (final Exception e) {
// Cache field as not existing
loaded.put(name, null);
throw e;
}
}
/**
* Attempts to get the NMS handle of a CraftBukkit object.
* <p>
* The only match currently attempted by this method is a retrieval by using
* a parameterless {@code getHandle()} method implemented by the runtime
* type of the specified object.
* </p>
*
* @param obj
* The object for which to retrieve an NMS handle.
* @return The NMS handle of the specified object, or {@code null} if it
* could not be retrieved using {@code getHandle()}.
*/
public synchronized static Object getHandle(final Object obj) {
try {
return getMethod(obj.getClass(), "getHandle").invoke(obj);
} catch (final Exception e) {
e.printStackTrace();
return null;
}
}
/**
* Retrieves a {@link Method} instance declared by the specified class with
* the specified name and argument types.
* Java access modifiers are ignored during this retrieval. No guarantee is
* made as to whether the field
* returned will be an instance or static field.
* <p>
* A global caching mechanism within this class is used to store method.
* Combined with synchronization, this guarantees that no method will be
* reflectively looked up twice.
* </p>
* <p>
* If a method is deemed suitable for return,
* {@link Method#setAccessible(boolean) setAccessible} will be invoked with
* an argument of {@code true} before it is returned. This ensures that
* callers do not have to check or worry about Java access modifiers when
* dealing with the returned instance.
* </p>
* <p>
* This method does <em>not</em> search superclasses of the specified type
* for methods with the specified signature. Callers wishing this behavior
* should use {@link Class#getDeclaredMethod(String, Class...)}.
*
* @param clazz
* The class which contains the method to retrieve.
* @param name
* The declared name of the method in the class.
* @param args
* The formal argument types of the method.
* @return A method object with the specified name declared by the specified
* class.
*/
public synchronized static Method getMethod(final Class<?> clazz, final String name, final Class<?>... args) {
if (!_loadedMethods.containsKey(clazz)) {
_loadedMethods.put(clazz, new HashMap<String, Map<ArrayWrapper<Class<?>>, Method>>());
}
final Map<String, Map<ArrayWrapper<Class<?>>, Method>> loadedMethodNames = _loadedMethods.get(clazz);
if (!loadedMethodNames.containsKey(name)) {
loadedMethodNames.put(name, new HashMap<ArrayWrapper<Class<?>>, Method>());
}
final Map<ArrayWrapper<Class<?>>, Method> loadedSignatures = loadedMethodNames.get(name);
final ArrayWrapper<Class<?>> wrappedArg = new ArrayWrapper<Class<?>>(args);
if (loadedSignatures.containsKey(wrappedArg)) {
return loadedSignatures.get(wrappedArg);
}
for (final Method m : clazz.getMethods()) {
if (m.getName().equals(name) && Arrays.equals(args, m.getParameterTypes())) {
m.setAccessible(true);
loadedSignatures.put(wrappedArg, m);
return m;
}
}
loadedSignatures.put(wrappedArg, null);
return null;
}
@SuppressWarnings("rawtypes")
public static List<Method> getMethodByParamsAndType(final Class source, final Class returnType, final Class... args) {
final List<Method> list = new ArrayList<>();
for (final Method method : findMethodByParams(source.getMethods(), args)) {
if (method.getReturnType().equals(returnType)) {
list.add(method);
}
}
return list;
}
/**
* Gets a {@link Class} object representing a type contained within the
* {@code net.minecraft.server} versioned package.
* The class instances returned by this method are cached, such that no
* lookup will be done twice (unless multiple threads are accessing this
* method simultaneously).
*
* @param className
* The name of the class, excluding the package, within NMS.
* @return The class instance representing the specified NMS class, or
* {@code null} if it could not be loaded.
*/
public synchronized static Class<?> getNMSClass(final String className) {
if (_loadedNMSClasses.containsKey(className)) {
return _loadedNMSClasses.get(className);
}
final String fullName = "net.minecraft.server." + getVersion() + className;
Class<?> clazz = null;
try {
clazz = Class.forName(fullName);
} catch (final Exception | NoClassDefFoundError | NoSuchMethodError e) {
_loadedNMSClasses.put(className, null);
return null;
}
_loadedNMSClasses.put(className, clazz);
return clazz;
}
/**
* Gets a {@link Class} object representing a type contained within the
* {@code org.bukkit.craftbukkit} versioned package.
* The class instances returned by this method are cached, such that no
* lookup will be done twice (unless multiple threads are accessing this
* method simultaneously).
*
* @param className
* The name of the class, excluding the package, within OBC. This
* name may contain a subpackage name, such as
* {@code inventory.CraftItemStack}.
* @return The class instance representing the specified OBC class, or
* {@code null} if it could not be loaded.
*/
public synchronized static Class<?> getOBCClass(final String className) {
if (_loadedOBCClasses.containsKey(className)) {
return _loadedOBCClasses.get(className);
}
final String fullName = "org.bukkit.craftbukkit." + getVersion() + className;
Class<?> clazz = null;
try {
clazz = Class.forName(fullName);
} catch (final Exception e) {
e.printStackTrace();
_loadedOBCClasses.put(className, null);
return null;
}
_loadedOBCClasses.put(className, clazz);
return clazz;
}
/**
* Gets the version string from the package name of the CraftBukkit server
* implementation.
* This is needed to bypass the JAR package name changing on each update.
*
* @return The version string of the OBC and NMS packages,
* <em>including the trailing dot</em>.
*/
public synchronized static String getVersion() {
if (_versionString == null) {
if (Bukkit.getServer() == null) {
// The server hasn't started, static initializer call?
return null;
}
final String name = Bukkit.getServer().getClass().getPackage().getName();
_versionString = name.substring(name.lastIndexOf('.') + 1) + ".";
}
return _versionString;
}
@SuppressWarnings("rawtypes")
private static List<Method> findMethodByParams(final Method[] methods, final Class... args) {
final List<Method> list = new ArrayList<>();
start:
for (final Method method : methods) {
if (method.getParameterTypes().length == args.length) {
final Class[] array = method.getParameterTypes();
for (int i = 0; i < args.length; i++) {
if (array[i] != args[i]) {
continue start;
}
}
method.setAccessible(true);
list.add(method);
}
}
return list;
}
}

View File

@ -0,0 +1,352 @@
package cn.citycraft.TellRaw.common;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import org.bukkit.configuration.serialization.ConfigurationSerializable;
import org.bukkit.configuration.serialization.ConfigurationSerialization;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import cn.citycraft.GsonAgent.api.stream.JsonWriter;
/**
* Represents a textual component of a message part.
* This can be used to not only represent string literals in a JSON message,
* but also to represent localized strings and other text values.
* <p>
* Different instances of this class can be created with static constructor
* methods.
* </p>
*/
public abstract class TextualComponent implements Cloneable {
static {
ConfigurationSerialization.registerClass(TextualComponent.ArbitraryTextTypeComponent.class);
ConfigurationSerialization.registerClass(TextualComponent.ComplexTextTypeComponent.class);
}
public static TextualComponent deserialize(final Map<String, Object> map) {
if (map.containsKey("key") && map.size() == 2 && map.containsKey("value")) {
// Arbitrary text component
return ArbitraryTextTypeComponent.deserialize(map);
} else if (map.size() >= 2 && map.containsKey("key") && !map.containsKey("value")) {
// Complex JSON object
return ComplexTextTypeComponent.deserialize(map);
}
return null;
}
public static boolean isTextKey(final String key) {
return key.equals("translate") || key.equals("text") || key.equals("score") || key.equals("selector");
}
/**
* Create a textual component representing a localized string.
* The client will see this text component as their localized version of the
* specified string <em>key</em>, which can be overridden by a resource
* pack.
* <p>
* If the specified translation key is not present on the client resource
* pack, the translation key will be displayed as a string literal to the
* client.
* </p>
*
* @param translateKey
* The string key which maps to localized text.
* @return The text component representing the specified localized text.
*/
public static TextualComponent localizedText(final String translateKey) {
return new ArbitraryTextTypeComponent("translate", translateKey);
}
/**
* Create a textual component representing a scoreboard value.
* The client will see their own score for the specified objective as the
* text represented by this component.
* <p>
* <b>This method is currently guaranteed to throw an
* {@code UnsupportedOperationException} as it is only supported on snapshot
* clients.</b>
* </p>
*
* @param scoreboardObjective
* The name of the objective for which to display the score.
* @return The text component representing the specified scoreboard score
* (for the viewing player), or {@code null} if an error occurs
* during JSON serialization.
*/
public static TextualComponent objectiveScore(final String scoreboardObjective) {
return objectiveScore("*", scoreboardObjective);
}
/**
* Create a textual component representing a scoreboard value.
* The client will see the score of the specified player for the specified
* objective as the text represented by this component.
* <p>
* <b>This method is currently guaranteed to throw an
* {@code UnsupportedOperationException} as it is only supported on snapshot
* clients.</b>
* </p>
*
* @param playerName
* The name of the player whos score will be shown. If this
* string represents the single-character sequence "*", the
* viewing player's score will be displayed.
* Standard minecraft selectors (@a, @p, etc) are <em>not</em>
* supported.
* @param scoreboardObjective
* The name of the objective for which to display the score.
* @return The text component representing the specified scoreboard score
* for the specified player, or {@code null} if an error occurs
* during JSON serialization.
*/
public static TextualComponent objectiveScore(final String playerName, final String scoreboardObjective) {
throwUnsupportedSnapshot(); // Remove this line when the feature is
// released to non-snapshot versions, in
// addition to updating ALL THE OVERLOADS
// documentation accordingly
return new ComplexTextTypeComponent("score", ImmutableMap.<String, String> builder().put("name", playerName).put("objective", scoreboardObjective).build());
}
/**
* Create a textual component representing a string literal.
* This is the default type of textual component when a single string
* literal is given to a method.
*
* @param textValue
* The text which will be represented.
* @return The text component representing the specified literal text.
*/
public static TextualComponent rawText(final String textValue) {
return new ArbitraryTextTypeComponent("text", textValue);
}
/**
* Create a textual component representing a player name, retrievable by
* using a standard minecraft selector.
* The client will see the players or entities captured by the specified
* selector as the text represented by this component.
* <p>
* <b>This method is currently guaranteed to throw an
* {@code UnsupportedOperationException} as it is only supported on snapshot
* clients.</b>
* </p>
*
* @param selector
* The minecraft player or entity selector which will capture the
* entities whose string representations will be displayed in the
* place of this text component.
* @return The text component representing the name of the entities captured
* by the selector.
*/
public static TextualComponent selector(final String selector) {
throwUnsupportedSnapshot(); // Remove this line when the feature is
// released to non-snapshot versions, in
// addition to updating ALL THE OVERLOADS
// documentation accordingly
return new ArbitraryTextTypeComponent("selector", selector);
}
private static void throwUnsupportedSnapshot() {
throw new UnsupportedOperationException("This feature is only supported in snapshot releases.");
}
static boolean isTranslatableText(final TextualComponent component) {
return component instanceof ComplexTextTypeComponent && ((ComplexTextTypeComponent) component).getKey().equals("translate");
}
/**
* Clones a textual component instance.
* The returned object should not reference this textual component instance,
* but should maintain the same key and value.
*/
@Override
public abstract TextualComponent clone() throws CloneNotSupportedException;
/**
* @return The JSON key used to represent text components of this type.
*/
public abstract String getKey();
/**
* @return A readable String
*/
public abstract String getReadableString();
@Override
public String toString() {
return getReadableString();
}
/**
* Writes the text data represented by this textual component to the
* specified JSON writer object.
* A new object within the writer is not started.
*
* @param writer
* The object to which to write the JSON data.
* @throws IOException
* If an error occurs while writing to the stream.
*/
public abstract void writeJson(JsonWriter writer) throws IOException;
/**
* Internal class used to represent all types of text components.
* Exception validating done is on keys and values.
*/
private static final class ArbitraryTextTypeComponent extends TextualComponent implements ConfigurationSerializable {
private String _key;
private String _value;
public ArbitraryTextTypeComponent(final String key, final String value) {
setKey(key);
setValue(value);
}
public static ArbitraryTextTypeComponent deserialize(final Map<String, Object> map) {
return new ArbitraryTextTypeComponent(map.get("key").toString(), map.get("value").toString());
}
@Override
public TextualComponent clone() throws CloneNotSupportedException {
// Since this is a private and final class, we can just
// reinstantiate this class instead of casting super.clone
return new ArbitraryTextTypeComponent(getKey(), getValue());
}
@Override
public String getKey() {
return _key;
}
@Override
public String getReadableString() {
return getValue();
}
public String getValue() {
return _value;
}
@Override
@SuppressWarnings("serial")
public Map<String, Object> serialize() {
return new HashMap<String, Object>() {
{
put("key", getKey());
put("value", getValue());
}
};
}
public void setKey(final String key) {
Preconditions.checkArgument(key != null && !key.isEmpty(), "The key must be specified.");
_key = key;
}
public void setValue(final String value) {
Preconditions.checkArgument(value != null, "The value must be specified.");
_value = value;
}
@Override
public void writeJson(final JsonWriter writer) throws IOException {
writer.name(getKey()).value(getValue());
}
}
/**
* Internal class used to represent a text component with a nested JSON
* value.
* Exception validating done is on keys and values.
*/
private static final class ComplexTextTypeComponent extends TextualComponent implements ConfigurationSerializable {
private String _key;
private Map<String, String> _value;
public ComplexTextTypeComponent(final String key, final Map<String, String> values) {
setKey(key);
setValue(values);
}
public static ComplexTextTypeComponent deserialize(final Map<String, Object> map) {
String key = null;
final Map<String, String> value = new HashMap<String, String>();
for (final Map.Entry<String, Object> valEntry : map.entrySet()) {
if (valEntry.getKey().equals("key")) {
key = (String) valEntry.getValue();
} else if (valEntry.getKey().startsWith("value.")) {
value.put(valEntry.getKey().substring(6) /*
* Strips out the
* value prefix
*/, valEntry.getValue().toString());
}
}
return new ComplexTextTypeComponent(key, value);
}
@Override
public TextualComponent clone() throws CloneNotSupportedException {
// Since this is a private and final class, we can just
// reinstantiate this class instead of casting super.clone
return new ComplexTextTypeComponent(getKey(), getValue());
}
@Override
public String getKey() {
return _key;
}
@Override
public String getReadableString() {
return getKey();
}
public Map<String, String> getValue() {
return _value;
}
@Override
@SuppressWarnings("serial")
public Map<String, Object> serialize() {
return new java.util.HashMap<String, Object>() {
{
put("key", getKey());
for (final Map.Entry<String, String> valEntry : getValue().entrySet()) {
put("value." + valEntry.getKey(), valEntry.getValue());
}
}
};
}
public void setKey(final String key) {
Preconditions.checkArgument(key != null && !key.isEmpty(), "The key must be specified.");
_key = key;
}
public void setValue(final Map<String, String> value) {
Preconditions.checkArgument(value != null, "The value must be specified.");
_value = value;
}
@Override
public void writeJson(final JsonWriter writer) throws IOException {
writer.name(getKey());
writer.beginObject();
for (final Map.Entry<String, String> jsonPair : _value.entrySet()) {
writer.name(jsonPair.getKey()).value(jsonPair.getValue());
}
writer.endObject();
}
}
}

View File

@ -0,0 +1,223 @@
package cn.citycraft.TellRaw.internal;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.bukkit.Achievement;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.Statistic;
import org.bukkit.Statistic.Type;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import cn.citycraft.TellRaw.FancyMessage;
import cn.citycraft.TellRaw.common.Reflection;
import cn.citycraft.TellRaw.common.TextualComponent;
/**
* Represents a formattable message. Such messages can use elements such as
* colors, formatting codes, hover and click data, and other features provided
* by the vanilla Minecraft <a
* href="http://minecraft.gamepedia.com/Tellraw#Raw_JSON_Text">JSON message
* formatter</a>.
* This class allows plugins to emulate the functionality of the vanilla
* Minecraft <a href="http://minecraft.gamepedia.com/Commands#tellraw">tellraw
* command</a>.
* <p>
* This class follows the builder pattern, allowing for method chaining. It is
* set up such that invocations of property-setting methods will affect the
* current editing component, and a call to {@link #then()} or
* {@link #then(Object)} will append a new editing component to the end of the
* message, optionally initializing it with text. Further property-setting
* method calls will affect that editing component.
* </p>
*/
public class FancyMessageInternal extends FancyMessage {
/**
* 新建自动序列化类
*/
public FancyMessageInternal() {
this("");
}
/**
* 新建自动序列化类
*
* @param firstPartText
* 第一个文本串
*/
public FancyMessageInternal(final String firstPartText) {
super(TextualComponent.rawText(firstPartText));
}
@Override
public FancyMessage achievementTooltip(final Achievement which) {
try {
final Object achievement = getNMSAchievementMethod.invoke(null, which);
return achievementTooltip((String) nmsAchievement_NameField.get(achievement));
} catch (final IllegalAccessException e) {
Bukkit.getLogger().log(Level.WARNING, "Could not access method.", e);
return this;
} catch (final IllegalArgumentException e) {
Bukkit.getLogger().log(Level.WARNING, "Argument could not be passed.", e);
return this;
} catch (final InvocationTargetException e) {
Bukkit.getLogger().log(Level.WARNING, "A error has occured durring invoking of method.", e);
return this;
}
}
@Override
public FancyMessage itemTooltip(final ItemStack itemStack) {
try {
final Object nmsItem = getOBCasNMSCopyMethod.invoke(null, itemStack);
return itemTooltip(getNMSsaveNBTMethod.invoke(nmsItem, nmsNBTTagCompound.newInstance()).toString());
} catch (final Exception e) {
e.printStackTrace();
return this;
}
}
@Override
public void send(final CommandSender sender, final String jsonString) {
if (!(sender instanceof Player)) {
sender.sendMessage(toOldMessageFormat());
return;
}
final Player player = (Player) sender;
try {
final Object handle = Reflection.getHandle(player);
if (nmsPlayerConnectionField == null) {
try {
nmsPlayerConnectionField = Reflection.getField(handle.getClass(), "playerConnection");
} catch (final Exception e) {
for (final Field field : handle.getClass().getDeclaredFields()) {
if (field.getType().getSimpleName().contains("NetHandlerPlayServer")) {
nmsPlayerConnectionField = field;
break;
}
}
}
}
final Object connection = nmsPlayerConnectionField.get(handle);
if (nmsSendPacketMethod == null) {
try {
nmsSendPacketMethod = Reflection.getMethod(connection.getClass(), "sendPacket", nmsPacketClass);
} catch (final Exception e) {
nmsSendPacketMethod = Reflection.getMethodByParamsAndType(connection.getClass(), Void.TYPE, nmsPacketClass).get(0);
}
}
if (nmsSendPacketMethod == null) {
throw new RuntimeException("could find field: sendPacket in EntityPlayer class");
}
nmsSendPacketMethod.invoke(connection, createChatPacket(jsonString));
} catch (final IllegalArgumentException e) {
Bukkit.getLogger().log(Level.WARNING, "Argument could not be passed.", e);
} catch (final IllegalAccessException e) {
Bukkit.getLogger().log(Level.WARNING, "Could not access method.", e);
} catch (final InstantiationException e) {
Bukkit.getLogger().log(Level.WARNING, "Underlying class is abstract.", e);
} catch (final InvocationTargetException e) {
Bukkit.getLogger().log(Level.WARNING, "A error has occured durring invoking of method.", e);
} catch (final NoSuchMethodException e) {
Bukkit.getLogger().log(Level.WARNING, "Could not find method.", e);
} catch (final ClassNotFoundException e) {
Bukkit.getLogger().log(Level.WARNING, "Could not find class.", e);
} catch (final SecurityException ex) {
Logger.getLogger(FancyMessageInternal.class.getName()).log(Level.SEVERE, null, ex);
}
}
@Override
public FancyMessage statisticTooltip(final Statistic which) {
final Type type = which.getType();
if (type != Type.UNTYPED) {
throw new IllegalArgumentException("That statistic requires an additional " + type + " parameter!");
}
try {
final Object statistic = getNMSStatisticMethod.invoke(null, which);
return achievementTooltip((String) nmsStatistic_NameField.get(statistic));
} catch (final IllegalAccessException e) {
Bukkit.getLogger().log(Level.WARNING, "Could not access method.", e);
return this;
} catch (final IllegalArgumentException e) {
Bukkit.getLogger().log(Level.WARNING, "Argument could not be passed.", e);
return this;
} catch (final InvocationTargetException e) {
Bukkit.getLogger().log(Level.WARNING, "A error has occured durring invoking of method.", e);
return this;
}
}
@Override
public FancyMessage statisticTooltip(final Statistic which, final EntityType entity) {
final Type type = which.getType();
if (type == Type.UNTYPED) {
throw new IllegalArgumentException("That statistic needs no additional parameter!");
}
if (type != Type.ENTITY) {
throw new IllegalArgumentException("Wrong parameter type for that statistic - needs " + type + "!");
}
try {
final Object statistic = getNMSEntityStatisticMethod.invoke(null, which, entity);
return achievementTooltip((String) nmsStatistic_NameField.get(statistic));
} catch (final IllegalAccessException e) {
Bukkit.getLogger().log(Level.WARNING, "Could not access method.", e);
return this;
} catch (final IllegalArgumentException e) {
Bukkit.getLogger().log(Level.WARNING, "Argument could not be passed.", e);
return this;
} catch (final InvocationTargetException e) {
Bukkit.getLogger().log(Level.WARNING, "A error has occured durring invoking of method.", e);
return this;
}
}
@Override
public FancyMessage statisticTooltip(final Statistic which, final Material item) {
final Type type = which.getType();
if (type == Type.UNTYPED) {
throw new IllegalArgumentException("That statistic needs no additional parameter!");
}
if ((type == Type.BLOCK && item.isBlock()) || type == Type.ENTITY) {
throw new IllegalArgumentException("Wrong parameter type for that statistic - needs " + type + "!");
}
try {
final Object statistic = getNMSMaterialStatisticMethod.invoke(null, which, item);
return achievementTooltip((String) nmsStatistic_NameField.get(statistic));
} catch (final IllegalAccessException e) {
Bukkit.getLogger().log(Level.WARNING, "Could not access method.", e);
return this;
} catch (final IllegalArgumentException e) {
Bukkit.getLogger().log(Level.WARNING, "Argument could not be passed.", e);
return this;
} catch (final InvocationTargetException e) {
Bukkit.getLogger().log(Level.WARNING, "A error has occured durring invoking of method.", e);
return this;
}
}
/**
* 创建Chat数据包
*
* @param json
* 需要创建的数据包
* @return 创建发包对象
* @throws IllegalArgumentException
* @throws IllegalAccessException
* @throws InstantiationException
* @throws InvocationTargetException
* @throws NoSuchMethodException
* @throws ClassNotFoundException
*/
private Object createChatPacket(final String json) throws IllegalArgumentException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException, ClassNotFoundException {
final Object serializedChatComponent = fromJsonMethod.invoke(nmsChatSerializerGsonInstance, json, nmsIChatBaseComponentClass);
return nmsPacketPlayOutChatConstructor.newInstance(serializedChatComponent);
}
}

View File

@ -0,0 +1,85 @@
package cn.citycraft.TellRaw.manual;
import org.bukkit.Achievement;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.Statistic;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import cn.citycraft.TellRaw.FancyMessage;
import cn.citycraft.TellRaw.common.TextualComponent;
/**
* Represents a formattable message. Such messages can use elements such as
* colors, formatting codes, hover and click data, and other features provided
* by the vanilla Minecraft <a
* href="http://minecraft.gamepedia.com/Tellraw#Raw_JSON_Text">JSON message
* formatter</a>.
* This class allows plugins to emulate the functionality of the vanilla
* Minecraft <a href="http://minecraft.gamepedia.com/Commands#tellraw">tellraw
* command</a>.
* <p>
* This class follows the builder pattern, allowing for method chaining. It is
* set up such that invocations of property-setting methods will affect the
* current editing component, and a call to {@link #then()} or
* {@link #then(Object)} will append a new editing component to the end of the
* message, optionally initializing it with text. Further property-setting
* method calls will affect that editing component.
* </p>
*/
public class FancyMessageManual extends FancyMessage {
/**
* 新建手动序列化类
*/
public FancyMessageManual() {
this("");
}
/**
* 新建手动序列化类
*
* @param firstPartText
* 第一个文本串
*/
public FancyMessageManual(final String firstPartText) {
super(TextualComponent.rawText(firstPartText));
}
@Override
public FancyMessage achievementTooltip(final Achievement which) {
throw new UnsupportedOperationException("暂时不支持当前操作."); // To change body of generated methods, choose Tools | Templates.
}
@Override
public FancyMessage itemTooltip(final ItemStack itemStack) {
this.itemTooltip(new GItemStack(itemStack).toString());
return this;
}
@Override
public void send(final CommandSender sender, final String jsonString) {
if (sender instanceof Player) {
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "tellraw " + sender.getName() + " " + jsonString);
} else {
sender.sendMessage(toOldMessageFormat());
}
}
@Override
public FancyMessage statisticTooltip(final Statistic which) {
throw new UnsupportedOperationException("暂时不支持当前操作.");
}
@Override
public FancyMessage statisticTooltip(final Statistic which, final EntityType entity) {
throw new UnsupportedOperationException("暂时不支持当前操作.");
}
@Override
public FancyMessage statisticTooltip(final Statistic which, final Material item) {
throw new UnsupportedOperationException("暂时不支持当前操作.");
}
}

View File

@ -0,0 +1,85 @@
package cn.citycraft.TellRaw.manual;
import java.io.IOException;
import java.io.StringWriter;
import java.util.Map;
import java.util.logging.Level;
import org.bukkit.Bukkit;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import cn.citycraft.GsonAgent.GsonAgent;
import cn.citycraft.GsonAgent.api.stream.JsonWriter;
import cn.citycraft.TellRaw.common.JsonRepresentedObject;
/**
* 序列化Item的类
*
* @since 2015年12月14日 下午1:30:51
* @author 许凯
*/
public class GItemStack implements JsonRepresentedObject {
private final ItemStack item;
private final String jsonString;
protected GItemStack(final ItemStack item) {
this.item = item.clone();
final StringWriter string = new StringWriter();
final JsonWriter json = GsonAgent.newJsonWriter(string);
try {
this.writeJson(json);
json.close();
} catch (final IOException e) {
throw new RuntimeException("invalid message:", e);
}
this.jsonString = string.toString();
}
@Override
public String toString() {
return this.jsonString;
}
@Override
public void writeJson(final JsonWriter json) throws IOException {
try {
json.beginObject();
json.nameWithoutQuotes("id").value(this.item.getTypeId());
json.nameWithoutQuotes("Damage").value(this.item.getDurability());
if (this.item.getAmount() > 1) {
json.nameWithoutQuotes("Count").value(this.item.getAmount());
}
if (this.item.hasItemMeta()) {
json.nameWithoutQuotes("tag").beginObject();
final ItemMeta im = item.getItemMeta();
if (im.hasEnchants()) {
json.nameWithoutQuotes("ench").beginArray();
for (final Map.Entry<Enchantment, Integer> ench : im.getEnchants().entrySet()) {
json.beginObject().nameWithoutQuotes("id").value(ench.getKey().getId()).nameWithoutQuotes("lvl").value(ench.getValue()).endObject();
}
json.endArray();
}
if (im.hasDisplayName() || im.hasLore()) {
json.nameWithoutQuotes("display").beginObject();
if (im.hasDisplayName()) {
json.nameWithoutQuotes("Name").value(im.getDisplayName());
}
if (im.hasLore()) {
json.nameWithoutQuotes("Lore").beginArray();
for (final String line : im.getLore()) {
json.value(line);
}
json.endArray();
}
json.endObject();
}
json.endObject();
}
json.endObject();
} catch (final IOException e) {
Bukkit.getLogger().log(Level.WARNING, "A problem occured during writing of JSON string", e);
}
}
}

View File

@ -0,0 +1,13 @@
Data:
#数据保存方式 [sqlite|MySQL]
FileSystem: sqlite
#MySQL数据库配置 只有当FileSystem配置为MySQL时有效
MySQL:
#数据库需要自行建立
database: minecraft
#数据表需要自行建立
tablename: prefixs
username: root
password:
ip: localhost
port: 3306

View File

@ -0,0 +1,21 @@
name: ${project.artifactId}
description: ${project.description}
main: ${project.groupId}.${project.artifactId}.${project.artifactId}
version: ${project.version}-Build#${env.GIT_ID}
author: 喵♂呜
website: ${jenkins.url}/job/${project.artifactId}/
commands:
${project.artifactId}:
description: ${project.artifactId} - ${project.description}
aliases:
- xxxx
usage: §b使用/${project.artifactId} help 查看帮助!
permission: ${project.artifactId}.reload
permission-message: §c你没有 <permission> 的权限来执行此命令!
permissions:
${project.artifactId}.use:
description: ${project.artifactId} 使用!
default: true
${project.artifactId}.reload:
description: 重新载入插件!
default: op