This commit is contained in:
HbmMods 2026-05-22 23:29:58 +02:00
parent 7db05f01ec
commit c99d1da3bf
5 changed files with 446 additions and 26 deletions

View File

@ -16,6 +16,9 @@
* Successor to the BAT9k * Successor to the BAT9k
* Larger footprint, way more storage space * Larger footprint, way more storage space
* Needs to be placed on a proper foundation or else it'll sink into the ground * Needs to be placed on a proper foundation or else it'll sink into the ground
* AUTOCAL Automatic Calculator
* Highly advanced programmable RoR device
* Can send and receive signals and do calculations with the same system as NTM's calculator
## Changed ## Changed
* RoR graphs can now have their min and max bounds set to a fixed number * RoR graphs can now have their min and max bounds set to a fixed number

View File

@ -1,7 +1,11 @@
package com.hbm.inventory.gui; package com.hbm.inventory.gui;
import java.awt.Desktop;
import java.io.File; import java.io.File;
import java.net.URI; import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays; import java.util.Arrays;
import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL11;
@ -59,11 +63,6 @@ public class GUIScreenRadioAUTOCAL extends GuiScreen {
if(checkClick(x, y, 28, 36, 18, 18)) { data = new NBTTagCompound(); data.setBoolean("ignore", true); } if(checkClick(x, y, 28, 36, 18, 18)) { data = new NBTTagCompound(); data.setBoolean("ignore", true); }
if(checkClick(x, y, 48, 36, 18, 18)) { data = new NBTTagCompound(); data.setBoolean("auto", true); } if(checkClick(x, y, 48, 36, 18, 18)) { data = new NBTTagCompound(); data.setBoolean("auto", true); }
if(data != null) {
mc.getSoundHandler().playSound(PositionedSoundRecord.func_147674_a(new ResourceLocation("gui.button.press"), 1.0F));
PacketDispatcher.wrapper.sendToServer(new NBTControlPacket(data, autocal.xCoord, autocal.yCoord, autocal.zCoord));
}
// open folder and generate new script file // open folder and generate new script file
if(checkClick(x, y, 104, 36, 18, 18)) { if(checkClick(x, y, 104, 36, 18, 18)) {
try { try {
@ -74,8 +73,38 @@ public class GUIScreenRadioAUTOCAL extends GuiScreen {
script.setExecutable(false); script.setExecutable(false);
Class oclass = Class.forName("java.awt.Desktop"); Class oclass = Class.forName("java.awt.Desktop");
Object object = oclass.getMethod("getDesktop", new Class[0]).invoke((Object) null, new Object[0]); Object object = oclass.getMethod("getDesktop", new Class[0]).invoke((Object) null, new Object[0]);
oclass.getMethod("browse", new Class[] { URI.class }).invoke(object, new Object[] { uploadFolder.toURI() }); oclass.getMethod("browse", new Class[] { URI.class }).invoke(object, new Object[] { script.toURI() });
} catch(Throwable ex) { MainRegistry.logger.error("Couldn\'t open link", ex); } //oclass.getMethod("edit", File.class).invoke(object, new Object[] { script });
} catch(Throwable ex) { MainRegistry.logger.error("Couldn't open link", ex); }
}
if(checkClick(x, y, 84, 36, 18, 18)) {
try {
File uploadFolder = new File(MainRegistry.configDir.getParentFile(), "hbmComputerUpload");
File script = new File(uploadFolder, "script.txt");
if(!uploadFolder.exists()) uploadFolder.mkdir();
if(!script.exists()) {
script.createNewFile();
script.setExecutable(false);
return;
}
/*FileReader reader = new FileReader(script);
BufferedReader buffer = new BufferedReader(reader);
String[] lines = buffer.lines().toArray(String[]::new);
buffer.close();
// this is going to blow the fuck up once we hit the max packet size, but let's ignore that for now
data = new NBTTagCompound();
StringBuilder builder = new StringBuilder();
for(int l = 0; l < lines.length; l++) {
builder.append(lines[i]);
if(l < lines.length - 1) builder.append("\n"); // yeah why the fuck not
}
data.setString("payload", builder.toString());*/
byte[] bytes = Files.readAllBytes(Paths.get(script.toURI()));
data = new NBTTagCompound();
data.setString("payload", new String(bytes, StandardCharsets.UTF_8));
} catch(Throwable ex) { }
} }
// this thing can both upload and download files so let's be careful about this // this thing can both upload and download files so let's be careful about this
@ -87,6 +116,11 @@ public class GUIScreenRadioAUTOCAL extends GuiScreen {
// but we can add some extra crap that would either halt common scripting langs entirely or at least disrupt them into not functioning // but we can add some extra crap that would either halt common scripting langs entirely or at least disrupt them into not functioning
// option 3: enforce validation so only MS-ES1 script can be received by the client. this means that info such as comments or incorrectly written commands // option 3: enforce validation so only MS-ES1 script can be received by the client. this means that info such as comments or incorrectly written commands
// are lost, however this is the safest way because it becomes impossible to send malicious code, but it also interferes with regular user operation more // are lost, however this is the safest way because it becomes impossible to send malicious code, but it also interferes with regular user operation more
if(data != null) {
mc.getSoundHandler().playSound(PositionedSoundRecord.func_147674_a(new ResourceLocation("gui.button.press"), 1.0F));
PacketDispatcher.wrapper.sendToServer(new NBTControlPacket(data, autocal.xCoord, autocal.yCoord, autocal.zCoord));
}
} }
protected boolean checkClick(int x, int y, int left, int top, int sizeX, int sizeY) { protected boolean checkClick(int x, int y, int left, int top, int sizeX, int sizeY) {
@ -100,8 +134,8 @@ public class GUIScreenRadioAUTOCAL extends GuiScreen {
if(checkClick(x, y, 48, 36, 18, 18)) this.func_146283_a(Arrays.asList(new String[] {EnumChatFormatting.RED + "Automatic Reboot", "Restarts the computer automatically when", "the program stops due to an error", "or after finishing."}), x, y); if(checkClick(x, y, 48, 36, 18, 18)) this.func_146283_a(Arrays.asList(new String[] {EnumChatFormatting.RED + "Automatic Reboot", "Restarts the computer automatically when", "the program stops due to an error", "or after finishing."}), x, y);
if(checkClick(x, y, 84, 36, 18, 18)) this.func_146283_a(Arrays.asList(new String[] {EnumChatFormatting.BLUE + "Upload Program"}), x, y); if(checkClick(x, y, 84, 36, 18, 18)) this.func_146283_a(Arrays.asList(new String[] {EnumChatFormatting.BLUE + "Upload Program"}), x, y);
if(checkClick(x, y, 104, 36, 18, 18)) this.func_146283_a(Arrays.asList(new String[] {EnumChatFormatting.BLUE + "Open Program Folder"}), x, y); if(checkClick(x, y, 104, 36, 18, 18)) this.func_146283_a(Arrays.asList(new String[] {EnumChatFormatting.BLUE + "Open Program File"}), x, y);
if(checkClick(x, y, 124, 36, 18, 18)) this.func_146283_a(Arrays.asList(new String[] {EnumChatFormatting.BLUE + "Download Program"}), x, y); if(checkClick(x, y, 124, 36, 18, 18)) this.func_146283_a(Arrays.asList(new String[] {EnumChatFormatting.BLUE + "Download Program", EnumChatFormatting.RED + "Currently unsupported!"}), x, y);
} }
private void drawGuiContainerBackgroundLayer(float f, int mouseX, int mouseY) { private void drawGuiContainerBackgroundLayer(float f, int mouseX, int mouseY) {
@ -110,8 +144,8 @@ public class GUIScreenRadioAUTOCAL extends GuiScreen {
drawTexturedModalRect(guiLeft, guiTop, 0, 0, xSize, ySize); drawTexturedModalRect(guiLeft, guiTop, 0, 0, xSize, ySize);
if(autocal.isOn) drawTexturedModalRect(guiLeft + 8, guiTop + 36, 150, 0, 18, 18); if(autocal.isOn) drawTexturedModalRect(guiLeft + 8, guiTop + 36, 150, 0, 18, 18);
if(autocal.ignoreError) drawTexturedModalRect(guiLeft + 28, guiTop + 36, 150, 18, 18, 18); if(!autocal.ignoreError) drawTexturedModalRect(guiLeft + 28, guiTop + 36, 150, 18, 18, 18);
if(autocal.autoReboot) drawTexturedModalRect(guiLeft + 48, guiTop + 36, 150, 36, 18, 18); if(!autocal.autoReboot) drawTexturedModalRect(guiLeft + 48, guiTop + 36, 150, 36, 18, 18);
} }
@Override @Override

View File

@ -8,27 +8,43 @@ import net.minecraft.world.World;
public interface IParse { public interface IParse {
public EnumStatementReturn eval(ParseContext ctx, String line); public EnumStatementReturn eval(ParseContext ctx, String line);
public void generateJumpPoints(ParseContext ctx, String line, int index);
public static class ParseContext { public static class ParseContext {
public World world; public World world;
public NBTTagCompound variables; public NBTTagCompound variables = new NBTTagCompound();
public HashMap<String, Integer> jmp; public HashMap<String, Integer> jmp = new HashMap();
public Object buffer; public String buffer = "";
public int clockSpeed; public int clockSpeed = 1;
public int current = 0;
public ParseContext(World world, NBTTagCompound variables, HashMap<String, Integer> jmp) { public ParseContext(World world) {
this.world = world; this.world = world;
this.variables = variables; }
this.jmp = jmp;
public void turnOff() {
this.clockSpeed = 1;
this.current = 0;
this.buffer = "";
if(!this.variables.hasNoTags()) this.variables = new NBTTagCompound();
} }
} }
public static enum EnumStatementReturn { public static enum EnumStatementReturn {
/** The command executed correctly (more or less) */
OK, OK,
/** The command hasn't been recognized */
UNRECOGNIZED_COMMAND, UNRECOGNIZED_COMMAND,
/** The expected parameters aren't present, or the parameters couldn't be parsed (i.e. using an undefined jump point) */
PARAMETER_ERROR, PARAMETER_ERROR,
/** Requests the AUTOCAL unit to end the tick, regardless of how many clock cycles are left */
END_TICK, END_TICK,
/** Requests an AUTOCAL shutdown */
SHUTDOWN,
/** Skips the instruction, doesn't use up a clock cycle */
SKIP,
/** General undefined behavior */
UNDEFINED UNDEFINED
} }
} }

View File

@ -1,9 +1,271 @@
package com.hbm.module; package com.hbm.module;
import java.util.Locale;
import com.hbm.tileentity.network.RTTYSystem;
import com.hbm.tileentity.network.RTTYSystem.RTTYChannel;
import com.hbm.tileentity.network.TileEntityRadioAUTOCAL;
import com.hbm.util.Calculator;
public class ParseMSES1 implements IParse { public class ParseMSES1 implements IParse {
@Override @Override
public EnumStatementReturn eval(ParseContext ctx, String line) { public EnumStatementReturn eval(ParseContext ctx, String line) {
return EnumStatementReturn.OK; String lower = line.toLowerCase(Locale.US);
// jump point destination, skip
if(lower.startsWith("dest ") || lower.startsWith("# ")) {
return EnumStatementReturn.SKIP;
}
// no operation, still eats up a clock cycle
if(lower.equals("nop")) {
return EnumStatementReturn.OK;
}
// sets the desired clock speed, then skips the operation
if(lower.startsWith("clockspeed ")) {
if(line.length() <= 11) return EnumStatementReturn.PARAMETER_ERROR;
try {
int speed = Integer.parseInt(line.substring(11));
if(speed < 1 || speed > TileEntityRadioAUTOCAL.MAX_CLOCK_SPEED) return EnumStatementReturn.PARAMETER_ERROR;
ctx.clockSpeed = speed;
} catch(Throwable ex) { return EnumStatementReturn.PARAMETER_ERROR; }
return EnumStatementReturn.SKIP;
}
// sets the script index to the jump point
if(lower.startsWith("jmp ")) {
if(line.length() <= 4) return EnumStatementReturn.PARAMETER_ERROR;
String jmpKey = line.substring(4);
if(ctx.jmp.containsKey(jmpKey)) {
ctx.current = ctx.jmp.get(jmpKey);
return EnumStatementReturn.OK;
}
return EnumStatementReturn.PARAMETER_ERROR;
}
// sets the script index to the jump point, if the buffer is the string 'true'
if(lower.startsWith("jmpif ")) {
if(line.length() <= 6) return EnumStatementReturn.PARAMETER_ERROR;
if(!ctx.buffer.equals("true")) return EnumStatementReturn.OK;
String jmpKey = line.substring(6);
if(ctx.jmp.containsKey(jmpKey)) {
ctx.current = ctx.jmp.get(jmpKey);
return EnumStatementReturn.OK;
}
return EnumStatementReturn.PARAMETER_ERROR;
}
// sets the script index to the jump point, if the buffer is the NOT 'true'
if(lower.startsWith("jmpnot ")) {
if(line.length() <= 7) return EnumStatementReturn.PARAMETER_ERROR;
if(ctx.buffer.equals("true")) return EnumStatementReturn.OK;
String jmpKey = line.substring(7);
if(ctx.jmp.containsKey(jmpKey)) {
ctx.current = ctx.jmp.get(jmpKey);
return EnumStatementReturn.OK;
}
return EnumStatementReturn.PARAMETER_ERROR;
}
// ends the tick regardless of remaining clock cycles
if(lower.equals("endtick")) {
return EnumStatementReturn.END_TICK;
}
// requests unit to shut down
if(lower.equals("shutdown")) {
return EnumStatementReturn.SHUTDOWN;
}
// loads the requested variable into the buffer
if(lower.startsWith("load ")) {
if(line.length() <= 5) return EnumStatementReturn.PARAMETER_ERROR;
ctx.buffer = ctx.variables.getString(line.substring(5));
return EnumStatementReturn.OK;
}
// saves the buffer with the specified name
if(lower.startsWith("save ")) {
if(line.length() <= 5 || ctx.buffer.isEmpty()) return EnumStatementReturn.PARAMETER_ERROR;
ctx.variables.setString(line.substring(5), ctx.buffer);
return EnumStatementReturn.OK;
}
// stores the specified value in the buffer
if(lower.startsWith("buffer ")) {
if(line.length() <= 7) return EnumStatementReturn.PARAMETER_ERROR;
ctx.buffer = line.substring(7);
return EnumStatementReturn.OK;
}
// runs the calculation, allows string substitution, saves result to buffer
if(lower.startsWith("eval ")) {
if(line.length() <= 5) return EnumStatementReturn.PARAMETER_ERROR;
String statement = substitute(ctx, line.substring(5));
try {
double result = Calculator.evaluateExpression(statement);
ctx.buffer = "" + result;
} catch(Throwable ex) { return EnumStatementReturn.PARAMETER_ERROR; }
return EnumStatementReturn.OK;
}
// runs the calculation, allows string substitution, rounds, saves result to buffer,
if(lower.startsWith("evalr ")) {
if(line.length() <= 6) return EnumStatementReturn.PARAMETER_ERROR;
String statement = substitute(ctx, line.substring(6));
try {
double result = Calculator.evaluateExpression(statement);
ctx.buffer = "" + (int) Math.round(result);
} catch(Throwable ex) { return EnumStatementReturn.PARAMETER_ERROR; }
return EnumStatementReturn.OK;
}
// runs the calculation from the buffer, allows string substitution, saves result to buffer
if(lower.equals("evalr")) {
if(ctx.buffer.isEmpty()) return EnumStatementReturn.PARAMETER_ERROR;
String statement = substitute(ctx, ctx.buffer);
try {
double result = Calculator.evaluateExpression(statement);
ctx.buffer = "" + (int) Math.round(result);
} catch(Throwable ex) { return EnumStatementReturn.PARAMETER_ERROR; }
return EnumStatementReturn.OK;
}
// rounds the buffer down to the nearest integer
if(lower.equals("rounddown") || lower.equals("floor")) {
if(ctx.buffer.isEmpty()) return EnumStatementReturn.PARAMETER_ERROR;
try {
double d = Double.parseDouble(ctx.buffer);
ctx.buffer = "" + (int) Math.floor(d);
} catch(Exception ex) { return EnumStatementReturn.PARAMETER_ERROR; }
return EnumStatementReturn.OK;
}
// rounds the buffer up to the nearest integer
if(lower.equals("roundup") || lower.equals("ceil")) {
if(ctx.buffer.isEmpty()) return EnumStatementReturn.PARAMETER_ERROR;
try {
double d = Double.parseDouble(ctx.buffer);
ctx.buffer = "" + (int) Math.ceil(d);
} catch(Exception ex) { return EnumStatementReturn.PARAMETER_ERROR; }
return EnumStatementReturn.OK;
}
// rounds the buffer to the nearest integer (.5 cutoff rule)
if(lower.equals("round") || lower.equals("nearest")) {
if(ctx.buffer.isEmpty()) return EnumStatementReturn.PARAMETER_ERROR;
try {
double d = Double.parseDouble(ctx.buffer);
ctx.buffer = "" + (int) Math.round(d);
} catch(Exception ex) { return EnumStatementReturn.PARAMETER_ERROR; }
return EnumStatementReturn.OK;
}
// concatenate, same as buffer but evaluates $var$ substitutions
if(lower.startsWith("concat ")) {
if(line.length() <= 7 || ctx.buffer.isEmpty()) return EnumStatementReturn.PARAMETER_ERROR;
String concat = substitute(ctx, line.substring(5));
ctx.buffer = concat;
return EnumStatementReturn.OK;
}
// compares the buffer with a value, allows substitutions
if(lower.startsWith("eq ")) {
if(line.length() <= 3 || ctx.buffer.isEmpty()) return EnumStatementReturn.PARAMETER_ERROR;
ctx.buffer = ctx.buffer.equals(substitute(ctx, line.substring(3))) ? "true" : "false";
return EnumStatementReturn.OK;
}
// greater than buffer
if(lower.startsWith("gtb ")) {
if(line.length() <= 3 || ctx.buffer.isEmpty()) return EnumStatementReturn.PARAMETER_ERROR;
try {
double buffer = Double.parseDouble(ctx.buffer);
double val = Double.parseDouble(line.substring(3));
ctx.buffer = val > buffer ? "true" : "false";
} catch(Exception ex) { return EnumStatementReturn.PARAMETER_ERROR; }
return EnumStatementReturn.OK;
}
// lower than buffer
if(lower.startsWith("ltb ")) {
if(line.length() <= 3 || ctx.buffer.isEmpty()) return EnumStatementReturn.PARAMETER_ERROR;
try {
double buffer = Double.parseDouble(ctx.buffer);
double val = Double.parseDouble(line.substring(3));
ctx.buffer = val < buffer ? "true" : "false";
} catch(Exception ex) { return EnumStatementReturn.PARAMETER_ERROR; }
return EnumStatementReturn.OK;
}
// greater than or equal buffer
if(lower.startsWith("geb ")) {
if(line.length() <= 3 || ctx.buffer.isEmpty()) return EnumStatementReturn.PARAMETER_ERROR;
try {
double buffer = Double.parseDouble(ctx.buffer);
double val = Double.parseDouble(line.substring(3));
ctx.buffer = val >= buffer ? "true" : "false";
} catch(Exception ex) { return EnumStatementReturn.PARAMETER_ERROR; }
return EnumStatementReturn.OK;
}
// lower than or equal buffer
if(lower.startsWith("leb ")) {
if(line.length() <= 3 || ctx.buffer.isEmpty()) return EnumStatementReturn.PARAMETER_ERROR;
try {
double buffer = Double.parseDouble(ctx.buffer);
double val = Double.parseDouble(line.substring(3));
ctx.buffer = val <= buffer ? "true" : "false";
} catch(Exception ex) { return EnumStatementReturn.PARAMETER_ERROR; }
return EnumStatementReturn.OK;
}
// sends an RoR signal using the buffer's contents as the message over the supplied channel
if(lower.startsWith("send ")) {
if(line.length() <= 5 || ctx.buffer.isEmpty()) return EnumStatementReturn.PARAMETER_ERROR;
RTTYSystem.broadcast(ctx.world, line.substring(5), ctx.buffer);
return EnumStatementReturn.OK;
}
// listnes to an RoR signal using the buffer as the channel, then saves the signal to the buffer
if(lower.equals("listen")) {
// this picks up expired signals too, so polling has to be implemented by the user
RTTYChannel chan = RTTYSystem.listen(ctx.world, ctx.buffer);
if(chan != null) ctx.buffer = chan.signal + "";
return EnumStatementReturn.OK;
}
return EnumStatementReturn.UNRECOGNIZED_COMMAND;
}
public String substitute(ParseContext ctx, String statement) {
if(!statement.contains("$")) return statement;
String[] frags = statement.split("\\$");
if(frags.length % 2 == 0 || frags.length < 3) return statement;
// since var names are enclosed with $ signs, we assume that every evenly numbered fragment is a var name
// example: 5 + $val1$ * $val2$ / (-$val3$)
// equals "5 + ", "val1", "* ", "val2", "/ (-", "val3", ")"
// 1 2 3 4 5 6 7
for(int i = 1; i < frags.length; i += 2) {
// special case, if we try to substitute $buffer$ then read the literal buffer
if(frags[i].equals("buffer")) {
frags[i] = ctx.buffer;
} else {
frags[i] = ctx.variables.getString(frags[i]);
}
}
return String.join("", frags);
}
@Override
public void generateJumpPoints(ParseContext ctx, String line, int index) {
if(line.startsWith("dest ") && line.length() > 5) {
ctx.jmp.put(line.substring(5), index);
}
} }
} }

View File

@ -1,9 +1,11 @@
package com.hbm.tileentity.network; package com.hbm.tileentity.network;
import java.util.HashMap;
import com.hbm.interfaces.IControlReceiver; import com.hbm.interfaces.IControlReceiver;
import com.hbm.inventory.gui.GUIScreenRadioAUTOCAL; import com.hbm.inventory.gui.GUIScreenRadioAUTOCAL;
import com.hbm.module.IParse;
import com.hbm.module.IParse.EnumStatementReturn;
import com.hbm.module.IParse.ParseContext;
import com.hbm.module.ParseMSES1;
import com.hbm.tileentity.IGUIProvider; import com.hbm.tileentity.IGUIProvider;
import com.hbm.tileentity.TileEntityTickingBase; import com.hbm.tileentity.TileEntityTickingBase;
@ -11,6 +13,8 @@ import io.netty.buffer.ByteBuf;
import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.Container; import net.minecraft.inventory.Container;
import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.nbt.NBTTagString;
import net.minecraft.world.World; import net.minecraft.world.World;
public class TileEntityRadioAUTOCAL extends TileEntityTickingBase implements IControlReceiver, IGUIProvider { public class TileEntityRadioAUTOCAL extends TileEntityTickingBase implements IControlReceiver, IGUIProvider {
@ -19,10 +23,11 @@ public class TileEntityRadioAUTOCAL extends TileEntityTickingBase implements ICo
public boolean ignoreError = false; public boolean ignoreError = false;
public boolean autoReboot = false; public boolean autoReboot = false;
public Object buffer; public static final int MAX_CLOCK_SPEED = 5;
public NBTTagCompound variables;
public String[] script; public String[] script = new String[0];
public HashMap<String, Integer> jmp = new HashMap(); public IParse msesv1 = new ParseMSES1();
public ParseContext ctx;
@Override @Override
public String getInventoryName() { public String getInventoryName() {
@ -33,9 +38,53 @@ public class TileEntityRadioAUTOCAL extends TileEntityTickingBase implements ICo
public void updateEntity() { public void updateEntity() {
if(!worldObj.isRemote) { if(!worldObj.isRemote) {
if(this.worldObj.getTotalWorldTime() % 60 == 0) this.markChanged(); // ensure we're always saved to disk
if(this.ctx == null) {
this.ctx = new ParseContext(worldObj);
}
if(this.ctx.world != this.worldObj) this.ctx.world = this.worldObj;
if(!this.isOn && this.autoReboot) {
this.isOn = true;
}
if(this.isOn) {
int emergencyBrake = 100;
for(int i = 0; i < this.ctx.clockSpeed && emergencyBrake > 0; i++) {
emergencyBrake--;
if(this.ctx.current == this.script.length) { this.stop("Program has terminated"); break; }
if(this.ctx.current < 0 || this.ctx.current >= this.script.length) { this.stop("Program index is out of bounds"); break; }
try {
int index = this.ctx.current;
this.ctx.current ++;
EnumStatementReturn ret = msesv1.eval(ctx, this.script[index]);
if(ret == EnumStatementReturn.END_TICK) break;
if(ret == EnumStatementReturn.SHUTDOWN) this.stop("Program requested shutdown");
if(!this.ignoreError) {
if(ret == EnumStatementReturn.UNRECOGNIZED_COMMAND) this.stop("Unrecognized command");
if(ret == EnumStatementReturn.PARAMETER_ERROR) this.stop("Parameter error");
if(ret == EnumStatementReturn.UNDEFINED) this.stop("Undefined behavior");
}
if(ret == EnumStatementReturn.SKIP) i--;
} catch(Exception ex) {
this.stop("Evaluation unsuccessful");
}
}
}
this.networkPackNT(15); this.networkPackNT(15);
} }
} }
public void stop(String reason) {
this.isOn = false;
this.ctx.turnOff();
}
@Override @Override
public void serialize(ByteBuf buf) { public void serialize(ByteBuf buf) {
@ -53,6 +102,49 @@ public class TileEntityRadioAUTOCAL extends TileEntityTickingBase implements ICo
this.autoReboot = buf.readBoolean(); this.autoReboot = buf.readBoolean();
} }
@Override
public void readFromNBT(NBTTagCompound nbt) {
super.readFromNBT(nbt);
this.isOn = nbt.getBoolean("isOn");
this.ignoreError = nbt.getBoolean("ignoreError");
this.autoReboot = nbt.getBoolean("autoReboot");
this.ctx = new ParseContext(null);
this.ctx.current = nbt.getInteger("current");
this.ctx.clockSpeed = nbt.getInteger("clockSpeed");
this.ctx.buffer = nbt.getString("buffer");
NBTTagList lineList = nbt.getTagList("script", 8);
this.script = new String[lineList.tagList.size()];
for(int i = 0; i < script.length; i++) {
this.script[i] = lineList.getStringTagAt(i);
this.msesv1.generateJumpPoints(ctx, script[i], i);
}
this.ctx.variables = nbt.getCompoundTag("variables");
}
@Override
public void writeToNBT(NBTTagCompound nbt) {
super.writeToNBT(nbt);
nbt.setBoolean("isOn", isOn);
nbt.setBoolean("ignoreError", ignoreError);
nbt.setBoolean("autoReboot", autoReboot);
nbt.setInteger("current", ctx.current);
nbt.setInteger("clockSpeed", ctx.clockSpeed);
nbt.setString("buffer", ctx.buffer);
NBTTagList lineList = new NBTTagList();
for(String line : this.script) {
lineList.appendTag(new NBTTagString(line));
}
nbt.setTag("script", lineList);
nbt.setTag("variables", this.ctx.variables);
}
@Override public Container provideContainer(int ID, EntityPlayer player, World world, int x, int y, int z) { return null; } @Override public Container provideContainer(int ID, EntityPlayer player, World world, int x, int y, int z) { return null; }
@Override public Object provideGUI(int ID, EntityPlayer player, World world, int x, int y, int z) { return new GUIScreenRadioAUTOCAL(this); } @Override public Object provideGUI(int ID, EntityPlayer player, World world, int x, int y, int z) { return new GUIScreenRadioAUTOCAL(this); }
@ -63,10 +155,23 @@ public class TileEntityRadioAUTOCAL extends TileEntityTickingBase implements ICo
@Override @Override
public void receiveControl(NBTTagCompound data) { public void receiveControl(NBTTagCompound data) {
if(data.hasKey("on")) this.isOn = !this.isOn; if(data.hasKey("on")) {
if(this.isOn) stop("User requested shutdown");
else this.isOn = true;
}
if(data.hasKey("ignore")) this.ignoreError = !this.ignoreError; if(data.hasKey("ignore")) this.ignoreError = !this.ignoreError;
if(data.hasKey("auto")) this.autoReboot = !this.autoReboot; if(data.hasKey("auto")) this.autoReboot = !this.autoReboot;
if(data.hasKey("payload")) {
this.ctx.jmp.clear();
this.script = data.getString("payload").split("\n");
for(int i = 0; i < script.length; i++) {
script[i] = script[i].trim();
this.msesv1.generateJumpPoints(ctx, script[i], i);
}
if(this.isOn) stop("Script has changed");
}
this.markChanged(); this.markChanged();
} }
} }