Add support for the new JSON chat message format. FIXES Ticket-109

In addition, the PacketConstructor can now handle non-wrapped objects,
along with Class types instead of instances in withPacket().
This commit is contained in:
Kristian S. Stangeland 2013-07-19 23:43:39 +02:00
parent 0b56df20d5
commit 6054d559e1
6 changed files with 487 additions and 349 deletions

View File

@ -1,96 +1,96 @@
package com.comphenix.protocol.error;
import java.io.PrintStream;
import org.bukkit.plugin.Plugin;
import com.comphenix.protocol.error.Report.ReportBuilder;
import com.comphenix.protocol.reflect.PrettyPrinter;
/**
* Represents a basic error reporter that prints error reports to the standard error stream.
* <p>
* Note that this implementation doesn't distinguish between {@link #reportWarning(Object, Report)}
* and {@link #reportDetailed(Object, Report)} - they both have the exact same behavior.
* @author Kristian
*/
public class BasicErrorReporter implements ErrorReporter {
private final PrintStream output;
/**
* Construct a new basic error reporter that prints directly the standard error stream.
*/
public BasicErrorReporter() {
this(System.err);
}
/**
* Construct a error reporter that prints to the given output stream.
* @param output - the output stream.
*/
public BasicErrorReporter(PrintStream output) {
this.output = output;
}
@Override
public void reportMinimal(Plugin sender, String methodName, Throwable error) {
output.println("Unhandled exception occured in " + methodName + " for " + sender.getName());
error.printStackTrace(output);
}
@Override
public void reportMinimal(Plugin sender, String methodName, Throwable error, Object... parameters) {
reportMinimal(sender, methodName, error);
// Also print parameters
printParameters(parameters);
}
@Override
public void reportWarning(Object sender, Report report) {
// Basic warning
output.println("[" + sender.getClass().getSimpleName() + "] " + report.getReportMessage());
if (report.getException() != null) {
report.getException().printStackTrace(output);
}
printParameters(report.getCallerParameters());
}
@Override
public void reportWarning(Object sender, ReportBuilder reportBuilder) {
reportWarning(sender, reportBuilder.build());
}
@Override
public void reportDetailed(Object sender, Report report) {
// No difference from warning
reportWarning(sender, report);
}
@Override
public void reportDetailed(Object sender, ReportBuilder reportBuilder) {
reportWarning(sender, reportBuilder);
}
/**
* Print the given parameters to the standard error stream.
* @param parameters - the output parameters.
*/
private void printParameters(Object[] parameters) {
if (parameters != null && parameters.length > 0) {
output.println("Parameters: ");
try {
for (Object parameter : parameters) {
if (parameter == null)
output.println("[NULL]");
else
output.println(PrettyPrinter.printObject(parameter));
}
} catch (IllegalAccessException e) {
// Damn it
e.printStackTrace();
}
}
}
}
package com.comphenix.protocol.error;
import java.io.PrintStream;
import org.bukkit.plugin.Plugin;
import com.comphenix.protocol.error.Report.ReportBuilder;
import com.comphenix.protocol.reflect.PrettyPrinter;
/**
* Represents a basic error reporter that prints error reports to the standard error stream.
* <p>
* Note that this implementation doesn't distinguish between {@link #reportWarning(Object, Report)}
* and {@link #reportDetailed(Object, Report)} - they both have the exact same behavior.
* @author Kristian
*/
public class BasicErrorReporter implements ErrorReporter {
private final PrintStream output;
/**
* Construct a new basic error reporter that prints directly the standard error stream.
*/
public BasicErrorReporter() {
this(System.err);
}
/**
* Construct a error reporter that prints to the given output stream.
* @param output - the output stream.
*/
public BasicErrorReporter(PrintStream output) {
this.output = output;
}
@Override
public void reportMinimal(Plugin sender, String methodName, Throwable error) {
output.println("Unhandled exception occured in " + methodName + " for " + sender.getName());
error.printStackTrace(output);
}
@Override
public void reportMinimal(Plugin sender, String methodName, Throwable error, Object... parameters) {
reportMinimal(sender, methodName, error);
// Also print parameters
printParameters(parameters);
}
@Override
public void reportWarning(Object sender, Report report) {
// Basic warning
output.println("[" + sender.getClass().getSimpleName() + "] " + report.getReportMessage());
if (report.getException() != null) {
report.getException().printStackTrace(output);
}
printParameters(report.getCallerParameters());
}
@Override
public void reportWarning(Object sender, ReportBuilder reportBuilder) {
reportWarning(sender, reportBuilder.build());
}
@Override
public void reportDetailed(Object sender, Report report) {
// No difference from warning
reportWarning(sender, report);
}
@Override
public void reportDetailed(Object sender, ReportBuilder reportBuilder) {
reportWarning(sender, reportBuilder);
}
/**
* Print the given parameters to the standard error stream.
* @param parameters - the output parameters.
*/
private void printParameters(Object[] parameters) {
if (parameters != null && parameters.length > 0) {
output.println("Parameters: ");
try {
for (Object parameter : parameters) {
if (parameter == null)
output.println("[NULL]");
else
output.println(PrettyPrinter.printObject(parameter));
}
} catch (IllegalAccessException e) {
// Damn it
e.printStackTrace();
}
}
}
}

View File

@ -1,74 +1,74 @@
/*
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.comphenix.protocol.error;
import org.bukkit.plugin.Plugin;
import com.comphenix.protocol.error.Report.ReportBuilder;
/**
* Represents an object that can forward an error {@link Report} to the display and permanent storage.
*
* @author Kristian
*/
public interface ErrorReporter {
/**
* Prints a small minimal error report regarding an exception from another plugin.
* @param sender - the other plugin.
* @param methodName - name of the caller method.
* @param error - the exception itself.
*/
public abstract void reportMinimal(Plugin sender, String methodName, Throwable error);
/**
* Prints a small minimal error report regarding an exception from another plugin.
* @param sender - the other plugin.
* @param methodName - name of the caller method.
* @param error - the exception itself.
* @param parameters - any relevant parameters to print.
*/
public abstract void reportMinimal(Plugin sender, String methodName, Throwable error, Object... parameters);
/**
* Prints a warning message from the current plugin.
* @param sender - the object containing the caller method.
* @param report - an error report to include.
*/
public abstract void reportWarning(Object sender, Report report);
/**
* Prints a warning message from the current plugin.
* @param sender - the object containing the caller method.
* @param reportBuilder - an error report builder that will be used to get the report.
*/
public abstract void reportWarning(Object sender, ReportBuilder reportBuilder);
/**
* Prints a detailed error report about an unhandled exception.
* @param sender - the object containing the caller method.
* @param report - an error report to include.
*/
public abstract void reportDetailed(Object sender, Report report);
/**
* Prints a detailed error report about an unhandled exception.
* @param sender - the object containing the caller method.
* @param reportBuilder - an error report builder that will be used to get the report.
*/
public abstract void reportDetailed(Object sender, ReportBuilder reportBuilder);
/*
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.comphenix.protocol.error;
import org.bukkit.plugin.Plugin;
import com.comphenix.protocol.error.Report.ReportBuilder;
/**
* Represents an object that can forward an error {@link Report} to the display and permanent storage.
*
* @author Kristian
*/
public interface ErrorReporter {
/**
* Prints a small minimal error report regarding an exception from another plugin.
* @param sender - the other plugin.
* @param methodName - name of the caller method.
* @param error - the exception itself.
*/
public abstract void reportMinimal(Plugin sender, String methodName, Throwable error);
/**
* Prints a small minimal error report regarding an exception from another plugin.
* @param sender - the other plugin.
* @param methodName - name of the caller method.
* @param error - the exception itself.
* @param parameters - any relevant parameters to print.
*/
public abstract void reportMinimal(Plugin sender, String methodName, Throwable error, Object... parameters);
/**
* Prints a warning message from the current plugin.
* @param sender - the object containing the caller method.
* @param report - an error report to include.
*/
public abstract void reportWarning(Object sender, Report report);
/**
* Prints a warning message from the current plugin.
* @param sender - the object containing the caller method.
* @param reportBuilder - an error report builder that will be used to get the report.
*/
public abstract void reportWarning(Object sender, ReportBuilder reportBuilder);
/**
* Prints a detailed error report about an unhandled exception.
* @param sender - the object containing the caller method.
* @param report - an error report to include.
*/
public abstract void reportDetailed(Object sender, Report report);
/**
* Prints a detailed error report about an unhandled exception.
* @param sender - the object containing the caller method.
* @param reportBuilder - an error report builder that will be used to get the report.
*/
public abstract void reportDetailed(Object sender, ReportBuilder reportBuilder);
}

View File

@ -1,162 +1,162 @@
package com.comphenix.protocol.error;
import javax.annotation.Nullable;
/**
* Represents a error or warning report.
*
* @author Kristian
*/
public class Report {
private final ReportType type;
private final Throwable exception;
private final Object[] messageParameters;
private final Object[] callerParameters;
/**
* Must be constructed through the factory method in Report.
*/
public static class ReportBuilder {
private ReportType type;
private Throwable exception;
private Object[] messageParameters;
private Object[] callerParameters;
private ReportBuilder() {
// Don't allow
}
/**
* Set the current report type. Cannot be NULL.
* @param type - report type.
* @return This builder, for chaining.
*/
public ReportBuilder type(ReportType type) {
if (type == null)
throw new IllegalArgumentException("Report type cannot be set to NULL.");
this.type = type;
return this;
}
/**
* Set the current exception that occured.
* @param exception - exception that occured.
* @return This builder, for chaining.
*/
public ReportBuilder error(@Nullable Throwable exception) {
this.exception = exception;
return this;
}
/**
* Set the message parameters that are used to construct a message text.
* @param messageParameters - parameters for the report type.
* @return This builder, for chaining.
*/
public ReportBuilder messageParam(@Nullable Object... messageParameters) {
this.messageParameters = messageParameters;
return this;
}
/**
* Set the parameters in the caller method. This is optional.
* @param callerParameters - parameters of the caller method.
* @return This builder, for chaining.
*/
public ReportBuilder callerParam(@Nullable Object... callerParameters) {
this.callerParameters = callerParameters;
return this;
}
/**
* Construct a new report with the provided input.
* @return A new report.
*/
public Report build() {
return new Report(type, exception, messageParameters, callerParameters);
}
}
/**
* Construct a new report builder.
* @param type - the initial report type.
* @return Report builder.
*/
public static ReportBuilder newBuilder(ReportType type) {
return new ReportBuilder().type(type);
}
/**
* Construct a new report with the given type and parameters.
* @param exception - exception that occured in the caller method.
* @param type - the report type that will be used to construct the message.
* @param messageParameters - parameters used to construct the report message.
* @param callerParameters - parameters from the caller method.
*/
protected Report(ReportType type, @Nullable Throwable exception, @Nullable Object[] messageParameters, @Nullable Object[] callerParameters) {
if (type == null)
throw new IllegalArgumentException("type cannot be NULL.");
this.type = type;
this.exception = exception;
this.messageParameters = messageParameters;
this.callerParameters = callerParameters;
}
/**
* Format the current report type with the provided message parameters.
* @return The formated report message.
*/
public String getReportMessage() {
return type.getMessage(messageParameters);
}
/**
* Retrieve the message parameters that will be used to construc the report message.
* <p<
* This should not be confused with the method parameters of the caller method.
* @return Message parameters.
*/
public Object[] getMessageParameters() {
return messageParameters;
}
/**
* Retrieve the parameters of the caller method. Optional - may be NULL.
* @return Parameters or the caller method.
*/
public Object[] getCallerParameters() {
return callerParameters;
}
/**
* Retrieve the report type.
* @return Report type.
*/
public ReportType getType() {
return type;
}
/**
* Retrieve the associated exception, or NULL if not found.
* @return Associated exception, or NULL.
*/
public Throwable getException() {
return exception;
}
/**
* Determine if we have any message parameters.
* @return TRUE if there are any message parameters, FALSE otherwise.
*/
public boolean hasMessageParameters() {
return messageParameters != null && messageParameters.length > 0;
}
/**
* Determine if we have any caller parameters.
* @return TRUE if there are any caller parameters, FALSE otherwise.
*/
public boolean hasCallerParameters() {
return callerParameters != null && callerParameters.length > 0;
}
}
package com.comphenix.protocol.error;
import javax.annotation.Nullable;
/**
* Represents a error or warning report.
*
* @author Kristian
*/
public class Report {
private final ReportType type;
private final Throwable exception;
private final Object[] messageParameters;
private final Object[] callerParameters;
/**
* Must be constructed through the factory method in Report.
*/
public static class ReportBuilder {
private ReportType type;
private Throwable exception;
private Object[] messageParameters;
private Object[] callerParameters;
private ReportBuilder() {
// Don't allow
}
/**
* Set the current report type. Cannot be NULL.
* @param type - report type.
* @return This builder, for chaining.
*/
public ReportBuilder type(ReportType type) {
if (type == null)
throw new IllegalArgumentException("Report type cannot be set to NULL.");
this.type = type;
return this;
}
/**
* Set the current exception that occured.
* @param exception - exception that occured.
* @return This builder, for chaining.
*/
public ReportBuilder error(@Nullable Throwable exception) {
this.exception = exception;
return this;
}
/**
* Set the message parameters that are used to construct a message text.
* @param messageParameters - parameters for the report type.
* @return This builder, for chaining.
*/
public ReportBuilder messageParam(@Nullable Object... messageParameters) {
this.messageParameters = messageParameters;
return this;
}
/**
* Set the parameters in the caller method. This is optional.
* @param callerParameters - parameters of the caller method.
* @return This builder, for chaining.
*/
public ReportBuilder callerParam(@Nullable Object... callerParameters) {
this.callerParameters = callerParameters;
return this;
}
/**
* Construct a new report with the provided input.
* @return A new report.
*/
public Report build() {
return new Report(type, exception, messageParameters, callerParameters);
}
}
/**
* Construct a new report builder.
* @param type - the initial report type.
* @return Report builder.
*/
public static ReportBuilder newBuilder(ReportType type) {
return new ReportBuilder().type(type);
}
/**
* Construct a new report with the given type and parameters.
* @param exception - exception that occured in the caller method.
* @param type - the report type that will be used to construct the message.
* @param messageParameters - parameters used to construct the report message.
* @param callerParameters - parameters from the caller method.
*/
protected Report(ReportType type, @Nullable Throwable exception, @Nullable Object[] messageParameters, @Nullable Object[] callerParameters) {
if (type == null)
throw new IllegalArgumentException("type cannot be NULL.");
this.type = type;
this.exception = exception;
this.messageParameters = messageParameters;
this.callerParameters = callerParameters;
}
/**
* Format the current report type with the provided message parameters.
* @return The formated report message.
*/
public String getReportMessage() {
return type.getMessage(messageParameters);
}
/**
* Retrieve the message parameters that will be used to construc the report message.
* <p<
* This should not be confused with the method parameters of the caller method.
* @return Message parameters.
*/
public Object[] getMessageParameters() {
return messageParameters;
}
/**
* Retrieve the parameters of the caller method. Optional - may be NULL.
* @return Parameters or the caller method.
*/
public Object[] getCallerParameters() {
return callerParameters;
}
/**
* Retrieve the report type.
* @return Report type.
*/
public ReportType getType() {
return type;
}
/**
* Retrieve the associated exception, or NULL if not found.
* @return Associated exception, or NULL.
*/
public Throwable getException() {
return exception;
}
/**
* Determine if we have any message parameters.
* @return TRUE if there are any message parameters, FALSE otherwise.
*/
public boolean hasMessageParameters() {
return messageParameters != null && messageParameters.length > 0;
}
/**
* Determine if we have any caller parameters.
* @return TRUE if there are any caller parameters, FALSE otherwise.
*/
public boolean hasCallerParameters() {
return callerParameters != null && callerParameters.length > 0;
}
}

View File

@ -0,0 +1,43 @@
package com.comphenix.protocol.error;
import org.bukkit.plugin.Plugin;
import com.comphenix.protocol.error.Report.ReportBuilder;
import com.google.common.base.Joiner;
/**
* Represents an error reporter that rethrows every exception instead.
* @author Kristian
*/
public class RethrowErrorReporter implements ErrorReporter {
@Override
public void reportMinimal(Plugin sender, String methodName, Throwable error) {
throw new RuntimeException("Minimal error by " + sender + " in " + methodName, error);
}
@Override
public void reportMinimal(Plugin sender, String methodName, Throwable error, Object... parameters) {
throw new RuntimeException(
"Minimal error by " + sender + " in " + methodName + " with " + Joiner.on(",").join(parameters), error);
}
@Override
public void reportWarning(Object sender, ReportBuilder reportBuilder) {
reportWarning(sender, reportBuilder.build());
}
@Override
public void reportWarning(Object sender, Report report) {
throw new RuntimeException("Warning by " + sender + ": " + report);
}
@Override
public void reportDetailed(Object sender, ReportBuilder reportBuilder) {
reportDetailed(sender, reportBuilder.build());
}
@Override
public void reportDetailed(Object sender, Report report) {
throw new RuntimeException("Detailed error " + sender + ": " + report, report.getException());
}
}

View File

@ -21,6 +21,7 @@ import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import com.comphenix.protocol.error.RethrowErrorReporter;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.injector.packet.PacketRegistry;
import com.comphenix.protocol.reflect.FieldAccessException;
@ -51,15 +52,19 @@ public class PacketConstructor {
// Used to unwrap Bukkit objects
private List<Unwrapper> unwrappers;
// Parameters that need to be unwrapped
private boolean[] unwrappable;
private PacketConstructor(Constructor<?> constructorMethod) {
this.constructorMethod = constructorMethod;
this.unwrappers = Lists.newArrayList((Unwrapper) new BukkitUnwrapper());
this.unwrappers = Lists.newArrayList((Unwrapper) new BukkitUnwrapper(new RethrowErrorReporter() ));
}
private PacketConstructor(int packetID, Constructor<?> constructorMethod, List<Unwrapper> unwrappers) {
private PacketConstructor(int packetID, Constructor<?> constructorMethod, List<Unwrapper> unwrappers, boolean[] unwrappable) {
this.packetID = packetID;
this.constructorMethod = constructorMethod;
this.unwrappers = unwrappers;
this.unwrappable = unwrappable;
}
public ImmutableList<Unwrapper> getUnwrappers() {
@ -80,31 +85,41 @@ public class PacketConstructor {
* @return A constructor with a different set of unwrappers.
*/
public PacketConstructor withUnwrappers(List<Unwrapper> unwrappers) {
return new PacketConstructor(packetID, constructorMethod, unwrappers);
return new PacketConstructor(packetID, constructorMethod, unwrappers, unwrappable);
}
/**
* Create a packet constructor that creates packets using the given types.
* <p>
* Note that if you pass a Class<?> as a value, it will use its type directly.
* @param id - packet ID.
* @param values - types to create.
* @param values - the values that will match each parameter in the desired constructor.
* @return A packet constructor with these types.
* @throws IllegalArgumentException If no packet constructor could be created with these types.
*/
public PacketConstructor withPacket(int id, Object[] values) {
Class<?>[] types = new Class<?>[values.length];
Throwable lastException = null;
boolean[] unwrappable = new boolean[values.length];
for (int i = 0; i < types.length; i++) {
// Default type
if (values[i] != null) {
types[i] = values[i].getClass();
types[i] = (values[i] instanceof Class) ? (Class<?>)values[i] : values[i].getClass();
for (Unwrapper unwrapper : unwrappers) {
Object result = unwrapper.unwrapItem(values[i]);
Object result = null;
try {
result = unwrapper.unwrapItem(values[i]);
} catch (Throwable e) {
lastException = e;
}
// Update type we're searching for
if (result != null) {
types[i] = result.getClass();
unwrappable[i] = true;
break;
}
}
@ -126,11 +141,11 @@ public class PacketConstructor {
if (isCompatible(types, params)) {
// Right, we've found our type
return new PacketConstructor(id, constructor, unwrappers);
return new PacketConstructor(id, constructor, unwrappers, unwrappable);
}
}
throw new IllegalArgumentException("No suitable constructor could be found.");
throw new IllegalArgumentException("No suitable constructor could be found.", lastException);
}
/**
@ -143,14 +158,16 @@ public class PacketConstructor {
*/
public PacketContainer createPacket(Object... values) throws FieldAccessException {
try {
// Convert types
// Convert types that needs to be converted
for (int i = 0; i < values.length; i++) {
for (Unwrapper unwrapper : unwrappers) {
Object converted = unwrapper.unwrapItem(values[i]);
if (converted != null) {
values[i] = converted;
break;
if (unwrappable[i]) {
for (Unwrapper unwrapper : unwrappers) {
Object converted = unwrapper.unwrapItem(values[i]);
if (converted != null) {
values[i] = converted;
break;
}
}
}
}

View File

@ -17,7 +17,11 @@
package com.comphenix.protocol.utility;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.List;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
@ -26,8 +30,13 @@ import org.bukkit.entity.Player;
import com.comphenix.protocol.Packets;
import com.comphenix.protocol.ProtocolManager;
import com.comphenix.protocol.injector.PacketConstructor;
import com.comphenix.protocol.injector.packet.PacketRegistry;
import com.comphenix.protocol.reflect.FieldAccessException;
import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.reflect.fuzzy.FuzzyMatchers;
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
import com.google.common.base.Strings;
import com.google.common.collect.Iterables;
/**
* Utility methods for sending chat messages.
@ -35,11 +44,14 @@ import com.google.common.base.Strings;
* @author Kristian
*/
public class ChatExtensions {
// Used to sent chat messages
private PacketConstructor chatConstructor;
private ProtocolManager manager;
// Whether or not we have to use the post-1.6.1 chat format
private static Constructor<?> jsonConstructor = getJsonFormatConstructor();
private static Method messageFactory;
public ChatExtensions(ProtocolManager manager) {
this.manager = manager;
}
@ -68,10 +80,59 @@ public class ChatExtensions {
* Send a message without invoking the packet listeners.
* @param player - the player to send it to.
* @param message - the message to send.
* @return TRUE if the message was sent successfully, FALSE otherwise.
* @throws InvocationTargetException If we were unable to send the message.
*/
private void sendMessageSilently(Player player, String message) throws InvocationTargetException {
if (jsonConstructor != null) {
sendMessageAsJson(player, message);
} else {
sendMessageAsString(player, message);
}
}
/**
* Send a message using the new JSON format in 1.6.1.
* @param player - the player to send it to.
* @param message - the message to send.
* @throws InvocationTargetException InvocationTargetException If we were unable to send the message.
*/
private void sendMessageAsJson(Player player, String message) throws InvocationTargetException {
Object messageObject = null;
if (chatConstructor == null) {
Class<?> messageClass = jsonConstructor.getParameterTypes()[0];
chatConstructor = manager.createPacketConstructor(Packets.Server.CHAT, messageClass);
// Try one of the string constructors
messageFactory = FuzzyReflection.fromClass(messageClass).getMethod(
FuzzyMethodContract.newBuilder().
requireModifier(Modifier.STATIC).
parameterCount(1).
parameterExactType(String.class).
returnTypeMatches(FuzzyMatchers.matchParent()).
build());
}
try {
messageObject = messageFactory.invoke(null, message);
} catch (Exception e) {
throw new InvocationTargetException(e);
}
try {
manager.sendServerPacket(player, chatConstructor.createPacket(messageObject), false);
} catch (FieldAccessException e) {
throw new InvocationTargetException(e);
}
}
/**
* Send a message as a pure string.
* @param player - the player.
* @param message - the message to send.
* @throws InvocationTargetException If anything went wrong.
*/
private void sendMessageAsString(Player player, String message) throws InvocationTargetException {
if (chatConstructor == null)
chatConstructor = manager.createPacketConstructor(Packets.Server.CHAT, message);
@ -143,4 +204,21 @@ public class ChatExtensions {
}
return current;
}
/**
* Retrieve a constructor for post-1.6.1 chat packets.
* @return A constructor for JSON-based packets.
*/
static Constructor<?> getJsonFormatConstructor() {
Class<?> chatPacket = PacketRegistry.getPacketClassFromID(3, true);
List<Constructor<?>> list = FuzzyReflection.fromClass(chatPacket).getConstructorList(
FuzzyMethodContract.newBuilder().
parameterCount(1).
parameterMatches(MinecraftReflection.getMinecraftObjectMatcher()).
build()
);
// First element or NULL
return Iterables.getFirst(list, null);
}
}