Files
P2SinNext/Assets/Code/ScriptVM.cs
2025-10-19 19:04:50 +05:00

807 lines
26 KiB
C#

using NUnit.Framework.Internal;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class ScriptVM : MonoBehaviour
{
private Script _currentScript;
private ExecutionContext _mainContext;
private Dictionary<int, ExecutionContext> _activeSubroutines = new Dictionary<int, ExecutionContext>();
private Dictionary<int, GameObject> _modelTempRegistry = new Dictionary<int, GameObject>();
private Dictionary<int, GameObject> _objectRegistry = new Dictionary<int, GameObject>();
private int selectionVariable;
// Jump Table îáðàáîò÷èêîâ êîìàíä
private Dictionary<uint, Action<ExecutionContext, ScriptCommand>> _opCodeHandlers;
public bool IsRunning => _mainContext != null && !_mainContext.IsFinished;
//SCRIPT LOGGING
void OnGUI()
{
GUILayout.BeginArea(new Rect(10, 10, 400, 600));
if (_mainContext != null)
{
GUILayout.Label($"MAIN: PC={_mainContext.ProgramCounter:X4} CMD=0x{GetCurrentCommand(_mainContext)?.OpCode:X4}");
GUILayout.Label($"Status: {(IsRunning ? "Running" : "Stopped")}");
GUILayout.Label($"Paused: {(_mainContext.IsPaused ? "+" : "-")} RemSec: -{_mainContext.PauseTimeRemaining}");
// Òåêóùèå ïàðàìåòðû êîìàíäû
var currentCmd = GetCurrentCommand(_mainContext);
if (currentCmd != null)
{
GUILayout.Label($"Params: {string.Join(", ", currentCmd.Params)}");
}
}
// Ïîäïðîãðàììû
GUILayout.Label($"Subroutines: {_activeSubroutines.Count}");
foreach (var kvp in _activeSubroutines)
{
var context = kvp.Value;
GUILayout.Label($"SUB[{kvp.Key:X2}] {context.ContextName}: PC={context.ProgramCounter:X4} CMD=0x{GetCurrentCommand(context)?.OpCode:X4}");
GUILayout.Label($" Paused: {(context.IsPaused ? "+" : "-")} RemSec: -{context.PauseTimeRemaining}");
}
GUILayout.EndArea();
}
void Awake()
{
InitializeJumpTable();
}
void Update()
{
if (_mainContext == null) return;
if (_mainContext.IsPaused && _mainContext.PauseTimeRemaining > 0)
{
_mainContext.PauseTimeRemaining -= Time.deltaTime;
if (_mainContext.PauseTimeRemaining <= 0)
{
_mainContext.PauseTimeRemaining = 0;
_mainContext.IsPaused = false;
_mainContext.ProgramCounter++;
MarkCurrentCommandCompleted(_mainContext); // Ïîìå÷àåì òåêóùóþ êîìàíäó êàê âûïîëíåííóþ
}
}
// Âûïîëíÿåì îñíîâíîé êîíòåêñò
if (!_mainContext.IsWaiting && !_mainContext.IsPaused)
{
ExecuteStep(_mainContext);
}
// Îáðàáàòûâàåì ïàóçó â ïîäïðîãðàììàõ
foreach (var context in _activeSubroutines.Values)
{
if (context.IsPaused && context.PauseTimeRemaining > 0)
{
context.PauseTimeRemaining -= Time.deltaTime;
if (context.PauseTimeRemaining <= 0)
{
context.PauseTimeRemaining = 0;
context.IsPaused = false;
context.ProgramCounter++;
MarkCurrentCommandCompleted(context);
}
}
}
// Âûïîëíÿåì âñå àêòèâíûå ïîäïðîãðàììû
foreach (var context in _activeSubroutines.Values)
{
if (!context.IsWaiting && !context.IsPaused)
{
ExecuteStep(context);
}
}
// Óäàëÿåì çàâåðøåííûå ïîäïðîãðàììû
_activeSubroutines = _activeSubroutines.Where(kvp => !kvp.Value.IsFinished).ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
}
public void LoadAndRunScript(Script script)
{
_currentScript = script;
_mainContext = new ExecutionContext(0, "MAIN", null);
_activeSubroutines.Clear();
_objectRegistry.Clear();
Debug.Log($"Script loaded with {script.Commands.Count} commands");
}
public void StartSubroutine(ushort subId)
{
if (_currentScript != null && _currentScript.SubroutineTable.TryGetValue(subId, out Subroutine sub))
{
var newContext = new ExecutionContext(sub.Address, sub.Name, new ScriptCommand {OpCode = 999});
_activeSubroutines[subId] = newContext;
Debug.Log($"Started independent subroutine {subId} at address {sub.Address:X4}");
}
else
{
Debug.LogWarning($"Cannot start subroutine {subId}: script not loaded or subroutine not found");
}
}
private bool IsCommandCompleted(uint commandId)
{
if (commandId < _currentScript.Commands.Count)
{
return _currentScript.Commands[(int)commandId].executedStatus == 3;
}
return false;
}
// WaitTo - stops thread and check command status at address
private void Handle_WaitTo(ExecutionContext ctx, ScriptCommand cmd)
{
uint targetCommandId = (uint)GetParam(cmd, 0);
if (IsCommandCompleted(targetCommandId))
{
ctx.ProgramCounter++;
cmd.executedStatus = 3;
}
}
private void ExecuteStep(ExecutionContext context)
{
if (context.ProgramCounter >= _currentScript.Commands.Count)
{
context.IsFinished = true;
if (context == _mainContext) Debug.Log("Main script finished");
return;
}
ScriptCommand cmd = _currentScript.Commands[(int)context.ProgramCounter];
cmd.executedStatus = 0; //cleaning status for command restart and proper wait
if (_opCodeHandlers.TryGetValue(cmd.OpCode, out var handler))
{
try
{
handler(context, cmd);
}
catch (Exception ex)
{
Debug.LogError($"Error executing command 0x{cmd.OpCode:X8}: {ex.Message}");
// Ïðè îøèáêå âñå ðàâíî ïîìå÷àåì êàê âûïîëíåííóþ, ÷òîáû íå çàâèñíóòü
cmd.executedStatus = 3;
context.ProgramCounter++;
}
}
else
{
Debug.LogWarning($"Unknown OpCode: 0x{cmd.OpCode:X8} at PC={context.ProgramCounter:X4}");
// Íåèçâåñòíûå êîìàíäû ïðîñòî ïðîïóñêàåì
cmd.executedStatus = 3;
context.ProgramCounter++;
}
}
private void InitializeJumpTable()
{
_opCodeHandlers = new Dictionary<uint, Action<ExecutionContext, ScriptCommand>>
{
// Óïðàâëåíèå ïîòîêîì
{ 0x00000007, Handle_JumpTo },
{ 0x00000001, Handle_If1Go },
{ 0x00000002, Handle_If0Go },
{ 0x00000004, Handle_IfNotEqualGo },
{ 0x0000000D, Handle_GoSub },
{ 0x0000000E, Handle_Return },
{ 0x00000012, Handle_WaitTo },
{ 0x0000001A, Handle_GetInput },
{ 0x0000002C, Handle_SetCamXY }, // Set Camera
//Characters commands
{ 0x00000030, Handle_CharLoad }, // CharLoad
{ 0x00000031, Handle_CharInit }, // CharInit
{ 0x000000D0, Handle_CharInit }, // Another CharInit???
{ 0x00000034, Handle_CharMoveTo }, // CanWait
{ 0x00000037, Handle_CharAnimate }, // CanWait
{ 0x00000038, Handle_CharAnimate2 }, // CanWait
{ 0x00000041, Handle_PlayerInit }, // Create player char at camera set
{ 0x000000D2, Handle_CharGlowShow }, // CharInitWithGlow
{ 0x0000003E, Handle_WaitCharAnimEnd }, // Wait by char id
{ 0x00000046, Handle_CharSetSubroutine }, // Set blockcharacter subroutine
//Pause
{ 0x0000005C, Handle_PausInit }, // PausInit
{ 0x0000005D, Handle_PauseFr }, // PauseFr_
// Ðàáîòà ñ ïåðåìåííûìè
{ 0x00000008, Handle_SetTemp },
{ 0x00000009, Handle_CopyVar },
{ 0x00000060, Handle_GetVar },
{ 0x0000005E, Handle_VarTrue },
{ 0x0000005F, Handle_VarFlse },
{ 0x00000073, Handle_VarDec },
{ 0x00000074, Handle_VarSet },
// Óïðàâëåíèå
{ 0x00000043, Handle_CtrlLock },
{ 0x00000044, Handle_CtrUnlck },
// Çàãðóçêà ìîäóëåé
{ 0x00000051, Handle_DungLoad },
{ 0x00000052, Handle_EventLoad },
{ 0x00000053, Handle_CityLoad },
{ 0x000000ED, Handle_BattleLoad },
// Âèäåî
{ 0x00000059, Handle_VideoPly },
// Ýôôåêòû
{ 0x00000092, Handle_ScrnFade },
// Òåêñò
{ 0x00000024, Handle_WindOpen },
{ 0x00000013, Handle_TextShow },
{ 0x00000025, Handle_WindClose }
};
}
// ========== ÎÁÐÀÁÎÒ×ÈÊÈ ÊÎÌÀÍÄ ==========
private void Handle_JumpTo(ExecutionContext ctx, ScriptCommand cmd)
{
uint jumpAddress = (uint)GetParam(cmd, 0);
ctx.ProgramCounter = jumpAddress;
cmd.executedStatus = 3; // Íåìåäëåííîå âûïîëíåíèå
}
private void Handle_If1Go(ExecutionContext ctx, ScriptCommand cmd)
{
int varAddress = GetParam(cmd, 0);
uint jumpAddress = (uint)GetParam(cmd, 1);
if (GetLocalVariable(ctx, varAddress) == 1)
ctx.ProgramCounter = jumpAddress;
else
ctx.ProgramCounter++;
cmd.executedStatus = 3;
}
private void Handle_If0Go(ExecutionContext ctx, ScriptCommand cmd)
{
int varAddress = GetParam(cmd, 0);
uint jumpAddress = (uint)GetParam(cmd, 1);
if (GetLocalVariable(ctx, varAddress) == 0)
ctx.ProgramCounter = jumpAddress;
else
ctx.ProgramCounter++;
cmd.executedStatus = 3;
}
private void Handle_IfNotEqualGo(ExecutionContext ctx, ScriptCommand cmd)
{
int varAddress = GetParam(cmd, 0);
int compareValue = GetParam(cmd, 1);
uint jumpAddress = (uint)GetParam(cmd, 2);
if (GetLocalVariable(ctx, varAddress) != compareValue)
ctx.ProgramCounter = jumpAddress;
else
ctx.ProgramCounter++;
cmd.executedStatus = 3;
}
private void Handle_GoSub(ExecutionContext ctx, ScriptCommand cmd)
{
ushort subId = (ushort)GetParam(cmd, 0);
if (_currentScript.SubroutineTable.TryGetValue(subId, out Subroutine sub))
{
var newContext = new ExecutionContext(sub.Address, sub.Name, cmd);
_activeSubroutines[subId] = newContext;
}
ctx.ProgramCounter++;
}
private void Handle_Return(ExecutionContext ctx, ScriptCommand cmd)
{
if (ctx.ExecutedByCmd != null) //main thread has ExecutedByCmd = null
{
// Äëÿ ïîäïðîãðàìì, âûçâàííûõ èç îñíîâíîãî ïîòîêà
ctx.ExecutedByCmd.executedStatus = 3;
ctx.IsFinished = true;
}
}
private void Handle_GetInput(ExecutionContext ctx, ScriptCommand cmd)
{
int varAddress = GetParam(cmd, 0);
SetLocalVariable(ctx, varAddress, selectionVariable);
ctx.ProgramCounter++;
cmd.executedStatus = 3;
}
// Îáðàáîò÷èêè êîìàíä ïàóçû:
private void Handle_PausInit(ExecutionContext ctx, ScriptCommand cmd)
{
// Ïðîñòî ñáðàñûâàåì ñ÷¸ò÷èê ïàóçû â êîíòåêñòå
ctx.PauseTimeRemaining = 0;
ctx.ProgramCounter++;
cmd.executedStatus = 3;
}
private void Handle_PauseFr(ExecutionContext ctx, ScriptCommand cmd)
{
int framesToPause = GetParam(cmd, 0);
ctx.PauseTimeRemaining = ctx.PauseTimeRemaining = framesToPause * (1f / App.Ps1FPS); //Ps1 FPS Compability
ctx.IsPaused = true; // Ñòàâèì êîíòåêñò íà ïàóçó
}
private void Handle_SetTemp(ExecutionContext ctx, ScriptCommand cmd)
{
int varAddress = GetParam(cmd, 0);
int value = GetParam(cmd, 1);
SetLocalVariable(ctx, varAddress, value);
ctx.ProgramCounter++;
cmd.executedStatus = 3;
}
private void Handle_CopyVar(ExecutionContext ctx, ScriptCommand cmd)
{
int srcAddress = GetParam(cmd, 0);
int dstAddress = GetParam(cmd, 1);
int value = GetLocalVariable(ctx, srcAddress);
SetLocalVariable(ctx, dstAddress, value);
ctx.ProgramCounter++;
cmd.executedStatus = 3;
}
private void Handle_GetVar(ExecutionContext ctx, ScriptCommand cmd)
{
int localVarAddress = GetParam(cmd, 0);
int globalVarAddress = GetParam(cmd, 1);
int value = App.GameState.GetGlobalVariable(globalVarAddress);
SetLocalVariable(ctx, localVarAddress, value);
ctx.ProgramCounter++;
cmd.executedStatus = 3;
}
private void Handle_VarTrue(ExecutionContext ctx, ScriptCommand cmd)
{
int globalVarAddress = GetParam(cmd, 0);
App.GameState.SetGlobalVariable(globalVarAddress, 1);
ctx.ProgramCounter++;
cmd.executedStatus = 3;
}
private void Handle_VarFlse(ExecutionContext ctx, ScriptCommand cmd)
{
int globalVarAddress = GetParam(cmd, 0);
App.GameState.SetGlobalVariable(globalVarAddress, 0);
ctx.ProgramCounter++;
cmd.executedStatus = 3;
}
private void Handle_VarSet(ExecutionContext ctx, ScriptCommand cmd)
{
int globalVarAddress = GetParam(cmd, 0);
int value = GetParam(cmd, 1);
App.GameState.SetGlobalVariable(globalVarAddress, value);
ctx.ProgramCounter++;
cmd.executedStatus = 3;
}
private void Handle_VarDec(ExecutionContext ctx, ScriptCommand cmd)
{
int globalVarAddress = GetParam(cmd, 0);
int currentValue = App.GameState.GetGlobalVariable(globalVarAddress);
App.GameState.SetGlobalVariable(globalVarAddress, currentValue - 1);
ctx.ProgramCounter++;
cmd.executedStatus = 3;
}
private void Handle_CtrlLock(ExecutionContext ctx, ScriptCommand cmd)
{
Debug.Log("Controls Locked");
App.GameState.IsPlayerControlLocked = true;
ctx.ProgramCounter++;
cmd.executedStatus = 3;
}
private void Handle_CtrUnlck(ExecutionContext ctx, ScriptCommand cmd)
{
Debug.Log("Controls Unlocked");
App.GameState.IsPlayerControlLocked = false;
if (_objectRegistry.TryGetValue(1, out GameObject playerObj))
{
ControlsController.Instance?.SetControlledObject(playerObj);
}
ctx.ProgramCounter++;
cmd.executedStatus = 3;
}
private void Handle_SetCamXY(ExecutionContext ctx, ScriptCommand cmd)
{
uint rot = (uint)GetParam(cmd, 0);
uint x = (uint)GetParam(cmd, 1);
uint y = (uint)GetParam(cmd, 2);
uint z = (uint)GetParam(cmd, 3);
App.CameraController.SetCamTargetXY(rot, x, y, z);
Debug.Log($"Camera position set {x}.{y}.{z}. Rot - {rot}");
ctx.ProgramCounter++;
cmd.executedStatus = 3;
}
private void Handle_TextShow(ExecutionContext ctx, ScriptCommand cmd)
{
int textOffset = GetParam(cmd, 0);
var textTokens = TextUtils.ParseText(_currentScript.TextData, textOffset);
// Ïåðåäàåì êîìàíäó â UI ìåíåäæåð
App.TextManager.ShowText(textTokens, cmd);
ctx.ProgramCounter++;
}
private void Handle_WindOpen(ExecutionContext ctx, ScriptCommand cmd)
{
App.UI.ShowMessageWindow();
ctx.ProgramCounter++;
cmd.executedStatus = 3;
}
private void Handle_WindClose(ExecutionContext ctx, ScriptCommand cmd)
{
App.UI.HideMessageWindow(ctx);
ctx.ProgramCounter++;
cmd.executedStatus = 3;
}
//CHARACTERS SECTION
private void Handle_CharLoad(ExecutionContext ctx, ScriptCommand cmd)
{
//Old PS1 method for loading sprite sheet in VRAM
//Now we simply creating disabled char model on scene
int modelId = GetParam(cmd, 0);
if (!_modelTempRegistry.ContainsKey(modelId))
{
GameObject model = App.ResourceManager.CharLoad(modelId);
_modelTempRegistry[modelId] = model;
}
ctx.ProgramCounter++;
cmd.executedStatus = 3;
}
private void Handle_CharInit(ExecutionContext ctx, ScriptCommand cmd)
{
// Ïàðàìåòðû: id, model_id, x, y, z, turn, dummy
int objectId = GetParam(cmd, 0);
int modelId = GetParam(cmd, 1);
uint posX = (uint)GetParam(cmd, 2);
uint posY = (uint)GetParam(cmd, 3);
uint posZ = (uint)GetParam(cmd, 4);
uint rotation = (uint)GetParam(cmd, 5);
int dummy = GetParam(cmd, 6); // Íåèñïîëüçóåìûé ïàðàìåòð
if (!_modelTempRegistry.TryGetValue(modelId, out GameObject templateModel))
{
Debug.LogWarning($"Model {modelId} not loaded, creating...");
templateModel = App.ResourceManager.CharLoad(modelId);
_modelTempRegistry[modelId] = templateModel;
}
if (_objectRegistry.TryGetValue(objectId, out GameObject existingModel))
{
Destroy(existingModel);
_objectRegistry.Remove(objectId);
}
GameObject characterInstance = App.ResourceManager.CharInit(templateModel, objectId, posX, posY, posZ, rotation);
_objectRegistry[objectId] = characterInstance;
ctx.ProgramCounter++;
cmd.executedStatus = 3;
}
// Activate player object at camera spot position and link controls
private void Handle_PlayerInit(ExecutionContext ctx, ScriptCommand cmd)
{
int rotation = GetParam(cmd, 0);
if (!_modelTempRegistry.TryGetValue(1, out GameObject templateModel))
{
Debug.LogWarning($"Player Model not loaded, creating...");
templateModel = App.ResourceManager.CharLoad(1);
_modelTempRegistry[1] = templateModel;
}
if (_objectRegistry.TryGetValue(1, out GameObject existingModel))
{
Destroy(existingModel);
_objectRegistry.Remove(1);
}
CameraController sceneCamera = App.CameraController;
GameObject character = App.ResourceManager.CharInit(templateModel, 1, sceneCamera.sourceX, sceneCamera.sourceY, sceneCamera.sourceZ, (uint)rotation);
_objectRegistry[1] = character;
ctx.ProgramCounter++;
cmd.executedStatus = 3;
}
private void Handle_CharGlowShow(ExecutionContext ctx, ScriptCommand cmd)
{
// Ïàðàìåòðû: id, x, y, z, glow, dummy
int charId = GetParam(cmd, 0);
uint posX = (uint)GetParam(cmd, 1);
uint posY = (uint)GetParam(cmd, 2);
uint posZ = (uint)GetParam(cmd, 3);
uint glow = (uint)GetParam(cmd, 4);
int dummy = GetParam(cmd, 5);
if (_objectRegistry.TryGetValue(charId, out GameObject characterObj))
{
App.ResourceManager.CharInit(characterObj, charId, posX, posY, posZ, glow); //TODO: Async GLOW
}
ctx.ProgramCounter++;
cmd.executedStatus = 3;
}
private void Handle_CharMoveTo(ExecutionContext ctx, ScriptCommand cmd)
{
int charId = GetParam(cmd, 0);
uint destX = (uint)GetParam(cmd, 1);
uint destZ = (uint)GetParam(cmd, 2);
uint endAction = (uint)GetParam(cmd, 3);
uint speed = (uint)GetParam(cmd, 4);
if (_objectRegistry.TryGetValue(charId, out GameObject characterObj) && characterObj is GameObject character)
{
var controller = character.GetComponent<CharacterController>();
if (controller != null)
{
//async move
controller.MoveToGameCoordinates(destX, destZ, endAction, speed);
}
}
ctx.ProgramCounter++;
cmd.executedStatus = 3;
}
private void Handle_CharAnimate(ExecutionContext ctx, ScriptCommand cmd)
{
int charId = GetParam(cmd, 0);
uint animationId = (uint)GetParam(cmd, 1);
uint repeatNum = (uint)GetParam(cmd, 2);
if (_objectRegistry.TryGetValue(charId, out GameObject characterObj) && characterObj is GameObject character)
{
var controller = character.GetComponent<CharacterController>();
if (controller != null)
{
controller.PlayAnimation((int)animationId, (int)Mathf.Max(1, repeatNum));
}
}
ctx.ProgramCounter++;
cmd.executedStatus = 3;
}
private void Handle_CharAnimate2(ExecutionContext ctx, ScriptCommand cmd)
{
Handle_CharAnimate(ctx, cmd);
}
private void Handle_WaitCharAnimEnd(ExecutionContext ctx, ScriptCommand cmd)
{
int charId = GetParam(cmd, 0);
if (_objectRegistry.TryGetValue(charId, out GameObject characterObj) && characterObj is GameObject character)
{
var controller = character.GetComponent<CharacterController>();
if (controller != null && !controller.IsMoving)
{
ctx.ProgramCounter++;
cmd.executedStatus = 3;
}
}
else
{
ctx.ProgramCounter++;
cmd.executedStatus = 3;
}
}
private void Handle_CharSetSubroutine(ExecutionContext ctx, ScriptCommand cmd)
{
int charId = GetParam(cmd, 0);
int subId = GetParam(cmd, 1);
_objectRegistry.TryGetValue(charId, out GameObject characterObj);
characterObj.GetComponent<CharacterController>().blockSubroutine = subId;
Debug.Log($"Sub {subId} set to char {charId}");
ctx.ProgramCounter++;
cmd.executedStatus = 3;
}
// SCENERY LOADERS
private void Handle_CityLoad(ExecutionContext ctx, ScriptCommand cmd)
{
int districtId = GetParam(cmd, 0);
int y = GetParam(cmd, 1);
int x = GetParam(cmd, 2);
App.SceneLoader.LoadCity(districtId, y, x);
_mainContext = null; // Çàâåðøàåì òåêóùèé ñêðèïò
}
private void Handle_BattleLoad(ExecutionContext ctx, ScriptCommand cmd)
{
int battleId = GetParam(cmd, 0);
App.SceneLoader.LoadBattle(battleId);
_mainContext = null; // Çàâåðøàåì òåêóùèé ñêðèïò
}
private void Handle_DungLoad(ExecutionContext ctx, ScriptCommand cmd)
{
int dungeonId = GetParam(cmd, 0);
App.SceneLoader.LoadDungeon(dungeonId);
_mainContext = null; // Çàâåðøàåì òåêóùèé ñêðèïò
}
private void Handle_EventLoad(ExecutionContext ctx, ScriptCommand cmd)
{
int hzId = GetParam(cmd, 0);
int eventId = GetParam(cmd, 1);
App.SceneLoader.LoadEvent(eventId, hzId);
_mainContext = null; // Çàâåðøàåì òåêóùèé ñêðèïò
}
private void Handle_VideoPly(ExecutionContext ctx, ScriptCommand cmd)
{
int videoId = GetParam(cmd, 0);
App.VideoPlayer.PlayVideo(videoId, cmd);
PauseContext(cmd);
}
private void Handle_ScrnFade(ExecutionContext ctx, ScriptCommand cmd)
{
int fadeType = GetParam(cmd, 0);
int duration = GetParam(cmd, 1);
//App.UI.ScreenFade(fadeType, duration, () => {
// ctx.ProgramCounter++;
//});
ctx.ProgramCounter++;
}
public void PauseContext(ScriptCommand cmd)
{
// Íàõîäèì êîíòåêñò, êîòîðûé âûïîëíÿåò ýòó êîìàíäó
if (_mainContext != null && GetCurrentCommand(_mainContext) == cmd)
{
_mainContext.IsPaused = true;
return;
}
foreach (var context in _activeSubroutines.Values)
{
if (GetCurrentCommand(context) == cmd)
{
context.IsPaused = true;
return;
}
}
}
public void ResumeContext(ScriptCommand cmd)
{
// Íàõîäèì êîíòåêñò è ñíèìàåì ïàóçó
if (_mainContext != null && GetCurrentCommand(_mainContext) == cmd)
{
_mainContext.IsPaused = false;
_mainContext.ProgramCounter++; // Ïåðåõîäèì ê ñëåäóþùåé êîìàíäå
return;
}
foreach (var context in _activeSubroutines.Values)
{
if (GetCurrentCommand(context) == cmd)
{
context.IsPaused = false;
context.ProgramCounter++; // Ïåðåõîäèì ê ñëåäóþùåé êîìàíäå
return;
}
}
}
// ========== ÂÑÏÎÌÎÃÀÒÅËÜÍÛÅ ÌÅÒÎÄÛ ==========
private ScriptCommand GetCurrentCommand(ExecutionContext ctx)
{
if (ctx.ProgramCounter < _currentScript.Commands.Count)
return _currentScript.Commands[(int)ctx.ProgramCounter];
return null;
}
private int GetParam(ScriptCommand cmd, int index)
{
return index < cmd.Params.Length ? cmd.Params[index] : 0;
}
private int GetLocalVariable(ExecutionContext ctx, int address)
{
return ctx.LocalVariables.TryGetValue(address, out int value) ? value : 0;
}
private void SetLocalVariable(ExecutionContext ctx, int address, int value)
{
ctx.LocalVariables[address] = value;
}
public void SetSelectionVariable(int value) //external after selection variable set
{
selectionVariable = value;
}
public void MarkCommandCompleted(ScriptCommand cmd)
{
cmd.executedStatus = 3;
ResumeContext(cmd);
}
private void MarkCurrentCommandCompleted(ExecutionContext ctx)
{
if (ctx.ProgramCounter > 0 && ctx.ProgramCounter - 1 < _currentScript.Commands.Count)
{
ScriptCommand cmd = _currentScript.Commands[(int)(ctx.ProgramCounter - 1)];
cmd.executedStatus = 3;
}
}
}
public class ExecutionContext
{
public ScriptCommand ExecutedByCmd { get; set; }
public string ContextName { get; set; }
public uint ProgramCounter { get; set; }
public Dictionary<int, int> LocalVariables { get; set; }
public bool IsWaiting { get; set; }
public bool IsPaused { get; set; }
public bool IsFinished { get; set; }
public float PauseTimeRemaining { get; set; }
public ExecutionContext(uint startAddress, string name, ScriptCommand cmd)
{
ContextName = name;
ExecutedByCmd = cmd;
ProgramCounter = startAddress;
LocalVariables = new Dictionary<int, int>();
PauseTimeRemaining = 0;
}
}