diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 0000000..2fc272c
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,23 @@
+name: build
+
+on: [push, pull_request]
+
+jobs:
+ build:
+
+ runs-on: ${{ matrix.os }}
+ strategy:
+ matrix:
+ dotnet: [ '3.1.200', '3.1.201' ]
+ build_mode: [ 'Release', 'Debug' ]
+ os: [ubuntu-latest, windows-latest, macOS-latest]
+ steps:
+ - uses: actions/checkout@v1
+ - name: Setup .NET Core
+ uses: actions/setup-dotnet@v1
+ with:
+ dotnet-version: ${{ matrix.dotnet }}
+ - name: Build
+ run: dotnet build src -c ${{ matrix.build_mode }}
+ - name: Run tests
+ run: dotnet test src -c ${{ matrix.build_mode }}
diff --git a/.gitignore b/.gitignore
index a346026..fdfc5cb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,15 +1,5 @@
-# Created by https://www.gitignore.io/api/linux,macos,windows,dotnetcore,intellij+iml,visualstudio,visualstudiocode
-# Edit at https://www.gitignore.io/?templates=linux,macos,windows,dotnetcore,intellij+iml,visualstudio,visualstudiocode
-
-### DotnetCore ###
-# .NET Core build folders
-/bin
-/obj
-
-# Common node modules locations
-/node_modules
-/wwwroot/node_modules
-
+# Created by https://www.gitignore.io/api/linux,macos,windows,intellij+iml,visualstudio,visualstudiocode
+# Edit at https://www.gitignore.io/?templates=linux,macos,windows,intellij+iml,visualstudio,visualstudiocode
### Intellij+iml ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
@@ -17,6 +7,7 @@
# User-specific stuff
.idea/**
+**/.idea/**
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
@@ -498,4 +489,4 @@ healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
-# End of https://www.gitignore.io/api/linux,macos,windows,dotnetcore,intellij+iml,visualstudio,visualstudiocode
\ No newline at end of file
+# End of https://www.gitignore.io/api/linux,macos,windows,intellij+iml,visualstudio,visualstudiocode
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..09f2798
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,312 @@
+Mozilla Public License Version 2.0
+
+ 1. Definitions
+
+1.1. "Contributor" means each individual or legal entity that creates, contributes
+to the creation of, or owns Covered Software.
+
+1.2. "Contributor Version" means the combination of the Contributions of others
+(if any) used by a Contributor and that particular Contributor's Contribution.
+
+ 1.3. "Contribution" means Covered Software of a particular Contributor.
+
+1.4. "Covered Software" means Source Code Form to which the initial Contributor
+has attached the notice in Exhibit A, the Executable Form of such Source Code
+Form, and Modifications of such Source Code Form, in each case including portions
+thereof.
+
+ 1.5. "Incompatible With Secondary Licenses" means
+
+(a) that the initial Contributor has attached the notice described in Exhibit
+B to the Covered Software; or
+
+(b) that the Covered Software was made available under the terms of version
+1.1 or earlier of the License, but not also under the terms of a Secondary
+License.
+
+1.6. "Executable Form" means any form of the work other than Source Code Form.
+
+1.7. "Larger Work" means a work that combines Covered Software with other
+material, in a separate file or files, that is not Covered Software.
+
+ 1.8. "License" means this document.
+
+1.9. "Licensable" means having the right to grant, to the maximum extent possible,
+whether at the time of the initial grant or subsequently, any and all of the
+rights conveyed by this License.
+
+ 1.10. "Modifications" means any of the following:
+
+(a) any file in Source Code Form that results from an addition to, deletion
+from, or modification of the contents of Covered Software; or
+
+(b) any new file in Source Code Form that contains any Covered Software.
+
+1.11. "Patent Claims" of a Contributor means any patent claim(s), including
+without limitation, method, process, and apparatus claims, in any patent Licensable
+by such Contributor that would be infringed, but for the grant of the License,
+by the making, using, selling, offering for sale, having made, import, or
+transfer of either its Contributions or its Contributor Version.
+
+1.12. "Secondary License" means either the GNU General Public License, Version
+2.0, the GNU Lesser General Public License, Version 2.1, the GNU Affero General
+Public License, Version 3.0, or any later versions of those licenses.
+
+1.13. "Source Code Form" means the form of the work preferred for making modifications.
+
+1.14. "You" (or "Your") means an individual or a legal entity exercising rights
+under this License. For legal entities, "You" includes any entity that controls,
+is controlled by, or is under common control with You. For purposes of this
+definition, "control" means (a) the power, direct or indirect, to cause the
+direction or management of such entity, whether by contract or otherwise,
+or (b) ownership of more than fifty percent (50%) of the outstanding shares
+or beneficial ownership of such entity.
+
+ 2. License Grants and Conditions
+
+ 2.1. Grants
+
+Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive
+license:
+
+(a) under intellectual property rights (other than patent or trademark) Licensable
+by such Contributor to use, reproduce, make available, modify, display, perform,
+distribute, and otherwise exploit its Contributions, either on an unmodified
+basis, with Modifications, or as part of a Larger Work; and
+
+(b) under Patent Claims of such Contributor to make, use, sell, offer for
+sale, have made, import, and otherwise transfer either its Contributions or
+its Contributor Version.
+
+ 2.2. Effective Date
+
+The licenses granted in Section 2.1 with respect to any Contribution become
+effective for each Contribution on the date the Contributor first distributes
+such Contribution.
+
+ 2.3. Limitations on Grant Scope
+
+The licenses granted in this Section 2 are the only rights granted under this
+License. No additional rights or licenses will be implied from the distribution
+or licensing of Covered Software under this License. Notwithstanding Section
+2.1(b) above, no patent license is granted by a Contributor:
+
+(a) for any code that a Contributor has removed from Covered Software; or
+
+(b) for infringements caused by: (i) Your and any other third party's modifications
+of Covered Software, or (ii) the combination of its Contributions with other
+software (except as part of its Contributor Version); or
+
+(c) under Patent Claims infringed by Covered Software in the absence of its
+Contributions.
+
+This License does not grant any rights in the trademarks, service marks, or
+logos of any Contributor (except as may be necessary to comply with the notice
+requirements in Section 3.4).
+
+ 2.4. Subsequent Licenses
+
+No Contributor makes additional grants as a result of Your choice to distribute
+the Covered Software under a subsequent version of this License (see Section
+10.2) or under the terms of a Secondary License (if permitted under the terms
+of Section 3.3).
+
+ 2.5. Representation
+
+Each Contributor represents that the Contributor believes its Contributions
+are its original creation(s) or it has sufficient rights to grant the rights
+to its Contributions conveyed by this License.
+
+ 2.6. Fair Use
+
+This License is not intended to limit any rights You have under applicable
+copyright doctrines of fair use, fair dealing, or other equivalents.
+
+ 2.7. Conditions
+
+Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
+Section 2.1.
+
+ 3. Responsibilities
+
+ 3.1. Distribution of Source Form
+
+All distribution of Covered Software in Source Code Form, including any Modifications
+that You create or to which You contribute, must be under the terms of this
+License. You must inform recipients that the Source Code Form of the Covered
+Software is governed by the terms of this License, and how they can obtain
+a copy of this License. You may not attempt to alter or restrict the recipients'
+rights in the Source Code Form.
+
+ 3.2. Distribution of Executable Form
+
+ If You distribute Covered Software in Executable Form then:
+
+(a) such Covered Software must also be made available in Source Code Form,
+as described in Section 3.1, and You must inform recipients of the Executable
+Form how they can obtain a copy of such Source Code Form by reasonable means
+in a timely manner, at a charge no more than the cost of distribution to the
+recipient; and
+
+(b) You may distribute such Executable Form under the terms of this License,
+or sublicense it under different terms, provided that the license for the
+Executable Form does not attempt to limit or alter the recipients' rights
+in the Source Code Form under this License.
+
+ 3.3. Distribution of a Larger Work
+
+You may create and distribute a Larger Work under terms of Your choice, provided
+that You also comply with the requirements of this License for the Covered
+Software. If the Larger Work is a combination of Covered Software with a work
+governed by one or more Secondary Licenses, and the Covered Software is not
+Incompatible With Secondary Licenses, this License permits You to additionally
+distribute such Covered Software under the terms of such Secondary License(s),
+so that the recipient of the Larger Work may, at their option, further distribute
+the Covered Software under the terms of either this License or such Secondary
+License(s).
+
+ 3.4. Notices
+
+You may not remove or alter the substance of any license notices (including
+copyright notices, patent notices, disclaimers of warranty, or limitations
+of liability) contained within the Source Code Form of the Covered Software,
+except that You may alter any license notices to the extent required to remedy
+known factual inaccuracies.
+
+ 3.5. Application of Additional Terms
+
+You may choose to offer, and to charge a fee for, warranty, support, indemnity
+or liability obligations to one or more recipients of Covered Software. However,
+You may do so only on Your own behalf, and not on behalf of any Contributor.
+You must make it absolutely clear that any such warranty, support, indemnity,
+or liability obligation is offered by You alone, and You hereby agree to indemnify
+every Contributor for any liability incurred by such Contributor as a result
+of warranty, support, indemnity or liability terms You offer. You may include
+additional disclaimers of warranty and limitations of liability specific to
+any jurisdiction.
+
+ 4. Inability to Comply Due to Statute or Regulation
+
+If it is impossible for You to comply with any of the terms of this License
+with respect to some or all of the Covered Software due to statute, judicial
+order, or regulation then You must: (a) comply with the terms of this License
+to the maximum extent possible; and (b) describe the limitations and the code
+they affect. Such description must be placed in a text file included with
+all distributions of the Covered Software under this License. Except to the
+extent prohibited by statute or regulation, such description must be sufficiently
+detailed for a recipient of ordinary skill to be able to understand it.
+
+ 5. Termination
+
+5.1. The rights granted under this License will terminate automatically if
+You fail to comply with any of its terms. However, if You become compliant,
+then the rights granted under this License from a particular Contributor are
+reinstated (a) provisionally, unless and until such Contributor explicitly
+and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor
+fails to notify You of the non-compliance by some reasonable means prior to
+60 days after You have come back into compliance. Moreover, Your grants from
+a particular Contributor are reinstated on an ongoing basis if such Contributor
+notifies You of the non-compliance by some reasonable means, this is the first
+time You have received notice of non-compliance with this License from such
+Contributor, and You become compliant prior to 30 days after Your receipt
+of the notice.
+
+5.2. If You initiate litigation against any entity by asserting a patent infringement
+claim (excluding declaratory judgment actions, counter-claims, and cross-claims)
+alleging that a Contributor Version directly or indirectly infringes any patent,
+then the rights granted to You by any and all Contributors for the Covered
+Software under Section 2.1 of this License shall terminate.
+
+5.3. In the event of termination under Sections 5.1 or 5.2 above, all end
+user license agreements (excluding distributors and resellers) which have
+been validly granted by You or Your distributors under this License prior
+to termination shall survive termination.
+
+ 6. Disclaimer of Warranty
+
+Covered Software is provided under this License on an "as is" basis, without
+warranty of any kind, either expressed, implied, or statutory, including,
+without limitation, warranties that the Covered Software is free of defects,
+merchantable, fit for a particular purpose or non-infringing. The entire risk
+as to the quality and performance of the Covered Software is with You. Should
+any Covered Software prove defective in any respect, You (not any Contributor)
+assume the cost of any necessary servicing, repair, or correction. This disclaimer
+of warranty constitutes an essential part of this License. No use of any Covered
+Software is authorized under this License except under this disclaimer.
+
+ 7. Limitation of Liability
+
+Under no circumstances and under no legal theory, whether tort (including
+negligence), contract, or otherwise, shall any Contributor, or anyone who
+distributes Covered Software as permitted above, be liable to You for any
+direct, indirect, special, incidental, or consequential damages of any character
+including, without limitation, damages for lost profits, loss of goodwill,
+work stoppage, computer failure or malfunction, or any and all other commercial
+damages or losses, even if such party shall have been informed of the possibility
+of such damages. This limitation of liability shall not apply to liability
+for death or personal injury resulting from such party's negligence to the
+extent applicable law prohibits such limitation. Some jurisdictions do not
+allow the exclusion or limitation of incidental or consequential damages,
+so this exclusion and limitation may not apply to You.
+
+ 8. Litigation
+
+Any litigation relating to this License may be brought only in the courts
+of a jurisdiction where the defendant maintains its principal place of business
+and such litigation shall be governed by laws of that jurisdiction, without
+reference to its conflict-of-law provisions. Nothing in this Section shall
+prevent a party's ability to bring cross-claims or counter-claims.
+
+ 9. Miscellaneous
+
+This License represents the complete agreement concerning the subject matter
+hereof. If any provision of this License is held to be unenforceable, such
+provision shall be reformed only to the extent necessary to make it enforceable.
+Any law or regulation which provides that the language of a contract shall
+be construed against the drafter shall not be used to construe this License
+against a Contributor.
+
+ 10. Versions of the License
+
+ 10.1. New Versions
+
+Mozilla Foundation is the license steward. Except as provided in Section 10.3,
+no one other than the license steward has the right to modify or publish new
+versions of this License. Each version will be given a distinguishing version
+number.
+
+ 10.2. Effect of New Versions
+
+You may distribute the Covered Software under the terms of the version of
+the License under which You originally received the Covered Software, or under
+the terms of any subsequent version published by the license steward.
+
+ 10.3. Modified Versions
+
+If you create software not governed by this License, and you want to create
+a new license for such software, you may create and use a modified version
+of this License if you rename the license and remove any references to the
+name of the license steward (except to note that such modified license differs
+from this License).
+
+10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses
+
+If You choose to distribute Source Code Form that is Incompatible With Secondary
+Licenses under the terms of this version of the License, the notice described
+in Exhibit B of this License must be attached. Exhibit A - Source Code Form
+License Notice
+
+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 http://mozilla.org/MPL/2.0/.
+
+If it is not possible or desirable to put the notice in a particular file,
+then You may include the notice in a location (such as a LICENSE file in a
+relevant directory) where a recipient would be likely to look for such a notice.
+
+You may add additional accurate notices of copyright ownership.
+
+Exhibit B - "Incompatible With Secondary Licenses" Notice
+
+This Source Code Form is "Incompatible With Secondary Licenses", as defined
+by the Mozilla Public License, v. 2.0.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..d3441f8
--- /dev/null
+++ b/README.md
@@ -0,0 +1,24 @@
+# SimAntics
+
+SimAntics is a port of FreeSO's reimplementation to .NET Standard.
+
+## Build Status
+
+| Service | Status |
+| ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| Github | [](https://github.com/simtactics/SimAntics/actions) |
+
+## Authors
+
+- **Anthony Foxclaw** - _Maintainer_ - [tonytins](https://github.com/tonytins)
+- **Rhys Simpson** - _Original work_ - [riperiperi](https://github.com/riperiperi)
+
+See also the list of [contributors](https://github.com/simtactics/SimAntics/contributors) who participated in this project.
+
+## License
+
+This project is licensed under the MPL 2.0 or later license - see the [LICENSE](LICENSE) file for details.
+
+## Disclaimer
+
+This project is not affiliated with or endorsed by Electronic Arts or Maxis.
diff --git a/src/SimAntics.Tests/SimAntics.Tests.csproj b/src/SimAntics.Tests/SimAntics.Tests.csproj
index 87f5bcb..42c1782 100644
--- a/src/SimAntics.Tests/SimAntics.Tests.csproj
+++ b/src/SimAntics.Tests/SimAntics.Tests.csproj
@@ -8,9 +8,13 @@
-
-
-
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+all
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+all
+
diff --git a/src/SimAntics.Tests/UnitTest1.cs b/src/SimAntics.Tests/UnitTest1.cs
index 4c490d0..d321034 100644
--- a/src/SimAntics.Tests/UnitTest1.cs
+++ b/src/SimAntics.Tests/UnitTest1.cs
@@ -1,4 +1,5 @@
using System;
+using System.Diagnostics;
using Xunit;
namespace SimAntics.Tests
@@ -8,6 +9,10 @@ namespace SimAntics.Tests
[Fact]
public void Test1()
{
+ var clock = new VMClock();
+ Console.WriteLine(clock.Ticks);
+ clock.Tick();
+ Console.WriteLine(clock.Ticks);
}
}
}
\ No newline at end of file
diff --git a/src/SimAntics.Tests/VMTest.cs b/src/SimAntics.Tests/VMTest.cs
new file mode 100644
index 0000000..70d9e34
--- /dev/null
+++ b/src/SimAntics.Tests/VMTest.cs
@@ -0,0 +1,12 @@
+// 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
+// http://mozilla.org/MPL/2.0/.
+namespace SimAntics.Tests
+{
+ public class VMTest
+ {
+ public VMTest()
+ {
+ }
+ }
+}
diff --git a/src/SimAntics.sln b/src/SimAntics.sln
index 7e884fd..4d1056d 100644
--- a/src/SimAntics.sln
+++ b/src/SimAntics.sln
@@ -1,5 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimAntics", "SimAntics\SimAntics.csproj", "{6B758449-9D5A-456A-A733-31B7841E538A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimAntics.Tests", "SimAntics.Tests\SimAntics.Tests.csproj", "{4B7461A4-982A-4D89-92E3-E4D4A3EC85FB}"
@@ -19,4 +20,9 @@ Global
{4B7461A4-982A-4D89-92E3-E4D4A3EC85FB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4B7461A4-982A-4D89-92E3-E4D4A3EC85FB}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
+ GlobalSection(MonoDevelopProperties) = preSolution
+ Policies = $0
+ $0.StandardHeader = $1
+ $1.Text = @This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.\nIf a copy of the MPL was not distributed with this file, You can obtain one at\nhttp://mozilla.org/MPL/2.0/.
+ EndGlobalSection
EndGlobal
diff --git a/src/SimAntics/Direction.cs b/src/SimAntics/Direction.cs
new file mode 100644
index 0000000..baf296f
--- /dev/null
+++ b/src/SimAntics/Direction.cs
@@ -0,0 +1,18 @@
+// 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
+// http://mozilla.org/MPL/2.0/.
+
+namespace SimAntics
+{
+ public enum Direction
+ {
+ NORTH,
+ NORTHEAST,
+ EAST,
+ SOUTHEAST,
+ SOUTH,
+ SOUTHWEST,
+ WEST,
+ NORTHWEST
+ }
+}
diff --git a/src/SimAntics/Engine/VMInstruction.cs b/src/SimAntics/Engine/VMInstruction.cs
deleted file mode 100644
index 8fa84e5..0000000
--- a/src/SimAntics/Engine/VMInstruction.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-namespace SimAntics.Engine
-{
- ///
- /// Compatibility class
- ///
- public class VMThread : VMInstruction { }
-
- ///
- /// Handles instruction sets
- ///
- public class VMInstruction
- {
- public static int MAX_USER_ACTIONS = 20;
-
- public VMContext Context;
-
- public bool IsCheck;
- }
-}
\ No newline at end of file
diff --git a/src/SimAntics/Engine/VMMemory.cs b/src/SimAntics/Engine/VMMemory.cs
new file mode 100644
index 0000000..48079e1
--- /dev/null
+++ b/src/SimAntics/Engine/VMMemory.cs
@@ -0,0 +1,12 @@
+// 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
+// http://mozilla.org/MPL/2.0/.
+namespace SimAntics.Engine
+{
+ public class VMMemory
+ {
+ public VMMemory()
+ {
+ }
+ }
+}
diff --git a/src/SimAntics/Engine/VMScheduler.cs b/src/SimAntics/Engine/VMScheduler.cs
new file mode 100644
index 0000000..492fffa
--- /dev/null
+++ b/src/SimAntics/Engine/VMScheduler.cs
@@ -0,0 +1,32 @@
+// 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
+// http://mozilla.org/MPL/2.0/.
+using System.Collections.Generic;
+using SimAntics.Engine.Entities;
+
+namespace SimAntics.Engine
+{
+ public class VMScheduler
+ {
+ VM VM { get; set; }
+
+ Dictionary> _tickScheduler = new Dictionary>();
+ List _tickThisFrame;
+
+ public HashSet PendingDeletion { get; set; } = new HashSet();
+ public uint CurrentTickID { get; set; }
+ public short CurrentObjectID { get; set; }
+ public bool RunningNow { get; set; }
+
+
+ public VMScheduler(VM vm)
+ {
+ VM = vm;
+ }
+
+ public void ScheduleTickIn(VMEntity _ent, uint delay)
+ {
+
+ }
+ }
+}
diff --git a/src/SimAntics/Engine/VMStackFrame.cs b/src/SimAntics/Engine/VMStackFrame.cs
new file mode 100644
index 0000000..17c0847
--- /dev/null
+++ b/src/SimAntics/Engine/VMStackFrame.cs
@@ -0,0 +1,178 @@
+// 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
+// http://mozilla.org/MPL/2.0/.
+using SimAntics.Engine.Entities;
+using SimAntics.Marshals;
+
+namespace SimAntics.Engine
+{
+ ///
+ /// Holds information about the execution of a routine
+ ///
+ public class VMStackFrame
+ {
+ public VMStackFrame() { }
+
+ /** Thread executing this routine **/
+ public VMThread Thread;
+
+ /** Routine that this context relates to **/
+ // public VMRoutine Routine;
+
+ /** Current instruction **/
+ public ushort InstructionPointer;
+
+ /** The object who executed this behavior **/
+ public VMEntity Caller;
+
+ /** The object the code is running on **/
+ public VMEntity Callee;
+
+ /** An object selected by the code to perform operations on. **/
+ public VMEntity StackObject
+ {
+ get { return _StackObject; }
+ set
+ {
+ _StackObject = value;
+ _StackObjectID = value?.ObjectID ?? 0;
+ }
+ }
+ public short StackObjectID
+ {
+ get { return _StackObjectID; }
+ set
+ {
+ _StackObjectID = value;
+ _StackObject = VM.GetObjectById(value);
+ }
+ }
+
+ VMEntity _StackObject;
+ public short _StackObjectID;
+
+ /** If true, this stack frame is not a subroutine. Return with a continue. **/
+ public bool DiscardResult;
+
+ /** Indicates that the current stack frame is part of an action tree.
+ ** Set by "idle for input, allow push", when an interaction is selected.
+ ** Used to stop recursive interactions, is only false when within "main".
+ **/
+ 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. **/
+ //public GameIffResource ScopeResource
+ //{
+ // get
+ // {
+ // return CodeOwner.Resource;
+ // }
+ //}
+
+ //public GameObject CodeOwner;
+ /**
+ * Routine locals
+ */
+ public short[] Locals;
+
+ /**
+ * Arguments
+ */
+ public short[] Args;
+
+ //public GameObjectResource CallerPrivate
+ //{
+ // get
+ // {
+ // return Caller.Object.Resource;
+ // }
+ //}
+
+ //public GameObjectResource CalleePrivate
+ //{
+ // get
+ // {
+ // return Callee.Object.Resource;
+ // }
+ //}
+
+ //public GameObjectResource StackObjPrivate
+ //{
+ // get
+ // {
+ // return StackObject.Object.Resource;
+ // }
+ //}
+
+ //public GameGlobal Global
+ //{
+ // get
+ // {
+ // return Thread.Context.Globals;
+ // }
+ //}
+
+ public VM VM
+ {
+ get
+ {
+ return Thread.Context.VM;
+ }
+ }
+
+ /** Utilities **/
+ //public VMInstruction GetCurrentInstruction()
+ //{
+ // return Routine.Instructions[InstructionPointer];
+ //}
+
+ //public T GetCurrentOperand()
+ //{
+ // return (T)GetCurrentInstruction().Operand;
+ //}
+
+ #region VM Marshalling Functions
+ //public virtual VMStackFrameMarshal Save()
+ //{
+ // return new VMStackFrameMarshal
+ // {
+ // RoutineID = Routine?.ID ?? 0,
+ // InstructionPointer = InstructionPointer,
+ // Caller = (Caller == null) ? (short)0 : Caller.ObjectID,
+ // Callee = (Callee == null) ? (short)0 : Callee.ObjectID,
+ // StackObject = StackObjectID,
+ // CodeOwnerGUID = CodeOwner.OBJ.GUID,
+ // Locals = (short[])Locals?.Clone(),
+ // Args = (short[])Args?.Clone(),
+ // DiscardResult = DiscardResult,
+ // ActionTree = ActionTree,
+ // };
+ //}
+
+ public virtual void Load(VMStackFrameMarshal input, VMContext context)
+ {
+ // CodeOwner = GameContent.Get.WorldObjects.Get(input.CodeOwnerGUID);
+
+ // Routine = null;
+ //if (input.RoutineID >= 8192) Routine = (VMRoutine)ScopeResource.SemiGlobal.GetRoutine(input.RoutineID);
+ //else if (input.RoutineID >= 4096) Routine = (VMRoutine)ScopeResource.GetRoutine(input.RoutineID);
+ //else Routine = (VMRoutine)Global.Resource.GetRoutine(input.RoutineID);
+
+ InstructionPointer = input.InstructionPointer;
+ Caller = context.VM.GetObjectById(input.Caller);
+ Callee = context.VM.GetObjectById(input.Callee);
+ StackObjectID = input.StackObject;
+ Locals = input.Locals;
+ Args = input.Args;
+ DiscardResult = input.DiscardResult;
+ ActionTree = input.ActionTree;
+ }
+
+ public VMStackFrame(VMStackFrameMarshal input, VMContext context, VMThread thread)
+ {
+ Thread = thread;
+ // Load(input, context);
+ }
+ #endregion
+ }
+}
diff --git a/src/SimAntics/Engine/VMThread.cs b/src/SimAntics/Engine/VMThread.cs
new file mode 100644
index 0000000..876d9d7
--- /dev/null
+++ b/src/SimAntics/Engine/VMThread.cs
@@ -0,0 +1,56 @@
+// 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
+// http://mozilla.org/MPL/2.0/.
+#if !Server
+#define IDE_COMPAT
+#endif
+
+using System.Collections.Generic;
+using SimAntics.Engine.Entities;
+
+namespace SimAntics.Engine
+{
+ ///
+ /// Compatibility class
+ ///
+ public class VMThread : VMInstruction { }
+
+ ///
+ /// Handles instruction sets
+ ///
+ public class VMInstruction
+ {
+ public static int MAX_USER_ACTIONS = 20;
+
+ public VMContext Context;
+
+ //check tree only vars
+ public bool IsCheck;
+
+ VMEntity Entity;
+
+ public List Stack;
+ bool ContinueExecution;
+
+ public string ThreadBreakString;
+ public int BreakFrame; //frame the last breakpoint was performed on
+ public bool RoutineDirty;
+
+ public bool Interrupt;
+
+ ushort ActionUID;
+
+ // Exception handling variables
+ // Don't need to be serialized.
+ public int DialogCooldown = 0;
+ // the number of ticks that have executed so far this frame. If this exceeds the allowed max,
+ // the thread resets, and a SimAntics Error pops up.
+ public int TicksThisFrame = 0;
+ // the maximum number of primitives a thread can execute in one frame. Tweak appropriately.
+
+ // variables for internal scheduler
+ public uint ScheduleIdleStart; // keep track of tick when we started idling for an object. must be synced!
+ public uint ScheduleIdleEnd;
+
+ }
+}
\ No newline at end of file
diff --git a/src/SimAntics/Entities/VMEntity.cs b/src/SimAntics/Entities/VMEntity.cs
new file mode 100644
index 0000000..8b54d6d
--- /dev/null
+++ b/src/SimAntics/Entities/VMEntity.cs
@@ -0,0 +1,158 @@
+// 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
+// http://mozilla.org/MPL/2.0/.
+using System.Collections.Generic;
+
+namespace SimAntics.Engine.Entities
+{
+ public class VMEntityRTTI
+ {
+ public string[] AttributeLabels;
+ }
+
+ public abstract class VMEntity
+ {
+ public static bool UseWorld = true;
+ public VMEntityRTTI RTTI;
+ public bool GhostImage;
+
+ public short ObjectID;
+ public uint PersistID;
+
+ public short[] ObjectData;
+ public LinkedList MyList = new LinkedList();
+ // public List SoundThreads;
+
+ // public VMRuntimeHeadline Headline;
+ ///
+ /// IS NOT serialized, but rather regenerated on deserialize.
+ ///
+ // public VMHeadlineRenderer HeadlineRenderer;
+
+ // public GameObject Object;
+ public VMThread Thread;
+ // public VMMultitileGroup MultitileGroup;
+
+ public short MainParam; //parameters passed to main on creation.
+ public short MainStackOBJ;
+
+ public VMEntity[] Contained = new VMEntity[0];
+ public VMEntity Container;
+ public short ContainerSlot;
+ ///
+ /// set when the entity is removed, threads owned by this object or with this object as callee will be cancelled/have their stack emptied
+ ///
+ public bool Dead;
+
+ /** Relationship variables **/
+ public Dictionary> MeToObject;
+ public Dictionary> MeToPersist;
+ //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.
+ //note this can point to false positives, but the worst case is a slow deletion if somehow every object is added.
+ public HashSet MayHaveRelToMe = new HashSet();
+
+ //signals which relationships have changed since the last time this was reset
+ //used to partial update relationships when doing an avatar save to db
+ public HashSet ChangedRels = new HashSet();
+
+ public ulong DynamicSpriteFlags; /** Used to show/hide dynamic sprites **/
+ public ulong DynamicSpriteFlags2;
+ //public VMObstacle Footprint;
+
+ //LotTilePos _Position = new LotTilePos(LotTilePos.OUT_OF_WORLD);
+ //public EntityComponent WorldUI;
+
+ public uint TimestampLockoutCount = 0;
+ //public Color LightColor = Color.White;
+
+ //inferred properties (from object resource)
+ //public GameGlobalResource SemiGlobal;
+ //public TTAB TreeTable;
+ //public TTAs TreeTableStrings;
+ //public Dictionary TreeByName;
+ //public SLOT Slots;
+ //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 virtual bool MovesOften
+ //{
+ // get
+ // {
+ // if (Container != null) return true;
+ // if (Slots == null) return false;
+ // if (!Slots.Slots.ContainsKey(3)) return false;
+ // var slots = Slots.Slots[3];
+ // return (slots.Count > 7);
+ // }
+ //}
+
+ //public string Name
+ //{
+ // get
+ // {
+ // if (MultitileGroup.Name != "") return MultitileGroup.Name;
+ // else return this.ToString();
+ // }
+ // set
+ // {
+ // MultitileGroup.Name = value;
+ // }
+ //}
+
+ //bool DynamicMultitile
+ //{
+ // get
+ // {
+ // return EntryPoints[8].ActionFunction >= 256;
+ // }
+ //}
+
+ //public override string ToString()
+ //{
+ // if (MultitileGroup.Name != "") return MultitileGroup.Name;
+ // var strings = Object.Resource.Get(Object.OBJ.CatalogStringsID);
+ // if (strings != null)
+ // {
+ // return strings.GetString(0);
+ // }
+ // var label = Object.OBJ.ChunkLabel;
+ // if (label != null && label.Length > 0)
+ // {
+ // return label;
+ // }
+ // return Object.OBJ.GUID.ToString("X");
+ //}
+
+ //positioning properties
+
+ protected static Direction[] DirectionNotches = new Direction[]
+ {
+ Direction.NORTH,
+ Direction.NORTHEAST,
+ Direction.EAST,
+ Direction.SOUTHEAST,
+ Direction.SOUTH,
+ Direction.SOUTHWEST,
+ Direction.WEST,
+ Direction.NORTHWEST
+ };
+
+ //public LotTilePos Position
+ //{
+ // get { return _Position; }
+ // set
+ // {
+ // _Position = value;
+ // if (UseWorld) WorldUI.Level = Position.Level;
+ // if (this is VMAvatar) ((VMAvatar)this).VisualPositionStart = null;
+ // VisualPosition = new Vector3(_Position.x / 16.0f, _Position.y / 16.0f, (_Position.Level - 1) * 2.95f);
+ // }
+ // }
+
+ // public abstract Vector3 VisualPosition { get; set; }
+ public abstract Direction Direction { get; set; }
+ public abstract float RadianDirection { get; set; }
+
+
+ }
+}
diff --git a/src/SimAntics/IVM.cs b/src/SimAntics/IVM.cs
index c5eb75a..cfee025 100644
--- a/src/SimAntics/IVM.cs
+++ b/src/SimAntics/IVM.cs
@@ -1,4 +1,8 @@
-namespace SimAntics
+// 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
+// http://mozilla.org/MPL/2.0/.
+
+namespace SimAntics
{
public interface IVM
{
diff --git a/src/SimAntics/Interfaces/VMIMotiveDecay.cs b/src/SimAntics/Interfaces/VMIMotiveDecay.cs
new file mode 100644
index 0000000..591b828
--- /dev/null
+++ b/src/SimAntics/Interfaces/VMIMotiveDecay.cs
@@ -0,0 +1,10 @@
+// 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
+// http://mozilla.org/MPL/2.0/.
+namespace SimAntics.Interfaces
+{
+ public interface VMIMotiveDecay : VMSerializable
+ {
+ // void Tick(VMAvatar avatar, VMContext context);
+ }
+}
diff --git a/src/SimAntics/Interfaces/VMSerializable.cs b/src/SimAntics/Interfaces/VMSerializable.cs
new file mode 100644
index 0000000..084352d
--- /dev/null
+++ b/src/SimAntics/Interfaces/VMSerializable.cs
@@ -0,0 +1,9 @@
+// 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
+// http://mozilla.org/MPL/2.0/.
+namespace SimAntics.Interfaces
+{
+ public interface VMSerializable
+ {
+ }
+}
\ No newline at end of file
diff --git a/src/SimAntics/Marshals/VMMarshal.cs b/src/SimAntics/Marshals/VMMarshal.cs
new file mode 100644
index 0000000..948fbd3
--- /dev/null
+++ b/src/SimAntics/Marshals/VMMarshal.cs
@@ -0,0 +1,13 @@
+// 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
+// http://mozilla.org/MPL/2.0/.
+using System;
+namespace SimAntics.Marshals
+{
+ public class VMMarshal
+ {
+ public VMMarshal()
+ {
+ }
+ }
+}
diff --git a/src/SimAntics/Marshals/VMStackFrameMarshal.cs b/src/SimAntics/Marshals/VMStackFrameMarshal.cs
new file mode 100644
index 0000000..f27dd29
--- /dev/null
+++ b/src/SimAntics/Marshals/VMStackFrameMarshal.cs
@@ -0,0 +1,70 @@
+// 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
+// http://mozilla.org/MPL/2.0/.
+using System;
+using System.IO;
+
+namespace SimAntics.Marshals
+{
+ public class VMStackFrameMarshal
+ {
+ public ushort RoutineID { get; set; }
+ public ushort InstructionPointer { get; set; }
+ public short Caller { get; set; }
+ public short Callee { get; set; }
+ public short StackObject { get; set; }
+ public uint CodeOwnerGUID { get; set; }
+ public short[] Locals { get; set; }
+ public short[] Args { get; set; }
+ public bool DiscardResult { get; set; }
+ public bool ActionTree { get; set; }
+
+ public int Version { get; set; }
+
+ public VMStackFrameMarshal() { }
+ public VMStackFrameMarshal(int version) { Version = version; }
+
+ public virtual void Deserialize(BinaryReader reader)
+ {
+ RoutineID = reader.ReadUInt16();
+ InstructionPointer = reader.ReadUInt16();
+ Caller = reader.ReadInt16();
+ Callee = reader.ReadInt16();
+ StackObject = reader.ReadInt16();
+ CodeOwnerGUID = reader.ReadUInt32();
+
+ var localN = reader.ReadInt32();
+ if (localN > -1)
+ {
+ Locals = new short[localN];
+ for (var i = 0; i < localN; i++) Locals[i] = reader.ReadInt16();
+ }
+
+ var argsN = reader.ReadInt32();
+ if (argsN > -1)
+ {
+ Args = new short[argsN];
+ for (var i = 0; i < argsN; i++) Args[i] = reader.ReadInt16();
+ }
+
+ if (Version > 3) DiscardResult = reader.ReadBoolean();
+ ActionTree = reader.ReadBoolean();
+ }
+
+ public virtual void SerializeInto(BinaryWriter writer)
+ {
+ writer.Write(RoutineID);
+ writer.Write(InstructionPointer);
+ writer.Write(Caller);
+ writer.Write(Callee);
+ writer.Write(StackObject);
+ writer.Write(CodeOwnerGUID);
+ writer.Write((Locals == null) ? -1 : Locals.Length);
+ //if (Locals != null) writer.Write(VMSerializableUtils.ToByteArray(Locals));
+ //writer.Write((Args == null) ? -1 : Args.Length);
+ //if (Args != null) writer.Write(VMSerializableUtils.ToByteArray(Args));
+ writer.Write(DiscardResult);
+ writer.Write(ActionTree);
+ }
+ }
+}
diff --git a/src/SimAntics/SimAntics.csproj b/src/SimAntics/SimAntics.csproj
index 2756020..0bdb0a6 100644
--- a/src/SimAntics/SimAntics.csproj
+++ b/src/SimAntics/SimAntics.csproj
@@ -4,4 +4,9 @@
netstandard2.0
+
+
+
+
+
diff --git a/src/SimAntics/VM.cs b/src/SimAntics/VM.cs
index b5aa11e..bf2d741 100644
--- a/src/SimAntics/VM.cs
+++ b/src/SimAntics/VM.cs
@@ -1,4 +1,10 @@
-using System;
+// 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
+// http://mozilla.org/MPL/2.0/.
+using System;
+using System.Collections.Generic;
+using SimAntics.Engine;
+using SimAntics.Engine.Entities;
namespace SimAntics
{
@@ -10,32 +16,129 @@ namespace SimAntics
public bool IsTS1 { get; set; }
public bool Ready { get; set; }
public bool BHAVDirty { get; set; }
+ public VMContext Context { get; internal set; }
+ public VMScheduler Scheduler { set; get; }
public delegate void VMRefreshHandler();
public delegate void VMLotSwitchHandler(uint lotId);
- public void Init()
+ Dictionary ObjectsById = new Dictionary();
+ short ObjectId = 1;
+
+ public List Entities = new List();
+ public HashSet SoundEntities = new HashSet();
+ public short[] GlobalState;
+
+ int GameTickRate = 60;
+ int GameTickNum = 0;
+ public int SpeedMultiplier = 1;
+ public int LastSpeedMultiplier;
+ int LastFrameSpeed = 1;
+ float Fraction;
+ public VMEntity GlobalBlockingDialog;
+
+ ///
+ /// Gets an entity from this VM.
+ ///
+ /// The entity's ID.
+ /// A VMEntity instance associated with the ID.
+ public VMEntity GetObjectById(short id)
+ {
+ return ObjectsById.ContainsKey(id) ? ObjectsById[id] : null;
+ }
+
+ ///
+ /// Constructs a new Virtual Machine instance.
+ ///
+ /// The VMContext instance to use.
+ public VM(VMContext context)
+ {
+ context.VM = this;
+ Context = context;
+ Scheduler = new VMScheduler(this);
+ }
+
+ public VMEntity GetObjectByPersist(uint id)
+ {
+ // return Entities.FirstOrDefault(x => x.PersistID == id);
+ throw new VMSimanticsException();
+ }
+
+ public virtual void Init()
+ {
+ // PlatformState = (TS1)?(VMAbstractLotState)new VMTS1LotState():new VMTSOLotState();
+ GlobalState = new short[38];
+ 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[17] = 4; //Runtime Code Version, is this in EA-Land.
+ // if (Driver is VMServerDriver) EODHost = new VMEODHost();
+ }
+
+ public virtual void Reset()
+ {
+ throw new NotImplementedException();
+ }
+ public virtual void Update()
{
throw new NotImplementedException();
}
- public void Reset()
- {
- throw new NotImplementedException();
- }
- public void Update()
+ public virtual void Tick()
{
throw new NotImplementedException();
}
- public void Tick()
+ public virtual void InternalTick(uint tickId)
{
throw new NotImplementedException();
}
-
- public void InternalTick(uint tickId)
+
+ ///
+ /// Adds an entity to this Virtual Machine.
+ ///
+ /// The entity to add.
+ public void AddEntity(VMEntity entity)
{
- throw new NotImplementedException();
+ entity.ObjectID = ObjectId;
+ ObjectsById.Add(entity.ObjectID, entity);
+ // AddToObjList(this.Entities, entity);
+ // if (!entity.GhostImage) Context.ObjectQueries.NewObject(entity);
+ // ObjectId = NextObjID();
+ }
+
+ public static void AddToObjList(List list, VMEntity entity)
+ {
+ if (list.Count == 0) { list.Add(entity); return; }
+ int id = entity.ObjectID;
+ var max = list.Count;
+ var min = 0;
+ while (max>min)
+ {
+ var mid = (max+min) / 2;
+ int nid = list[mid].ObjectID;
+ if (id < nid) max = mid;
+ else if (id == nid) return; //do not add dupes
+ else min = mid+1;
+ }
+ list.Insert(min, entity);
+ // list.Insert((list[min].ObjectID>id)?min:((list[max].ObjectID > id)?max:max+1), entity);
+ }
+
+ ///
+ /// Removes an entity from this Virtual Machine.
+ ///
+ /// The entity to remove.
+ public void RemoveEntity(VMEntity entity)
+ {
+ if (Entities.Contains(entity))
+ {
+ // Context.ObjectQueries.RemoveObject(entity);
+ this.Entities.Remove(entity);
+ ObjectsById.Remove(entity.ObjectID);
+ // Scheduler.DescheduleTick(entity);
+ if (entity.ObjectID < ObjectId) ObjectId = entity.ObjectID; //this id is now the smallest free object id.
+ }
+ entity.Dead = true;
}
}
}
\ No newline at end of file
diff --git a/src/SimAntics/VMClock.cs b/src/SimAntics/VMClock.cs
index d638d3c..850b197 100644
--- a/src/SimAntics/VMClock.cs
+++ b/src/SimAntics/VMClock.cs
@@ -1,3 +1,6 @@
+// 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
+// http://mozilla.org/MPL/2.0/.
using System;
namespace SimAntics
@@ -20,7 +23,7 @@ namespace SimAntics
public int TimeOfDay => (Hours >= 6 && Hours < 18) ? 0 : 1;
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() {}
diff --git a/src/SimAntics/VMContext.cs b/src/SimAntics/VMContext.cs
index a0ee48b..92232a6 100644
--- a/src/SimAntics/VMContext.cs
+++ b/src/SimAntics/VMContext.cs
@@ -1,8 +1,11 @@
+// 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
+// http://mozilla.org/MPL/2.0/.
namespace SimAntics
{
public class VMContext
{
public static bool useWorld = true;
- public VM Vm;
- }
+ public VM VM { get; set; }
+ }
}
\ No newline at end of file
diff --git a/src/SimAntics/VMSimanticsException.cs b/src/SimAntics/VMSimanticsException.cs
new file mode 100644
index 0000000..abb78fb
--- /dev/null
+++ b/src/SimAntics/VMSimanticsException.cs
@@ -0,0 +1,98 @@
+// 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
+// http://mozilla.org/MPL/2.0/.
+using System;
+using System.Collections.Generic;
+using System.Text;
+using SimAntics.Engine;
+
+namespace SimAntics
+{
+ public class VMSimanticsException : Exception
+ {
+ readonly string _message;
+ VMStackFrame _context;
+
+ public VMSimanticsException() { }
+
+ public VMSimanticsException(string message, VMStackFrame context) : base(message)
+ {
+ _context = context;
+ _message = message;
+ }
+
+ public override string ToString()
+ {
+ var output = new StringBuilder();
+ output.Append(_message);
+ output.AppendLine();
+ output.AppendLine();
+ output.Append(GetStackTrace());
+ return output.ToString();
+ }
+
+ public string GetStackTrace()
+ {
+ if (_context == null) return "No Stack Info.";
+
+ var stack = _context.Thread.Stack;
+ return GetStackTrace(stack);
+ }
+
+ public static string GetStackTrace(List stack)
+ {
+ var output = new StringBuilder();
+ var prevEE = "";
+ var prevER = "";
+
+ for (var i = stack.Count - 1; i >= 0; i--)
+ {
+ if (i == 9 && i <= stack.Count - 8)
+ {
+ output.Append("...");
+ output.AppendLine();
+ }
+ if (i > 8 && i <= stack.Count - 8) continue;
+ var frame = stack[i];
+ //run in tree:76
+
+ var callerStr = frame.Caller.ToString();
+ var calleeStr = frame.Callee?.ToString();
+
+ if (callerStr != prevER || calleeStr != prevEE)
+ {
+ output.Append('(');
+ output.Append(callerStr);
+ output.Append(':');
+ output.Append(calleeStr);
+ output.Append(") ");
+ output.AppendLine();
+ prevEE = calleeStr;
+ prevER = callerStr;
+ }
+
+ output.Append(" > ");
+
+ /*if (frame is VMRoutingFrame)
+ {
+ output.Append("VMRoutingFrame with state: ");
+ output.Append(((VMRoutingFrame)frame).State.ToString());
+ }
+ else
+ {
+ output.Append(frame.Routine.Rti.Name.TrimEnd('\0'));
+ output.Append(':');
+ output.Append(frame.InstructionPointer);
+ output.Append(" (");
+ var opcode = frame.GetCurrentInstruction().Opcode;
+ var primitive = (opcode > 255) ? null : VMContext.Primitives[opcode];
+ output.Append((primitive == null) ? opcode.ToString() : primitive.Name);
+ output.Append(")");
+ }*/
+ output.AppendLine();
+ }
+
+ return output.ToString();
+ }
+ }
+}