Slight refractor

- Bumped unit tests to .NET 8
This commit is contained in:
Tony Bark 2025-02-18 08:17:56 -05:00
parent 3e3958c67f
commit e7184729df
19 changed files with 617 additions and 614 deletions

View file

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
@ -9,18 +9,19 @@
<RootNamespace>SimAntics.Tests</RootNamespace> <RootNamespace>SimAntics.Tests</RootNamespace>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" /> <ItemGroup>
<PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1"> <PackageReference Include="xunit" Version="2.4.1" />
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> <PrivateAssets>all</PrivateAssets>
<PackageReference Include="coverlet.collector" Version="1.2.1"> </PackageReference>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <PackageReference Include="coverlet.collector" Version="1.3.0">
<PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> <PrivateAssets>all</PrivateAssets>
</ItemGroup> </PackageReference>
</ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\SimAI\SimAI.csproj" /> <ProjectReference Include="..\SimAI\SimAI.csproj" />

View file

@ -1,16 +1,17 @@
using System.Diagnostics; using System.Diagnostics;
using SimAI;
using Xunit; using Xunit;
namespace SimAI.Tests; namespace SimAntics.Tests;
public class VMClockTest public class VMClockTest
{ {
[Fact] [Fact]
public void TickTest() public void TickTest()
{ {
var clock = new VMClock(); var clock = new VMClock();
Debug.WriteLine(clock.Ticks); Debug.WriteLine(clock.Ticks);
clock.Tick(); clock.Tick();
Debug.WriteLine(clock.Ticks); Debug.WriteLine(clock.Ticks);
} }
} }

View file

@ -5,7 +5,7 @@ namespace SimAI.Tests;
public class VMTest public class VMTest
{ {
public VMTest() public VMTest()
{ {
} }
} }

View file

@ -1,16 +1,16 @@
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. // This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at // If a copy of the MPL was not distributed with this file, You can obtain one at
// http://mozilla.org/MPL/2.0/. // http://mozilla.org/MPL/2.0/.
namespace SimAI; namespace SimAntics;
public enum Direction public enum Direction
{ {
NORTH, NORTH,
NORTHEAST, NORTHEAST,
EAST, EAST,
SOUTHEAST, SOUTHEAST,
SOUTH, SOUTH,
SOUTHWEST, SOUTHWEST,
WEST, WEST,
NORTHWEST NORTHWEST
} }

View file

@ -1,132 +1,130 @@
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. // This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at // If a copy of the MPL was not distributed with this file, You can obtain one at
// http://mozilla.org/MPL/2.0/. // http://mozilla.org/MPL/2.0/.
using SimAI;
namespace SimAntics.Engine.Entities; namespace SimAntics.Engine.Entities;
public class VMEntityRTTI public class VMEntityRTTI
{ {
public string[]? AttributeLabels; public string[]? AttributeLabels;
} }
public abstract class VMEntity public abstract class VMEntity
{ {
public static bool UseWorld = true; public static bool UseWorld = true;
public VMEntityRTTI? RTTI; public VMEntityRTTI? RTTI;
public bool GhostImage; public bool GhostImage;
public short ObjectID; public short ObjectID;
public uint PersistID; public uint PersistID;
public short[]? ObjectData; public short[]? ObjectData;
public LinkedList<short> MyList = new(); public LinkedList<short> MyList = new();
// public List<VMSoundEntry> SoundThreads; // public List<VMSoundEntry> SoundThreads;
// public VMRuntimeHeadline Headline; // public VMRuntimeHeadline Headline;
/// <summary> /// <summary>
/// IS NOT serialized, but rather regenerated on deserialize. /// IS NOT serialized, but rather regenerated on deserialize.
/// </summary> /// </summary>
// public VMHeadlineRenderer HeadlineRenderer; // public VMHeadlineRenderer HeadlineRenderer;
// public GameObject Object; // public GameObject Object;
public VMThread? Thread; public VMThread? Thread;
// public VMMultitileGroup MultitileGroup; // public VMMultitileGroup MultitileGroup;
public short MainParam; //parameters passed to main on creation. public short MainParam; //parameters passed to main on creation.
public short MainStackOBJ; public short MainStackOBJ;
public VMEntity[] Contained = new VMEntity[0]; public VMEntity[] Contained = new VMEntity[0];
public VMEntity? Container; public VMEntity? Container;
public short ContainerSlot; public short ContainerSlot;
/// <summary> /// <summary>
/// set when the entity is removed, threads owned by this object or with this object as callee will be cancelled/have their stack emptied /// set when the entity is removed, threads owned by this object or with this object as callee will be cancelled/have their stack emptied
/// </summary> /// </summary>
public bool Dead; public bool Dead;
/** Relationship variables **/ /** Relationship variables **/
public Dictionary<ushort, List<short>>? MeToObject; public Dictionary<ushort, List<short>>? MeToObject;
public Dictionary<uint, List<short>>? MeToPersist; public Dictionary<uint, List<short>>? MeToPersist;
//a runtime cache for objects that have relationships to us. Used to get a quick reference to objects //a runtime cache for objects that have relationships to us. Used to get a quick reference to objects
//that may need to delete a relationship to us. //that may need to delete a relationship to us.
//note this can point to false positives, but the worst case is a slow deletion if somehow every object is added. //note this can point to false positives, but the worst case is a slow deletion if somehow every object is added.
public HashSet<ushort> MayHaveRelToMe = new(); public HashSet<ushort> MayHaveRelToMe = new();
//signals which relationships have changed since the last time this was reset //signals which relationships have changed since the last time this was reset
//used to partial update relationships when doing an avatar save to db //used to partial update relationships when doing an avatar save to db
public HashSet<uint> ChangedRels = new(); public HashSet<uint> ChangedRels = new();
public ulong DynamicSpriteFlags; /** Used to show/hide dynamic sprites **/ public ulong DynamicSpriteFlags; /** Used to show/hide dynamic sprites **/
public ulong DynamicSpriteFlags2; public ulong DynamicSpriteFlags2;
//public VMObstacle Footprint; //public VMObstacle Footprint;
//LotTilePos _Position = new LotTilePos(LotTilePos.OUT_OF_WORLD); //LotTilePos _Position = new LotTilePos(LotTilePos.OUT_OF_WORLD);
//public EntityComponent WorldUI; //public EntityComponent WorldUI;
public uint TimestampLockoutCount = 0; public uint TimestampLockoutCount = 0;
//public Color LightColor = Color.White; //public Color LightColor = Color.White;
//inferred properties (from object resource) //inferred properties (from object resource)
//public GameGlobalResource SemiGlobal; //public GameGlobalResource SemiGlobal;
//public TTAB TreeTable; //public TTAB TreeTable;
//public TTAs TreeTableStrings; //public TTAs TreeTableStrings;
//public Dictionary<string, VMTreeByNameTableEntry> TreeByName; //public Dictionary<string, VMTreeByNameTableEntry> TreeByName;
//public SLOT Slots; //public SLOT Slots;
//public OBJD MasterDefinition; //if this object is multitile, its master definition will be stored here. //public OBJD MasterDefinition; //if this object is multitile, its master definition will be stored here.
//public OBJfFunctionEntry[] EntryPoints; /** Entry points for specific events, eg. init, main, clean... **/ //public OBJfFunctionEntry[] EntryPoints; /** Entry points for specific events, eg. init, main, clean... **/
//public virtual bool MovesOften //public virtual bool MovesOften
//{ //{
// get // get
// { // {
// if (Container != null) return true; // if (Container != null) return true;
// if (Slots == null) return false; // if (Slots == null) return false;
// if (!Slots.Slots.ContainsKey(3)) return false; // if (!Slots.Slots.ContainsKey(3)) return false;
// var slots = Slots.Slots[3]; // var slots = Slots.Slots[3];
// return (slots.Count > 7); // return (slots.Count > 7);
// } // }
//} //}
//public string Name //public string Name
//{ //{
// get // get
// { // {
// if (MultitileGroup.Name != "") return MultitileGroup.Name; // if (MultitileGroup.Name != "") return MultitileGroup.Name;
// else return this.ToString(); // else return this.ToString();
// } // }
// set // set
// { // {
// MultitileGroup.Name = value; // MultitileGroup.Name = value;
// } // }
//} //}
//bool DynamicMultitile //bool DynamicMultitile
//{ //{
// get // get
// { // {
// return EntryPoints[8].ActionFunction >= 256; // return EntryPoints[8].ActionFunction >= 256;
// } // }
//} //}
//public override string ToString() //public override string ToString()
//{ //{
// if (MultitileGroup.Name != "") return MultitileGroup.Name; // if (MultitileGroup.Name != "") return MultitileGroup.Name;
// var strings = Object.Resource.Get<CTSS>(Object.OBJ.CatalogStringsID); // var strings = Object.Resource.Get<CTSS>(Object.OBJ.CatalogStringsID);
// if (strings != null) // if (strings != null)
// { // {
// return strings.GetString(0); // return strings.GetString(0);
// } // }
// var label = Object.OBJ.ChunkLabel; // var label = Object.OBJ.ChunkLabel;
// if (label != null && label.Length > 0) // if (label != null && label.Length > 0)
// { // {
// return label; // return label;
// } // }
// return Object.OBJ.GUID.ToString("X"); // return Object.OBJ.GUID.ToString("X");
//} //}
//positioning properties //positioning properties
protected static Direction[] DirectionNotches = new Direction[] protected static Direction[] DirectionNotches = new Direction[]
{ {
Direction.NORTH, Direction.NORTH,
Direction.NORTHEAST, Direction.NORTHEAST,
Direction.EAST, Direction.EAST,
@ -135,23 +133,23 @@ public abstract class VMEntity
Direction.SOUTHWEST, Direction.SOUTHWEST,
Direction.WEST, Direction.WEST,
Direction.NORTHWEST Direction.NORTHWEST
}; };
//public LotTilePos Position //public LotTilePos Position
//{ //{
// get { return _Position; } // get { return _Position; }
// set // set
// { // {
// _Position = value; // _Position = value;
// if (UseWorld) WorldUI.Level = Position.Level; // if (UseWorld) WorldUI.Level = Position.Level;
// if (this is VMAvatar) ((VMAvatar)this).VisualPositionStart = null; // if (this is VMAvatar) ((VMAvatar)this).VisualPositionStart = null;
// VisualPosition = new Vector3(_Position.x / 16.0f, _Position.y / 16.0f, (_Position.Level - 1) * 2.95f); // VisualPosition = new Vector3(_Position.x / 16.0f, _Position.y / 16.0f, (_Position.Level - 1) * 2.95f);
// } // }
// } // }
// public abstract Vector3 VisualPosition { get; set; } // public abstract Vector3 VisualPosition { get; set; }
public abstract Direction Direction { get; set; } public abstract Direction Direction { get; set; }
public abstract float RadianDirection { get; set; } public abstract float RadianDirection { get; set; }
} }

View file

@ -1,11 +1,11 @@
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. // This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at // If a copy of the MPL was not distributed with this file, You can obtain one at
// http://mozilla.org/MPL/2.0/. // http://mozilla.org/MPL/2.0/.
namespace SimAI.Engine; namespace SimAntics.Engine;
public class VMMemory public class VMMemory
{ {
public VMMemory() public VMMemory()
{ {
} }
} }

View file

@ -3,25 +3,25 @@
// http://mozilla.org/MPL/2.0/. // http://mozilla.org/MPL/2.0/.
using SimAntics.Engine.Entities; using SimAntics.Engine.Entities;
namespace SimAI.Engine; namespace SimAntics.Engine;
public class VMScheduler public class VMScheduler
{ {
VM VM { get; set; } VM VM { get; set; }
Dictionary<uint, List<VMEntity>> _tickScheduler = new(); Dictionary<uint, List<VMEntity>> _tickScheduler = new();
List<VMEntity> _tickThisFrame; List<VMEntity> _tickThisFrame;
public HashSet<VMEntity> PendingDeletion { get; set; } = new HashSet<VMEntity>(); public HashSet<VMEntity> PendingDeletion { get; set; } = new HashSet<VMEntity>();
public uint CurrentTickID { get; set; } public uint CurrentTickID { get; set; }
public short CurrentObjectID { get; set; } public short CurrentObjectID { get; set; }
public bool RunningNow { get; set; } public bool RunningNow { get; set; }
public VMScheduler(VM vm) => VM = vm; public VMScheduler(VM vm) => VM = vm;
public void ScheduleTickIn(VMEntity _ent, uint delay) public void ScheduleTickIn(VMEntity _ent, uint delay)
{ {
} }
} }

View file

@ -3,171 +3,172 @@
// http://mozilla.org/MPL/2.0/. // http://mozilla.org/MPL/2.0/.
using SimAntics.Engine.Entities; using SimAntics.Engine.Entities;
using SimAntics.Marshals;
namespace SimAI.Engine; namespace SimAntics.Engine;
/// <summary> /// <summary>
/// Holds information about the execution of a routine /// Holds information about the execution of a routine
/// </summary> /// </summary>
public class VMStackFrame public class VMStackFrame
{ {
public VMStackFrame() { } public VMStackFrame() { }
/** Thread executing this routine **/ /** Thread executing this routine **/
public VMThread Thread; public VMThread Thread;
/** Routine that this context relates to **/ /** Routine that this context relates to **/
// public VMRoutine Routine; // public VMRoutine Routine;
/** Current instruction **/ /** Current instruction **/
public ushort InstructionPointer; public ushort InstructionPointer;
/** The object who executed this behavior **/ /** The object who executed this behavior **/
public VMEntity Caller; public VMEntity Caller;
/** The object the code is running on **/ /** The object the code is running on **/
public VMEntity Callee; public VMEntity Callee;
/** An object selected by the code to perform operations on. **/ /** An object selected by the code to perform operations on. **/
public VMEntity StackObject public VMEntity StackObject
{ {
get { return _StackObject; } get { return _StackObject; }
set set
{ {
_StackObject = value; _StackObject = value;
_StackObjectID = value?.ObjectID ?? 0; _StackObjectID = value?.ObjectID ?? 0;
} }
} }
public short StackObjectID public short StackObjectID
{ {
get { return _StackObjectID; } get { return _StackObjectID; }
set set
{ {
_StackObjectID = value; _StackObjectID = value;
_StackObject = VM.GetObjectById(value); _StackObject = VM.GetObjectById(value);
} }
} }
VMEntity _StackObject; VMEntity _StackObject;
public short _StackObjectID; public short _StackObjectID;
/** If true, this stack frame is not a subroutine. Return with a continue. **/ /** If true, this stack frame is not a subroutine. Return with a continue. **/
public bool DiscardResult; public bool DiscardResult;
/** Indicates that the current stack frame is part of an action tree. /** Indicates that the current stack frame is part of an action tree.
** Set by "idle for input, allow push", when an interaction is selected. ** Set by "idle for input, allow push", when an interaction is selected.
** Used to stop recursive interactions, is only false when within "main". ** Used to stop recursive interactions, is only false when within "main".
**/ **/
public bool ActionTree; public bool ActionTree;
/** Used to get strings and other resources (for primitives) from the code owner, as it may not be the callee but instead a semiglobal or global. **/ /** Used to get strings and other resources (for primitives) from the code owner, as it may not be the callee but instead a semiglobal or global. **/
//public GameIffResource ScopeResource //public GameIffResource ScopeResource
//{ //{
// get // get
// { // {
// return CodeOwner.Resource; // return CodeOwner.Resource;
// } // }
//} //}
//public GameObject CodeOwner; //public GameObject CodeOwner;
/** /**
* Routine locals * Routine locals
*/ */
public short[] Locals; public short[] Locals;
/** /**
* Arguments * Arguments
*/ */
public short[] Args; public short[] Args;
//public GameObjectResource CallerPrivate //public GameObjectResource CallerPrivate
//{ //{
// get // get
// { // {
// return Caller.Object.Resource; // return Caller.Object.Resource;
// } // }
//} //}
//public GameObjectResource CalleePrivate //public GameObjectResource CalleePrivate
//{ //{
// get // get
// { // {
// return Callee.Object.Resource; // return Callee.Object.Resource;
// } // }
//} //}
//public GameObjectResource StackObjPrivate //public GameObjectResource StackObjPrivate
//{ //{
// get // get
// { // {
// return StackObject.Object.Resource; // return StackObject.Object.Resource;
// } // }
//} //}
//public GameGlobal Global //public GameGlobal Global
//{ //{
// get // get
// { // {
// return Thread.Context.Globals; // return Thread.Context.Globals;
// } // }
//} //}
public VM VM public VM VM
{ {
get get
{ {
return Thread.Context.VM; return Thread.Context.VM;
} }
} }
/** Utilities **/ /** Utilities **/
//public VMInstruction GetCurrentInstruction() //public VMInstruction GetCurrentInstruction()
//{ //{
// return Routine.Instructions[InstructionPointer]; // return Routine.Instructions[InstructionPointer];
//} //}
//public T GetCurrentOperand<T>() //public T GetCurrentOperand<T>()
//{ //{
// return (T)GetCurrentInstruction().Operand; // return (T)GetCurrentInstruction().Operand;
//} //}
#region VM Marshalling Functions #region VM Marshalling Functions
//public virtual VMStackFrameMarshal Save() //public virtual VMStackFrameMarshal Save()
//{ //{
// return new VMStackFrameMarshal // return new VMStackFrameMarshal
// { // {
// RoutineID = Routine?.ID ?? 0, // RoutineID = Routine?.ID ?? 0,
// InstructionPointer = InstructionPointer, // InstructionPointer = InstructionPointer,
// Caller = (Caller == null) ? (short)0 : Caller.ObjectID, // Caller = (Caller == null) ? (short)0 : Caller.ObjectID,
// Callee = (Callee == null) ? (short)0 : Callee.ObjectID, // Callee = (Callee == null) ? (short)0 : Callee.ObjectID,
// StackObject = StackObjectID, // StackObject = StackObjectID,
// CodeOwnerGUID = CodeOwner.OBJ.GUID, // CodeOwnerGUID = CodeOwner.OBJ.GUID,
// Locals = (short[])Locals?.Clone(), // Locals = (short[])Locals?.Clone(),
// Args = (short[])Args?.Clone(), // Args = (short[])Args?.Clone(),
// DiscardResult = DiscardResult, // DiscardResult = DiscardResult,
// ActionTree = ActionTree, // ActionTree = ActionTree,
// }; // };
//} //}
public virtual void Load(VMStackFrameMarshal input, VMContext context) public virtual void Load(VMStackFrameMarshal input, VMContext context)
{ {
// CodeOwner = GameContent.Get.WorldObjects.Get(input.CodeOwnerGUID); // CodeOwner = GameContent.Get.WorldObjects.Get(input.CodeOwnerGUID);
// Routine = null; // Routine = null;
//if (input.RoutineID >= 8192) Routine = (VMRoutine)ScopeResource.SemiGlobal.GetRoutine(input.RoutineID); //if (input.RoutineID >= 8192) Routine = (VMRoutine)ScopeResource.SemiGlobal.GetRoutine(input.RoutineID);
//else if (input.RoutineID >= 4096) Routine = (VMRoutine)ScopeResource.GetRoutine(input.RoutineID); //else if (input.RoutineID >= 4096) Routine = (VMRoutine)ScopeResource.GetRoutine(input.RoutineID);
//else Routine = (VMRoutine)Global.Resource.GetRoutine(input.RoutineID); //else Routine = (VMRoutine)Global.Resource.GetRoutine(input.RoutineID);
InstructionPointer = input.InstructionPointer; InstructionPointer = input.InstructionPointer;
Caller = context.VM.GetObjectById(input.Caller); Caller = context.VM.GetObjectById(input.Caller);
Callee = context.VM.GetObjectById(input.Callee); Callee = context.VM.GetObjectById(input.Callee);
StackObjectID = input.StackObject; StackObjectID = input.StackObject;
Locals = input.Locals; Locals = input.Locals;
Args = input.Args; Args = input.Args;
DiscardResult = input.DiscardResult; DiscardResult = input.DiscardResult;
ActionTree = input.ActionTree; ActionTree = input.ActionTree;
} }
public VMStackFrame(VMStackFrameMarshal input, VMContext context, VMThread thread) => Thread = thread;// Load(input, context); public VMStackFrame(VMStackFrameMarshal input, VMContext context, VMThread thread) => Thread = thread;// Load(input, context);
#endregion #endregion
} }

View file

@ -5,9 +5,7 @@
#define IDE_COMPAT #define IDE_COMPAT
#endif #endif
using SimAntics.Engine.Entities; namespace SimAntics.Engine;
namespace SimAI.Engine;
/// <summary> /// <summary>
/// Compatibility class /// Compatibility class
@ -19,36 +17,36 @@ public class VMThread : VMInstruction { }
/// </summary> /// </summary>
public class VMInstruction public class VMInstruction
{ {
public static int MAX_USER_ACTIONS = 20; public static int MAX_USER_ACTIONS = 20;
public VMContext? Context; public VMContext? Context;
//check tree only vars //check tree only vars
public bool IsCheck; public bool IsCheck;
VMEntity? Entity; VMEntity? Entity;
public List<VMStackFrame>? Stack; public List<VMStackFrame>? Stack;
bool ContinueExecution; bool ContinueExecution;
public string? ThreadBreakString; public string? ThreadBreakString;
public int BreakFrame; //frame the last breakpoint was performed on public int BreakFrame; //frame the last breakpoint was performed on
public bool RoutineDirty; public bool RoutineDirty;
public bool Interrupt; public bool Interrupt;
ushort ActionUID; ushort ActionUID;
// Exception handling variables // Exception handling variables
// Don't need to be serialized. // Don't need to be serialized.
public int DialogCooldown = 0; public int DialogCooldown = 0;
// the number of ticks that have executed so far this frame. If this exceeds the allowed max, // the number of ticks that have executed so far this frame. If this exceeds the allowed max,
// the thread resets, and a SimAI Error pops up. // the thread resets, and a SimAI Error pops up.
public int TicksThisFrame = 0; public int TicksThisFrame = 0;
// the maximum number of primitives a thread can execute in one frame. Tweak appropriately. // the maximum number of primitives a thread can execute in one frame. Tweak appropriately.
// variables for internal scheduler // variables for internal scheduler
public uint ScheduleIdleStart; // keep track of tick when we started idling for an object. must be synced! public uint ScheduleIdleStart; // keep track of tick when we started idling for an object. must be synced!
public uint ScheduleIdleEnd; public uint ScheduleIdleEnd;
} }

View file

@ -1,2 +1,3 @@
global using SimAI.Engine; global using SimAntics.Engine;
global using SimAI.Marshals; global using SimAntics.Marshals;
global using SimAntics.Engine.Entities;

View file

@ -1,13 +1,13 @@
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. // This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at // If a copy of the MPL was not distributed with this file, You can obtain one at
// http://mozilla.org/MPL/2.0/. // http://mozilla.org/MPL/2.0/.
namespace SimAI; namespace SimAntics;
public interface IVM public interface IVM
{ {
void Init(); void Init();
void Reset(); void Reset();
void Update(); void Update();
void Tick(); void Tick();
void InternalTick(uint tickId); void InternalTick(uint tickId);
} }

View file

@ -1,9 +1,9 @@
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. // This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at // If a copy of the MPL was not distributed with this file, You can obtain one at
// http://mozilla.org/MPL/2.0/. // http://mozilla.org/MPL/2.0/.
namespace SimAI.Interfaces; namespace SimAntics.Interfaces;
public interface VMIMotiveDecay : VMSerializable public interface VMIMotiveDecay : VMSerializable
{ {
// void Tick(VMAvatar avatar, VMContext context); // void Tick(VMAvatar avatar, VMContext context);
} }

View file

@ -1,7 +1,7 @@
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. // This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at // If a copy of the MPL was not distributed with this file, You can obtain one at
// http://mozilla.org/MPL/2.0/. // http://mozilla.org/MPL/2.0/.
namespace SimAI.Interfaces; namespace SimAntics.Interfaces;
public interface VMSerializable public interface VMSerializable
{ {

View file

@ -1,11 +1,11 @@
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. // This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at // If a copy of the MPL was not distributed with this file, You can obtain one at
// http://mozilla.org/MPL/2.0/. // http://mozilla.org/MPL/2.0/.
namespace SimAI.Marshals; namespace SimAntics.Marshals;
public class VMMarshal public class VMMarshal
{ {
public VMMarshal() public VMMarshal()
{ {
} }
} }

View file

@ -1,66 +1,66 @@
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. // This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at // If a copy of the MPL was not distributed with this file, You can obtain one at
// http://mozilla.org/MPL/2.0/. // http://mozilla.org/MPL/2.0/.
namespace SimAI.Marshals; namespace SimAntics.Marshals;
public class VMStackFrameMarshal public class VMStackFrameMarshal
{ {
public ushort RoutineID { get; set; } public ushort RoutineID { get; set; }
public ushort InstructionPointer { get; set; } public ushort InstructionPointer { get; set; }
public short Caller { get; set; } public short Caller { get; set; }
public short Callee { get; set; } public short Callee { get; set; }
public short StackObject { get; set; } public short StackObject { get; set; }
public uint CodeOwnerGUID { get; set; } public uint CodeOwnerGUID { get; set; }
public short[] Locals { get; set; } public short[] Locals { get; set; }
public short[] Args { get; set; } public short[] Args { get; set; }
public bool DiscardResult { get; set; } public bool DiscardResult { get; set; }
public bool ActionTree { get; set; } public bool ActionTree { get; set; }
public int Version { get; set; } public int Version { get; set; }
public VMStackFrameMarshal() { } public VMStackFrameMarshal() { }
public VMStackFrameMarshal(int version) => Version = version; public VMStackFrameMarshal(int version) => Version = version;
public virtual void Deserialize(BinaryReader reader) public virtual void Deserialize(BinaryReader reader)
{ {
RoutineID = reader.ReadUInt16(); RoutineID = reader.ReadUInt16();
InstructionPointer = reader.ReadUInt16(); InstructionPointer = reader.ReadUInt16();
Caller = reader.ReadInt16(); Caller = reader.ReadInt16();
Callee = reader.ReadInt16(); Callee = reader.ReadInt16();
StackObject = reader.ReadInt16(); StackObject = reader.ReadInt16();
CodeOwnerGUID = reader.ReadUInt32(); CodeOwnerGUID = reader.ReadUInt32();
var localN = reader.ReadInt32(); var localN = reader.ReadInt32();
if (localN > -1) if (localN > -1)
{ {
Locals = new short[localN]; Locals = new short[localN];
for (var i = 0; i < localN; i++) Locals[i] = reader.ReadInt16(); for (var i = 0; i < localN; i++) Locals[i] = reader.ReadInt16();
} }
var argsN = reader.ReadInt32(); var argsN = reader.ReadInt32();
if (argsN > -1) if (argsN > -1)
{ {
Args = new short[argsN]; Args = new short[argsN];
for (var i = 0; i < argsN; i++) Args[i] = reader.ReadInt16(); for (var i = 0; i < argsN; i++) Args[i] = reader.ReadInt16();
} }
if (Version > 3) DiscardResult = reader.ReadBoolean(); if (Version > 3) DiscardResult = reader.ReadBoolean();
ActionTree = reader.ReadBoolean(); ActionTree = reader.ReadBoolean();
} }
public virtual void SerializeInto(BinaryWriter writer) public virtual void SerializeInto(BinaryWriter writer)
{ {
writer.Write(RoutineID); writer.Write(RoutineID);
writer.Write(InstructionPointer); writer.Write(InstructionPointer);
writer.Write(Caller); writer.Write(Caller);
writer.Write(Callee); writer.Write(Callee);
writer.Write(StackObject); writer.Write(StackObject);
writer.Write(CodeOwnerGUID); writer.Write(CodeOwnerGUID);
writer.Write((Locals == null) ? -1 : Locals.Length); writer.Write(Locals == null ? -1 : Locals.Length);
//if (Locals != null) writer.Write(VMSerializableUtils.ToByteArray(Locals)); //if (Locals != null) writer.Write(VMSerializableUtils.ToByteArray(Locals));
//writer.Write((Args == null) ? -1 : Args.Length); //writer.Write((Args == null) ? -1 : Args.Length);
//if (Args != null) writer.Write(VMSerializableUtils.ToByteArray(Args)); //if (Args != null) writer.Write(VMSerializableUtils.ToByteArray(Args));
writer.Write(DiscardResult); writer.Write(DiscardResult);
writer.Write(ActionTree); writer.Write(ActionTree);
} }
} }

View file

@ -1,140 +1,142 @@
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. // This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at // If a copy of the MPL was not distributed with this file, You can obtain one at
// http://mozilla.org/MPL/2.0/. // http://mozilla.org/MPL/2.0/.
using SimAI;
using SimAntics.Engine;
using SimAntics.Engine.Entities; using SimAntics.Engine.Entities;
namespace SimAI; namespace SimAntics;
/// <summary> /// <summary>
/// VM is an abstract class that contains the /// VM is an abstract class that contains the
/// </summary> /// </summary>
public abstract class VM : IVM public abstract class VM : IVM
{ {
public bool IsTS1 { get; set; } public bool IsTS1 { get; set; }
public bool Ready { get; set; } public bool Ready { get; set; }
public bool BHAVDirty { get; set; } public bool BHAVDirty { get; set; }
public VMContext Context { get; internal set; } public VMContext Context { get; internal set; }
public VMScheduler Scheduler { set; get; } public VMScheduler Scheduler { set; get; }
public delegate void VMRefreshHandler(); public delegate void VMRefreshHandler();
public delegate void VMLotSwitchHandler(uint lotId); public delegate void VMLotSwitchHandler(uint lotId);
Dictionary<short, VMEntity> ObjectsById = new(); Dictionary<short, VMEntity> ObjectsById = new();
short ObjectId = 1; short ObjectId = 1;
public List<VMEntity> Entities = new(); public List<VMEntity> Entities = new();
public HashSet<VMEntity> SoundEntities = new(); public HashSet<VMEntity> SoundEntities = new();
public short[] GlobalState; public short[] GlobalState;
int GameTickRate = 60; int GameTickRate = 60;
int GameTickNum = 0; int GameTickNum = 0;
public int SpeedMultiplier = 1; public int SpeedMultiplier = 1;
public int LastSpeedMultiplier; public int LastSpeedMultiplier;
int LastFrameSpeed = 1; int LastFrameSpeed = 1;
float Fraction; float Fraction;
public VMEntity GlobalBlockingDialog; public VMEntity GlobalBlockingDialog;
/// <summary> /// <summary>
/// Gets an entity from this VM. /// Gets an entity from this VM.
/// </summary> /// </summary>
/// <param name="id">The entity's ID.</param> /// <param name="id">The entity's ID.</param>
/// <returns>A VMEntity instance associated with the ID.</returns> /// <returns>A VMEntity instance associated with the ID.</returns>
public VMEntity? GetObjectById(short id) public VMEntity? GetObjectById(short id)
{ {
return ObjectsById.ContainsKey(id) ? ObjectsById[id] : null; return ObjectsById.ContainsKey(id) ? ObjectsById[id] : null;
} }
/// <summary> /// <summary>
/// Constructs a new Virtual Machine instance. /// Constructs a new Virtual Machine instance.
/// </summary> /// </summary>
/// <param name="context">The VMContext instance to use.</param> /// <param name="context">The VMContext instance to use.</param>
public VM(VMContext context) public VM(VMContext context)
{ {
context.VM = this; context.VM = this;
Context = context; Context = context;
Scheduler = new VMScheduler(this); Scheduler = new VMScheduler(this);
} }
public VMEntity GetObjectByPersist(uint id) public VMEntity GetObjectByPersist(uint id)
{ {
// return Entities.FirstOrDefault(x => x.PersistID == id); // return Entities.FirstOrDefault(x => x.PersistID == id);
throw new VMSimanticsException(); throw new VMSimanticsException();
} }
public virtual void Init() public virtual void Init()
{ {
// PlatformState = (TS1)?(VMAbstractLotState)new VMTS1LotState():new VMTSOLotState(); // PlatformState = (TS1)?(VMAbstractLotState)new VMTS1LotState():new VMTSOLotState();
GlobalState = new short[38]; GlobalState = new short[38];
GlobalState[20] = 255; //Game Edition. Basically, what "expansion packs" are running. Let's just say all of them. GlobalState[20] = 255; //Game Edition. Basically, what "expansion packs" are running. Let's just say all of them.
GlobalState[25] = 4; //as seen in EA-Land edith's simulator globals, this needs to be set for people to do their idle interactions. GlobalState[25] = 4; //as seen in EA-Land edith's simulator globals, this needs to be set for people to do their idle interactions.
GlobalState[17] = 4; //Runtime Code Version, is this in EA-Land. GlobalState[17] = 4; //Runtime Code Version, is this in EA-Land.
// if (Driver is VMServerDriver) EODHost = new VMEODHost(); // if (Driver is VMServerDriver) EODHost = new VMEODHost();
} }
public virtual void Reset() public virtual void Reset()
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
public virtual void Update() public virtual void Update()
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
public virtual void Tick() public virtual void Tick()
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
public virtual void InternalTick(uint tickId) public virtual void InternalTick(uint tickId)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
/// <summary> /// <summary>
/// Adds an entity to this Virtual Machine. /// Adds an entity to this Virtual Machine.
/// </summary> /// </summary>
/// <param name="entity">The entity to add.</param> /// <param name="entity">The entity to add.</param>
public void AddEntity(VMEntity entity) public void AddEntity(VMEntity entity)
{ {
entity.ObjectID = ObjectId; entity.ObjectID = ObjectId;
ObjectsById.Add(entity.ObjectID, entity); ObjectsById.Add(entity.ObjectID, entity);
// AddToObjList(this.Entities, entity); // AddToObjList(this.Entities, entity);
// if (!entity.GhostImage) Context.ObjectQueries.NewObject(entity); // if (!entity.GhostImage) Context.ObjectQueries.NewObject(entity);
// ObjectId = NextObjID(); // ObjectId = NextObjID();
} }
public static void AddToObjList(List<VMEntity> list, VMEntity entity) public static void AddToObjList(List<VMEntity> list, VMEntity entity)
{ {
if (list.Count == 0) { list.Add(entity); return; } if (list.Count == 0) { list.Add(entity); return; }
int id = entity.ObjectID; int id = entity.ObjectID;
var max = list.Count; var max = list.Count;
var min = 0; var min = 0;
while (max > min) while (max > min)
{ {
var mid = (max + min) / 2; var mid = (max + min) / 2;
int nid = list[mid].ObjectID; int nid = list[mid].ObjectID;
if (id < nid) max = mid; if (id < nid) max = mid;
else if (id == nid) return; //do not add dupes else if (id == nid) return; //do not add dupes
else min = mid + 1; else min = mid + 1;
} }
list.Insert(min, entity); list.Insert(min, entity);
// list.Insert((list[min].ObjectID>id)?min:((list[max].ObjectID > id)?max:max+1), entity); // list.Insert((list[min].ObjectID>id)?min:((list[max].ObjectID > id)?max:max+1), entity);
} }
/// <summary> /// <summary>
/// Removes an entity from this Virtual Machine. /// Removes an entity from this Virtual Machine.
/// </summary> /// </summary>
/// <param name="entity">The entity to remove.</param> /// <param name="entity">The entity to remove.</param>
public void RemoveEntity(VMEntity entity) public void RemoveEntity(VMEntity entity)
{ {
if (Entities.Contains(entity)) if (Entities.Contains(entity))
{ {
// Context.ObjectQueries.RemoveObject(entity); // Context.ObjectQueries.RemoveObject(entity);
this.Entities.Remove(entity); Entities.Remove(entity);
ObjectsById.Remove(entity.ObjectID); ObjectsById.Remove(entity.ObjectID);
// Scheduler.DescheduleTick(entity); // Scheduler.DescheduleTick(entity);
if (entity.ObjectID < ObjectId) ObjectId = entity.ObjectID; //this id is now the smallest free object id. if (entity.ObjectID < ObjectId) ObjectId = entity.ObjectID; //this id is now the smallest free object id.
} }
entity.Dead = true; entity.Dead = true;
} }
} }

View file

@ -2,43 +2,43 @@
// If a copy of the MPL was not distributed with this file, You can obtain one at // If a copy of the MPL was not distributed with this file, You can obtain one at
// http://mozilla.org/MPL/2.0/. // http://mozilla.org/MPL/2.0/.
namespace SimAI; namespace SimAntics;
public class VMClock public class VMClock
{ {
public long Ticks { get; set; } public long Ticks { get; set; }
public int MinuteFractions { get; set; } public int MinuteFractions { get; set; }
public int TicksPerMinute { get; set; } public int TicksPerMinute { get; set; }
public int Minutes { get; set; } public int Minutes { get; set; }
public int Hours { get; set; } public int Hours { get; set; }
public int DayOfMonth = 1; public int DayOfMonth = 1;
public int Month = 6; public int Month = 6;
public int Year = 1997; public int Year = 1997;
public int FirePercent { get; set; } public int FirePercent { get; set; }
public long UTCStart = DateTime.UtcNow.Ticks; public long UTCStart = DateTime.UtcNow.Ticks;
public int TimeOfDay => (Hours >= 6 && Hours < 18) ? 0 : 1; public int TimeOfDay => Hours >= 6 && Hours < 18 ? 0 : 1;
public int Seconds => MinuteFractions * 60 / TicksPerMinute; public int Seconds => MinuteFractions * 60 / TicksPerMinute;
public DateTime UTCNow => new DateTime(UTCStart).AddSeconds(Ticks / 30.0); public DateTime UTCNow => new DateTime(UTCStart).AddSeconds(Ticks / 30.0);
public VMClock() { } public VMClock() { }
public void Tick() public void Tick()
{ {
if (FirePercent < 2000) FirePercent++; if (FirePercent < 2000) FirePercent++;
if (++MinuteFractions < TicksPerMinute) return; if (++MinuteFractions < TicksPerMinute) return;
MinuteFractions = 0; MinuteFractions = 0;
if (++Minutes < 60) return; if (++Minutes < 60) return;
Minutes = 0; Minutes = 0;
if (++DayOfMonth <= 30) return; if (++DayOfMonth <= 30) return;
DayOfMonth = 1; DayOfMonth = 1;
if (++Month <= 12) return; if (++Month <= 12) return;
Month = 1; Month = 1;
Year++; Year++;
Ticks++; Ticks++;
} }
} }

View file

@ -1,10 +1,10 @@
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. // This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at // If a copy of the MPL was not distributed with this file, You can obtain one at
// http://mozilla.org/MPL/2.0/. // http://mozilla.org/MPL/2.0/.
namespace SimAI; namespace SimAntics;
public class VMContext public class VMContext
{ {
public static bool useWorld = true; public static bool useWorld = true;
public VM? VM { get; set; } public VM? VM { get; set; }
} }

View file

@ -2,93 +2,94 @@
// If a copy of the MPL was not distributed with this file, You can obtain one at // If a copy of the MPL was not distributed with this file, You can obtain one at
// http://mozilla.org/MPL/2.0/. // http://mozilla.org/MPL/2.0/.
using System.Text; using System.Text;
using SimAntics.Engine;
namespace SimAI; namespace SimAntics;
public class VMSimanticsException : Exception public class VMSimanticsException : Exception
{ {
readonly string _message; readonly string _message;
VMStackFrame _context; VMStackFrame _context;
public VMSimanticsException() { } public VMSimanticsException() { }
public VMSimanticsException(string message, VMStackFrame context) : base(message) public VMSimanticsException(string message, VMStackFrame context) : base(message)
{ {
_context = context; _context = context;
_message = message; _message = message;
} }
public override string ToString() public override string ToString()
{ {
var output = new StringBuilder(); var output = new StringBuilder();
output.Append(_message); output.Append(_message);
output.AppendLine(); output.AppendLine();
output.AppendLine(); output.AppendLine();
output.Append(GetStackTrace()); output.Append(GetStackTrace());
return output.ToString(); return output.ToString();
} }
public string GetStackTrace() public string GetStackTrace()
{ {
if (_context == null) return "No Stack Info."; if (_context == null) return "No Stack Info.";
var stack = _context.Thread.Stack; var stack = _context.Thread.Stack;
return GetStackTrace(stack); return GetStackTrace(stack);
} }
public static string GetStackTrace(List<VMStackFrame> stack) public static string GetStackTrace(List<VMStackFrame> stack)
{ {
var output = new StringBuilder(); var output = new StringBuilder();
var prevEE = ""; var prevEE = "";
var prevER = ""; var prevER = "";
for (var i = stack.Count - 1; i >= 0; i--) for (var i = stack.Count - 1; i >= 0; i--)
{ {
if (i == 9 && i <= stack.Count - 8) if (i == 9 && i <= stack.Count - 8)
{ {
output.Append("..."); output.Append("...");
output.AppendLine(); output.AppendLine();
} }
if (i > 8 && i <= stack.Count - 8) continue; if (i > 8 && i <= stack.Count - 8) continue;
var frame = stack[i]; var frame = stack[i];
//run in tree:76 //run in tree:76
var callerStr = frame.Caller.ToString(); var callerStr = frame.Caller.ToString();
var calleeStr = frame.Callee?.ToString(); var calleeStr = frame.Callee?.ToString();
if (callerStr != prevER || calleeStr != prevEE) if (callerStr != prevER || calleeStr != prevEE)
{ {
output.Append('('); output.Append('(');
output.Append(callerStr); output.Append(callerStr);
output.Append(':'); output.Append(':');
output.Append(calleeStr); output.Append(calleeStr);
output.Append(") "); output.Append(") ");
output.AppendLine(); output.AppendLine();
prevEE = calleeStr; prevEE = calleeStr;
prevER = callerStr; prevER = callerStr;
} }
output.Append(" > "); output.Append(" > ");
/*if (frame is VMRoutingFrame) /*if (frame is VMRoutingFrame)
{ {
output.Append("VMRoutingFrame with state: "); output.Append("VMRoutingFrame with state: ");
output.Append(((VMRoutingFrame)frame).State.ToString()); output.Append(((VMRoutingFrame)frame).State.ToString());
} }
else else
{ {
output.Append(frame.Routine.Rti.Name.TrimEnd('\0')); output.Append(frame.Routine.Rti.Name.TrimEnd('\0'));
output.Append(':'); output.Append(':');
output.Append(frame.InstructionPointer); output.Append(frame.InstructionPointer);
output.Append(" ("); output.Append(" (");
var opcode = frame.GetCurrentInstruction().Opcode; var opcode = frame.GetCurrentInstruction().Opcode;
var primitive = (opcode > 255) ? null : VMContext.Primitives[opcode]; var primitive = (opcode > 255) ? null : VMContext.Primitives[opcode];
output.Append((primitive == null) ? opcode.ToString() : primitive.Name); output.Append((primitive == null) ? opcode.ToString() : primitive.Name);
output.Append(")"); output.Append(")");
}*/ }*/
output.AppendLine(); output.AppendLine();
} }
return output.ToString(); return output.ToString();
} }
} }