Skip to content

Commit

Permalink
internal: expand ic time registers to 8 bytes
Browse files Browse the repository at this point in the history
  • Loading branch information
MrTJP committed Mar 28, 2024
1 parent cf9ea30 commit 9a72ff1
Show file tree
Hide file tree
Showing 21 changed files with 276 additions and 186 deletions.
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
// 1.19.2 2024-03-05T10:07:47.482285 ProjectRed-Fabrication Languages: en_us
e0b0d15a05df8eb45303f71c9f7fe26312e3d2a1 assets/projectred_fabrication/lang/en_us.json
// 1.19.2 2024-03-27T14:58:23.336271 ProjectRed-Fabrication Languages: en_us
a30f492c97e6f45bf76f7ae499af270f92dedc90 assets/projectred_fabrication/lang/en_us.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,11 @@
"projectred_fabrication.tooltip.bottom": "Bottom",
"projectred_fabrication.tooltip.bundled_input": "Bundled input",
"projectred_fabrication.tooltip.bundled_output": "Bundled output",
"projectred_fabrication.tooltip.cannot_fabricate": "Cannot fabricate",
"projectred_fabrication.tooltip.corrupted_discard": "Corrupted NBT data, please discard",
"projectred_fabrication.tooltip.defect_chance": "Defect chance",
"projectred_fabrication.tooltip.fab_err.compile_format": "Cannot fabricate: Re-compile required",
"projectred_fabrication.tooltip.fab_err.generic": "Cannot fabricate",
"projectred_fabrication.tooltip.fab_err.not_compiled": "Cannot fabricate: Not compiled",
"projectred_fabrication.tooltip.input_mask": "Input mask",
"projectred_fabrication.tooltip.io_none": "None",
"projectred_fabrication.tooltip.io_types": "IO types",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,9 @@ protected void addTranslations() {
add(UL_BUNDLED_INPUT, "Bundled input");
add(UL_BUNDLED_OUTPUT, "Bundled output");
add(UL_IO_NONE, "None");
add(UL_CANNOT_FABRICATE, "Cannot fabricate");
add(UL_FAB_ERR_NOT_COMPILED, "Cannot fabricate: Not compiled");
add(UL_FAB_ERR_COMPILE_FORMAT, "Cannot fabricate: Re-compile required");
add(UL_FAB_ERR_GENERIC, "Cannot fabricate");

add(UL_IO_GATE_TILE, "IO Gate");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import mrtjp.fengine.TileCoord;
import mrtjp.projectred.fabrication.engine.InterfaceSpec;
import mrtjp.projectred.fabrication.engine.PRFabricationEngine;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.Tag;
Expand All @@ -22,6 +23,8 @@ public class EditorDataUtils {

// ICEditorStateMachine
public static final String KEY_COMP_STATE = "state"; // byte
public static final String KEY_SIM_START_TIME = "sim_start_time"; // long
public static final String KEY_COMPILE_FORMAT = "compile_format"; // int
public static final String KEY_FLAT_MAP = "flat_map"; // String
public static final String KEY_SIMULATION = "sim_cont"; // CompoundTag
public static final String KEY_COMPILER_LOG = "compiler_log"; // CompoundTag
Expand Down Expand Up @@ -54,7 +57,15 @@ public static boolean hasFabricationTarget(@Nullable CompoundTag tag) {
}

public static boolean canFabricate(@Nullable CompoundTag tag) {
return hasFabricationTarget(tag) && tag.getBoolean(KEY_IS_BUILT) && getErrorCount(tag) == 0;
return hasFabricationTarget(tag) && isBuilt(tag) && isCompileFormatValid(tag) && getErrorCount(tag) == 0;
}

public static boolean isBuilt(CompoundTag tag) {
return tag.getBoolean(KEY_IS_BUILT);
}

public static boolean isCompileFormatValid(CompoundTag tag) {
return tag.getInt(KEY_COMPILE_FORMAT) == PRFabricationEngine.COMPILE_FORMAT;
}

public static int getErrorCount(CompoundTag tag) {
Expand All @@ -68,6 +79,7 @@ public static int getWarningCount(CompoundTag tag) {
// Creates copy of editor tag with only the data required to fabricate a gate
public static CompoundTag createFabricationCopy(CompoundTag editorTag) {
CompoundTag copy = new CompoundTag();
copy.putInt(KEY_COMPILE_FORMAT, editorTag.getInt(KEY_COMPILE_FORMAT));
copy.putBoolean(KEY_IS_BUILT, editorTag.getBoolean(KEY_IS_BUILT));
copy.putString(KEY_IC_NAME, editorTag.getString(KEY_IC_NAME));
copy.putInt(KEY_TILE_COUNT, editorTag.getInt(KEY_TILE_COUNT));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import mrtjp.projectred.fabrication.engine.log.IODirectionMismatchError;
import mrtjp.projectred.fabrication.engine.log.NoInputsError;
import mrtjp.projectred.fabrication.engine.log.NoOutputsError;
import net.covers1624.quack.collection.FastStream;
import net.minecraft.nbt.CompoundTag;

import javax.annotation.Nullable;
Expand All @@ -33,6 +34,7 @@ public class ICEditorStateMachine {
public static final int KEY_COMPILER_LOG_NODE_EXECUTED = 3;
public static final int KEY_COMPILER_LOG_PROBLEM_ADDED = 4;
public static final int KEY_AUTO_COMPILE_STATE = 5;
public static final int KEY_SIM_START_TIME_CHANGED = 6;

public static final int KEY_CLIENT_COMPILE_CLICKED = 10;
public static final int KEY_CLIENT_AUTO_COMPILE_TOGGLED = 11;
Expand Down Expand Up @@ -60,6 +62,8 @@ public class ICEditorStateMachine {
private final ICSimulationContainer simulationContainer = new ICSimulationContainer();
private final ICCompilerLog compilerLog = new ICCompilerLog(this);

private int lastCompiledFormat = 0;
private long lastSimStartTime = 0;
private String lastCompiledFlatMap = PRFabricationEngine.EMPTY_FLAT_MAP_SERIALIZED;

private boolean autoCompileAvailable = true;
Expand All @@ -76,6 +80,8 @@ public ICCompilerLog getCompilerLog() {

public void save(CompoundTag tag) {
tag.putByte(KEY_COMP_STATE, (byte) currentState);
tag.putInt(KEY_COMPILE_FORMAT, lastCompiledFormat);
tag.putLong(KEY_SIM_START_TIME, editor.getGameTime() - lastSimStartTime);
tag.putString(KEY_FLAT_MAP, lastCompiledFlatMap);

CompoundTag simTag = new CompoundTag();
Expand All @@ -92,6 +98,7 @@ public void save(CompoundTag tag) {

public void load(CompoundTag tag) {
currentState = tag.getByte(KEY_COMP_STATE) & 0xFF;
lastCompiledFormat = tag.getInt(KEY_COMPILE_FORMAT);
lastCompiledFlatMap = tag.getString(KEY_FLAT_MAP);
simulationContainer.load(tag.getCompound(KEY_SIMULATION));
compilerLog.load(tag.getCompound(KEY_COMPILER_LOG));
Expand Down Expand Up @@ -132,6 +139,9 @@ public void readStateMachineStream(MCDataInput in, int key) {
case KEY_AUTO_COMPILE_STATE:
readAutoCompileState(in);
break;
case KEY_SIM_START_TIME_CHANGED:
lastSimStartTime = in.readLong();
break;

// Client -> Server packets
case KEY_CLIENT_COMPILE_CLICKED:
Expand All @@ -150,6 +160,10 @@ public MCDataOutput getStateMachineStream(int key) {
return editor.getStateMachineStream(key);
}

public void onChunkLoad() {
lastSimStartTime = editor.getGameTime() - lastSimStartTime;
}

//region State Machine events
public void onTick(long time) {
states[currentState].onTick(time);
Expand Down Expand Up @@ -195,6 +209,12 @@ private void writeAutoCompileState(MCDataOutput out) {
int acState = (autoCompileAvailable ? 0x1 : 0) | (enableAutoCompile ? 0x2 : 0);
out.writeByte(acState);
}

private void setLastSimStartTimeAndSend(long time) {
if (time == lastSimStartTime) return;
lastSimStartTime = time;
getStateMachineStream(KEY_SIM_START_TIME_CHANGED).writeLong(time);
}
//endregion

//region Client-side utilities
Expand Down Expand Up @@ -236,6 +256,10 @@ public boolean isAutoCompileEnabled() {
public boolean isAutoCompileAvailable() {
return autoCompileAvailable;
}

public long getSimSystemTime() {
return editor.getGameTime() - lastSimStartTime;
}
//endregion

private void enterState(int id, boolean force) {
Expand Down Expand Up @@ -382,6 +406,7 @@ public void onTick(long time) {
if (assembler.isDone()) {
ICFlatMap map = assembler.result();
assembler = null; //TODO make assemblers clearable
lastCompiledFormat = PRFabricationEngine.COMPILE_FORMAT;
lastCompiledFlatMap = PRFabricationEngine.instance.serializeFlatMap(map);
simulationContainer.setFlatMap(map);

Expand Down Expand Up @@ -438,7 +463,7 @@ private void restartAssembly() {
int m = ioMask >> r*2 & 0x3;
if (m == 0x3) {
int finalR = r;
List<TileCoord> coordList = ioTiles.stream()
List<TileCoord> coordList = FastStream.of(ioTiles)
.filter(io -> io.getIOSide() == finalR)
.map(io -> ((BaseTile)io).getPos())
.toList();
Expand All @@ -459,24 +484,16 @@ private void restartAssembly() {

private class StateSimulating implements State {

private long lastTime = -1;

@Override
public void onTick(long time) {

// Note: Because this is always -1 initially, 1 tick will be missed on every chunk load. Not a big deal for
// IC Workbench tile, because there are no external interaction. But FabricatedGateParts get around this
// by saving the elapsed time to NBT, and then use IChunkLoadTile hook to convert the elapsed to new lastTime.
// May be worth implementing IChunkLoadTile on workbench tile, but this is okay for now.
if (lastTime == -1) {
lastTime = time;
if (!checkFormat()) {
LOGGER.warn("Loaded simulation from incompatible format. Exiting simulation state.");
enterStateAndSend(STATE_AWAITING_COMPILE);
return;
}

long elapsedTime = time - lastTime;
lastTime = time;

simulationContainer.progressTime(elapsedTime);
long elapsedTime = editor.getGameTime() - lastSimStartTime;
simulationContainer.setSystemTime(elapsedTime);
simulationContainer.pushTime();
propagateAndNotify();
}
Expand All @@ -499,6 +516,10 @@ private void propagateAndNotify() {
if (callback != null) callback.onSimulationComplete(changeMask, simulationContainer);
}

private boolean checkFormat() {
return lastCompiledFormat == PRFabricationEngine.COMPILE_FORMAT;
}

@Override
public void onTileMapChanged() {
enterStateAndSend(STATE_AWAITING_COMPILE); //TODO enter initial if tile map was emptied
Expand All @@ -511,7 +532,7 @@ public boolean canTransitionTo(int id) {

@Override
public void onStateEntered(int previousStateId) {
lastTime = -1;
setLastSimStartTimeAndSend(editor.getGameTime());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ public void readDesc(MCDataInput in) {
stateMachine.readDesc(in);
}

public void onChunkLoad() {
stateMachine.onChunkLoad();
}

private void clear() {
tileMap.removeAll();
stateMachine.reset();
Expand Down Expand Up @@ -245,6 +249,10 @@ public MCDataOutput getStateMachineStream(int key) {
return network.getBufferedStream(STREAM_ID_FSM, key);
}

public long getGameTime() {
return network.getGameTime();
}

//region Server Utils
public void addTile(BaseTile tile, TileCoord pos) {
if (network.isClientSide()) throw new RuntimeException("Tiles can only be added server-side");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

public class ICSimulationContainer {

private ICSimulation simulation = PRFabricationEngine.EMPTY_SIMULATION;
private ICSimulation simulation = PRFabricationEngine.instance.deserializeSimulation(PRFabricationEngine.EMPTY_SIMULATION_SERIALIZED);

/**
* Inputs to the simulation indexed by rotation (0-3).
Expand Down Expand Up @@ -50,6 +50,10 @@ public void setSystemTime(long systemTime) {
this.systemTime = systemTime;
}

public long getSystemTime() {
return systemTime;
}

public void progressTime(long time) {
systemTime += time;
}
Expand Down Expand Up @@ -123,20 +127,11 @@ public void pullInputs(int rmask) {
}

public void pushTime() {

simulation.queueRegByteVal(PRFabricationEngine.REG_TIME_3, (byte) (systemTime >>> 24));
simulation.queueRegByteVal(PRFabricationEngine.REG_TIME_2, (byte) (systemTime >>> 16));
simulation.queueRegByteVal(PRFabricationEngine.REG_TIME_1, (byte) (systemTime >>> 8));
simulation.queueRegByteVal(PRFabricationEngine.REG_TIME_0, (byte) (systemTime));
simulation.queueRegLongVal(PRFabricationEngine.REG_TIME, 0, systemTime);
}

public void pullTime() {

systemTime = 0;
systemTime |= (long) (simulation.getRegByteVal(PRFabricationEngine.REG_TIME_3) & 0xFF) << 24;
systemTime |= (simulation.getRegByteVal(PRFabricationEngine.REG_TIME_2) & 0xFF) << 16;
systemTime |= (simulation.getRegByteVal(PRFabricationEngine.REG_TIME_1) & 0xFF) << 8;
systemTime |= (simulation.getRegByteVal(PRFabricationEngine.REG_TIME_0) & 0xFF);
systemTime = simulation.getRegLongVal(PRFabricationEngine.REG_TIME, 0);
}

public int pullOutputs() {
Expand Down Expand Up @@ -180,6 +175,14 @@ public byte pullRegisterValue(int regId) {
return simulation.getRegByteVal(regId);
}

public long pullLongValue(int r7, int r6, int r5, int r4, int r3, int r2, int r1, int r0) {
return simulation.getRegLongVal(r7, r6, r5, r4, r3, r2, r1, r0);
}

public long pullLongValue(int[] r, int offset) {
return simulation.getRegLongVal(r, offset);
}

public void simulate() {
simulation.propagate(null);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,35 @@ public class PRFabricationEngine extends FabricationEngine {
public static final int REG_IN_BASE = 0;
public static final int REG_OUT_BASE = 64;

public static final int REG_TIME_3 = 128; // Upper 8 bits of time
public static final int REG_TIME_2 = 129;
public static final int REG_TIME_1 = 130;
public static final int REG_TIME_0 = 131; // Lower 8 bits of time
public static final int REG_TIME_7 = 128; // Upper 8 bits of time
public static final int REG_TIME_6 = 129;
public static final int REG_TIME_5 = 130;
public static final int REG_TIME_4 = 131;
public static final int REG_TIME_3 = 132;
public static final int REG_TIME_2 = 133;
public static final int REG_TIME_1 = 134;
public static final int REG_TIME_0 = 135; // Lower 8 bits of time

public static final int REG_ZERO = 132;
public static final int REG_ONE = 133;
public static final int REG_ZERO = 136;
public static final int REG_ONE = 137;

public static final int[] REG_TIME = { REG_TIME_7, REG_TIME_6, REG_TIME_5, REG_TIME_4, REG_TIME_3, REG_TIME_2, REG_TIME_1, REG_TIME_0 };

public static final PRFabricationEngine instance = new PRFabricationEngine();

public static final ICFlatMap EMPTY_FLAT_MAP = instance.newAssembler().result();
public static final ICSimulation EMPTY_SIMULATION = new ICSimulation(EMPTY_FLAT_MAP);

public static final String EMPTY_FLAT_MAP_SERIALIZED = instance.serializeFlatMap(EMPTY_FLAT_MAP);
public static final String EMPTY_SIMULATION_SERIALIZED = instance.serializeSimulation(EMPTY_SIMULATION);
public static final String EMPTY_SIMULATION_SERIALIZED = instance.serializeSimulation(new ICSimulation(EMPTY_FLAT_MAP));

// Implementation-specific compilation format. A compiled flatmap is expected to have certain static registers and such
// in order to function. Additionally, gate classes are expected to be forward compatible. If any breaking changes need
// to be made, this format number should be incremented. Any incompatible compile formats should be dropped and players
// should be alerted. Example:
// * Gates already in-world with compiled designs should stop functioning with a clearly visible reason why
// * IC Blueprints with compiled designs should notify player that they must be re-compiled in the workbench
// * Etc.
public static final int COMPILE_FORMAT = 1;

public static int inputRegisterId(int r, int i) {
return REG_IN_BASE + r * 16 + i;
Expand Down Expand Up @@ -67,10 +81,9 @@ private void addStaticRegisters(ICAssembler assembler) {
}

// Add time registers
assembler.addRegister(REG_TIME_3, new ByteRegister());
assembler.addRegister(REG_TIME_2, new ByteRegister());
assembler.addRegister(REG_TIME_1, new ByteRegister());
assembler.addRegister(REG_TIME_0, new ByteRegister());
for (int i = 0; i < 8; i++) {
assembler.addRegister(REG_TIME[i], new ByteRegister());
}

// Add zero and one registers
assembler.addRegister(REG_ZERO, new StaticByteRegister((byte) 0));
Expand Down
Loading

0 comments on commit 9a72ff1

Please sign in to comment.