rough, this is a waste of tokens...

This commit is contained in:
2026-09-17 22:35:37 -04:00
parent 8fa8dc4ba9
commit d9c44d2f26
8 changed files with 156955 additions and 39 deletions
@@ -64,26 +64,14 @@ public class BasePositionObject extends BaseObject {
@Override
public int getWidth() {
float w = width.getFloatValue();
if (w == 0f) {
Object image = getImage();
if (image == null) {
w = 0f;
}
}
return Math.round(w * scaleWidth.getFloatValue());
// A zero authored size means "use the image's natural size"; the
// renderer falls back to the decoded image dimensions when this is 0.
return Math.round(width.getFloatValue() * scaleWidth.getFloatValue());
}
@Override
public int getHeight() {
float h = height.getFloatValue();
if (h == 0f) {
Object image = getImage();
if (image == null) {
h = 0f;
}
}
return Math.round(h * scaleHeight.getFloatValue());
return Math.round(height.getFloatValue() * scaleHeight.getFloatValue());
}
@Override
@@ -458,9 +458,23 @@ public final class VsmxInterpreter {
/** Runs the script's main body, populating the given global variables object. */
public synchronized void run(VsmxObject globalVariables) {
// This can be invoked re-entrantly (Controller.changeResource loads and
// runs a new resource while the previous resource's script is still on
// the stack), so the outer execution state must be preserved and
// restored exactly like interpretFunction does. Without this, the
// nested run clobbers pc/exit/stack/callStates and the outer script
// crashes with a null operand stack after the nested run returns.
int savedPc = pc;
boolean savedExit = exit;
Deque<VsmxBaseObject> savedStack = stack;
Deque<VsmxCallState> savedCallStates = callStates;
VsmxCallState savedCallState = callState;
pc = 0;
exit = false;
callStates = new ArrayDeque<>();
stack = null;
callState = null;
pushCallState(VsmxNull.singleton, 0, false, true);
this.globalVariables = globalVariables;
@@ -470,8 +484,16 @@ public final class VsmxInterpreter {
interpret();
callStates.clear();
callState = null;
pc = savedPc;
exit = savedExit;
stack = savedStack;
callStates = savedCallStates;
callState = savedCallState;
}
/** Requests the currently-running script to stop after the current instruction. */
public void stop() {
exit = true;
}
private void callFunction(VsmxFunction function, VsmxBaseObject thisObject, VsmxBaseObject[] arguments,
@@ -68,6 +68,10 @@ public class Controller extends BaseNativeObject {
if (!resource.equals(resourceName)) {
resource = resourceName;
menuHost.changeResource(resourceName);
// The resource switch abandons this interpreter; stop the script
// that requested it so it does not keep running against a stale
// menu (the PSP drops the old resource's script at this point).
interpreter.stop();
}
return VsmxBoolean.getValue(true);
}
@@ -50,7 +50,7 @@ public class GlobalVariables extends BaseNativeObject {
}
public void writeln(VsmxBaseObject object, VsmxBaseObject s1, VsmxBaseObject s2, VsmxBaseObject s3) {
log.append(s1.getStringValue()).append(s3.getStringValue()).append('\n');
log.append(s1.getStringValue()).append(s2.getStringValue()).append(s3.getStringValue()).append('\n');
}
public VsmxBaseObject parseFloat(VsmxBaseObject object, VsmxBaseObject value) {
@@ -76,7 +76,10 @@ public class Timer extends BaseNativeObject {
if (due != null) {
if (due.function instanceof VsmxFunction f) {
synchronized (callbackLock) {
interpreter.interpretFunction(f, due.object, due.params);
// Fire on the interpreter that compiled the callback so
// timers survive a resource switch (each resource owns
// its own interpreter).
f.getInterpreter().interpretFunction(f, due.object, due.params);
}
}
continue;