/// <summary> /// Ends a thread on the ScriptMachine. /// </summary> /// <param name="Args">A ScriptArguments instance.</param> public static void EndThread(ref ScriptArguments Args) { SCMThread Thread = Args.GetThread(); Thread.WakeCounter = -1; Thread.Finished = true; }
/// <summary> /// Starts a new thread on the ScriptMachine. /// </summary> /// <param name="Args">A ScriptArguments instance.</param> public static void StartThread(ref ScriptArguments Args) { Args.GetVM().StartThread((uint)Args.GetIntParameter(0), false); var Threads = Args.GetVM().GetThreads(); SCMThread Thread = Threads[Threads.Count - 1]; var Locals = Thread.Locals.ToArray(); // Copy arguments to locals for (var i = 1u; i < Args.GetParameters().Count; ++i) { if (Args[i].Type == SCMType.EndOfArgList) { break; } /**reinterpret_cast<ScriptInt*>(Thread.Locals.ToArray() + * sizeof(int) * (i - 1)) = args[i].integerValue();*/ byte[] SrcInt = BitConverter.GetBytes(Args[i].IntegerValue()); Array.Copy(SrcInt, 0, Locals, sizeof(int) * (i - 1), SrcInt.Length - 1); Thread.Locals.AddRange(Locals); } }
/// <summary> /// Starts a thread on this ScriptMachine instance. /// </summary> /// <param name="StartAddress">The address to start executing from.</param> /// <param name="Mission">Is this a mission thread?</param> public void StartThread(uint StartAddress, bool Mission) { SCMThread Thread = new SCMThread(); for (int i = 0; i < SCM_THREAD_LOCAL_SIZE * SCM_VARIABLE_SIZE; ++i) { Thread.Locals[i] = (char)0; } Thread.Name = "THREAD"; Thread.ConditionResult = false; Thread.ConditionCount = 0; Thread.ConditionAND = false; Thread.ProgramCounter = StartAddress; Thread.BaseAddress = StartAddress; /* Indicates where negative jumps should jump from */ Thread.WakeCounter = 0; Thread.IsMission = Mission; Thread.Finished = false; Thread.StackDepth = 0; Thread.DeathOrArrestCheck = true; Thread.WastedOrBusted = false; Thread.AllowWaitSkip = false; activeThreads.Add(Thread); }
public ScriptArguments(List <SCMOpcodeParameter> P, SCMThread T, ScriptMachine M) { parameters = P; thread = T; machine = M; }
private void ExecuteThread(SCMThread Thread, int MSPassed) { ///TODO: Fully implement this. /*auto player = state->world->getPlayer(); * * if (player) * {*/ if (Thread.IsMission && Thread.DeathOrArrestCheck /*&& * (player->isWasted() || player->isBusted())*/) { Thread.WastedOrBusted = true; Thread.StackDepth = 0; Thread.ProgramCounter = Thread.Calls[(int)Thread.StackDepth]; } //} // There is 02a1 opcode that is used only during "Kingdom Come", which // basically acts like a wait command, but waiting time can be skipped // by pressing 'X'? PS2 button if (Thread.AllowWaitSkip /*&& getState()->input[0].pressed(GameInputState::Jump)*/) { Thread.WakeCounter = 0; Thread.AllowWaitSkip = false; } if (Thread.WakeCounter > 0) { Thread.WakeCounter = Math.Max(Thread.WakeCounter - MSPassed, 0); } if (Thread.WakeCounter > 0) { return; } while (Thread.WakeCounter == 0) { var PC = Thread.ProgramCounter; var Opcode = file.Read <ushort>(PC); bool IsNegatedConditional = ((Opcode & SCM_NEGATE_CONDITIONAL_MASK) == SCM_NEGATE_CONDITIONAL_MASK); Opcode = (ushort)(Opcode & ~SCM_NEGATE_CONDITIONAL_MASK); ScriptFunctionMeta FoundCode; if (!module.FindOpcode(Opcode, out FoundCode)) { throw new IllegalInstruction <Exception>(Opcode, PC, Thread.Name); } ScriptFunctionMeta Code = FoundCode; PC += sizeof(ushort); List <SCMOpcodeParameter> Parameters = new List <SCMOpcodeParameter>(); bool HasExtraParameters = Code.Arguments < 0; var RequiredParams = Math.Abs(Code.Arguments); for (int p = 0; p < RequiredParams || HasExtraParameters; ++p) { //byte was originally SCMByte ... might have to change to char. var type_r = file.Read <byte>(PC); var type = (SCMType)type_r; if (type_r > 42) { // for implicit strings, we need the byte we just read. type = SCMType.TString; } else { PC += sizeof(byte); } //TODO: Is this correct? //Parameters.push_back(SCMOpcodeParameter{ type, { 0} }); Parameters.Add(new SCMOpcodeParameter(type)); switch (type) { case SCMType.EndOfArgList: HasExtraParameters = false; break; case SCMType.TInt8: lock (Parameters) //Thread safety { SCMOpcodeParameter Param = Parameters.LastOrDefault(); Param.Integer = file.Read <byte>(PC); Parameters[Parameters.Count - 1] = Param; } PC += sizeof(byte); break; case SCMType.TInt16: lock (Parameters) //Thread safety { SCMOpcodeParameter Param = Parameters.LastOrDefault(); Param.Integer = file.Read <short>(PC); Parameters[Parameters.Count - 1] = Param; } PC += sizeof(byte) * 2; break; case SCMType.TGlobal: { var v = file.Read <ushort>(PC); lock (Parameters) //Thread safety { SCMOpcodeParameter Param = Parameters.LastOrDefault(); //TODO: This was originally GlobalData.data() + v... Param.GlobalPtr = (IntPtr)globalData.ToArray().Length + v * SCM_VARIABLE_SIZE; Parameters[Parameters.Count - 1] = Param; } if (v >= file.GlobalsSize) { Debug.WriteLine("ERROR: ScriptMachine.cs: Global out of bounds! " + v.ToString() + " " + file.GlobalsSize.ToString()); } PC += sizeof(byte) * 2; } break; case SCMType.TLocal: { var v = file.Read <ushort>(PC); lock (Parameters) { SCMOpcodeParameter Param = Parameters.LastOrDefault(); //Not sure if this is correct, was originally Locals.data() + v... Param.GlobalPtr = (IntPtr)Thread.Locals.ToArray().Length + v * SCM_VARIABLE_SIZE; Parameters[Parameters.Count - 1] = Param; } if (v >= SCM_THREAD_LOCAL_SIZE) { Debug.WriteLine("Scriptmachine.CS: Local out of bounds!"); } PC += sizeof(byte) * 2; } break; case SCMType.TInt32: lock (Parameters) //Thread safety { SCMOpcodeParameter Param = Parameters.LastOrDefault(); Param.Integer = file.Read <int>(PC); Parameters[Parameters.Count - 1] = Param; } PC += sizeof(byte) * 4; break; case SCMType.TString: lock (Parameters) //Thread safety { SCMOpcodeParameter Param = Parameters.LastOrDefault(); char[] Str = Param.Str.ToArray(); //Copy a string from the file data to the string. Array.Copy(file.Data.ToArray(), (int)PC, Str, 0, 8); Param.Str = new string(Str); Parameters[Parameters.Count - 1] = Param; } PC += sizeof(byte) * 8; break; case SCMType.TFloat16: lock (Parameters) //Thread safety { SCMOpcodeParameter Param = Parameters.LastOrDefault(); Param.Real = file.Read <short>(PC) / 16f; Parameters[Parameters.Count - 1] = Param; } PC += sizeof(byte) * 2; break; default: throw new UnknownType <Exception>((char)type, PC, Thread.Name); } ; ScriptArguments Sca = new ScriptArguments(Parameters, Thread, this);