Skip to content

Instantly share code, notes, and snippets.

@jarcode-foss
Created May 15, 2015 07:55
Show Gist options
  • Save jarcode-foss/36a82d097f7fb9c926c8 to your computer and use it in GitHub Desktop.
Save jarcode-foss/36a82d097f7fb9c926c8 to your computer and use it in GitHub Desktop.
package jarcode.consoles;
import net.minecraft.server.v1_8_R2.*;
import java.lang.reflect.Field;
import java.util.Arrays;
public class CommandBlockListenerWrapper extends CommandBlockListenerAbstract {
private static final Field COMMAND_RESULT, CHAT_COMPONENT;
private static final String[] OVERRIDEN_COMMANDS = {"link"};
private ConsoleListener consoleListener;
static {
try {
COMMAND_RESULT = CommandBlockListenerAbstract.class.getDeclaredField("b");
CHAT_COMPONENT = CommandBlockListenerAbstract.class.getDeclaredField("d");
COMMAND_RESULT.setAccessible(true);
CHAT_COMPONENT.setAccessible(true);
}
catch (Throwable e) {
throw new RuntimeException(e);
}
}
private void setResult(int result) {
try {
COMMAND_RESULT.setInt(this, result);
}
catch (Throwable e) {
throw new RuntimeException(e);
}
}
private void setChatComponent(Object obj) {
try {
CHAT_COMPONENT.set(this, obj);
}
catch (Throwable e) {
throw new RuntimeException(e);
}
}
CommandBlockListenerAbstract underlying;
// this is a cheat to make this act like an inner class when we get this$0 via reflection later
@SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
private final TileEntityCommand this$0;
CommandBlockListenerWrapper(CommandBlockListenerAbstract underlying, TileEntityCommand command) {
this.underlying = underlying;
this.this$0 = command;
}
public void setConsoleListener(ConsoleListener listener) {
consoleListener = listener;
}
public boolean listening() {
return consoleListener != null;
}
@Override
public int j() {
return underlying.j();
}
@Override
public IChatBaseComponent k() {
return underlying.k();
}
@Override
public void a(NBTTagCompound nbttagcompound) {
underlying.a(nbttagcompound);
}
@Override
public void b(NBTTagCompound nbttagcompound) {
underlying.b(nbttagcompound);
}
@Override
public boolean a(int i, String s) {
return underlying.a(i, s);
}
@Override
public void setCommand(String s) {
underlying.setCommand(s);
}
@Override
public String getCommand() {
return underlying.getCommand();
}
private boolean override() {
String command = getCommand().toLowerCase();
if(command.startsWith("/")) {
command = command.substring(1);
}
command = command.split(" ")[0];
return Arrays.asList(OVERRIDEN_COMMANDS).contains(command);
}
@Override
public void a(World world) {
if (consoleListener != null) {
sendMessage(new ChatComponentText(consoleListener.execute(this.sender, getCommand())));
setResult(0);
return;
}
if (!ConsoleHandler.getInstance().commandBlocksEnabled && !override()) {
setChatComponent(new ChatComponentText("You cannot use server commands"));
h();
setResult(0);
return;
}
if(world.isClientSide) {
setResult(0);
}
MinecraftServer minecraftserver = MinecraftServer.getServer();
if(minecraftserver != null && minecraftserver.N()) {
minecraftserver.getCommandHandler();
try {
setChatComponent(null);
setResult(executeCommand(this, this.sender, getCommand()));
} catch (Throwable var6) {
var6.printStackTrace();
}
} else {
setResult(0);
}
}
@Override
public String getName() {
return underlying.getName();
}
@Override
public IChatBaseComponent getScoreboardDisplayName() {
return underlying.getScoreboardDisplayName();
}
@Override
public void setName(String s) {
underlying.setName(s);
}
@Override
public void sendMessage(IChatBaseComponent ichatbasecomponent) {
underlying.sendMessage(ichatbasecomponent);
}
@Override
public boolean getSendCommandFeedback() {
return underlying.getSendCommandFeedback();
}
@Override
public void a(CommandObjectiveExecutor.EnumCommandResult result, int i) {
underlying.a(result, i);
}
@Override
public void h() {
underlying.h();
}
@Override
public void b(IChatBaseComponent ichatbasecomponent) {
underlying.b(ichatbasecomponent);
}
@Override
public void a(boolean flag) {
underlying.a(flag);
}
@Override
public boolean m() {
return underlying.m();
}
@Override
public boolean a(EntityHuman entityhuman) {
return override() || underlying.a(entityhuman);
}
@Override
public CommandObjectiveExecutor n() {
return underlying.n();
}
@Override
public BlockPosition getChunkCoordinates() {
return null;
}
@Override
public Vec3D d() {
return underlying.d();
}
@Override
public World getWorld() {
return underlying.getWorld();
}
@Override
public Entity f() {
return underlying.f();
}
}
// ... previous code
private static final Field PACKET_LIST;
private static final Field PACKET_ENTITY_ID;
private static final Field COMMAND_LISTENER;
static {
try {
PACKET_LIST = PacketPlayOutEntityMetadata.class.getDeclaredField("b");
PACKET_LIST.setAccessible(true);
PACKET_ENTITY_ID = PacketPlayOutEntityMetadata.class.getDeclaredField("a");
PACKET_ENTITY_ID.setAccessible(true);
// important part here
COMMAND_LISTENER = TileEntityCommand.class.getDeclaredField("a");
COMMAND_LISTENER.setAccessible(true);
overrideFinal(COMMAND_LISTENER);
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
static {
INSTANCE.paintThread.start();
}
private static Object get(Field field, Object instance) {
try {
return field.get(instance);
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
public static ConsoleHandler getInstance() {
return INSTANCE;
}
public static boolean isRegistered(CommandBlock block) {
TileEntityCommand entity = ((CraftCommandBlock) block).getTileEntity();
CommandBlockListenerAbstract obj = entity.getCommandBlock();
return obj instanceof CommandBlockListenerWrapper && ((CommandBlockListenerWrapper) obj).listening();
}
public static boolean registerListener(CommandBlock block, ConsoleListener listener) {
TileEntityCommand entity = ((CraftCommandBlock) block).getTileEntity();
CommandBlockListenerAbstract obj = entity.getCommandBlock();
if (obj instanceof CommandBlockListenerWrapper && !isRegistered(block)) {
((CommandBlockListenerWrapper) obj).setConsoleListener(listener);
return true;
}
else return false;
}
public static boolean wrap(CommandBlock block) {
try {
TileEntityCommand entity = ((CraftCommandBlock) block).getTileEntity();
CommandBlockListenerAbstract obj = entity.getCommandBlock();
if (!(obj instanceof CommandBlockListenerWrapper)) {
COMMAND_LISTENER.set(entity, new CommandBlockListenerWrapper(obj, entity));
return true;
}
else return false;
}
catch (IllegalAccessException e) {
e.printStackTrace();
}
return false;
}
public static boolean restoreCommandBlock(CommandBlock block) {
TileEntityCommand entity = ((CraftCommandBlock) block).getTileEntity();
Object obj = entity.getCommandBlock();
if (obj instanceof CommandBlockListenerWrapper) {
((CommandBlockListenerWrapper) obj).setConsoleListener(null);
return true;
}
else return false;
}
private static void overrideFinal(Field field) throws NoSuchFieldException, IllegalAccessException {
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
// remove the final flag on the security int/bytes
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
}
// more code...
import org.bukkit.command.CommandSender;
public interface ConsoleListener {
public String execute(CommandSender sender, String text);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment