Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
17c8d6b
Merge pull request #32 from FramePerfection/feat/multi-previous-posit…
FramePerfection Dec 22, 2025
effe289
Merge branch 'release-0.7.0' into Development
FramePerfection Dec 22, 2025
aea75e6
extract and trim 'ProcessStream' into separate project
FramePerfection Sep 14, 2025
1c7b88e
adjust namespaces in STROOP.Core
FramePerfection Sep 21, 2025
7c46f1e
use file scoped namespaces in 'STROOP.Core'
FramePerfection Sep 21, 2025
d53951d
fix form closing crash
FramePerfection Sep 21, 2025
feb96ff
move 'CoreLoop' to 'STROOP.Core'
FramePerfection Sep 21, 2025
57bd875
move emulator specific implementations to 'STROOP.Core.GameMemoryAcce…
FramePerfection Sep 21, 2025
cd345ba
move 'StFileIO' into 'STROOP.Core.GameMemoryAccess' namespace
FramePerfection Sep 21, 2025
bd7925a
remove 'SharpZipLib' package reference
FramePerfection Sep 21, 2025
2e84492
move 'ProcessStreamExtensions' to 'STROOP.Utilities' directory
FramePerfection Sep 21, 2025
d0b792b
move general utilities to 'STROOP.Core.Utilities'
FramePerfection Sep 21, 2025
00b9d1f
move 'DeclaredStringAttribute' to 'STROOP.Core.Utilities' and rename …
FramePerfection Sep 21, 2025
84f653d
create 'STROOP.Variables' project
FramePerfection Sep 22, 2025
d7c834e
move memory layout classes, removing 'MappingConfig.GetVariables' ent…
FramePerfection Sep 22, 2025
cbfe0b9
schmoove utilities and enums
FramePerfection Sep 22, 2025
0ff14ca
execute initializers for all 'STROOP' assemblies
FramePerfection Sep 22, 2025
e937aa4
move parts of the variable logic to 'STROOP.Variables'
FramePerfection Sep 22, 2025
7ed557b
move 'BaseAddressType' to 'STROOP.Variables.SM64MemoryLayout' namespace
FramePerfection Oct 12, 2025
b660f90
remove remnants of the old locking feature
FramePerfection Oct 12, 2025
e39361f
move remaining base address initializers to their respective tabs
FramePerfection Oct 12, 2025
dd35c34
apply syntax style to 'STROOP.Variables'
FramePerfection Oct 12, 2025
124842e
apply syntax style to 'STROOP.Core'
FramePerfection Oct 13, 2025
d0118ed
move remaining classes in 'STROOP.Core.Emulators' -> 'STROOP.Core.Gam…
FramePerfection Oct 13, 2025
07cf73e
disable nullable
FramePerfection Oct 13, 2025
9ffe766
remove 'BaseAddressType.Absolute'
FramePerfection Oct 13, 2025
df80a77
refactor formatting methods of 'MemoryDescriptor' as extension methods
FramePerfection Oct 13, 2025
de3a10f
extract 'NamedVariableGroup.ViewProperties' to dedicated class 'Commo…
FramePerfection Oct 13, 2025
80d3eeb
extract 'IVariableView'
FramePerfection Oct 13, 2025
09a9da4
extract 'CustomVariableView'
FramePerfection Oct 13, 2025
743b454
extract 'XmlMemoryBasedVariableView<>'
FramePerfection Oct 13, 2025
efb5da4
move 'GetterFunction' and 'SetterFunction' into 'IVariableView<T>'
FramePerfection Oct 13, 2025
6b7c57d
eliminate ugly 'NamedVariableCollection.SetVariableValue' hack
FramePerfection Oct 13, 2025
8dc1a7d
clean up some no longer used keys
FramePerfection Oct 17, 2025
c867358
refactor WatchVarWrappers to VariableCells and extract their core log…
FramePerfection Oct 19, 2025
d165e18
refactor 'SetValueByKey' to take only string values and add documenta…
FramePerfection Oct 19, 2025
b818eba
eliminate 'IVariable.Name' property
FramePerfection Oct 19, 2025
5dd6b69
eliminate 'IVariable.DisplayPriority' property
FramePerfection Oct 19, 2025
d509740
move static 'VariableSpecialDictionary' instance from 'WatchVariableS…
FramePerfection Oct 24, 2025
6615e31
get rid of 'WatchVariable' remnants
FramePerfection Oct 24, 2025
fe812d6
make 'AddVariables' an interface method of 'IVariablePanel'
FramePerfection Oct 24, 2025
135e5a7
rename 'VariablePanelUiContext' -> 'WinFormsVariablePanelUiContext'
FramePerfection Oct 24, 2025
b8d248c
kinda split up 'VariablePanel' into semantic partial classes
FramePerfection Oct 24, 2025
904e929
clean up remaining variable cell classes in 'STROOP' project
FramePerfection Oct 25, 2025
517e4d5
fix 'MemoryDescriptor.CreateVariable'
FramePerfection Dec 7, 2025
d7b12bb
remove 'Copy as Table' and 'Copy for Code' options
FramePerfection Jan 9, 2026
8bdeace
replace ';' separator with ',' in 'CopyUtilities.CopyPosition'
FramePerfection Jan 9, 2026
446be7a
Merge pull request #36 from FramePerfection/fix/seperator-for-positio…
FramePerfection Jan 9, 2026
54e8f9c
Merge remote-tracking branch 'origin/Development' into refac/27-extra…
FramePerfection Jan 9, 2026
6b7daca
override 'VariablePanel.ScrollToControl' to avoid unintentional scrol…
FramePerfection Jan 7, 2026
fe2ed74
delete invalid folder include from 'STROOP.Variables.csproj'
FramePerfection Jan 9, 2026
fe27d9d
refactor number cell wrappers as decorator classes
FramePerfection Jan 9, 2026
3f15fe4
simplify ROM version selection
FramePerfection Jan 9, 2026
99511bf
delete unused 'IUpdatable' interface
FramePerfection Jan 9, 2026
7467c41
fix crash in custom tab due to CopyTypeEnum mismatch
FramePerfection Jan 9, 2026
cec29b3
fix type conversions for memory writers 'long', 'int', 'short'
FramePerfection Jan 12, 2026
c9b24c0
Merge pull request #35 from FramePerfection/refac/27-extract-core-logic
FramePerfection Jan 12, 2026
dbe2717
Merge branch 'hotfix/string-reading-in-m64-header' into Development
FramePerfection Jan 17, 2026
1de81be
Merge branch 'hotfix/loading-form-race-condition' into Development
FramePerfection Feb 28, 2026
b46c6ad
add 'Win32NativeMethods' project for CsWin32 usage
FramePerfection Mar 6, 2026
0d58025
replace PInvokes in 'Kernal32NativeMethods.cs' with CsWin32 usages
FramePerfection Mar 6, 2026
6e3516f
use CsWin32 for 'SigScanSharp'
FramePerfection Mar 6, 2026
23c715c
use CsWin32 for 'RichTextBoxEx'
FramePerfection Mar 6, 2026
0040126
use CsWin32 for 'MouseUtility'
FramePerfection Mar 6, 2026
c044999
delete unused 'CarretlessTextBox'
FramePerfection Mar 6, 2026
903ab60
pull 'VirtualQueryEx' into 'STROOP.Win32' project and document intent
FramePerfection Mar 6, 2026
f2ab57e
rename 'Kernal32NativeMethods' -> 'ProcessHelper'
FramePerfection Mar 6, 2026
c72fd24
Merge pull request #41 from FramePerfection/refac/use-cswin32
FramePerfection Mar 7, 2026
227d364
use 'PInvoke.GetAsyncKeyState' instead of event handlers
FramePerfection Mar 6, 2026
30a3cdf
Merge pull request #42 from FramePerfection/fix/global-keyboard-getti…
FramePerfection Mar 7, 2026
afdfbaa
add github build actions
FramePerfection Mar 27, 2026
2c48bb6
Merge pull request #43 from FramePerfection/add-github-build-action
FramePerfection Mar 28, 2026
799c01a
Allocate enough memory for the SYMBOL_INFO
FramePerfection Mar 28, 2026
da71f62
Merge pull request #44 from FramePerfection/fix/wrong-SymFromName-usage
FramePerfection Mar 28, 2026
7055ab8
set 'InterpolationMode.High' in 'ObjectSlot.OnPaint'
FramePerfection Mar 28, 2026
b850a35
Merge pull request #45 from FramePerfection/fix/object-slot-image-filter
FramePerfection Mar 28, 2026
6446743
apply "groupList" attribute in 'VariableCellFactory.ParseXml'
FramePerfection Mar 28, 2026
9ac4019
Merge pull request #46 from FramePerfection/fix/disrespecting-groupLi…
FramePerfection Mar 29, 2026
540a883
bump version
FramePerfection Mar 29, 2026
fc3d5ec
add automatic builds for release candidates and fix up some naming sh…
FramePerfection Mar 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
31 changes: 31 additions & 0 deletions .github/workflows/build-debug.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# .github/workflows/debug-build.yml
name: PR Debug Build (Development)

on:
pull_request:
branches:
- Development

jobs:
debug-build:
runs-on: windows-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Setup .NET SDK
uses: actions/setup-dotnet@v3
with:
dotnet-version: '8.0.x'

- name: Restore dependencies
run: dotnet restore

- name: Build solution (Debug)
run: dotnet build ./STROOP.sln -c Debug -o ./artifacts --no-restore

- name: Upload debug build artifact
uses: actions/upload-artifact@v4
with:
name: debug-build
path: ./artifacts
57 changes: 57 additions & 0 deletions .github/workflows/build-release-candidate.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# .github/workflows/build-release-candidate.yml
name: Release Candidate Build

on:
push:
branches:
- release-*

jobs:
release-build:
runs-on: windows-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Setup .NET SDK
uses: actions/setup-dotnet@v3
with:
dotnet-version: '8.0.x'

- name: Restore dependencies
run: dotnet restore

- name: Build solution (Release)
run: dotnet build ./STROOP.sln -c Release -o ./artifacts --no-restore

- name: Determine release branch name and short commit
id: meta
shell: bash
run: |
# Get branch name from ref (refs/heads/release-...)
BRANCH_REF="${GITHUB_REF#refs/heads/}"
# sanitize branch for filenames: replace slashes with -
BRANCH_NAME="${BRANCH_REF//\//-}"
SHORT_SHA="${GITHUB_SHA::7}"
echo "branch=${BRANCH_NAME}" >> "$GITHUB_OUTPUT"
echo "short_sha=${SHORT_SHA}" >> "$GITHUB_OUTPUT"

- name: Write release metadata file
run: |
echo "branch=${{ steps.meta.outputs.branch }}" > ./artifacts/release-info.txt
echo "commit=${{ steps.meta.outputs.short_sha }}" >> ./artifacts/release-info.txt
echo "built_at=$(date -u +"%Y-%m-%dT%H:%M:%SZ")" >> ./artifacts/release-info.txt
shell: bash

- name: Prepare artifact filename
id: filename
shell: bash
run: |
TARGET="release-build-${{ steps.meta.outputs.branch }}-${{ steps.meta.outputs.short_sha }}"
echo "name=${TARGET}" >> "$GITHUB_OUTPUT"

- name: Upload release build artifact
uses: actions/upload-artifact@v4
with:
name: ${{ steps.filename.outputs.name }}
path: ./artifacts
31 changes: 31 additions & 0 deletions .github/workflows/build-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# .github/workflows/build-release.yml
name: Release Build

on:
push:
branches:
- Release

jobs:
release-build:
runs-on: windows-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Setup .NET SDK
uses: actions/setup-dotnet@v3
with:
dotnet-version: '8.0.x'

- name: Restore dependencies
run: dotnet restore

- name: Build solution (Release)
run: dotnet build ./STROOP.sln -c Release -o ./artifacts --no-restore

- name: Upload release build artifact
uses: actions/upload-artifact@v4
with:
name: release-build
path: ./artifacts
48 changes: 48 additions & 0 deletions STROOP.Core/CoreLoop.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using System.Diagnostics;

namespace STROOP.Core;

public class CoreLoop
{
private List<double> _fpsTimes = new List<double>();
private byte[] _ram;
private object _mStreamProcess = new object();

public double FpsInPractice => _fpsTimes.Count == 0 ? 0 : 1 / _fpsTimes.Average();
public double lastFrameTime => _fpsTimes.Count == 0 ? double.NaN : _fpsTimes.Last();

public void Run(CancellationToken cancellationToken, Action handleEvents, Func<double> getTargetedFps)
{
Stopwatch frameStopwatch = Stopwatch.StartNew();

while (!cancellationToken.IsCancellationRequested)
{
double timeToWait;
lock (_mStreamProcess)
{
ProcessStream.Instance.RefreshRam();
ProcessStream.Instance.OnUpdate?.Invoke();
}

handleEvents();

// Calculate delay to match correct FPS
frameStopwatch.Stop();
double timePassed = frameStopwatch.ElapsedTicks / (double)Stopwatch.Frequency;
timeToWait = getTargetedFps() - timePassed;
timeToWait = Math.Max(timeToWait, 0);

// Calculate Fps
while (_fpsTimes.Count() >= 10)
_fpsTimes.RemoveAt(0);
_fpsTimes.Add(timePassed + timeToWait);

frameStopwatch.Restart();

if (timeToWait > 0)
Thread.Sleep(new TimeSpan((long)(timeToWait * 10000000)));
else
Thread.Yield();
}
}
}
12 changes: 12 additions & 0 deletions STROOP.Core/Emulator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace STROOP.Core;

public class Emulator
{
public string Name;
public string ProcessName;
public uint RamStart;
public bool AllowAutoDetect;
public string Dll;
public Type IOType;
public EndiannessType Endianness = EndiannessType.Little;
}
7 changes: 7 additions & 0 deletions STROOP.Core/EndiannessType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace STROOP.Core;

public enum EndiannessType
{
Big,
Little,
}
93 changes: 93 additions & 0 deletions STROOP.Core/EndiannessUtilities.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
namespace STROOP.Core;

public static class EndiannessUtilities
{
private static readonly byte[] _fixAddress = { 0x00, 0x03, 0x02, 0x01, 0x00 };

public static UIntPtr SwapAddressEndianness(UIntPtr address, int dataSize)
{
switch (dataSize)
{
case 1:
case 2:
case 3:
return new UIntPtr(address.ToUInt64() & ~0x03UL | _fixAddress[dataSize] - address.ToUInt64() & 0x03UL);
default:
if (AddressIsMisaligned(address))
throw new Exception("Misaligned data");
return address;
}
}

public static uint SwapAddressEndianness(uint address, int dataSize)
{
switch (dataSize)
{
case 1:
case 2:
case 3:
return (uint)(address & ~0x03) | _fixAddress[dataSize] - address & 0x03;
default:
if (AddressIsMisaligned(address))
throw new Exception("Misaligned data");
return address;
}
}

public static bool DataIsMisaligned(UIntPtr address, int dataSize, EndiannessType endianness)
{
// Get the number of bytes remaining to alignment for the address
int bytesToAlignment = NumberOfBytesToAlignment(address);
if (endianness == EndiannessType.Little) // Little endianess goes backwards in count, not forwards
bytesToAlignment = _fixAddress[bytesToAlignment];

// All datasize greater than 4 must already have an aligned address, and an aligned data size (multiple of 4)
if (dataSize >= 4)
return bytesToAlignment != 0 || dataSize % 4 != 0;

// If we are already aligned, we really have 4 bytes remaining
if (bytesToAlignment == 0)
bytesToAlignment = 4;

// Be sure the bytes fit in the remaining section and do go past the 4-byte alignment
return bytesToAlignment < dataSize;
}

public static bool AddressIsMisaligned(UIntPtr address) => (address.ToUInt64() & 0x03) != 0;

public static bool AddressIsMisaligned(uint address) => (address & 0x03) != 0;

private static readonly byte[] _bytesToAlignment = new byte[] { 0x00, 0x03, 0x02, 0x01 };

public static int NumberOfBytesToAlignment(UIntPtr address) => _bytesToAlignment[address.ToUInt64() & 0x03];

public static int NumberOfBytesToAlignment(uint address) => _bytesToAlignment[address & 0x03];

public static uint AlignedAddressFloor(uint address) => address & ~0x03U;

public static UIntPtr AlignedAddressFloor(UIntPtr address) => (UIntPtr)(address.ToUInt64() & ~0x03U);

public static uint AlignedAddressCeil(uint address) => (address & ~0x03U) + 4;

public static UIntPtr AlignedAddressCeil(UIntPtr address) => (UIntPtr)((address.ToUInt64() & ~0x03U) + 4);

public static byte[] SwapByteEndianness(byte[] bytes)
{
if (bytes.Length < 3)
return bytes.Reverse().ToArray();

if (bytes.Length % 4 != 0)
throw new ArgumentException("Bytes are not a multiple of 4");

byte[] result = new byte[bytes.Length];
for (int i = 0; i < bytes.Length; i += 4)
{
result[i] = bytes[i + 3];
result[i + 1] = bytes[i + 2];
result[i + 2] = bytes[i + 1];
result[i + 3] = bytes[i];
}

return result;
}
}
Loading
Loading