Implement Message Json and sendRaw methods
This commit is contained in:
parent
9587b756c9
commit
7f45486600
@ -0,0 +1,98 @@
|
||||
package com.massivecraft.massivecore.adapter;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
import com.massivecraft.massivecore.xlib.gson.JsonDeserializationContext;
|
||||
import com.massivecraft.massivecore.xlib.gson.JsonDeserializer;
|
||||
import com.massivecraft.massivecore.xlib.gson.JsonElement;
|
||||
import com.massivecraft.massivecore.xlib.gson.JsonNull;
|
||||
import com.massivecraft.massivecore.xlib.gson.JsonParseException;
|
||||
import com.massivecraft.massivecore.xlib.gson.JsonPrimitive;
|
||||
import com.massivecraft.massivecore.xlib.gson.JsonSerializationContext;
|
||||
import com.massivecraft.massivecore.xlib.gson.JsonSerializer;
|
||||
|
||||
public class LowercaseEnumAdapter<T extends Enum<T>> implements JsonDeserializer<T>, JsonSerializer<T>
|
||||
{
|
||||
// -------------------------------------------- //
|
||||
// FIELDS
|
||||
// -------------------------------------------- //
|
||||
|
||||
protected final Class<T> clazz;
|
||||
public Class<T> getClazz() { return this.clazz; }
|
||||
|
||||
// -------------------------------------------- //
|
||||
// INSTANCE & CONSTRUCT
|
||||
// -------------------------------------------- //
|
||||
|
||||
public static <T extends Enum<T>> LowercaseEnumAdapter<T> get(Class<T> clazz)
|
||||
{
|
||||
return new LowercaseEnumAdapter<T>(clazz);
|
||||
}
|
||||
|
||||
public LowercaseEnumAdapter(Class<T> clazz)
|
||||
{
|
||||
if (clazz == null) throw new IllegalArgumentException("passed clazz param is null");
|
||||
if ( ! clazz.isEnum()) throw new IllegalArgumentException("passed clazz param must be an enum");
|
||||
this.clazz = clazz;
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// OVERRIDE
|
||||
// -------------------------------------------- //
|
||||
|
||||
@Override
|
||||
public JsonElement serialize(T src, Type typeOfSrc, JsonSerializationContext context)
|
||||
{
|
||||
if (src == null) return JsonNull.INSTANCE;
|
||||
return new JsonPrimitive(src.name().toLowerCase());
|
||||
}
|
||||
|
||||
@Override
|
||||
public T deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
|
||||
{
|
||||
if (json == null) return null;
|
||||
T value = getEnumValueFrom(json);
|
||||
return value;
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// UTIL
|
||||
// -------------------------------------------- //
|
||||
|
||||
public static <T> T[] getEnumValues(Class<T> clazz)
|
||||
{
|
||||
if (clazz == null) throw new IllegalArgumentException("passed clazz param is null");
|
||||
if ( ! clazz.isEnum()) throw new IllegalArgumentException("passed clazz param must be an enum");
|
||||
|
||||
T[] ret = clazz.getEnumConstants();
|
||||
if (ret == null) throw new RuntimeException("failed to retrieve enum constants at runtime");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static String getComparable(Enum<?> value)
|
||||
{
|
||||
if (value == null) return null;
|
||||
return getComparable(value.name());
|
||||
}
|
||||
|
||||
public static String getComparable(String string)
|
||||
{
|
||||
if (string == null) return null;
|
||||
return string.toLowerCase();
|
||||
}
|
||||
|
||||
public T getEnumValueFrom(JsonElement json)
|
||||
{
|
||||
String jsonString = json.getAsString();
|
||||
jsonString = getComparable(jsonString);
|
||||
|
||||
for (T value : getEnumValues(clazz))
|
||||
{
|
||||
if (getComparable(value).equals(jsonString)) return value;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -24,6 +24,7 @@ import com.massivecraft.massivecore.cmd.req.Req;
|
||||
import com.massivecraft.massivecore.cmd.req.ReqHasPerm;
|
||||
import com.massivecraft.massivecore.collections.MassiveList;
|
||||
import com.massivecraft.massivecore.mixin.Mixin;
|
||||
import com.massivecraft.massivecore.mson.Mson;
|
||||
import com.massivecraft.massivecore.util.PermUtil;
|
||||
import com.massivecraft.massivecore.util.Txt;
|
||||
|
||||
@ -1093,6 +1094,45 @@ public class MassiveCommand
|
||||
return Mixin.msgOne(this.sender, msgs);
|
||||
}
|
||||
|
||||
// CONVENIENCE RAW
|
||||
|
||||
public boolean sendRaw(Mson mson)
|
||||
{
|
||||
return Mixin.messageRawOne(this.sender, mson);
|
||||
}
|
||||
|
||||
public boolean sendRaw(Mson... mson)
|
||||
{
|
||||
return Mixin.messageRawOne(this.sender, mson);
|
||||
}
|
||||
|
||||
public boolean sendRaw(Collection<Mson> mson)
|
||||
{
|
||||
return Mixin.messageRawOne(this.sender, mson);
|
||||
}
|
||||
|
||||
// CONVENIENCE MSON
|
||||
|
||||
public Mson mson()
|
||||
{
|
||||
return Mson.mson();
|
||||
}
|
||||
|
||||
public Mson mson(Object... parts)
|
||||
{
|
||||
return Mson.mson(parts);
|
||||
}
|
||||
|
||||
public List<Mson> msons(Object... parts)
|
||||
{
|
||||
return Mson.msons(parts);
|
||||
}
|
||||
|
||||
public List<Mson> msons(Collection<?> parts)
|
||||
{
|
||||
return Mson.msons(parts);
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// ARGUMENT READERS
|
||||
// -------------------------------------------- //
|
||||
|
@ -35,7 +35,7 @@ public class MassiveCoreBukkitCommand extends Command implements PluginIdentifia
|
||||
name,
|
||||
massiveCommand.getDesc(),
|
||||
massiveCommand.getUseageTemplate(),
|
||||
new ArrayList<String>() // We don't use aliases
|
||||
Collections.<String>emptyList() // We don't use aliases
|
||||
);
|
||||
this.massiveCommand = massiveCommand;
|
||||
}
|
||||
|
@ -5,11 +5,12 @@ import java.util.Collection;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import com.massivecraft.massivecore.Predictate;
|
||||
import com.massivecraft.massivecore.mson.Mson;
|
||||
|
||||
public interface MessageMixin
|
||||
{
|
||||
// -------------------------------------------- //
|
||||
// RAW MESSAGE
|
||||
// MESSAGE
|
||||
// -------------------------------------------- //
|
||||
|
||||
// All
|
||||
@ -28,7 +29,7 @@ public interface MessageMixin
|
||||
public boolean messageOne(Object sendeeObject, Collection<String> messages);
|
||||
|
||||
// -------------------------------------------- //
|
||||
// PARSE MESSAGE
|
||||
// PARSE MSG
|
||||
// -------------------------------------------- //
|
||||
|
||||
// All
|
||||
@ -46,4 +47,23 @@ public interface MessageMixin
|
||||
public boolean msgOne(Object sendeeObject, String msg, Object... args);
|
||||
public boolean msgOne(Object sendeeObject, Collection<String> msgs);
|
||||
|
||||
// -------------------------------------------- //
|
||||
// RAW MESSAGE
|
||||
// -------------------------------------------- //
|
||||
|
||||
// All
|
||||
public boolean messageRawAll(Mson mson);
|
||||
public boolean messageRawAll(Mson... msons);
|
||||
public boolean messageRawAll(Collection<Mson> msons);
|
||||
|
||||
// Predictate
|
||||
public boolean messageRawPredictate(Predictate<CommandSender> predictate, Mson mson);
|
||||
public boolean messageRawPredictate(Predictate<CommandSender> predictate, Mson... msons);
|
||||
public boolean messageRawPredictate(Predictate<CommandSender> predictate, Collection<Mson> msons);
|
||||
|
||||
// One
|
||||
public boolean messageRawOne(Object sendeeObject, Mson mson);
|
||||
public boolean messageRawOne(Object sendeeObject, Mson... msons);
|
||||
public boolean messageRawOne(Object sendeeObject, Collection<Mson> msons);
|
||||
|
||||
}
|
||||
|
@ -2,24 +2,25 @@ package com.massivecraft.massivecore.mixin;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import com.massivecraft.massivecore.Predictate;
|
||||
import com.massivecraft.massivecore.util.MUtil;
|
||||
import com.massivecraft.massivecore.mson.Mson;
|
||||
import com.massivecraft.massivecore.util.Txt;
|
||||
|
||||
public abstract class MessageMixinAbstract implements MessageMixin
|
||||
{
|
||||
// -------------------------------------------- //
|
||||
// RAW MESSAGE
|
||||
// MESSAGE
|
||||
// -------------------------------------------- //
|
||||
|
||||
// All
|
||||
@Override
|
||||
public boolean messageAll(String message)
|
||||
{
|
||||
return this.messageAll(Arrays.asList(message));
|
||||
return this.messageAll(Collections.singleton(message));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -32,7 +33,7 @@ public abstract class MessageMixinAbstract implements MessageMixin
|
||||
@Override
|
||||
public boolean messagePredictate(Predictate<CommandSender> predictate, String message)
|
||||
{
|
||||
return this.messagePredictate(predictate, MUtil.list(message));
|
||||
return this.messagePredictate(predictate, Collections.singleton(message));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -45,7 +46,7 @@ public abstract class MessageMixinAbstract implements MessageMixin
|
||||
@Override
|
||||
public boolean messageOne(Object sendeeObject, String message)
|
||||
{
|
||||
return this.messageOne(sendeeObject, MUtil.list(message));
|
||||
return this.messageOne(sendeeObject, Collections.singleton(message));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -55,7 +56,7 @@ public abstract class MessageMixinAbstract implements MessageMixin
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// PARSE MESSAGE
|
||||
// PARSE MSG
|
||||
// -------------------------------------------- //
|
||||
// They are all in abstract!
|
||||
|
||||
@ -116,4 +117,47 @@ public abstract class MessageMixinAbstract implements MessageMixin
|
||||
return this.messageOne(sendeeObject, Txt.parse(msgs));
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// RAW MESSAGE
|
||||
// -------------------------------------------- //
|
||||
|
||||
// All
|
||||
@Override
|
||||
public boolean messageRawAll(Mson mson)
|
||||
{
|
||||
return this.messageRawAll(Arrays.asList(mson));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean messageRawAll(Mson... msons)
|
||||
{
|
||||
return this.messageRawAll(Arrays.asList(msons));
|
||||
}
|
||||
|
||||
// Predictate
|
||||
@Override
|
||||
public boolean messageRawPredictate(Predictate<CommandSender> predictate, Mson mson)
|
||||
{
|
||||
return this.messageRawPredictate(predictate, Arrays.asList(mson));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean messageRawPredictate(Predictate<CommandSender> predictate, Mson... msons)
|
||||
{
|
||||
return this.messageRawPredictate(predictate, Arrays.asList(msons));
|
||||
}
|
||||
|
||||
// One
|
||||
@Override
|
||||
public boolean messageRawOne(Object sendeeObject, Mson mson)
|
||||
{
|
||||
return this.messageRawOne(sendeeObject, Arrays.asList(mson));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean messageRawOne(Object sendeeObject, Mson... msons)
|
||||
{
|
||||
return this.messageRawOne(sendeeObject, Arrays.asList(msons));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -3,9 +3,12 @@ package com.massivecraft.massivecore.mixin;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import com.massivecraft.massivecore.Predictate;
|
||||
import com.massivecraft.massivecore.mson.Mson;
|
||||
import com.massivecraft.massivecore.util.IdUtil;
|
||||
import com.massivecraft.massivecore.util.PacketUtil;
|
||||
|
||||
public class MessageMixinDefault extends MessageMixinAbstract
|
||||
{
|
||||
@ -53,5 +56,57 @@ public class MessageMixinDefault extends MessageMixinAbstract
|
||||
sendee.sendMessage(messages.toArray(new String[0]));
|
||||
return true;
|
||||
}
|
||||
|
||||
// Raw message aka. JsonString
|
||||
@Override
|
||||
public boolean messageRawAll(Collection<Mson> msons)
|
||||
{
|
||||
if (msons == null) return false;
|
||||
for (CommandSender sender : IdUtil.getOnlineSenders())
|
||||
{
|
||||
this.messageRawOne(sender, msons);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean messageRawPredictate(Predictate<CommandSender> predictate, Collection<Mson> msons)
|
||||
{
|
||||
if (predictate == null) return false;
|
||||
if (msons == null) return false;
|
||||
for (CommandSender sender : IdUtil.getOnlineSenders())
|
||||
{
|
||||
if ( ! predictate.apply(sender)) continue;
|
||||
this.messageRawOne(sender, msons);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean messageRawOne(Object sendeeObject, Collection<Mson> msons)
|
||||
{
|
||||
if (msons == null) return false;
|
||||
|
||||
CommandSender sender = IdUtil.getSender(sendeeObject);
|
||||
if (sender == null) return false;
|
||||
|
||||
if (sender instanceof Player && PacketUtil.isRawAvailable())
|
||||
{
|
||||
Player player = (Player) sender;
|
||||
for (Mson mson : msons)
|
||||
{
|
||||
PacketUtil.sendRaw(player, mson.toRaw());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (Mson mson : msons)
|
||||
{
|
||||
sender.sendMessage(mson.toPlain());
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ import org.bukkit.permissions.Permissible;
|
||||
|
||||
import com.massivecraft.massivecore.Predictate;
|
||||
import com.massivecraft.massivecore.event.EventMassiveCorePlayerLeave;
|
||||
import com.massivecraft.massivecore.mson.Mson;
|
||||
import com.massivecraft.massivecore.ps.PS;
|
||||
import com.massivecraft.massivecore.teleport.Destination;
|
||||
|
||||
@ -312,6 +313,48 @@ public class Mixin
|
||||
return getMessageMixin().msgOne(senderObject, msgs);
|
||||
}
|
||||
|
||||
// RAW All
|
||||
public static boolean messageRawAll(Mson mson)
|
||||
{
|
||||
return getMessageMixin().messageRawAll(mson);
|
||||
}
|
||||
public static boolean messageRawAll(Mson... msons)
|
||||
{
|
||||
return getMessageMixin().messageRawAll(msons);
|
||||
}
|
||||
public static boolean messageRawAll(Collection<Mson> msons)
|
||||
{
|
||||
return getMessageMixin().messageRawAll(msons);
|
||||
}
|
||||
|
||||
// RAW Predictate
|
||||
public static boolean messageRawPredictate(Predictate<CommandSender> predictate, Mson mson)
|
||||
{
|
||||
return getMessageMixin().messageRawPredictate(predictate, mson);
|
||||
}
|
||||
public static boolean messageRawPredictate(Predictate<CommandSender> predictate, Mson... msons)
|
||||
{
|
||||
return getMessageMixin().messageRawPredictate(predictate, msons);
|
||||
}
|
||||
public static boolean messageRawPredictate(Predictate<CommandSender> predictate, Collection<Mson> msons)
|
||||
{
|
||||
return getMessageMixin().messageRawPredictate(predictate, msons);
|
||||
}
|
||||
|
||||
// RAW One
|
||||
public static boolean messageRawOne(Object senderObject, Mson mson)
|
||||
{
|
||||
return getMessageMixin().messageRawOne(senderObject, mson);
|
||||
}
|
||||
public static boolean messageRawOne(Object senderObject, Mson... msons)
|
||||
{
|
||||
return getMessageMixin().messageRawOne(senderObject, msons);
|
||||
}
|
||||
public static boolean messageRawOne(Object senderObject, Collection<Mson> msons)
|
||||
{
|
||||
return getMessageMixin().messageRawOne(senderObject, msons);
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// STATIC EXPOSE: TITLE
|
||||
// -------------------------------------------- //
|
||||
|
@ -3,7 +3,7 @@ package com.massivecraft.massivecore.mixin;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import com.massivecraft.massivecore.util.IdUtil;
|
||||
import com.massivecraft.massivecore.util.TitleUtil;
|
||||
import com.massivecraft.massivecore.util.PacketUtil;
|
||||
|
||||
public class TitleMixinDefault extends TitleMixinAbstract
|
||||
{
|
||||
@ -29,13 +29,13 @@ public class TitleMixinDefault extends TitleMixinAbstract
|
||||
if (titleSub == null) titleSub = "";
|
||||
if (titleMain == null) titleMain = "";
|
||||
|
||||
return TitleUtil.sendTitle(player, ticksIn, ticksStay, ticksOut, titleMain, titleSub);
|
||||
return PacketUtil.sendTitle(player, ticksIn, ticksStay, ticksOut, titleMain, titleSub);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTitlesAvailable()
|
||||
{
|
||||
return TitleUtil.isAvailable();
|
||||
return PacketUtil.isTitleAvailable();
|
||||
}
|
||||
|
||||
}
|
||||
|
108
src/com/massivecraft/massivecore/mson/ATest.java
Normal file
108
src/com/massivecraft/massivecore/mson/ATest.java
Normal file
@ -0,0 +1,108 @@
|
||||
package com.massivecraft.massivecore.mson;
|
||||
|
||||
import static com.massivecraft.massivecore.mson.Mson.mson;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.bukkit.ChatColor;
|
||||
|
||||
import com.massivecraft.massivecore.collections.MassiveList;
|
||||
import com.massivecraft.massivecore.util.Txt;
|
||||
|
||||
public class ATest
|
||||
{
|
||||
public static void main(String[] args)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Test getMsonFrom
|
||||
Mson ofMson = mson(new Mson().text("hello"));
|
||||
System.out.println("ofMson:" + ofMson); // Success
|
||||
|
||||
Mson ofString = mson("hello");
|
||||
System.out.println("ofString:" + ofString); // Success
|
||||
|
||||
Mson ofCollection = mson(new MassiveList<String>("hello ", "you!"));
|
||||
System.out.println("ofCollection:" + ofCollection); // Success
|
||||
|
||||
// Test children
|
||||
Mson child = mson("test").color(ChatColor.BLUE)
|
||||
.addChild(" test2").link("www.massivecraft.com")
|
||||
.addChild(" test3 ")
|
||||
.addChildren("this ", "is only ", "one way to do it!")
|
||||
.root()
|
||||
.tooltip("Holy moly!");
|
||||
System.out.println("child:" + child.root()); // Success
|
||||
|
||||
// Test siblings
|
||||
Mson sibling = mson(
|
||||
"test",
|
||||
" test2",
|
||||
" test3",
|
||||
new Mson().text(" Test4, children: ").addChild("Child1 ")
|
||||
.addSiblings("Sibling 1 ", "Sibling 2 ", "Sibling 3 ")
|
||||
.addSibling("Sibling 4").root()
|
||||
).tooltip("Holy moly!");
|
||||
System.out.println("sibling:" + sibling.root()); // Success
|
||||
|
||||
// Test fromParsedMessage
|
||||
Mson parsed = Mson.fromParsedMessage(Txt.parse("white <i>in<em>fo <b><em><bold>bad <lime>green"));
|
||||
System.out.println("parsed:" + parsed); // Success
|
||||
|
||||
Mson parsed2 = Mson.parse("white <i>in<em>fo <b><bold>bad <lime>green");
|
||||
System.out.println("parsed2:" + parsed2.toRaw()); // Success
|
||||
|
||||
Mson parseFormat = Mson.parse("<i>insert here %s whatever <g> you <b>%s <g>could wish for!", "!1337!", "herpi derp");
|
||||
System.out.println("parseFormat:" + parseFormat); // Success
|
||||
|
||||
// Test format
|
||||
Mson format = Mson.format("Just a %s simple string! :)", "very");
|
||||
System.out.println("format:" + format); // Success
|
||||
|
||||
// Test split
|
||||
List<Mson> split = format.split(Txt.REGEX_WHITESPACE.toString());
|
||||
System.out.println("split:" + mson(split)); // Success
|
||||
|
||||
/*
|
||||
* Test replace
|
||||
*/
|
||||
|
||||
Mson charr = mson("1 2 3 4 5 6 1 7 tests").addChild(" 01010101").root().replace('1', '0');
|
||||
System.out.println("char:" + charr); // Success
|
||||
|
||||
Mson sequence = mson("1 2 3 4 5 6 1 7 tests").addChild(" 01010101").root().replace("1", "0");
|
||||
System.out.println("sequence:" + sequence); // Success
|
||||
|
||||
Mson regex = mson("1 2 3 4 5 6 1 7 tests").addChild(" 01010101").root().replaceAll("1", "0");
|
||||
System.out.println("regex:" + regex); // Success
|
||||
|
||||
//Mson replaceFirst = Mson.of("1 2 3 4 5 6 1 7 tests").addChild(" 01010101").getRoot().replaceFirst("1", "0");
|
||||
//System.out.println("replaceFirst:" + replaceFirst.toRaw()); // Success
|
||||
|
||||
/*
|
||||
* Test special replaceAll
|
||||
*/
|
||||
|
||||
// replace string mson
|
||||
Mson replaceAll1 = mson("1 2 3 4 5 6 1 7 tests").color(ChatColor.BLUE).addChild(" 1+1+1").addChild("herpiderp").root().replaceAll("1", mson("0"));
|
||||
System.out.println("replaceAll1:" + replaceAll1.root()); // Success
|
||||
|
||||
Mson overload = mson("hello").addChild("hello").addChild("hello").root().replaceAll("hello", mson("lol"));
|
||||
System.out.println("overload:" + overload.root()); // Success
|
||||
|
||||
Mson toReplace = new Mson().text("hallo");
|
||||
|
||||
// replace mson mson
|
||||
Mson replaceAll2 = mson("1 2 3 4 5 6 7 tests").addChild(toReplace).addSibling(" miep").root().replaceAll(toReplace, mson("tests"));
|
||||
System.out.println("replaceAll2:" + replaceAll2.root()); // Success
|
||||
|
||||
Mson overload2 = mson("1 2 3 4 5 6 7 tests").addChild("hallo").addChild("hallo").addChild("hallo").addSibling(" miep").root().replaceAll(mson("hallo"), mson("tests"));
|
||||
System.out.println("overload2:" + overload2.root()); // Success
|
||||
}
|
||||
catch(Throwable t)
|
||||
{
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
897
src/com/massivecraft/massivecore/mson/Mson.java
Normal file
897
src/com/massivecraft/massivecore/mson/Mson.java
Normal file
@ -0,0 +1,897 @@
|
||||
package com.massivecraft.massivecore.mson;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Objects;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import com.massivecraft.massivecore.Predictate;
|
||||
import com.massivecraft.massivecore.adapter.LowercaseEnumAdapter;
|
||||
import com.massivecraft.massivecore.collections.MassiveList;
|
||||
import com.massivecraft.massivecore.mixin.Mixin;
|
||||
import com.massivecraft.massivecore.util.MUtil;
|
||||
import com.massivecraft.massivecore.util.Txt;
|
||||
import com.massivecraft.massivecore.xlib.gson.Gson;
|
||||
import com.massivecraft.massivecore.xlib.gson.GsonBuilder;
|
||||
import com.massivecraft.massivecore.xlib.gson.JsonElement;
|
||||
|
||||
public class Mson implements Serializable
|
||||
{
|
||||
// -------------------------------------------- //
|
||||
// CONSTANTS
|
||||
// -------------------------------------------- //
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public static final Pattern PARSE_PREFIX = Pattern.compile("\u00A7");
|
||||
|
||||
// -------------------------------------------- //
|
||||
// GSON
|
||||
// -------------------------------------------- //
|
||||
|
||||
public static final Gson GSON = new GsonBuilder()
|
||||
.disableHtmlEscaping()
|
||||
.registerTypeAdapter(ChatColor.class, LowercaseEnumAdapter.get(ChatColor.class))
|
||||
.registerTypeAdapter(MsonEventAction.class, LowercaseEnumAdapter.get(MsonEventAction.class))
|
||||
.create();
|
||||
|
||||
// -------------------------------------------- //
|
||||
// FIELDS
|
||||
// -------------------------------------------- //
|
||||
|
||||
// FIELD: The Msons text
|
||||
// A parents text can't be null, then Mojang throws an exception.
|
||||
// It does not make sense for something which doesn't have extras
|
||||
// to not have text, because then it doesn't show up at all.
|
||||
protected String text = "";
|
||||
public String text() { return this.text; }
|
||||
public Mson text(String text) { this.text = Objects.requireNonNull(text); return this; }
|
||||
public boolean textHas() { return ! this.text().isEmpty(); }
|
||||
|
||||
// FIELD: Color of the mson
|
||||
protected ChatColor color = null;
|
||||
public ChatColor color() { return this.color; }
|
||||
public ChatColor colorEffective() { return color() != null ? color() : colorInherited(); }
|
||||
public ChatColor colorInherited() { return parentHas() ? parent().colorEffective() : null; }
|
||||
public Mson color(ChatColor color)
|
||||
{
|
||||
if (color != null && ! color.isColor()) throw new IllegalArgumentException("color must be a color");
|
||||
this.color = color;
|
||||
return this;
|
||||
}
|
||||
|
||||
// FIELD: bold
|
||||
protected Boolean bold = null;
|
||||
public Boolean bold() { return bold; }
|
||||
public Mson bold(Boolean bold) { this.bold = bold; return this; }
|
||||
public boolean boldEffective() { return bold() != null ? bold() : boldInherited(); }
|
||||
public boolean boldInherited() { return parentHas() && parent().boldEffective(); }
|
||||
|
||||
// FIELD: italic
|
||||
protected Boolean italic = null;
|
||||
public Boolean italic() { return this.italic; }
|
||||
public Mson italic(Boolean italic) { this.italic = italic; return this; }
|
||||
public boolean italicEffective() { return italic() != null ? italic() : italicInherited(); }
|
||||
protected boolean italicInherited() { return parentHas() && parent().italicEffective(); }
|
||||
|
||||
// FIELD: underlined
|
||||
protected Boolean underlined = null;
|
||||
public Boolean underlined() { return this.underlined; }
|
||||
public Mson underlined(Boolean underlined) { this.underlined = underlined; return this; }
|
||||
public boolean underlinedEffective() { return italic() != null ? italic() : italicInherited(); }
|
||||
protected boolean underlinedInherited() { return parentHas() && parent().underlinedEffective(); }
|
||||
|
||||
// FIELD: strikethrough
|
||||
protected Boolean strikethrough = null;
|
||||
public Boolean strikethrough() { return this.strikethrough; }
|
||||
public Mson striketrhough(Boolean strikethrough) { this.strikethrough = strikethrough; return this; }
|
||||
public boolean strikethroughEffective() { return strikethrough() != null ? strikethrough() : strikethroughInherited(); }
|
||||
protected boolean strikethroughInherited() { return parentHas() && parent().strikethroughEffective(); }
|
||||
|
||||
// FIELD: obfuscated
|
||||
protected Boolean obfuscated = null;
|
||||
public Boolean obfuscated() { return this.obfuscated; }
|
||||
public Mson obfuscated(Boolean obfuscated) { this.obfuscated = obfuscated; return this; }
|
||||
public boolean obfuscatedEffective() { return obfuscated() != null ? obfuscated() : obfuscatedInherited(); }
|
||||
protected boolean obfuscatedInherited() { return parentHas() && parent().obfuscatedEffective(); }
|
||||
|
||||
// FIELD: The Events which happen when you click, hover over or shift-click the message
|
||||
protected MsonEvent clickEvent = null;
|
||||
public MsonEvent clickEvent() { return this.clickEvent; }
|
||||
public MsonEvent clickEventEffective() { return clickEvent() != null ? clickEvent() : clickEventInherited(); }
|
||||
protected MsonEvent clickEventInherited() { return this.parentHas() ? this.parent().clickEventEffective() : null; }
|
||||
public Mson clickEvent(MsonEvent clickEvent)
|
||||
{
|
||||
if (clickEvent != null && ! clickEvent.isClickEvent()) throw new IllegalArgumentException("clickEvent may not be hoverEvent");
|
||||
this.clickEvent = clickEvent;
|
||||
return this;
|
||||
}
|
||||
|
||||
protected MsonEvent hoverEvent = null;
|
||||
public MsonEvent hoverEvent() { return this.hoverEvent; }
|
||||
public MsonEvent hoverEventEffective() { return hoverEvent() != null ? hoverEvent() : hoverEventInherited(); }
|
||||
protected MsonEvent hoverEventInherited() { return this.parentHas() ? this.parent().hoverEventEffective() : null; }
|
||||
public Mson hoverEvent(MsonEvent hoverEvent)
|
||||
{
|
||||
if (hoverEvent != null && ! hoverEvent.isHoverEvent()) throw new IllegalArgumentException("hoverEvent may not be clickEvent");
|
||||
this.hoverEvent = hoverEvent;
|
||||
return this;
|
||||
}
|
||||
|
||||
protected String insertionString = null;
|
||||
public String insertionString() { return this.insertionString; }
|
||||
public String insertionStringEffective() { return insertionString() != null ? insertionString() : insertionStringInherited(); }
|
||||
public Mson insertionString(String insertionString) { this.insertionString = insertionString; return this; }
|
||||
protected String insertionStringInherited() { return this.parentHas() ? this.parent().insertionStringEffective() : null; }
|
||||
|
||||
// The other parts of the message
|
||||
protected List<Mson> extra = null;
|
||||
public List<Mson> extra() { return this.extra; }
|
||||
public Mson extra(List<Mson> extra) { this.extra = extra; return this; }
|
||||
public boolean extraHas() { return this.extra() != null; }
|
||||
|
||||
public List<Mson> extraCreative()
|
||||
{
|
||||
if ( ! this.extraHas()) this.extra(new MassiveList<Mson>());
|
||||
return this.extra();
|
||||
}
|
||||
|
||||
// Parent & Root
|
||||
protected transient Mson parent = null;
|
||||
public Mson parent() { return this.parent; }
|
||||
public Mson parent(Mson parent) { this.parent = parent; return this; }
|
||||
public boolean parentHas() { return this.parent() != null; }
|
||||
|
||||
public Mson parentCreative()
|
||||
{
|
||||
if ( ! this.parentHas()) this.parent(new Mson());
|
||||
return this.parent();
|
||||
}
|
||||
|
||||
public boolean isRoot() { return this.parent() == null; }
|
||||
public Mson root()
|
||||
{
|
||||
Mson root = this;
|
||||
while (true)
|
||||
{
|
||||
Mson parent = root.parent();
|
||||
if (parent == null) break;
|
||||
root = parent;
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// CONVENIENCE MSON EVENT
|
||||
// -------------------------------------------- //
|
||||
|
||||
public Mson link(String link) { this.clickEvent(MsonEvent.openUrl(link)); return this; }
|
||||
|
||||
public Mson suggest(String replace) { this.clickEvent(MsonEvent.replace(replace)); return this; }
|
||||
|
||||
public Mson command(String command) { this.clickEvent(MsonEvent.performCmd(command)); return this; }
|
||||
|
||||
public Mson tooltip(String tooltip) { this.hoverEvent(MsonEvent.hoverText(text)); return this; }
|
||||
public Mson tooltip(String... tooltip) { this.hoverEvent(MsonEvent.hoverText(text)); return this; }
|
||||
public Mson tooltip(Collection<String> tooltip) { this.hoverEvent(MsonEvent.hoverText(text)); return this; }
|
||||
|
||||
public Mson tooltipParse(String tooltip) { this.hoverEvent(MsonEvent.hoverTextParse(text)); return this; }
|
||||
public Mson tooltipParse(String... tooltip) { this.hoverEvent(MsonEvent.hoverTextParse(text)); return this; }
|
||||
public Mson tooltipParse(Collection<String> tooltip) { this.hoverEvent(MsonEvent.hoverTextParse(text)); return this; }
|
||||
|
||||
// -------------------------------------------- //
|
||||
// CONVENIENCE STYLE
|
||||
// -------------------------------------------- //
|
||||
|
||||
public Mson style(ChatColor... styles)
|
||||
{
|
||||
for (ChatColor style : styles)
|
||||
{
|
||||
this.style(style);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Mson style(ChatColor style)
|
||||
{
|
||||
if (style == ChatColor.RESET) return this.removeStyles();
|
||||
if (style == ChatColor.BOLD) return this.bold(true);
|
||||
if (style == ChatColor.ITALIC) return this.italic(true);
|
||||
if (style == ChatColor.UNDERLINE) return this.underlined(true);
|
||||
if (style == ChatColor.STRIKETHROUGH) return this.striketrhough(true);
|
||||
if (style == ChatColor.MAGIC) return this.obfuscated(true);
|
||||
if (style.isColor()) return this.color(color);
|
||||
|
||||
throw new UnsupportedOperationException(style.name());
|
||||
}
|
||||
|
||||
public Mson removeStyles()
|
||||
{
|
||||
// NOTE: We can't use null.
|
||||
// Since we want to override color and format in parents.
|
||||
this.color = ChatColor.WHITE;
|
||||
this.bold = false;
|
||||
this.italic = false;
|
||||
this.underlined = false;
|
||||
this.strikethrough = false;
|
||||
this.obfuscated = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// BUILD TREE
|
||||
// -------------------------------------------- //
|
||||
|
||||
// Child, called on parent or root
|
||||
public Mson addChild(Object child)
|
||||
{
|
||||
if (child == null) throw new NullPointerException("child");
|
||||
|
||||
Mson mson = Mson.mson(child);
|
||||
List<Mson> extra = this.extraCreative();
|
||||
|
||||
mson.parent(this);
|
||||
extra.add(mson);
|
||||
|
||||
return mson; // Return child
|
||||
}
|
||||
|
||||
public Mson addChildren(Object... children)
|
||||
{
|
||||
if (children == null) throw new NullPointerException("children");
|
||||
|
||||
for (Object part : children)
|
||||
{
|
||||
this.addChild(part);
|
||||
}
|
||||
|
||||
return this; // Return this
|
||||
}
|
||||
|
||||
// Sibling, normally called on child
|
||||
public Mson addSibling(Object sibling)
|
||||
{
|
||||
if (sibling == null) throw new NullPointerException("sibling");
|
||||
Mson parent = this.parentCreative();
|
||||
return parent.addChild(sibling); // Return sibling
|
||||
}
|
||||
|
||||
public Mson addSiblings(Object... siblings)
|
||||
{
|
||||
if (siblings == null) throw new NullPointerException("siblings");
|
||||
Mson parent = this.parentCreative();
|
||||
|
||||
if ( ! parent.equals(this.parent())) this.parent(parent);
|
||||
parent.addChildren(siblings);
|
||||
return this; // Return this
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// SIMPLE CLEAN
|
||||
// -------------------------------------------- //
|
||||
// These methods, exist to clean up after mistakes.
|
||||
// So they are very forgiving.
|
||||
|
||||
public boolean isEmpty()
|
||||
{
|
||||
// It has text, not empty.
|
||||
if (this.textHas()) return false;
|
||||
|
||||
if (this.extraHas())
|
||||
{
|
||||
for (Mson extra : this.extra())
|
||||
{
|
||||
// It is null. So kinda empty.
|
||||
if (extra == null) continue;
|
||||
|
||||
// It is empty
|
||||
if (extra.isEmpty()) continue;
|
||||
|
||||
// It was not empty.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// We are empty.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Detaches uneccessary extras.
|
||||
public Mson simpleClean()
|
||||
{
|
||||
if ( ! this.extraHas()) return this;
|
||||
if (this.extra().isEmpty())
|
||||
{
|
||||
this.extra(null);
|
||||
return this;
|
||||
}
|
||||
|
||||
for (ListIterator<Mson> it = this.extra().listIterator(); it.hasNext();)
|
||||
{
|
||||
Mson extra = it.next();
|
||||
if (extra == null)
|
||||
{
|
||||
it.remove();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (extra.isEmpty())
|
||||
{
|
||||
extra.parent(null);
|
||||
it.remove();
|
||||
continue;
|
||||
}
|
||||
|
||||
extra.simpleClean();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// CONSTRUCT
|
||||
// -------------------------------------------- //
|
||||
|
||||
public Mson()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public static Mson mson()
|
||||
{
|
||||
return new Mson();
|
||||
}
|
||||
|
||||
public static Mson mson(Object... parts)
|
||||
{
|
||||
return Mson.getMson(parts);
|
||||
}
|
||||
|
||||
private static Mson getMson(Object part)
|
||||
{
|
||||
if (part == null) throw new NullPointerException("part");
|
||||
|
||||
if (part instanceof Mson)
|
||||
{
|
||||
return (Mson) part;
|
||||
}
|
||||
else if (part instanceof String)
|
||||
{
|
||||
String text = (String) part;
|
||||
return mson().text(text);
|
||||
}
|
||||
else if (part instanceof Collection<?>)
|
||||
{
|
||||
Collection<?> parts = (Collection<?>) part;
|
||||
List<Mson> msons = Mson.msons(parts);
|
||||
|
||||
if (msons.isEmpty()) return mson();
|
||||
if (msons.size() == 1) return msons.get(0);
|
||||
|
||||
return mson().extra(msons);
|
||||
}
|
||||
else if (part instanceof Object[])
|
||||
{
|
||||
Object[] parts = (Object[]) part;
|
||||
return getMson(Arrays.asList(parts));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IllegalArgumentException("We only accept Strings, Msons, Collections and Arrays");
|
||||
}
|
||||
}
|
||||
|
||||
public static List<Mson> msons(Object... parts)
|
||||
{
|
||||
return msons(Arrays.asList(parts));
|
||||
}
|
||||
|
||||
public static List<Mson> msons(Collection<?> parts)
|
||||
{
|
||||
if (parts == null) throw new NullPointerException("parts");
|
||||
|
||||
List<Mson> msons = new MassiveList<Mson>();
|
||||
|
||||
for (Object part : parts)
|
||||
{
|
||||
msons.add(getMson(part));
|
||||
}
|
||||
|
||||
return msons;
|
||||
}
|
||||
|
||||
public static Mson fromParsedMessage(String message)
|
||||
{
|
||||
if (message == null) throw new NullPointerException("message");
|
||||
|
||||
// Everything must have a color.
|
||||
// Because when we split, we assume that each part starts with a color code.
|
||||
// Here we assure it starts with one.
|
||||
message = ensureStartsWithColorCode(message);
|
||||
|
||||
// We split at color/format change.
|
||||
String[] parts = PARSE_PREFIX.split(message);
|
||||
|
||||
// Since we start with a color, the first element will be empty.
|
||||
// We don't want that empty element.
|
||||
parts = Arrays.copyOfRange(parts, 1, parts.length);
|
||||
|
||||
List<Mson> msons = new ArrayList<Mson>();
|
||||
|
||||
ChatColor latestColor = null;
|
||||
Boolean bold = null;
|
||||
Boolean italic = null;
|
||||
Boolean underlined = null;
|
||||
Boolean strikethrough = null;
|
||||
Boolean obfuscated = null;
|
||||
|
||||
for (String part : parts)
|
||||
{
|
||||
ChatColor color = ChatColor.getByChar(part.charAt(0));
|
||||
String text = part.substring(1);
|
||||
|
||||
if ((color != null && color.isColor()) || color == ChatColor.RESET)
|
||||
{
|
||||
latestColor = color;
|
||||
bold = null;
|
||||
italic = null;
|
||||
underlined = null;
|
||||
strikethrough = null;
|
||||
obfuscated = null;
|
||||
}
|
||||
if (color == ChatColor.RESET) latestColor = null;
|
||||
else if (color == ChatColor.BOLD) bold = true;
|
||||
else if (color == ChatColor.ITALIC) italic = true;
|
||||
else if (color == ChatColor.UNDERLINE) underlined = true;
|
||||
else if (color == ChatColor.STRIKETHROUGH) strikethrough = true;
|
||||
else if (color == ChatColor.MAGIC) obfuscated = true;
|
||||
|
||||
// Don't add empty msons.
|
||||
if (text.isEmpty()) continue;
|
||||
|
||||
Mson mson = new Mson()
|
||||
.text(text)
|
||||
.color(latestColor)
|
||||
.bold(bold)
|
||||
.italic(italic)
|
||||
.underlined(underlined)
|
||||
.striketrhough(strikethrough)
|
||||
.obfuscated(obfuscated);
|
||||
|
||||
msons.add(mson);
|
||||
}
|
||||
|
||||
return Mson.mson(msons);
|
||||
}
|
||||
|
||||
private static String ensureStartsWithColorCode(String message)
|
||||
{
|
||||
if ( ! message.startsWith("\u00A7"))
|
||||
{
|
||||
message = ChatColor.RESET + message;
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
// Parse redirects, convert to Mson directly
|
||||
public static Mson parse(String string) { return Mson.fromParsedMessage(Txt.parse(string)); }
|
||||
public static Mson parse(String format, Object... args) { return Mson.fromParsedMessage(Txt.parse(format, args)); }
|
||||
|
||||
public static Mson format(String format, Object... args)
|
||||
{
|
||||
return Mson.mson(String.format(format, args));
|
||||
}
|
||||
|
||||
public Mson copy()
|
||||
{
|
||||
Mson copy = new Mson()
|
||||
.text(this.text)
|
||||
.color(this.color)
|
||||
.bold(this.bold)
|
||||
.italic(this.italic)
|
||||
.underlined(this.underlined)
|
||||
.striketrhough(this.strikethrough)
|
||||
.obfuscated(this.obfuscated)
|
||||
.insertionString(this.insertionString)
|
||||
.clickEvent(this.clickEvent)
|
||||
.hoverEvent(this.hoverEvent);
|
||||
|
||||
if (this.extraHas())
|
||||
{
|
||||
List<Mson> extras = new MassiveList<Mson>(this.extra.size());
|
||||
for (Mson extra : this.extra)
|
||||
{
|
||||
Mson extraCopy = extra.copy();
|
||||
extraCopy.parent(copy);
|
||||
extras.add(extraCopy);
|
||||
}
|
||||
copy.extra(extras);
|
||||
}
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
private Mson copyFormatAndBehaviour(Mson ancestor)
|
||||
{
|
||||
if (ancestor == null) throw new NullPointerException("ancestor");
|
||||
|
||||
this.color(ancestor.color());
|
||||
this.bold(ancestor.bold());
|
||||
this.italic(ancestor.italic());
|
||||
this.underlined(ancestor.underlined());
|
||||
this.striketrhough(ancestor.strikethrough());
|
||||
this.obfuscated(ancestor.obfuscated());
|
||||
this.hoverEvent(ancestor.hoverEvent());
|
||||
this.clickEvent(ancestor.clickEvent());
|
||||
this.insertionString(ancestor.insertionString());
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// STRING LIKE METHODS
|
||||
// -------------------------------------------- //
|
||||
|
||||
// Split
|
||||
public List<Mson> split(String regex)
|
||||
{
|
||||
return this.split(regex, 0);
|
||||
}
|
||||
|
||||
public List<Mson> split(String regex, int limit)
|
||||
{
|
||||
return split(Pattern.compile(regex), limit);
|
||||
}
|
||||
|
||||
public List<Mson> split(Pattern pattern)
|
||||
{
|
||||
return this.split(pattern, 0);
|
||||
}
|
||||
|
||||
public List<Mson> split(Pattern pattern, int limit)
|
||||
{
|
||||
if (pattern == null) throw new NullPointerException("pattern");
|
||||
|
||||
boolean limited = (limit == 0 ? false : true);
|
||||
List<Mson> msons = new MassiveList<Mson>();
|
||||
|
||||
String[] splited = pattern.split(this.text(), limit);
|
||||
if (splited.length == 1) return new MassiveList<Mson>(this);
|
||||
|
||||
for (String string : splited)
|
||||
{
|
||||
if (string.isEmpty()) continue;
|
||||
Mson part = new Mson().text(string);
|
||||
part.copyFormatAndBehaviour(this);
|
||||
msons.add(part);
|
||||
}
|
||||
|
||||
int size = msons.size();
|
||||
|
||||
for (Mson part : this.extraCreative())
|
||||
{
|
||||
if (limited)
|
||||
{
|
||||
limit -= size;
|
||||
if (limit <= 0) break;
|
||||
}
|
||||
|
||||
List<Mson> innerMsons = part.split(pattern, limit);
|
||||
msons.addAll(innerMsons);
|
||||
size = innerMsons.size();
|
||||
}
|
||||
|
||||
return msons;
|
||||
}
|
||||
|
||||
// Replace
|
||||
public Mson replace(char oldChar, char newChar)
|
||||
{
|
||||
this.text(this.text().replace(oldChar, newChar));
|
||||
|
||||
if (this.extraHas())
|
||||
{
|
||||
for (Mson part : this.extra())
|
||||
{
|
||||
part.replace(oldChar, newChar);
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public Mson replace(CharSequence replace, CharSequence replacement)
|
||||
{
|
||||
if (replace == null) throw new NullPointerException("replace");
|
||||
if (replacement == null) throw new NullPointerException("replacement");
|
||||
|
||||
this.text(this.text().replace(replace, replacement));
|
||||
|
||||
if (this.extraHas())
|
||||
{
|
||||
for (Mson part : this.extra())
|
||||
{
|
||||
part.replace(replace, replacement);
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public Mson replaceAll(String regex, String replacement)
|
||||
{
|
||||
if (regex == null) throw new NullPointerException("regex");
|
||||
if (replacement == null) throw new NullPointerException("replacement");
|
||||
|
||||
this.text(this.text().replaceAll(regex, replacement));
|
||||
|
||||
if (this.extraHas())
|
||||
{
|
||||
for (Mson part : this.extra())
|
||||
{
|
||||
part.replaceAll(regex, replacement);
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
// Special replace all
|
||||
public Mson replaceAll(String regex, Mson replacement)
|
||||
{
|
||||
return replaceAll(Pattern.compile(regex), replacement);
|
||||
}
|
||||
|
||||
public Mson replaceAll(Pattern pattern, Mson replacement)
|
||||
{
|
||||
if (pattern == null) throw new NullPointerException("pattern");
|
||||
if (replacement == null) throw new NullPointerException("replacement");
|
||||
|
||||
// We don't want the same object to eventually be part of itself
|
||||
Mson repCopy = replacement.copy();
|
||||
String text = (this.text() + " "); // Prepare text
|
||||
|
||||
// Split the string of this msons text and create an iterator
|
||||
// and create the list of mson with the replacements in between ...
|
||||
List<Mson> msons = new MassiveList<Mson>();
|
||||
|
||||
for (ListIterator<String> it = Arrays.asList(pattern.split(text)).listIterator(); it.hasNext();)
|
||||
{
|
||||
String string = it.next();
|
||||
|
||||
// string might be empty, we don't want these empty msons
|
||||
if ( ! string.isEmpty())
|
||||
{
|
||||
Mson part = Mson.mson(string);
|
||||
msons.add(part);
|
||||
|
||||
// Delete security spacing at the last string
|
||||
if ( ! it.hasNext()) part.text(string.substring(0, string.length() - 1));
|
||||
}
|
||||
|
||||
// In between every part, add in replacement
|
||||
if (it.hasNext()) msons.add(repCopy);
|
||||
}
|
||||
|
||||
// ... and forge back together, unless the whole text is "replaced", then set it to be the replacement itself.
|
||||
Mson mson;
|
||||
if ( ! msons.isEmpty())
|
||||
{
|
||||
mson = msons.get(0).copy();
|
||||
msons.remove(0);
|
||||
mson.copyFormatAndBehaviour(this);
|
||||
if ( ! msons.isEmpty()) mson.extra(msons);
|
||||
}
|
||||
else
|
||||
{
|
||||
mson = repCopy;
|
||||
}
|
||||
|
||||
mson.parent(this.parent());
|
||||
|
||||
// If there is no extra, return here...
|
||||
List<Mson> extra = this.extra();
|
||||
if (extra == null) return mson;
|
||||
|
||||
// ... otherwise iterate over the extra and modify it.
|
||||
for (ListIterator<Mson> it = extra.listIterator(); it.hasNext();)
|
||||
{
|
||||
Mson part = it.next();
|
||||
int index = extra.indexOf(part);
|
||||
|
||||
part = part.replaceAll(pattern, replacement);
|
||||
part.parent(mson);
|
||||
|
||||
extra.set(index, part);
|
||||
}
|
||||
|
||||
// If the current mson has any extra ...
|
||||
List<Mson> extras = mson.extra();
|
||||
if( extras != null)
|
||||
{
|
||||
// ... apply tree structure again ...
|
||||
extras.get(extras.size() - 1).extra(extra);
|
||||
}
|
||||
else
|
||||
{
|
||||
// ... set the extra directly ...
|
||||
mson.extra(extra);
|
||||
}
|
||||
|
||||
mson.simpleClean();
|
||||
// ... and return recreated mson
|
||||
return mson;
|
||||
}
|
||||
|
||||
public Mson replaceAll(Mson replace, Mson replacement)
|
||||
{
|
||||
if (replace == null) throw new NullPointerException("replace");
|
||||
if (replacement == null) throw new NullPointerException("replacement");
|
||||
|
||||
// We don't want the same object to eventually be part of itself
|
||||
Mson repCopy = replacement.copy();
|
||||
|
||||
Mson mson = this;
|
||||
List<Mson> extra = this.extra();
|
||||
|
||||
if (mson.equals(replace))
|
||||
{
|
||||
mson = repCopy;
|
||||
mson.parent(this.parent());
|
||||
if (extra != null) mson.extraCreative().addAll(extra);
|
||||
}
|
||||
|
||||
if (extra == null) return mson;
|
||||
|
||||
for (ListIterator<Mson> it = extra.listIterator(); it.hasNext();)
|
||||
{
|
||||
int index = it.nextIndex();
|
||||
Mson part = it.next();
|
||||
|
||||
part = part.replaceAll(replace, replacement);
|
||||
part.parent(mson);
|
||||
|
||||
extra.set(index, part);
|
||||
}
|
||||
|
||||
mson.extra(extra);
|
||||
return mson;
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// SEND
|
||||
// -------------------------------------------- //
|
||||
|
||||
// All
|
||||
public boolean sendAll()
|
||||
{
|
||||
return Mixin.messageRawAll(this);
|
||||
}
|
||||
|
||||
// Predictate
|
||||
public boolean sendPredictate(Predictate<CommandSender> predictate)
|
||||
{
|
||||
return Mixin.messageRawPredictate(predictate, this);
|
||||
}
|
||||
|
||||
// One
|
||||
public boolean sendOne(Object senderObject)
|
||||
{
|
||||
return Mixin.messageRawOne(senderObject, this);
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// TO JSON, RAW, PLAIN & STRING
|
||||
// -------------------------------------------- //
|
||||
|
||||
public JsonElement rootToJson() { return this.root().toJson(); }
|
||||
public JsonElement toJson()
|
||||
{
|
||||
return GSON.toJsonTree(this);
|
||||
}
|
||||
|
||||
public String rootToRaw() { return this.root().toRaw(); }
|
||||
public String toRaw()
|
||||
{
|
||||
return this.toJson().toString();
|
||||
}
|
||||
|
||||
public String toPlain()
|
||||
{
|
||||
StringBuilder ret = new StringBuilder();
|
||||
|
||||
ret.append(toPlainSimple(this));
|
||||
|
||||
if (this.extraHas())
|
||||
{
|
||||
for (Mson part : this.extra())
|
||||
{
|
||||
ret.append(ChatColor.RESET);
|
||||
ret.append(part.toPlain());
|
||||
}
|
||||
}
|
||||
|
||||
return ret.toString();
|
||||
}
|
||||
|
||||
// Turns a single mson (without it's children) into plain text.
|
||||
protected static String toPlainSimple(Mson mson)
|
||||
{
|
||||
if (mson.textHas())
|
||||
{
|
||||
// Color must be put in BEFORE formatting.
|
||||
// http://minecraft.gamepedia.com/Formatting_codes#Formatting_codes
|
||||
|
||||
StringBuilder ret = new StringBuilder(mson.text().length());
|
||||
if (mson.colorEffective() != null) ret.append(mson.colorEffective());
|
||||
if (mson.boldEffective()) ret.append(ChatColor.BOLD);
|
||||
if (mson.italicEffective()) ret.append(ChatColor.ITALIC);
|
||||
if (mson.underlinedEffective()) ret.append(ChatColor.UNDERLINE);
|
||||
if (mson.strikethroughEffective()) ret.append(ChatColor.STRIKETHROUGH);
|
||||
if (mson.obfuscatedEffective()) ret.append(ChatColor.MAGIC);
|
||||
ret.append(mson.text());
|
||||
|
||||
return ret.toString();
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return this.toRaw();
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// EQUALS AND HASHCODE
|
||||
// -------------------------------------------- //
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + Objects.hashCode(this.text);
|
||||
result = prime * result + Objects.hashCode(this.color);
|
||||
result = prime * result + Objects.hashCode(this.bold);
|
||||
result = prime * result + Objects.hashCode(this.italic);
|
||||
result = prime * result + Objects.hashCode(this.obfuscated);
|
||||
result = prime * result + Objects.hashCode(this.strikethrough);
|
||||
result = prime * result + Objects.hashCode(this.underlined);
|
||||
result = prime * result + Objects.hashCode(this.clickEvent);
|
||||
result = prime * result + Objects.hashCode(this.hoverEvent);
|
||||
result = prime * result + Objects.hashCode(this.insertionString);
|
||||
result = prime * result + Objects.hashCode(this.extra);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (this == obj) return true;
|
||||
if ( ! (obj instanceof Mson)) return false;
|
||||
Mson that = (Mson) obj;
|
||||
|
||||
if ( ! MUtil.equals(this.text, that.text)) return false;
|
||||
if ( ! MUtil.equals(this.color, that.color)) return false;
|
||||
if ( ! MUtil.equals(this.bold, that.bold)) return false;
|
||||
if ( ! MUtil.equals(this.italic, that.italic)) return false;
|
||||
if ( ! MUtil.equals(this.obfuscated, that.obfuscated)) return false;
|
||||
if ( ! MUtil.equals(this.strikethrough, that.strikethrough)) return false;
|
||||
if ( ! MUtil.equals(this.underlined, that.underlined)) return false;
|
||||
if ( ! MUtil.equals(this.clickEvent, that.clickEvent)) return false;
|
||||
if ( ! MUtil.equals(this.hoverEvent, that.hoverEvent)) return false;
|
||||
if ( ! MUtil.equals(this.insertionString, that.insertionString)) return false;
|
||||
if ( ! MUtil.equals(this.extra, that.extra)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
129
src/com/massivecraft/massivecore/mson/MsonEvent.java
Normal file
129
src/com/massivecraft/massivecore/mson/MsonEvent.java
Normal file
@ -0,0 +1,129 @@
|
||||
package com.massivecraft.massivecore.mson;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.Objects;
|
||||
|
||||
import com.massivecraft.massivecore.util.MUtil;
|
||||
import com.massivecraft.massivecore.util.Txt;
|
||||
|
||||
public class MsonEvent implements Serializable
|
||||
{
|
||||
// -------------------------------------------- //
|
||||
// CONSTANTS
|
||||
// -------------------------------------------- //
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
// -------------------------------------------- //
|
||||
// FIELDS
|
||||
// -------------------------------------------- //
|
||||
|
||||
protected final MsonEventAction action;
|
||||
public MsonEventAction getEventActionType() { return this.action; }
|
||||
|
||||
protected final String value;
|
||||
public String getActionText() { return this.value; }
|
||||
|
||||
// -------------------------------------------- //
|
||||
// CONSTRUCT
|
||||
// -------------------------------------------- //
|
||||
|
||||
protected MsonEvent(MsonEventAction action, String value)
|
||||
{
|
||||
this.action = action;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// FACTORY
|
||||
// -------------------------------------------- //
|
||||
|
||||
public static MsonEvent valueOf(MsonEventAction type, String action)
|
||||
{
|
||||
return new MsonEvent(type, action);
|
||||
}
|
||||
|
||||
// clickEvents
|
||||
public static MsonEvent openUrl(String url)
|
||||
{
|
||||
return MsonEvent.valueOf(MsonEventAction.OPEN_URL, url);
|
||||
}
|
||||
|
||||
public static MsonEvent replace(String replace)
|
||||
{
|
||||
return MsonEvent.valueOf(MsonEventAction.SUGGEST_COMMAND , replace);
|
||||
}
|
||||
|
||||
public static MsonEvent performCmd(String cmd)
|
||||
{
|
||||
return MsonEvent.valueOf(MsonEventAction.RUN_COMMAND, cmd);
|
||||
}
|
||||
|
||||
// hoverEvents
|
||||
public static MsonEvent hoverText(String hoverText)
|
||||
{
|
||||
return MsonEvent.valueOf(MsonEventAction.SHOW_TEXT, hoverText);
|
||||
}
|
||||
|
||||
public static MsonEvent hoverText(String... hoverTexts)
|
||||
{
|
||||
return MsonEvent.valueOf(MsonEventAction.SHOW_TEXT, Txt.implode(hoverTexts, "\n"));
|
||||
}
|
||||
|
||||
public static MsonEvent hoverText(Collection<String> hoverTexts)
|
||||
{
|
||||
return MsonEvent.valueOf(MsonEventAction.SHOW_TEXT, Txt.implode(hoverTexts, "\n"));
|
||||
}
|
||||
|
||||
// hoverEventsParsed
|
||||
public static MsonEvent hoverTextParse(String hoverText)
|
||||
{
|
||||
return MsonEvent.valueOf(MsonEventAction.SHOW_TEXT, Txt.parse(hoverText));
|
||||
}
|
||||
|
||||
public static MsonEvent hoverTextParse(String... hoverTexts)
|
||||
{
|
||||
return MsonEvent.valueOf(MsonEventAction.SHOW_TEXT, Txt.parse(Txt.implode(hoverTexts, "\n")));
|
||||
}
|
||||
|
||||
public static MsonEvent hoverTextParse(Collection<String> hoverTexts)
|
||||
{
|
||||
return MsonEvent.valueOf(MsonEventAction.SHOW_TEXT, Txt.parse(Txt.implode(hoverTexts, "\n")));
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// CONVENIENCE
|
||||
// -------------------------------------------- //
|
||||
|
||||
public boolean isHoverEvent() { return this.getEventActionType().isHoverAction(); }
|
||||
public boolean isClickEvent() { return this.getEventActionType().isClickAction(); }
|
||||
|
||||
// -------------------------------------------- //
|
||||
// EQUALS AND HASHCODE
|
||||
// -------------------------------------------- //
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + Objects.hashCode(action);
|
||||
result = prime * result + Objects.hashCode(value);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (this == obj) return true;
|
||||
if ( ! (obj instanceof MsonEvent)) return false;
|
||||
MsonEvent that = (MsonEvent) obj;
|
||||
|
||||
if ( ! MUtil.equals(this.action, that.action)) return false;
|
||||
if ( ! MUtil.equals(this.value, that.value)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
44
src/com/massivecraft/massivecore/mson/MsonEventAction.java
Normal file
44
src/com/massivecraft/massivecore/mson/MsonEventAction.java
Normal file
@ -0,0 +1,44 @@
|
||||
package com.massivecraft.massivecore.mson;
|
||||
|
||||
public enum MsonEventAction
|
||||
{
|
||||
// -------------------------------------------- //
|
||||
// ENUM
|
||||
// -------------------------------------------- //
|
||||
|
||||
SUGGEST_COMMAND(),
|
||||
RUN_COMMAND(),
|
||||
OPEN_URL(),
|
||||
SHOW_TEXT(true)
|
||||
|
||||
// End of list
|
||||
;
|
||||
|
||||
// -------------------------------------------- //
|
||||
// FIELD
|
||||
// -------------------------------------------- //
|
||||
|
||||
private boolean isHoverAction;
|
||||
public boolean isHoverAction() { return this.isHoverAction; }
|
||||
|
||||
// NOTE: This behaviour might change.
|
||||
// So to check if something is a click action this method should be called.
|
||||
// Doing !action.isHoverAction();
|
||||
// Shouldn't be done outside of this class.
|
||||
public boolean isClickAction() { return ! this.isHoverAction(); }
|
||||
|
||||
// -------------------------------------------- //
|
||||
// CONSTRUCT
|
||||
// -------------------------------------------- //
|
||||
|
||||
private MsonEventAction(boolean isHoveraction)
|
||||
{
|
||||
this.isHoverAction = isHoveraction;
|
||||
}
|
||||
|
||||
private MsonEventAction()
|
||||
{
|
||||
this(false);
|
||||
}
|
||||
|
||||
}
|
@ -9,6 +9,7 @@ import org.bukkit.command.ConsoleCommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import com.massivecraft.massivecore.mixin.Mixin;
|
||||
import com.massivecraft.massivecore.mson.Mson;
|
||||
import com.massivecraft.massivecore.util.IdUtil;
|
||||
|
||||
public abstract class SenderEntity<E extends SenderEntity<E>> extends Entity<E>
|
||||
@ -159,6 +160,23 @@ public abstract class SenderEntity<E extends SenderEntity<E>> extends Entity<E>
|
||||
return Mixin.msgOne(this.getId(), msgs);
|
||||
}
|
||||
|
||||
// CONVENIENCE SEND RAW
|
||||
|
||||
public boolean sendRaw(Mson mson)
|
||||
{
|
||||
return Mixin.messageRawOne(this.getId(), mson);
|
||||
}
|
||||
|
||||
public boolean sendRaw(Mson... msons)
|
||||
{
|
||||
return Mixin.messageRawOne(this.getId(), msons);
|
||||
}
|
||||
|
||||
public boolean sendRaw(Collection<Mson> msons)
|
||||
{
|
||||
return Mixin.messageRawOne(this.getId(), msons);
|
||||
}
|
||||
|
||||
// CONVENIENCE GAME-MODE
|
||||
|
||||
public GameMode getGameMode(GameMode def)
|
||||
|
272
src/com/massivecraft/massivecore/util/PacketUtil.java
Normal file
272
src/com/massivecraft/massivecore/util/PacketUtil.java
Normal file
@ -0,0 +1,272 @@
|
||||
package com.massivecraft.massivecore.util;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import com.massivecraft.massivecore.MassiveCore;
|
||||
import com.massivecraft.massivecore.particleeffect.ReflectionUtils;
|
||||
import com.massivecraft.massivecore.particleeffect.ReflectionUtils.PackageType;
|
||||
|
||||
public final class PacketUtil
|
||||
{
|
||||
// -------------------------------------------- //
|
||||
// FIELDS
|
||||
// -------------------------------------------- //
|
||||
|
||||
// Is using
|
||||
private static boolean useTitles = false;
|
||||
private static boolean useRaw = false;
|
||||
|
||||
// The enums used to tell which packet it is.
|
||||
// They correspond to the commands with the same name.
|
||||
private static Class<?> titleEnumClass;
|
||||
private static Enum<?> titleMainEnum;
|
||||
private static Enum<?> titleSubEnum;
|
||||
private static Enum<?> titleTimesEnum;
|
||||
|
||||
// Method used to prepare text so it can be sent
|
||||
private static Method chatSerializer;
|
||||
// The object we send instead of a string
|
||||
private static Class<?> iChatBaseComponent;
|
||||
|
||||
// Handling the players conenction
|
||||
private static Method getHandle;
|
||||
private static Field playerConnection;
|
||||
private static Method sendPacket;
|
||||
|
||||
// The title packet and its constructor
|
||||
private static Constructor<?> titlePacketConstructor;
|
||||
private static Constructor<?> titlePacketConstructorTimes;
|
||||
|
||||
// The chat packet and its constructor
|
||||
private static Constructor<?> chatPacketConstructor;
|
||||
|
||||
// -------------------------------------------- //
|
||||
// SETUP
|
||||
// -------------------------------------------- //
|
||||
|
||||
static
|
||||
{
|
||||
try
|
||||
{
|
||||
// The enum used for titles
|
||||
titleEnumClass = getTitleEnumClass();
|
||||
|
||||
// Get the title enum values.
|
||||
for (Object o : titleEnumClass.getEnumConstants())
|
||||
{
|
||||
Enum<?> e = (Enum<?>) o;
|
||||
if (e.name().equalsIgnoreCase("TITLE")) titleMainEnum = e;
|
||||
else if (e.name().equalsIgnoreCase("SUBTITLE")) titleSubEnum = e;
|
||||
else if (e.name().equalsIgnoreCase("TIMES")) titleTimesEnum = e;
|
||||
}
|
||||
|
||||
// Get chatserializer and chat component.
|
||||
iChatBaseComponent = PackageType.MINECRAFT_SERVER.getClass("IChatBaseComponent");
|
||||
|
||||
chatSerializer = getChatSerializer();
|
||||
|
||||
// Get title packet and it's constructor
|
||||
Class<?> titlePacketClass = PackageType.MINECRAFT_SERVER.getClass("PacketPlayOutTitle");
|
||||
titlePacketConstructor = ReflectionUtils.getConstructor(titlePacketClass, titleEnumClass, iChatBaseComponent);
|
||||
titlePacketConstructorTimes = ReflectionUtils.getConstructor(titlePacketClass, titleEnumClass, iChatBaseComponent, Integer.class, Integer.class, Integer.class);
|
||||
|
||||
// Get Chat packet and it's constructor
|
||||
Class<?> chatPacketClass = PackageType.MINECRAFT_SERVER.getClass("PacketPlayOutChat");
|
||||
chatPacketConstructor = ReflectionUtils.getConstructor(chatPacketClass, iChatBaseComponent);
|
||||
|
||||
// Player connection
|
||||
getHandle = ReflectionUtils.getMethod("CraftPlayer", PackageType.CRAFTBUKKIT_ENTITY, "getHandle");
|
||||
playerConnection = ReflectionUtils.getField("EntityPlayer", PackageType.MINECRAFT_SERVER, false, "playerConnection");
|
||||
sendPacket = ReflectionUtils.getMethod(playerConnection.getType(), "sendPacket", PackageType.MINECRAFT_SERVER.getClass("Packet"));
|
||||
|
||||
// Set accessible
|
||||
setAllAccessible();
|
||||
|
||||
// This succeeded, we use titles and the chat.
|
||||
useTitles = true;
|
||||
useRaw = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MassiveCore.get().log(Level.INFO, "If you use 1.7.X or below, disregard this error");
|
||||
MassiveCore.get().log(Level.INFO, "If you use 1.8.X or above, please report at https://github.com/MassiveCraft/MassiveCore/issues");
|
||||
ex.printStackTrace();
|
||||
MassiveCore.get().log(Level.INFO, "If you use 1.7.X or below, disregard this error");
|
||||
MassiveCore.get().log(Level.INFO, "If you use 1.8.X or above, please report at https://github.com/MassiveCraft/MassiveCore/issues");
|
||||
|
||||
// It didn't succeed, we will not use titles.
|
||||
useTitles = false;
|
||||
useRaw = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static Class<?> getTitleEnumClass() throws ClassNotFoundException
|
||||
{
|
||||
Class<?> ret;
|
||||
try
|
||||
{
|
||||
ret = titleEnumClass = PackageType.MINECRAFT_SERVER.getClass("EnumTitleAction");
|
||||
}
|
||||
catch (ClassNotFoundException e)
|
||||
{
|
||||
// Since 1.8.3
|
||||
ret = titleEnumClass = PackageType.MINECRAFT_SERVER.getClass("PacketPlayOutTitle$EnumTitleAction");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static Method getChatSerializer() throws Exception
|
||||
{
|
||||
Method ret;
|
||||
try
|
||||
{
|
||||
ret = chatSerializer = PackageType.MINECRAFT_SERVER.getClass("ChatSerializer").getDeclaredMethod("a", String.class);
|
||||
}
|
||||
catch (ClassNotFoundException e)
|
||||
{
|
||||
// Since 1.8.3
|
||||
ret = chatSerializer = PackageType.MINECRAFT_SERVER.getClass("IChatBaseComponent$ChatSerializer").getDeclaredMethod("a", String.class);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static void setAllAccessible()
|
||||
{
|
||||
chatSerializer.setAccessible(true);
|
||||
titlePacketConstructor.setAccessible(true);
|
||||
titlePacketConstructorTimes.setAccessible(true);
|
||||
chatPacketConstructor.setAccessible(true);
|
||||
getHandle.setAccessible(true);
|
||||
playerConnection.setAccessible(true);
|
||||
sendPacket.setAccessible(true);
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// AVAILABLE
|
||||
// -------------------------------------------- //
|
||||
|
||||
public static boolean isTitleAvailable()
|
||||
{
|
||||
return useTitles;
|
||||
}
|
||||
|
||||
public static boolean isRawAvailable()
|
||||
{
|
||||
return useRaw;
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// SEND TITLES
|
||||
// -------------------------------------------- //
|
||||
|
||||
public static boolean sendTitle(Player player, int ticksIn, int ticksStay, int ticksOut, String titleMain, String titleSub)
|
||||
{
|
||||
if ( ! useTitles) return false;
|
||||
|
||||
try
|
||||
{
|
||||
// Fadein, stay, fadeout
|
||||
Object timesPacket = titlePacketConstructorTimes.newInstance(titleTimesEnum, null, ticksIn, ticksStay, ticksOut);
|
||||
sendPacket(player, timesPacket);
|
||||
|
||||
if (titleMain != null)
|
||||
{
|
||||
titleMain = toJson(titleMain);
|
||||
|
||||
// Title
|
||||
Object titleMainChat = toChatBaseComponent(titleMain);
|
||||
Object titleMainPacket = titlePacketConstructor.newInstance(titleMainEnum, titleMainChat);
|
||||
sendPacket(player, titleMainPacket);
|
||||
|
||||
}
|
||||
|
||||
if (titleSub != null)
|
||||
{
|
||||
titleSub = toJson(titleSub);
|
||||
// SubTitle
|
||||
Object titleSubChat = toChatBaseComponent(titleSub);
|
||||
Object titleSubPacket = titlePacketConstructor.newInstance(titleSubEnum, titleSubChat);
|
||||
sendPacket(player, titleSubPacket);
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MassiveCore.get().log("<b>Sending title failed!");
|
||||
ex.printStackTrace();
|
||||
// So we failed, didn't work.
|
||||
return false;
|
||||
}
|
||||
|
||||
//It worked.
|
||||
return true;
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// SEND RAW
|
||||
// -------------------------------------------- //
|
||||
|
||||
public static boolean sendRaw(Player player, String string)
|
||||
{
|
||||
if ( ! useRaw) return false;
|
||||
|
||||
try
|
||||
{
|
||||
Object rawChat = toChatBaseComponent(string);
|
||||
Object chatPacket = chatPacketConstructor.newInstance(rawChat);
|
||||
|
||||
sendPacket(player, chatPacket);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MassiveCore.get().log("<b>Sending raw chat failed!");
|
||||
ex.printStackTrace();
|
||||
// So we failed and it didn't work.
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// UTIL
|
||||
// -------------------------------------------- //
|
||||
|
||||
public static void sendPacket(Player player, Object packet) throws Exception
|
||||
{
|
||||
sendPacket.invoke(getPlayerConnection(player), packet);
|
||||
}
|
||||
|
||||
public static Object getPlayerConnection(Player player) throws Exception
|
||||
{
|
||||
return playerConnection.get(getHandle.invoke(player));
|
||||
}
|
||||
|
||||
public static Object toChatBaseComponent(String str) throws Exception
|
||||
{
|
||||
return chatSerializer.invoke(null, str);
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// JSON
|
||||
// -------------------------------------------- //
|
||||
|
||||
public static String toJson(String str)
|
||||
{
|
||||
str = JSONObject.escape(str);
|
||||
|
||||
str = "{\"text\": \"" + str + "\"}";
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
}
|
@ -1,206 +0,0 @@
|
||||
package com.massivecraft.massivecore.util;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import com.massivecraft.massivecore.MassiveCore;
|
||||
import com.massivecraft.massivecore.particleeffect.ReflectionUtils;
|
||||
import com.massivecraft.massivecore.particleeffect.ReflectionUtils.PackageType;
|
||||
|
||||
public final class TitleUtil
|
||||
{
|
||||
// -------------------------------------------- //
|
||||
// FIELDS
|
||||
// -------------------------------------------- //
|
||||
|
||||
private static boolean useTitles = false;
|
||||
|
||||
// The enums used to tell which packet it is.
|
||||
// They correspond to the commands with the same name.
|
||||
private static Class<?> titleEnumClass;
|
||||
private static Enum<?> titleEnum;
|
||||
private static Enum<?> subtitleEnum;
|
||||
private static Enum<?> timesEnum;
|
||||
|
||||
// Method used to prepare text so it can be send
|
||||
private static Method chatSerializer;
|
||||
// The object we send instead of a string
|
||||
private static Class<?> iChatBaseComponent;
|
||||
|
||||
// Handling the players conenction
|
||||
private static Method getHandle;
|
||||
private static Field playerConnection;
|
||||
private static Method sendPacket;
|
||||
|
||||
// The packet and its constructor
|
||||
private static Constructor<?> packetConstructor;
|
||||
private static Constructor<?> packetConstructorTimes;
|
||||
|
||||
// -------------------------------------------- //
|
||||
// SETUP
|
||||
// -------------------------------------------- //
|
||||
|
||||
static
|
||||
{
|
||||
try
|
||||
{
|
||||
// The enum used
|
||||
try
|
||||
{
|
||||
titleEnumClass = PackageType.MINECRAFT_SERVER.getClass("EnumTitleAction");
|
||||
}
|
||||
catch (ClassNotFoundException e)
|
||||
{
|
||||
// Since 1.8.3
|
||||
titleEnumClass = PackageType.MINECRAFT_SERVER.getClass("PacketPlayOutTitle$EnumTitleAction");
|
||||
}
|
||||
|
||||
// Get the enum values.
|
||||
for (Object o : titleEnumClass.getEnumConstants())
|
||||
{
|
||||
Enum<?> e = (Enum<?>) o;
|
||||
if (e.name().equalsIgnoreCase("TITLE")) titleEnum = e;
|
||||
else if (e.name().equalsIgnoreCase("SUBTITLE")) subtitleEnum = e;
|
||||
else if (e.name().equalsIgnoreCase("TIMES")) timesEnum = e;
|
||||
}
|
||||
|
||||
// Get chatserializer and chat component.
|
||||
iChatBaseComponent = PackageType.MINECRAFT_SERVER.getClass("IChatBaseComponent");
|
||||
|
||||
try
|
||||
{
|
||||
chatSerializer = PackageType.MINECRAFT_SERVER.getClass("ChatSerializer").getDeclaredMethod("a", String.class);
|
||||
}
|
||||
catch (ClassNotFoundException e)
|
||||
{
|
||||
// Since 1.8.3
|
||||
chatSerializer = PackageType.MINECRAFT_SERVER.getClass("IChatBaseComponent$ChatSerializer").getDeclaredMethod("a", String.class);
|
||||
}
|
||||
|
||||
// Get packet and it's constructor
|
||||
Class<?> packetClass = PackageType.MINECRAFT_SERVER.getClass("PacketPlayOutTitle");
|
||||
packetConstructor = ReflectionUtils.getConstructor(packetClass, titleEnumClass, iChatBaseComponent);
|
||||
packetConstructorTimes = ReflectionUtils.getConstructor(packetClass, titleEnumClass, iChatBaseComponent, Integer.class, Integer.class, Integer.class);
|
||||
|
||||
// Player connection
|
||||
getHandle = ReflectionUtils.getMethod("CraftPlayer", PackageType.CRAFTBUKKIT_ENTITY, "getHandle");
|
||||
playerConnection = ReflectionUtils.getField("EntityPlayer", PackageType.MINECRAFT_SERVER, false, "playerConnection");
|
||||
sendPacket = ReflectionUtils.getMethod(playerConnection.getType(), "sendPacket", PackageType.MINECRAFT_SERVER.getClass("Packet"));
|
||||
|
||||
// Set accesible
|
||||
chatSerializer.setAccessible(true);
|
||||
packetConstructor.setAccessible(true);
|
||||
packetConstructorTimes.setAccessible(true);
|
||||
getHandle.setAccessible(true);
|
||||
playerConnection.setAccessible(true);
|
||||
sendPacket.setAccessible(true);
|
||||
|
||||
// This succeeded, we use titles.
|
||||
useTitles = true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MassiveCore.get().log(Level.INFO, "If you use 1.7.X or below, disregard this error");
|
||||
MassiveCore.get().log(Level.INFO, "If you use 1.8.X or above, please report at https://github.com/MassiveCraft/MassiveCore/issues");
|
||||
e.printStackTrace();
|
||||
MassiveCore.get().log(Level.INFO, "If you use 1.7.X or below, disregard this error");
|
||||
MassiveCore.get().log(Level.INFO, "If you use 1.8.X or above, please report at https://github.com/MassiveCraft/MassiveCore/issues");
|
||||
|
||||
// It didn't suceed, we will not use titles.
|
||||
useTitles = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// AVAILABLE
|
||||
// -------------------------------------------- //
|
||||
|
||||
public static boolean isAvailable()
|
||||
{
|
||||
return useTitles;
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// SEND TITLES
|
||||
// -------------------------------------------- //
|
||||
|
||||
public static boolean sendTitle(Player player, int ticksIn, int ticksStay, int ticksOut, String titleMain, String titleSub)
|
||||
{
|
||||
if ( ! useTitles)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Fadein, stay, fadeout
|
||||
Object timesPacket = packetConstructorTimes.newInstance(timesEnum, null, ticksIn, ticksStay, ticksOut);
|
||||
sendPacket.invoke(playerConnection.get( getHandle.invoke(player) ), timesPacket);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
// So we failed, didn't work.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (titleMain != null)
|
||||
{
|
||||
titleMain = toJson(titleMain);
|
||||
try
|
||||
{
|
||||
// Title
|
||||
Object titleMainChat = chatSerializer.invoke(null, titleMain);
|
||||
Object titleMainPacket = packetConstructor.newInstance(titleEnum, titleMainChat);
|
||||
sendPacket.invoke(playerConnection.get(getHandle.invoke(player)), titleMainPacket);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
// So we failed, didn't work.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (titleSub != null)
|
||||
{
|
||||
titleSub = toJson(titleSub);
|
||||
try
|
||||
{
|
||||
// SubTitle
|
||||
Object titleSubChat = chatSerializer.invoke(null, titleSub);
|
||||
Object titleSubPacket = packetConstructor.newInstance(subtitleEnum, titleSubChat);
|
||||
sendPacket.invoke(playerConnection.get(getHandle.invoke(player)), titleSubPacket);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
// So we failed, didn't work.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//It worked.
|
||||
return true;
|
||||
}
|
||||
|
||||
// -------------------------------------------- //
|
||||
// JSON
|
||||
// -------------------------------------------- //
|
||||
|
||||
public static String toJson(String str)
|
||||
{
|
||||
str = JSONObject.escape(str);
|
||||
|
||||
str = "{\"text\": \"" + str + "\"}";
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user