Check diffs.
Basically, all code is now compiled and executed on the server side
This commit is contained in:
Gabriel Tofvesson 2017-05-15 17:24:26 +02:00
parent b05a04b659
commit 5bea0f3e28
13 changed files with 144 additions and 97 deletions

View File

@ -1,8 +1,6 @@
package org.teamavion.pcomp;
import net.minecraft.nbt.JsonToNBT;
import net.minecraft.nbt.NBTException;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.client.Minecraft;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
import net.minecraft.world.WorldProvider;
@ -12,6 +10,7 @@ import net.minecraftforge.fml.common.Mod.EventHandler;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.network.NetworkRegistry;
import net.minecraftforge.fml.common.registry.GameRegistry;
import net.minecraftforge.fml.relauncher.Side;
import org.teamavion.pcomp.blocks.Computer;
import org.teamavion.pcomp.gui.GUIHandler;
import org.teamavion.pcomp.tile.TileEntityComputer;
@ -20,9 +19,6 @@ import org.teamavion.util.automation.SetupHelper;
import org.teamavion.util.support.NetworkChannel;
import org.teamavion.util.support.Reflection;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Mod(modid = PComp.MODID, version = PComp.VERSION)
public class PComp
{
@ -42,23 +38,18 @@ public class PComp
SetupHelper.registerRenders(PComp.class);
channel = new NetworkChannel(MODID);
channel.registerWorldHandler((side, worldEvent) -> {
World w = (World) Reflection.getValue("world", DimensionManager.getProvider((Integer) Reflection.getValue("id", worldEvent, worldEvent.getClass())), WorldProvider.class); // Get World
World w = (World) (side==Side.SERVER?
Reflection.getValue("world", DimensionManager.getProvider((Integer) Reflection.getValue("id", worldEvent, worldEvent.getClass())), WorldProvider.class):
Reflection.getValue("world", Minecraft.getMinecraft(), Minecraft.class)); // Get World
TileEntity t = w.getTileEntity(worldEvent.getPos());
try {
if (t != null) {
Matcher m = Pattern.compile("(\\d+):(\\d+):(\\d+);(\\d+);(.+)").matcher(worldEvent.getData());
if(!m.matches()) throw new RuntimeException();
String s1;
NBTTagCompound n = JsonToNBT.getTagFromJson((s1=m.group(5)).substring(8, s1.length()-1)
.replace("&rbr;", "}")
.replace("&lbr;", "{")
.replace(""", "\"")
.replace("&", "&"));
t.readFromNBT(n);
}
} catch (NBTException e) {
e.printStackTrace();
if (t == null){
System.err.println("A referenced TileEntity ("+worldEvent.getPos().toString()+") was null!");
return null;
}
t.readFromNBT(worldEvent.getEvent());
t.markDirty();
if(worldEvent.getEvent().hasKey("update")) return new NetworkChannel.WorldEvent(t.getPos(), t.getWorld().provider.getDimension(), t.serializeNBT());
if(worldEvent.getEvent().hasKey("exec")) if(t instanceof TileEntityComputer) ((TileEntityComputer) t).exec();
return null;
});
NetworkRegistry.INSTANCE.registerGuiHandler(this, new GUIHandler());

View File

@ -23,6 +23,8 @@ public class Computer extends Block {
@Override
public boolean onBlockActivated(World worldIn, BlockPos pos, IBlockState state, EntityPlayer playerIn, EnumHand hand, EnumFacing facing, float hitX, float hitY, float hitZ) {
TileEntity t = worldIn.getTileEntity(pos);
if(t!=null) t.setPos(pos);
playerIn.openGui(PComp.instance, ID_COMPUTER, worldIn, pos.getX(), pos.getY(), pos.getZ());
return true;
}
@ -30,7 +32,9 @@ public class Computer extends Block {
@Nullable
@Override
public TileEntity createTileEntity(World world, IBlockState state) {
return new TileEntityComputer();
TileEntityComputer t = new TileEntityComputer();
t.setWorld(world);
return t;
}
@Override

View File

@ -8,7 +8,11 @@ public class ContainerComputer extends Container{
protected final TileEntityComputer computer;
public ContainerComputer(TileEntityComputer computer){ this.computer = computer; }
public ContainerComputer(TileEntityComputer computer){
this.computer = computer;
computer.getWorld().scheduleBlockUpdate(computer.getPos(), computer.getBlockType(), 0, 0);
computer.markDirty();
}
@Override
public boolean canInteractWith(EntityPlayer playerIn) {

View File

@ -1,6 +1,5 @@
package org.teamavion.pcomp.gui;
import com.google.gson.JsonObject;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiScreen;
@ -11,17 +10,9 @@ import org.teamavion.pcomp.PComp;
import org.teamavion.pcomp.net.DataListener;
import org.teamavion.pcomp.tile.TileEntityComputer;
import org.teamavion.util.support.NetworkChannel;
import org.teamavion.util.support.Reflection;
import org.teamavion.util.support.Result;
import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;
import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@SuppressWarnings({"unchecked", "WeakerAccess"})
@ -37,7 +28,12 @@ public class GUIComputer extends GuiScreen implements DataListener<HashMap<Integ
protected GuiTextField[] inputLines;
protected GuiButton button;
public GUIComputer(TileEntityComputer computer){ this.computer = computer; }
public GUIComputer(TileEntityComputer computer){
this.computer = computer;
NBTTagCompound n = new NBTTagCompound();
n.setString("update", "");
PComp.instance.channel.sendToServer(new NetworkChannel.WorldEvent(computer.getPos(), computer.getWorld().provider.getDimension(), n));
}
@Override
public void drawBackground(int tint) {
@ -188,73 +184,26 @@ public class GUIComputer extends GuiScreen implements DataListener<HashMap<Integ
break;
}
if(button.mousePressed(Minecraft.getMinecraft(), mouseX, mouseY)){
StringBuilder sb = new StringBuilder();
File f = File.createTempFile("exec", ".java");
ArrayList<GuiTextField> skip = new ArrayList<>();
for(GuiTextField t : inputLines) if(t.getText().startsWith("import ") && t.getText().endsWith(";")){ skip.add(t); sb.append(t.getText()); }
sb.append("public class ").append(f.getName().substring(0, f.getName().length() - 5)).append("{public static void main(String[] args){");
for(GuiTextField t : inputLines) if(!skip.contains(t)) sb.append(t.getText());
sb.append("}}");
JavaCompiler jc = ToolProvider.getSystemJavaCompiler();
try (OutputStream out = new FileOutputStream(f)) { out.write(sb.toString().getBytes()); }
int result = jc.run(null, null, null, f.getAbsolutePath());
if(result==0){
//noinspection ResultOfMethodCallIgnored
f.delete();
f = new File(f.getAbsolutePath().substring(0, f.getAbsolutePath().length()-5)+".class");
byte[] b;
try{
InputStream i = new FileInputStream(f);
ArrayList<Byte> a = new ArrayList<>();
byte[] b1 = new byte[4096];
int i1;
while(i.available()>0){
i1 = i.read(b1);
for(int j = 0; j<i1; ++j) a.add(b1[j]);
}
i.close();
b = new byte[a.size()];
for(int j = 0; j<a.size(); ++j) b[j] = a.get(j);
}catch(Exception e){ return; }
finally {
//noinspection ResultOfMethodCallIgnored
f.delete();
}
Result<Class<?>> compiled = (Result<Class<?>>) Reflection.invokeMethod(
Reflection.getMethod(ClassLoader.class, "defineClass", byte[].class, int.class, int.class),
GUIComputer.class.getClassLoader(),
b,
0,
b.length);
if(compiled.success){
for(Method m : compiled.value.getDeclaredMethods())
if(m.getName().equals("main") && Modifier.isStatic(m.getModifiers()) && Arrays.equals(m.getParameterTypes(), new Class<?>[]{String[].class}))
{
m.setAccessible(true);
try {
m.invoke(null, (Object) new String[]{});
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
}
}
NBTTagCompound n = new NBTTagCompound();
n.setString("exec", "");
sync(n);
}
}
@Override
public void onGuiClosed() {
computer.unregisterDataListener(this);
for(int i = 0; i<inputLines.length; ++i) computer.writeLine(i, inputLines[i].getText());
NBTTagCompound n = new NBTTagCompound();
computer.writeToNBT(n);
JsonObject j = new JsonObject();
j.addProperty("tag", n.toString().replace("&", "&amp;").replace("\"", "&quot;").replace("{", "&lbr;").replace("}", "&rbr;"));
PComp.instance.channel.sendToServer(new NetworkChannel.WorldEvent(computer.getPos(), computer.getWorld().provider.getDimension(), j));
computer.markDirty();
sync(new NBTTagCompound());
super.onGuiClosed();
}
protected void sync(NBTTagCompound n){
for(int i = 0; i<inputLines.length; ++i) computer.writeLine(i, inputLines[i].getText());
computer.writeToNBT(n);
PComp.instance.channel.sendToServer(new NetworkChannel.WorldEvent(computer.getPos(), computer.getWorld().provider.getDimension(), n));
computer.markDirty();
}
@Override
protected void mouseReleased(int mouseX, int mouseY, int state) {
super.mouseReleased(mouseX, mouseY, state);

View File

@ -1,6 +1,5 @@
package org.teamavion.pcomp.gui;
import com.google.gson.JsonObject;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.nbt.NBTTagCompound;
@ -26,9 +25,8 @@ public class GUIHandler implements IGuiHandler{
TileEntity t = world.getTileEntity(new BlockPos(x, y, z));
if(!(t instanceof TileEntityComputer)) return null; // Something went wrong. ID-clash maybe?
NBTTagCompound n = new NBTTagCompound();
t.writeToNBT(n);JsonObject j = new JsonObject();
j.addProperty("tag", n.toString().replace("&", "&amp;").replace("\"", "&quot;").replace("{", "&lbr;").replace("}", "&rbr;"));
PComp.instance.channel.sendTo(new NetworkChannel.WorldEvent(new BlockPos(x, y, z), world.provider.getDimension(), j), (EntityPlayerMP) player);
t.writeToNBT(n);
PComp.instance.channel.sendTo(new NetworkChannel.WorldEvent(new BlockPos(x, y, z), world.provider.getDimension(), n), (EntityPlayerMP) player);
return new ContainerComputer((TileEntityComputer) t);
}
return null;

View File

@ -2,13 +2,26 @@ package org.teamavion.pcomp.tile;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.play.server.SPacketUpdateTileEntity;
import net.minecraft.tileentity.TileEntity;
import org.teamavion.pcomp.net.DataListener;
import org.teamavion.util.support.Reflection;
import org.teamavion.util.support.Result;
import javax.annotation.Nullable;
import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;
import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
public class TileEntityComputer extends TileEntity{
@SuppressWarnings("unchecked")
public class TileEntityComputer extends TileEntity {
protected final HashMap<Integer, String> lines = new HashMap<>();
protected final ArrayList<DataListener<HashMap<Integer, String>>> dataListeners = new ArrayList<>();
@ -20,6 +33,20 @@ public class TileEntityComputer extends TileEntity{
public String readLine(int line){ return lines.keySet().contains(line)?lines.get(line):""; }
public void writeLine(int line, String data){ lines.put(line, data); }
@Nullable
@Override
public SPacketUpdateTileEntity getUpdatePacket() {
NBTTagCompound t = new NBTTagCompound();
t = writeToNBT(t);
return new SPacketUpdateTileEntity(pos, 0, t);
}
@Override
public void onDataPacket(NetworkManager net, SPacketUpdateTileEntity pkt) {
readFromNBT(pkt.getNbtCompound());
super.onDataPacket(net, pkt);
}
@Override
public NBTTagCompound writeToNBT(NBTTagCompound compound) {
int j = 0, k = 0;
@ -32,6 +59,18 @@ public class TileEntityComputer extends TileEntity{
return super.writeToNBT(compound);
}
@Override
public NBTTagCompound serializeNBT() {
NBTTagCompound n = new NBTTagCompound();
writeToNBT(n);
return n;
}
@Override
public void deserializeNBT(NBTTagCompound nbt) {
readFromNBT(nbt);
}
@Override
public void readFromNBT(NBTTagCompound compound) {
super.readFromNBT(compound);
@ -42,6 +81,68 @@ public class TileEntityComputer extends TileEntity{
for(DataListener<HashMap<Integer, String>> d : dataListeners) d.getData(lines);
}
public void exec(){
try{
StringBuilder sb = new StringBuilder();
File f = File.createTempFile("exec", ".java");
ArrayList<Integer> skip = new ArrayList<>();
int min = Integer.MAX_VALUE, max = Integer.MIN_VALUE;
for(Integer key : lines.keySet()){
if(min>key) min = key;
if(max<key) max = key;
}
String s;
for(int i = min; i<max+1; ++i) if(lines.containsKey(i) && (s=lines.get(i)).startsWith("import ") && s.endsWith(";")) { skip.add(i); sb.append(s); }
sb.append("public class ").append(f.getName().substring(0, f.getName().length() - 5)).append("{public static void main(String[] args){");
for(int i = min; i<max+1; ++i) if(!skip.contains(i) && (s=lines.get(i))!=null) sb.append(s);
sb.append("}}");
JavaCompiler jc = ToolProvider.getSystemJavaCompiler();
try (OutputStream out = new FileOutputStream(f)) { out.write(sb.toString().getBytes()); }
int result = jc.run(null, null, null, f.getAbsolutePath());
if(result==0){
//noinspection ResultOfMethodCallIgnored
f.delete();
f = new File(f.getAbsolutePath().substring(0, f.getAbsolutePath().length()-5)+".class");
byte[] b;
try{
InputStream i = new FileInputStream(f);
ArrayList<Byte> a = new ArrayList<>();
byte[] b1 = new byte[4096];
int i1;
while(i.available()>0){
i1 = i.read(b1);
for(int j = 0; j<i1; ++j) a.add(b1[j]);
}
i.close();
b = new byte[a.size()];
for(int j = 0; j<a.size(); ++j) b[j] = a.get(j);
}catch(Exception e){ return; }
finally {
//noinspection ResultOfMethodCallIgnored
f.delete();
}
Result<Class<?>> compiled = (Result<Class<?>>) Reflection.invokeMethod(
Reflection.getMethod(ClassLoader.class, "defineClass", byte[].class, int.class, int.class),
TileEntityComputer.class.getClassLoader(),
b,
0,
b.length);
if(compiled.success){
for(Method m : compiled.value.getDeclaredMethods())
if(m.getName().equals("main") && Modifier.isStatic(m.getModifiers()) && Arrays.equals(m.getParameterTypes(), new Class<?>[]{String[].class}))
{
m.setAccessible(true);
try {
m.invoke(null, new Object[]{new String[]{}});
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
}
}
}catch(Exception e){ e.printStackTrace(); }
}
public void registerDataListener(DataListener<HashMap<Integer, String>> listener){ dataListeners.add(listener); listener.getData(lines); }
public void unregisterDataListener(DataListener<HashMap<Integer, String>> listener){ dataListeners.remove(listener); }

Binary file not shown.