Created
September 11, 2014 02:17
-
-
Save aadnk/8f21faa9276988530691 to your computer and use it in GitHub Desktop.
Change the "unknown command message" with TinyProtocol.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.comphenix.example; | |
import org.bukkit.ChatColor; | |
import org.bukkit.entity.Player; | |
import org.bukkit.event.Listener; | |
import org.bukkit.plugin.java.JavaPlugin; | |
import org.json.simple.JSONObject; | |
public class ChangingUnknownCommand extends JavaPlugin implements Listener { | |
private MessageTransformer transformer; | |
@Override | |
public void onEnable() { | |
transformer = new MessageTransformer(this) { | |
@Override | |
protected Object onSendingChat(Player receiver, Object json) { | |
return transformPrimitives(json, new Processor() { | |
@Override | |
public Object process(Object value, Object parent) { | |
return processValue(value); | |
} | |
}); | |
} | |
}; | |
} | |
@SuppressWarnings("unchecked") | |
private Object processValue(Object value) { | |
if (value instanceof String) { | |
String stripped = ChatColor.stripColor((String) value); | |
if ("Unknown command. Type \"/help\" for help.".equals(stripped)) { | |
JSONObject result = new JSONObject(); | |
// Add a color | |
result.put("color", "red"); | |
result.put("text", "Wrong. Try again! Also note that we can apply a color to the " + | |
"entire multi-lined messages, unlike ChatColor.RED."); | |
return result; | |
} | |
} | |
return value; | |
} | |
@Override | |
public void onDisable() { | |
super.onDisable(); | |
transformer.close(); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.comphenix.example; | |
import net.minecraft.util.com.google.gson.Gson; | |
import net.minecraft.util.io.netty.channel.Channel; | |
import org.bukkit.entity.Player; | |
import org.bukkit.plugin.Plugin; | |
import org.json.simple.JSONArray; | |
import org.json.simple.JSONObject; | |
import org.json.simple.JSONValue; | |
import org.json.simple.parser.JSONParser; | |
import org.json.simple.parser.ParseException; | |
import com.comphenix.example.Reflection.FieldAccessor; | |
import com.google.common.base.Objects; | |
public abstract class MessageTransformer { | |
// Explosion packet | |
private Class<?> chatClass = Reflection.getClass("{nms}.PacketPlayOutChat"); | |
// For looking up the base component | |
private Class<Object> componentClass = Reflection.getUntypedClass("{nms}.IChatBaseComponent"); | |
private FieldAccessor<Object> componentField = Reflection.getField(chatClass, componentClass, 0); | |
// Converting between the base component and JSON | |
private Class<?> serializerClass = Reflection.getClass("{nms}.ChatSerializer"); | |
private Gson chatGson = Reflection.getField(serializerClass, Gson.class, 0).get(null); | |
// A thread-safe JSON parser | |
private ThreadLocal<JSONParser> parser = new ThreadLocal<JSONParser>() { | |
protected JSONParser initialValue() { | |
return new JSONParser(); | |
} | |
}; | |
// For processing JSON | |
public interface Processor { | |
public Object process(Object value, Object parent); | |
} | |
// Private instance | |
private TinyProtocol protocol; | |
/** | |
* Construct a new chat message transformer. | |
* @param plugin - the parent plugin. | |
*/ | |
public MessageTransformer(Plugin plugin) { | |
protocol = new TinyProtocol(plugin) { | |
@Override | |
public Object onPacketOutAsync(Player reciever, Channel channel, Object packet) { | |
// Ignore other packets | |
if (chatClass.isInstance(packet)) { | |
processChatPacket(reciever, packet); | |
return packet; | |
} | |
return super.onPacketOutAsync(reciever, channel, packet); | |
} | |
}; | |
} | |
/** | |
* Invoked when the server is sending a chat message to a player. | |
* @param receiver - the receiving player. | |
* @param json - the message that is being sent. | |
* @return The message to send. | |
*/ | |
protected abstract Object onSendingChat(Player receiver, Object json); | |
/** | |
* Handle a chat packet. | |
* @param reciever - the receiving player. | |
* @param packet | |
*/ | |
private void processChatPacket(Player reciever, Object packet) { | |
try { | |
// We get an IChatBaseComponent, and then convert it to JSON | |
Object componentValue = componentField.get(packet); | |
String componentJson = getJson(componentValue); | |
// Get the output JSON | |
Object data = parser.get().parse(componentJson); | |
String output = JSONValue.toJSONString(onSendingChat(reciever, data)); | |
// Write back the changed string | |
if (!Objects.equal(componentJson, output)) { | |
componentField.set(packet, getComponent(output)); | |
} | |
} catch (ParseException e) { | |
e.printStackTrace(); | |
} | |
} | |
/** | |
* Retrieve the JSON representation of the given chat component. | |
* @param component - the chat component. | |
* @return The JSON. | |
*/ | |
private String getJson(Object component) { | |
return chatGson.toJson(component); | |
} | |
/** | |
* Retrieve the chat component from the given JSON. | |
* @param json - the JSON. | |
* @return The chat component. | |
*/ | |
private Object getComponent(String json) { | |
return chatGson.fromJson(json, componentClass); | |
} | |
/** | |
* Tranform an arbitrary JSON object, array or primitive value. | |
* @param value - the value. | |
* @param processor - the processor. | |
* @return The processed value. | |
*/ | |
protected Object transformPrimitives(Object value, Processor processor) { | |
return transformPrimitives(value, null, processor); | |
} | |
/** | |
* Tranform an arbitrary JSON object, array or primitive value. | |
* @param value - the value. | |
* @param parent - the parent object or array. | |
* @param processor - the processor. | |
* @return The processed value. | |
*/ | |
protected Object transformPrimitives(Object value, Object parent, Processor processor) { | |
// Check its type | |
if (value instanceof JSONObject) { | |
return transformPrimitives((JSONObject) value, processor); | |
} else if (value instanceof JSONArray) { | |
return transformPrimitives((JSONArray) value, processor); | |
} else { | |
return processor.process(value, parent); | |
} | |
} | |
/** | |
* Transform every key-value mapping in the given JSON object. | |
* @param source - the object. | |
* @param processor - the processor. | |
* @return The processed object. | |
*/ | |
@SuppressWarnings("unchecked") | |
protected JSONObject transformPrimitives(JSONObject source, Processor processor) { | |
for (Object key : source.keySet().toArray()) { | |
Object value = source.get(key); | |
source.put(key, transformPrimitives(value, source, processor)); | |
} | |
return source; | |
} | |
/** | |
* Transform every descendant in the given JSON array and all | |
* @param source - the array. | |
* @param processor - the processor. | |
* @return The processed array. | |
*/ | |
@SuppressWarnings("unchecked") | |
protected JSONArray transformPrimitives(JSONArray source, Processor processor) { | |
for (int i = 0; i < source.size(); i++) { | |
Object value = source.get(i); | |
source.set(i, transformPrimitives(value, source, processor)); | |
} | |
return source; | |
} | |
/** | |
* Close the current transformer. | |
*/ | |
public void close() { | |
if (protocol != null) { | |
protocol.close(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
chatClass labelled as explosion packet :D