diff --git a/.github/workflows/build-debug.yml b/.github/workflows/build-debug.yml new file mode 100644 index 000000000..73d3807eb --- /dev/null +++ b/.github/workflows/build-debug.yml @@ -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 diff --git a/.github/workflows/build-release-candidate.yml b/.github/workflows/build-release-candidate.yml new file mode 100644 index 000000000..3a7444ad0 --- /dev/null +++ b/.github/workflows/build-release-candidate.yml @@ -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 diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml new file mode 100644 index 000000000..01776aac1 --- /dev/null +++ b/.github/workflows/build-release.yml @@ -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 diff --git a/STROOP.Core/CoreLoop.cs b/STROOP.Core/CoreLoop.cs new file mode 100644 index 000000000..993babbb3 --- /dev/null +++ b/STROOP.Core/CoreLoop.cs @@ -0,0 +1,48 @@ +using System.Diagnostics; + +namespace STROOP.Core; + +public class CoreLoop +{ + private List _fpsTimes = new List(); + 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 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(); + } + } +} diff --git a/STROOP.Core/Emulator.cs b/STROOP.Core/Emulator.cs new file mode 100644 index 000000000..52ca69651 --- /dev/null +++ b/STROOP.Core/Emulator.cs @@ -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; +} diff --git a/STROOP.Core/EndiannessType.cs b/STROOP.Core/EndiannessType.cs new file mode 100644 index 000000000..43c25b0e4 --- /dev/null +++ b/STROOP.Core/EndiannessType.cs @@ -0,0 +1,7 @@ +namespace STROOP.Core; + +public enum EndiannessType +{ + Big, + Little, +} diff --git a/STROOP.Core/EndiannessUtilities.cs b/STROOP.Core/EndiannessUtilities.cs new file mode 100644 index 000000000..e9f5fb369 --- /dev/null +++ b/STROOP.Core/EndiannessUtilities.cs @@ -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; + } +} diff --git a/STROOP.Core/GameMemoryAccess/BaseProcessIO.cs b/STROOP.Core/GameMemoryAccess/BaseProcessIO.cs new file mode 100644 index 000000000..1340bc763 --- /dev/null +++ b/STROOP.Core/GameMemoryAccess/BaseProcessIO.cs @@ -0,0 +1,114 @@ +using System.Diagnostics; +using System.Text; + +namespace STROOP.Core.GameMemoryAccess; + +public abstract class BaseProcessIO : IEmuRamIO +{ + public abstract event EventHandler OnClose; + + protected StringBuilder messageLogBuilder = new StringBuilder(); + + protected abstract bool WriteFunc(UIntPtr address, byte[] buffer); + protected abstract bool ReadFunc(UIntPtr address, byte[] buffer); + protected abstract UIntPtr BaseOffset { get; } + protected abstract EndiannessType Endianness { get; } + public abstract byte[] ReadAllMemory(); + + public abstract bool IsSuspended { get; } + + public abstract string Name { get; } + public abstract Process Process { get; } + + public abstract bool Suspend(); + public abstract bool Resume(); + + public BaseProcessIO() + { + } + + public string GetLastMessages() + { + string? result = messageLogBuilder.ToString(); + messageLogBuilder.Clear(); + return result; + } + + public bool ReadRelative(uint address, byte[] buffer, EndiannessType endianness) => ReadAbsolute(GetAbsoluteAddress(address, buffer.Length), buffer, endianness); + + private static readonly byte[] _swapByteOrder = new byte[] { 0x03, 0x02, 0x01, 0x00 }; + + public bool ReadAbsolute(UIntPtr address, byte[] buffer, EndiannessType endianness) + { + if (Endianness == endianness) + { + return ReadFunc(address, buffer); + } + else + { + // Not a between alignment, or aligned write + if (buffer.Length >= 4 && buffer.Length % 4 != 0) + throw new Exception("Misaligned data"); + + address = EndiannessUtilities.SwapAddressEndianness(address, buffer.Length); + byte[] readBytes = new byte[buffer.Length]; + if (!ReadFunc(address, readBytes)) + return false; + + readBytes = EndiannessUtilities.SwapByteEndianness(readBytes); + Buffer.BlockCopy(readBytes, 0, buffer, 0, buffer.Length); + + return true; + } + } + + public bool WriteRelative(uint address, byte[] buffer, EndiannessType endianness) => WriteAbsolute(GetAbsoluteAddress(address, buffer.Length), buffer, endianness); + + public bool WriteAbsolute(UIntPtr address, byte[] buffer, EndiannessType endianness) + { + // Safety bounds check + if (address.ToUInt64() < BaseOffset.ToUInt64() + || address.ToUInt64() + (uint)buffer.Length >= BaseOffset.ToUInt64() + ProcessStream.MAX_RAM_SIZE) + return false; + + if (Endianness == endianness) + { + return WriteFunc(address, buffer); + } + else + { + bool success = true; + byte[] toWrite = EndiannessUtilities.SwapByteEndianness(buffer); + + // Between alignment writes + if (buffer.Length < 4) + { + address = EndiannessUtilities.SwapAddressEndianness(address, toWrite.Length); + success &= WriteFunc(address, toWrite); + } + else if (buffer.Length % 4 == 0) // Full alignment writes + { + success &= WriteFunc(address, toWrite); + } + else + { + throw new Exception("Misaligned data"); + } + + return success; + } + } + + public UIntPtr GetAbsoluteAddress(uint n64Address, int size) + { + n64Address &= ~0x80000000U; + UIntPtr absoluteAddress = (UIntPtr)(BaseOffset.ToUInt64() + n64Address); + return EndiannessUtilities.SwapAddressEndianness(absoluteAddress, size); + } + + public uint GetRelativeAddress(UIntPtr absoluteAddress, int size) + { + uint n64address = 0x80000000 | (uint)(absoluteAddress.ToUInt64() - BaseOffset.ToUInt64()); + return EndiannessUtilities.SwapAddressEndianness(n64address, size); + } +} diff --git a/STROOP.Core/GameMemoryAccess/DolphinNotRunningGameException.cs b/STROOP.Core/GameMemoryAccess/DolphinNotRunningGameException.cs new file mode 100644 index 000000000..1d6ac509c --- /dev/null +++ b/STROOP.Core/GameMemoryAccess/DolphinNotRunningGameException.cs @@ -0,0 +1,9 @@ +namespace STROOP.Core.GameMemoryAccess; + +public class DolphinNotRunningGameException : Exception +{ + public DolphinNotRunningGameException() + : base("Dolphin running, but emulator hasn't started") + { + } +} diff --git a/STROOP.Core/GameMemoryAccess/DolphinProcessIO.cs b/STROOP.Core/GameMemoryAccess/DolphinProcessIO.cs new file mode 100644 index 000000000..4e9bf04b9 --- /dev/null +++ b/STROOP.Core/GameMemoryAccess/DolphinProcessIO.cs @@ -0,0 +1,63 @@ +using STROOP.Win32; +using System.Diagnostics; +using System.Runtime.InteropServices; +using Windows.Win32.Foundation; +using Windows.Win32.System.ProcessStatus; + +namespace STROOP.Core.GameMemoryAccess; + +public class DolphinProcessIO : WindowsProcessRamIO +{ + public DolphinProcessIO(Process process, Emulator emulator) + : base(process, emulator) + { + } + + protected override void CalculateOffset() + { + VirtualQueryEx.MemoryBasicInformation info; + IntPtr infoSize = (IntPtr)Marshal.SizeOf(typeof(VirtualQueryEx.MemoryBasicInformation)); + + _baseOffset = (UIntPtr)0; + bool mem1Found = false; + for (IntPtr p = new IntPtr(); + VirtualQueryEx.Invoke(_processHandle, p, out info, infoSize) == infoSize; + p = (IntPtr)(p.ToInt64() + info.RegionSize.ToInt64())) + { + if (mem1Found) + { + if (info.BaseAddress == _baseOffset + 0x10000000) + { + break; + } + else if (info.BaseAddress.ToUInt64() > _baseOffset.ToUInt64() + 0x10000000) + { + break; + } + + continue; + } + + if (info.RegionSize == (IntPtr)0x2000000 && info.Type == VirtualQueryEx.MemoryType.MEM_MAPPED) + { + // Here, it's likely the right page, but it can happen that multiple pages with these criteria + // exists and have nothing to do with the emulated memory. Only the right page has valid + // working set information so an additional check is required that it is backed by physical + // memory. + if (NativeMethodWrappers.QueryWorkingSetEx((HANDLE)_processHandle, info.BaseAddress, out PSAPI_WORKING_SET_EX_INFORMATION wsInfo)) + { + if ((wsInfo.VirtualAttributes.Flags & 0x01) != 0) + { + _baseOffset = info.BaseAddress; + mem1Found = true; + } + } + } + } + + if (_baseOffset.ToUInt64() == 0) + throw new DolphinNotRunningGameException(); + + _baseOffset = (UIntPtr)(_baseOffset.ToUInt64() + _emulator.RamStart); + } +} diff --git a/STROOP/Utilities/Stream/SigScanSharp.cs b/STROOP.Core/GameMemoryAccess/SigScanSharp.cs similarity index 82% rename from STROOP/Utilities/Stream/SigScanSharp.cs rename to STROOP.Core/GameMemoryAccess/SigScanSharp.cs index 04722cf40..7c8425176 100644 --- a/STROOP/Utilities/Stream/SigScanSharp.cs +++ b/STROOP.Core/GameMemoryAccess/SigScanSharp.cs @@ -24,10 +24,10 @@ * */ -using System; -using System.Collections.Generic; -using System.Runtime.InteropServices; using System.Diagnostics; +using STROOP.Win32; + +namespace STROOP.Core.GameMemoryAccess; public class SigScanSharp { @@ -52,7 +52,7 @@ public bool SelectModule(ProcessModule targetModule) g_dictStringPatterns.Clear(); try { - return Win32.ReadProcessMemory(g_hProcess, g_lpModuleBase, g_arrModuleBuffer, (IntPtr)targetModule.ModuleMemorySize); + return NativeMethodWrappers.ReadProcessMemory(g_hProcess, (UIntPtr)g_lpModuleBase, g_arrModuleBuffer); } catch (AccessViolationException) { @@ -72,7 +72,7 @@ private bool PatternCheck(int nOffset, byte[] arrPattern) if (arrPattern[i] == 0x0) continue; - if (arrPattern[i] != this.g_arrModuleBuffer[nOffset + i]) + if (arrPattern[i] != g_arrModuleBuffer[nOffset + i]) return false; } @@ -88,7 +88,7 @@ public IntPtr FindPattern(byte[] arrPattern, ref int minOffset, out long lTime) for (int nModuleIndex = minOffset; nModuleIndex < g_arrModuleBuffer.Length; nModuleIndex++) { - if (this.g_arrModuleBuffer[nModuleIndex] != arrPattern[0]) + if (g_arrModuleBuffer[nModuleIndex] != arrPattern[0]) continue; if (PatternCheck(nModuleIndex, arrPattern)) @@ -107,15 +107,9 @@ private byte[] ParsePatternString(string szPattern) { List patternbytes = new List(); - foreach (var szByte in szPattern.Split(' ')) + foreach (string? szByte in szPattern.Split(' ')) patternbytes.Add(szByte == "?" ? (byte)0x0 : Convert.ToByte(szByte, 16)); return patternbytes.ToArray(); } - - private static class Win32 - { - [DllImport("kernel32.dll")] - public static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, IntPtr dwSize, IntPtr lpNumberOfBytesRead = default(IntPtr)); - } } diff --git a/STROOP.Core/GameMemoryAccess/StFileIO.cs b/STROOP.Core/GameMemoryAccess/StFileIO.cs new file mode 100644 index 000000000..c598e135c --- /dev/null +++ b/STROOP.Core/GameMemoryAccess/StFileIO.cs @@ -0,0 +1,73 @@ +using System.Diagnostics; +using System.IO.Compression; + +namespace STROOP.Core.GameMemoryAccess; + +public class StFileIO : BaseProcessIO +{ + public override bool IsSuspended => false; + + public override event EventHandler OnClose; + + private string _path; + public string Path => _path; + + protected override UIntPtr BaseOffset => new UIntPtr(0x1B0); + protected override EndiannessType Endianness => EndiannessType.Little; + + public override string Name => System.IO.Path.GetFileName(_path); + public override Process Process => null; + + private byte[] _data; + + public StFileIO(string path) : base() + { + _path = path; + LoadMemory(); + } + + private void LoadMemory() + { + using FileStream? fileStream = new FileStream(_path, FileMode.Open); + using GZipStream? gzipStream = new GZipStream(fileStream, CompressionMode.Decompress); + using MemoryStream unzip = new MemoryStream(); + gzipStream.CopyTo(unzip); + _data = unzip.ToArray(); + } + + public void SaveMemory(string path) + { + using FileStream? fileStream = new FileStream(path, FileMode.Create); + using GZipStream? gzipStream = new GZipStream(fileStream, CompressionMode.Compress); + gzipStream.Write(_data, 0, _data.Length); + } + + public override bool Resume() => true; + + public override bool Suspend() => true; + + protected override bool WriteFunc(UIntPtr address, byte[] buffer) + { + if ((uint)address + buffer.Length > _data.Length) + return false; + + Array.Copy(buffer, 0, _data, (uint)address, buffer.Length); + return true; + } + + protected override bool ReadFunc(UIntPtr address, byte[] buffer) + { + if ((uint)address + buffer.Length > _data.Length) + return false; + + Array.Copy(_data, (uint)address, buffer, 0, buffer.Length); + return true; + } + + public override byte[] ReadAllMemory() + { + byte[] output = new byte[_data.Length]; + Array.Copy(_data, output, _data.Length); + return output; + } +} diff --git a/STROOP.Core/GameMemoryAccess/WindowsProcessIO.cs b/STROOP.Core/GameMemoryAccess/WindowsProcessIO.cs new file mode 100644 index 000000000..f0271e1c6 --- /dev/null +++ b/STROOP.Core/GameMemoryAccess/WindowsProcessIO.cs @@ -0,0 +1,265 @@ +using STROOP.Win32; +using System.ComponentModel; +using System.Diagnostics; +using Windows.Win32; +using Windows.Win32.Foundation; +using Windows.Win32.System.Threading; +using static STROOP.Core.ProcessHelper; + +namespace STROOP.Core.GameMemoryAccess; + +public class WindowsProcessRamIO : BaseProcessIO, IDisposable +{ + protected IntPtr _processHandle; + protected Process _process; + protected bool _isSuspended = false; + protected UIntPtr _baseOffset; + protected Emulator _emulator; + + public override bool IsSuspended => _isSuspended; + + protected override EndiannessType Endianness => _emulator.Endianness; + protected override UIntPtr BaseOffset => _baseOffset; + + public override string Name => _process.ProcessName; + public override Process Process => _process; + + public override event EventHandler OnClose; + + public WindowsProcessRamIO(Process process, Emulator emulator) : base() + { + _process = process; + _emulator = emulator; + + _process.EnableRaisingEvents = true; + + var accessFlags = PROCESS_ACCESS_RIGHTS.PROCESS_QUERY_LIMITED_INFORMATION + | PROCESS_ACCESS_RIGHTS.PROCESS_SUSPEND_RESUME + | PROCESS_ACCESS_RIGHTS.PROCESS_VM_OPERATION + | PROCESS_ACCESS_RIGHTS.PROCESS_VM_READ + | PROCESS_ACCESS_RIGHTS.PROCESS_VM_WRITE; + + _processHandle = PInvoke.OpenProcess(accessFlags, false, (uint)_process.Id); + try + { + CalculateOffset(); + } + catch (Exception e) + { + PInvoke.CloseHandle((HANDLE)_processHandle); + throw; + } + + _process.Exited += _process_Exited; + } + + private void _process_Exited(object sender, EventArgs e) + { + Dispose(); + OnClose.Invoke(sender, e); + } + + protected override bool ReadFunc(UIntPtr address, byte[] buffer) + => NativeMethodWrappers.ReadProcessMemory(_processHandle, address, buffer); + + protected override bool WriteFunc(UIntPtr address, byte[] buffer) + => NativeMethodWrappers.WriteProcessMemory(_processHandle, address, buffer); + + public override byte[] ReadAllMemory() + { + List output = new List(); + byte[] buffer = new byte[1]; + int numBytes = 1; + + for (uint address = 0; true; address++) + { + if (!NativeMethodWrappers.ReadProcessMemory(_processHandle, address, buffer)) + break; + output.Add(buffer[0]); + } + + return output.ToArray(); + } + + private bool CompareBytes(byte[] a, byte[] b) + { + if (a.Length != b.Length) return false; + for (int i = 0; i < a.Length; i++) + if (a[i] != b[i]) + return false; + return true; + } + + // see https://msdn.microsoft.com/en-us/library/windows/desktop/ms684139%28v=vs.85%29.aspx + public static bool Is64Bit(Process process) + => Environment.Is64BitOperatingSystem + && PInvoke.IsWow64Process(process.SafeHandle, out var isWow64) + ? !isWow64 + : throw new Win32Exception(); + + protected virtual void CalculateOffset() + { + // Find CORE_RDRAM export from mupen if present + if (PInvoke.SymInitialize(_process.SafeHandle, null, true)) + { + try + { + if (NativeMethodWrappers.GetSymbolAddress(_process.SafeHandle, "CORE_RDRAM", out var address)) + { + bool is64Bit = Is64Bit(_process); + byte[]? buffer = new byte[is64Bit ? 8 : 4]; + ReadAbsolute((UIntPtr)address, buffer, EndiannessType.Little); + _baseOffset = (UIntPtr)(is64Bit ? BitConverter.ToUInt64(buffer, 0) : (ulong)BitConverter.ToUInt32(buffer, 0)); + return; + } + } + finally + { + if (!PInvoke.SymCleanup(_process.SafeHandle)) + throw new Win32Exception(); + } + } + else + { + // documentation doesn't say what to do when SymInitialize returns false, so just call this and don't care for its result for good (or bad) measure :shrug: + // https://learn.microsoft.com/en-us/windows/win32/api/dbghelp/nf-dbghelp-syminitialize + PInvoke.SymCleanup(_process.SafeHandle); + } + + // Find DLL offset if needed + IntPtr dllOffset = new IntPtr(); + + if (_emulator != null && _emulator.Dll != null) + { + ProcessModule dll = _process.Modules.Cast() + ?.FirstOrDefault(d => d.ModuleName == _emulator.Dll); + + if (dll == null) + throw new ArgumentNullException("Could not find "); + + dllOffset = dll.BaseAddress; + } + + _baseOffset = (UIntPtr)(_emulator.RamStart + (ulong)dllOffset.ToInt64()); + + if (!_emulator.AllowAutoDetect) + return; + + // Address of create_thread + foreach ((string name, uint offset) x in new[] { ("US", 0x246338), ("JP", 0x246338) }) + { + string? path = $"Resources/AutoDetectFile {x.name}.bin"; + if (!File.Exists(path)) + continue; + + byte[]? autoDetectPattern = File.ReadAllBytes(path); + byte[]? comparisonBuffer = new byte[autoDetectPattern.Length]; + + SigScanSharp? processScanner = new SigScanSharp(Process.Handle); + int minOffset = 0; + while (processScanner.SelectModule(Process.MainModule)) + { + IntPtr foundPatternAddress = processScanner.FindPattern(autoDetectPattern, ref minOffset, out long t); + minOffset += autoDetectPattern.Length; + if (foundPatternAddress != IntPtr.Zero) + { + UIntPtr newBaseOffset = UIntPtr.Subtract((UIntPtr)(long)foundPatternAddress, (int)x.offset); + _baseOffset = newBaseOffset; + if (VerifyCandidate(newBaseOffset)) + goto verified; + } + else + break; + } + } + + messageLogBuilder.AppendLine("Unable to verify or correct RAM start.\r\nVerify that the game is currently running."); + verified: ; + + bool VerifyCandidate(UIntPtr candidate) + { + try + { + byte[]? mem = new byte[0x200]; + byte?[]? expectedSignature = new byte?[] + { + null, 0x80, 0x1a, 0x3c, + null, null, 0x5a, 0x27, + 0x08, 0x00, 0x40, 0x03, + 0x00, 0x00, 0x00, 0x00, + }; + if (!ReadFunc(candidate, mem)) + return false; + + for (int i = 0; i < expectedSignature.Length; i++) + { + if (expectedSignature[i].HasValue && mem[i] != expectedSignature[i].Value) + return false; + else if (!expectedSignature[i].HasValue) + expectedSignature[i] = mem[i]; + } + + foreach (int location in new[] { 0x80, 0x100, 0x180 }) + for (int i = 0; i < expectedSignature.Length; i++) + if (expectedSignature[i].Value != mem[i + location]) + return false; + } + catch (Exception e) + { + return false; + } + + return true; + } + } + + public override bool Suspend() + { + SuspendProcess(_process); + _isSuspended = true; + return true; + } + + public override bool Resume() + { + // Resume all threads + ResumeProcess(_process); + _isSuspended = false; + return true; + } + + #region IDisposable Support + + private bool disposedValue = false; // To detect redundant calls + + protected virtual void Dispose(bool disposing) + { + if (!disposedValue) + { + if (disposing) + { + if (IsSuspended) + Resume(); + _process.Exited -= _process_Exited; + } + + // Close old process + PInvoke.CloseHandle((HANDLE)_processHandle); + + disposedValue = true; + } + } + + ~WindowsProcessRamIO() + { + Dispose(false); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + #endregion +} diff --git a/STROOP.Core/IEmuRamIO.cs b/STROOP.Core/IEmuRamIO.cs new file mode 100644 index 000000000..498be15cd --- /dev/null +++ b/STROOP.Core/IEmuRamIO.cs @@ -0,0 +1,25 @@ +using System.Diagnostics; + +namespace STROOP.Core; + +public interface IEmuRamIO +{ + string Name { get; } + Process Process { get; } + string GetLastMessages(); + bool Suspend(); + bool Resume(); + + bool IsSuspended { get; } + + bool ReadRelative(uint address, byte[] buffer, EndiannessType endianness); + bool ReadAbsolute(UIntPtr address, byte[] buffer, EndiannessType endianness); + bool WriteRelative(uint address, byte[] buffer, EndiannessType endianness); + bool WriteAbsolute(UIntPtr address, byte[] buffer, EndiannessType endianness); + byte[] ReadAllMemory(); + + UIntPtr GetAbsoluteAddress(uint n64Address, int size); + uint GetRelativeAddress(UIntPtr absoluteAddress, int size); + + event EventHandler OnClose; +} diff --git a/STROOP.Core/ProcessHelper.cs b/STROOP.Core/ProcessHelper.cs new file mode 100644 index 000000000..5c64268ef --- /dev/null +++ b/STROOP.Core/ProcessHelper.cs @@ -0,0 +1,45 @@ +using System.Diagnostics; +using System.Runtime.InteropServices; +using Windows.Win32; +using Windows.Win32.Foundation; +using Windows.Win32.System.Threading; + +namespace STROOP.Core; + +public static class ProcessHelper +{ + public static void ResumeProcess(Process process) + { + // Resume all threads + foreach (ProcessThread pT in process.Threads) + { + HANDLE pOpenThread = PInvoke.OpenThread(THREAD_ACCESS_RIGHTS.THREAD_SUSPEND_RESUME, false, (uint)pT.Id); + + if (pOpenThread == IntPtr.Zero) + continue; + + uint suspendCount = 0; + do + { + suspendCount = PInvoke.ResumeThread(pOpenThread); + } while (suspendCount > 0); + + PInvoke.CloseHandle(pOpenThread); + } + } + + public static void SuspendProcess(Process process) + { + // Pause all threads + foreach (ProcessThread pT in process.Threads) + { + HANDLE pOpenThread = PInvoke.OpenThread(THREAD_ACCESS_RIGHTS.THREAD_SUSPEND_RESUME, false, (uint)pT.Id); + + if (pOpenThread == IntPtr.Zero) + continue; + + PInvoke.SuspendThread(pOpenThread); + PInvoke.CloseHandle(pOpenThread); + } + } +} diff --git a/STROOP.Core/ProcessStream.cs b/STROOP.Core/ProcessStream.cs new file mode 100644 index 000000000..71b4b6fa2 --- /dev/null +++ b/STROOP.Core/ProcessStream.cs @@ -0,0 +1,453 @@ +namespace STROOP.Core; + +public class ProcessStream : IDisposable +{ + public const int MAX_RAM_SIZE = 0x800000; + + public static ProcessStream Instance; + + private IEmuRamIO _io; + public IEmuRamIO IO => _io; + + private byte[] _ram; + private object _mStreamProcess = new object(); + + public event EventHandler OnDisconnect; + public event EventHandler WarnReadonlyOff; + public readonly Action OnUpdate; + + public bool Readonly { get; set; } = false; + public bool ShowWarning { get; set; } = false; + + public byte[] Ram => _ram; + public string ProcessName => _io?.Name ?? "(No Emulator)"; + + public ProcessStream(Action onUpdate) + { + OnUpdate = onUpdate; + _ram = new byte[0x800000]; + } + + public bool SwitchIO(IEmuRamIO newIO) + { + lock (_mStreamProcess) + { + // Dipose of old process + (_io as IDisposable)?.Dispose(); + if (_io != null) + _io.OnClose -= ProcessClosed; + + // Check for no process + if (newIO == null) + goto Error; + + try + { + // Open and set new process + _io = newIO; + _io.OnClose += ProcessClosed; + } + catch (Exception) // Failed to create process + { + goto Error; + } + + return true; + + Error: + _io = null; + return false; + } + } + + private int suspendCounter = 0; + + private class SuspendScope : Scope + { + private readonly ProcessStream stream; + + public SuspendScope(ProcessStream stream) + { + this.stream = stream; + if (stream.suspendCounter == 0) + stream._io?.Suspend(); + stream.suspendCounter++; + } + + protected override void Close() + { + stream.suspendCounter--; + if (stream.suspendCounter == 0) + stream._io?.Resume(); + } + } + + public Scope Suspend() => new SuspendScope(this); + + private void ProcessClosed(object sender, EventArgs e) + { + OnDisconnect?.Invoke(this, new EventArgs()); + } + + public UIntPtr GetAbsoluteAddress(uint relativeAddress, int size = 0) => _io?.GetAbsoluteAddress(relativeAddress, size) ?? new UIntPtr(0); + + public uint GetRelativeAddress(UIntPtr relativeAddress, int size) => _io?.GetRelativeAddress(relativeAddress, size) ?? 0; + + public object GetValue(Type type, uint address, bool absoluteAddress = false, uint? mask = null, int? shift = null) + { + if (type == typeof(byte)) return GetByte(address, absoluteAddress, mask, shift); + if (type == typeof(sbyte)) return GetSByte(address, absoluteAddress, mask, shift); + if (type == typeof(short)) return GetInt16(address, absoluteAddress, mask, shift); + if (type == typeof(ushort)) return GetUInt16(address, absoluteAddress, mask, shift); + if (type == typeof(int)) return GetInt32(address, absoluteAddress, mask, shift); + if (type == typeof(uint)) return GetUInt32(address, absoluteAddress, mask, shift); + if (type == typeof(float)) return GetSingle(address, absoluteAddress, mask, shift); + if (type == typeof(double)) return GetDouble(address, absoluteAddress, mask, shift); + + throw new ArgumentOutOfRangeException("Cannot call ProcessStream.GetValue with type " + type); + } + + public byte GetByte(uint address, bool absoluteAddress = false, uint? mask = null, int? shift = null) + { + byte value = ReadRam((UIntPtr)address, 1, EndiannessType.Little, absoluteAddress)[0]; + if (mask.HasValue) value = (byte)(value & mask.Value); + if (shift.HasValue) value = (byte)(value >> shift.Value); + return value; + } + + public sbyte GetSByte(uint address, bool absoluteAddress = false, uint? mask = null, int? shift = null) + { + sbyte value = (sbyte)ReadRam((UIntPtr)address, 1, EndiannessType.Little, absoluteAddress)[0]; + if (mask.HasValue) value = (sbyte)(value & mask.Value); + if (shift.HasValue) value = (sbyte)(value >> shift.Value); + return value; + } + + public short GetInt16(uint address, bool absoluteAddress = false, uint? mask = null, int? shift = null) + { + short value = BitConverter.ToInt16(ReadRam((UIntPtr)address, 2, EndiannessType.Little, absoluteAddress), 0); + if (mask.HasValue) value = (short)(value & mask.Value); + if (shift.HasValue) value = (short)(value >> shift.Value); + return value; + } + + public ushort GetUInt16(uint address, bool absoluteAddress = false, uint? mask = null, int? shift = null) + { + ushort value = BitConverter.ToUInt16(ReadRam((UIntPtr)address, 2, EndiannessType.Little, absoluteAddress), 0); + if (mask.HasValue) value = (ushort)(value & mask.Value); + if (shift.HasValue) value = (ushort)(value >> shift.Value); + return value; + } + + public int GetInt32(uint address, bool absoluteAddress = false, uint? mask = null, int? shift = null) + { + int value = BitConverter.ToInt32(ReadRam((UIntPtr)address, 4, EndiannessType.Little, absoluteAddress), 0); + if (mask.HasValue) value = (int)(value & mask.Value); + if (shift.HasValue) value = (int)(value >> shift.Value); + return value; + } + + public uint GetUInt32(uint address, bool absoluteAddress = false, uint? mask = null, int? shift = null) + { + uint value = BitConverter.ToUInt32(ReadRam((UIntPtr)address, 4, EndiannessType.Little, absoluteAddress), 0); + if (mask.HasValue) value = (uint)(value & mask.Value); + if (shift.HasValue) value = (uint)(value >> shift.Value); + return value; + } + + public float GetSingle(uint address, bool absoluteAddress = false, uint? mask = null, int? shift = null) => BitConverter.ToSingle(ReadRam((UIntPtr)address, 4, EndiannessType.Little, absoluteAddress), 0); + + public double GetDouble(uint address, bool absoluteAddress = false, uint? mask = null, int? shift = null) => BitConverter.ToDouble(ReadRam((UIntPtr)address, 8, EndiannessType.Little, absoluteAddress), 0); + + public byte[] ReadRam(uint address, int length, EndiannessType endianness, bool absoluteAddress = false) => ReadRam((UIntPtr)address, length, endianness, absoluteAddress); + + public byte[] ReadRam(UIntPtr address, int length, EndiannessType endianness, bool absoluteAddress = false) + { + byte[] readBytes = new byte[length]; + + // Get local address + uint localAddress; + if (absoluteAddress) + localAddress = _io?.GetRelativeAddress(address, length) ?? 0; + else + localAddress = address.ToUInt32(); + localAddress &= ~0x80000000; + + if (EndiannessUtilities.DataIsMisaligned(address, length, EndiannessType.Big)) + return readBytes; + + /// Fix endianness + switch (endianness) + { + case EndiannessType.Little: + // Address is not little endian, fix: + localAddress = EndiannessUtilities.SwapAddressEndianness(localAddress, length); + + if (localAddress + length > _ram.Length) + break; + + Buffer.BlockCopy(_ram, (int)localAddress, readBytes, 0, length); + break; + + case EndiannessType.Big: + // Read padded if misaligned address + byte[] swapBytes; + uint alignedAddress = EndiannessUtilities.AlignedAddressFloor(localAddress); + + + int alignedReadByteCount = readBytes.Length / 4 * 4 + 8; + if (alignedAddress + alignedReadByteCount > _ram.Length) + break; + swapBytes = new byte[alignedReadByteCount]; + + // Read memory + Buffer.BlockCopy(_ram, (int)alignedAddress, swapBytes, 0, swapBytes.Length); + swapBytes = EndiannessUtilities.SwapByteEndianness(swapBytes); + + // Copy memory + Buffer.BlockCopy(swapBytes, (int)(localAddress - alignedAddress), readBytes, 0, readBytes.Length); + + break; + } + + + return readBytes; + } + + public bool ReadProcessMemory(UIntPtr address, byte[] buffer, EndiannessType endianness) => _io?.ReadAbsolute(address, buffer, endianness) ?? false; + + public byte[] ReadAllMemory() => _io?.ReadAllMemory(); + + public bool CheckReadonlyOff() + { + if (ShowWarning) + WarnReadonlyOff?.Invoke(this, new EventArgs()); + + return Readonly; + } + + public bool SetValue(byte value, uint address, bool absoluteAddress = false, uint? mask = null, int? shift = null) + { + if (shift.HasValue) + { + value = (byte)(value << shift.Value); + } + + if (mask.HasValue) + { + byte oldValue = GetByte(address, absoluteAddress); + value = (byte)(oldValue & ~mask.Value | value & mask.Value); + } + + bool returnValue = WriteRam(new byte[] { value }, (UIntPtr)address, EndiannessType.Little, absoluteAddress); + return returnValue; + } + + public bool SetValue(sbyte value, uint address, bool absoluteAddress = false, uint? mask = null, int? shift = null) + { + if (shift.HasValue) + { + value = (sbyte)(value << shift.Value); + } + + if (mask.HasValue) + { + sbyte oldValue = GetSByte(address, absoluteAddress); + value = (sbyte)(oldValue & ~mask.Value | value & mask.Value); + } + + bool returnValue = WriteRam(new byte[] { (byte)value }, (UIntPtr)address, EndiannessType.Little, absoluteAddress); + return returnValue; + } + + public bool SetValue(short value, uint address, bool absoluteAddress = false, uint? mask = null, int? shift = null) + { + if (shift.HasValue) + { + value = (short)(value << shift.Value); + } + + if (mask.HasValue) + { + short oldValue = GetInt16(address, absoluteAddress); + value = (short)(oldValue & ~mask.Value | value & mask.Value); + } + + bool returnValue = WriteRam(BitConverter.GetBytes(value), (UIntPtr)address, EndiannessType.Little, absoluteAddress); + return returnValue; + } + + public bool SetValue(ushort value, uint address, bool absoluteAddress = false, uint? mask = null, int? shift = null) + { + if (shift.HasValue) + { + value = (ushort)(value << shift.Value); + } + + if (mask.HasValue) + { + ushort oldValue = GetUInt16(address, absoluteAddress); + value = (ushort)(oldValue & ~mask.Value | value & mask.Value); + } + + bool returnValue = WriteRam(BitConverter.GetBytes(value), (UIntPtr)address, EndiannessType.Little, absoluteAddress); + return returnValue; + } + + public bool SetValue(int value, uint address, bool absoluteAddress = false, uint? mask = null, int? shift = null) + { + if (shift.HasValue) + { + value = (int)(value << shift.Value); + } + + if (mask.HasValue) + { + int oldValue = GetInt32(address, absoluteAddress); + value = (int)(oldValue & ~mask.Value | value & mask.Value); + } + + bool returnValue = WriteRam(BitConverter.GetBytes(value), (UIntPtr)address, EndiannessType.Little, absoluteAddress); + return returnValue; + } + + public bool SetValue(uint value, uint address, bool absoluteAddress = false, uint? mask = null, int? shift = null) + { + if (shift.HasValue) + { + value = (uint)(value << shift.Value); + } + + if (mask.HasValue) + { + uint oldValue = GetUInt32(address, absoluteAddress); + value = (uint)(oldValue & ~mask.Value | value & mask.Value); + } + + bool returnValue = WriteRam(BitConverter.GetBytes(value), (UIntPtr)address, EndiannessType.Little, absoluteAddress); + return returnValue; + } + + public bool SetValue(float value, uint address, bool absoluteAddress = false, uint? mask = null, int? shift = null) + { + bool returnValue = WriteRam(BitConverter.GetBytes(value), (UIntPtr)address, EndiannessType.Little, absoluteAddress); + return returnValue; + } + + public bool SetValue(double value, uint address, bool absoluteAddress = false, uint? mask = null, int? shift = null) + { + byte[] bytes = BitConverter.GetBytes(value); + byte[] bytes1 = bytes.Take(4).ToArray(); + byte[] bytes2 = bytes.Skip(4).Take(4).ToArray(); + byte[] bytesSwapped = bytes2.Concat(bytes1).ToArray(); + + bool returnValue = WriteRam(bytesSwapped, (UIntPtr)address, EndiannessType.Little, absoluteAddress); + return returnValue; + } + + public bool WriteRam(byte[] buffer, uint address, EndiannessType endianness, + int bufferStart = 0, int? length = null, bool safeWrite = true) => WriteRam(buffer, (UIntPtr)address, endianness, false, bufferStart, length, safeWrite); + + private object ram_write_lock = new object(); + + public bool WriteRam(byte[] buffer, UIntPtr address, EndiannessType endianness, bool absoluteAddress = false, + int bufferStart = 0, int? length = null, bool safeWrite = true) + { + lock (ram_write_lock) + { + if (length == null) + length = buffer.Length - bufferStart; + + if (CheckReadonlyOff()) + return false; + + byte[] writeBytes = new byte[length.Value]; + Array.Copy(buffer, bufferStart, writeBytes, 0, length.Value); + + // Attempt to pause the game before writing + bool preSuspended = _io?.IsSuspended ?? false; + if (safeWrite) + _io?.Suspend(); + + if (EndiannessUtilities.DataIsMisaligned(address, length.Value, EndiannessType.Big)) + throw new Exception("Misaligned data"); + + // Write memory to game/process + bool result; + if (absoluteAddress) + result = _io?.WriteAbsolute(address, writeBytes, endianness) ?? false; + else + { + result = _io?.WriteRelative(address.ToUInt32(), writeBytes, endianness) ?? false; + if (result && _io.ReadRelative(address.ToUInt32(), writeBytes, endianness)) + Array.Copy(writeBytes, 0, Ram, address.ToUInt32() & 0x00FFFFFF, writeBytes.Length); + } + + // Resume stream + if (safeWrite && !preSuspended) + _io?.Resume(); + + return result; + } + } + + public bool RefreshRam() + { + lock (_ram) + { + try + { + // Read whole ram value to buffer + if (_ram.Length != MAX_RAM_SIZE) + _ram = new byte[MAX_RAM_SIZE]; + + return _io?.ReadRelative(0, _ram, EndiannessType.Little) ?? false; + } + catch (Exception) + { + return false; + } + } + } + + public bool GetAllRam(out byte[] allRam) + { + allRam = new byte[MAX_RAM_SIZE]; + try + { + return _io?.ReadRelative(0, allRam, EndiannessType.Little) ?? false; + } + catch + { + return false; + } + } + + #region IDisposable Support + + private bool disposedValue = false; // To detect redundant calls + + protected virtual void Dispose(bool disposing) + { + if (!disposedValue) + { + if (disposing) + { + if (_io != null) + { + _io.OnClose -= ProcessClosed; + (_io as IDisposable)?.Dispose(); + } + } + + disposedValue = true; + } + } + + public void Dispose() + { + Dispose(true); + } + + #endregion +} diff --git a/STROOP.Core/RomVersion.cs b/STROOP.Core/RomVersion.cs new file mode 100644 index 000000000..51881601b --- /dev/null +++ b/STROOP.Core/RomVersion.cs @@ -0,0 +1,9 @@ +namespace STROOP.Core; + +public enum RomVersion +{ + US, + JP, + SH, + EU, +}; diff --git a/STROOP.Core/STROOP.Core.csproj b/STROOP.Core/STROOP.Core.csproj new file mode 100644 index 000000000..86bbab216 --- /dev/null +++ b/STROOP.Core/STROOP.Core.csproj @@ -0,0 +1,12 @@ + + + + net8.0 + enable + disable + + + + + + diff --git a/STROOP.Core/Scopes.cs b/STROOP.Core/Scopes.cs new file mode 100644 index 000000000..4bb9298aa --- /dev/null +++ b/STROOP.Core/Scopes.cs @@ -0,0 +1,63 @@ +namespace STROOP.Core; + +#pragma warning disable CA1063 // Implement IDisposable correctly - this is not a resource! +public abstract class Scope : IDisposable +{ + protected Scope() + { + } + + protected abstract void Close(); + void IDisposable.Dispose() => Close(); +} +#pragma warning restore CA1063 + +public sealed class AccessScope : Scope +{ + public static T content => scopes.Count == 0 ? default(T) : scopes.Peek().obj; + + private static Stack> scopes = new Stack>(); + private T obj; + + public AccessScope(T obj) + { + this.obj = obj; + scopes.Push(this); + } + + protected override void Close() + { + if (scopes.Pop() != this) + throw new Exception($"Scopes must be disposed in reverse creation order."); + } +} + +public class IgnoreScope : Scope +{ + private Stack scopeStack = new Stack(); + + private IgnoreScope parent; + + public IgnoreScope() + { + } + + private IgnoreScope(IgnoreScope parent) => this.parent = parent; + + public IgnoreScope New() + { + IgnoreScope? newScope = new IgnoreScope(this); + scopeStack.Push(newScope); + return newScope; + } + + protected override void Close() + { + if (parent.scopeStack.Pop() != this) + throw new InvalidOperationException("IgnoreScopes popped in invalid order"); + } + + public bool ignore => scopeStack.Count > 0; + + public static implicit operator bool(IgnoreScope ignoreScope) => ignoreScope.ignore; +} diff --git a/STROOP.Core/Utilities/EqualityComparer.cs b/STROOP.Core/Utilities/EqualityComparer.cs new file mode 100644 index 000000000..f20708432 --- /dev/null +++ b/STROOP.Core/Utilities/EqualityComparer.cs @@ -0,0 +1,17 @@ +namespace STROOP.Core.Utilities; + +public class EqualityComparer : IEqualityComparer +{ + private Func equalsFunc; + private Func getHashCodeFunc; + + public EqualityComparer(Func equalsFunc, Func getHashCodeFunc = null) + { + this.equalsFunc = equalsFunc; + this.getHashCodeFunc = getHashCodeFunc ?? (_ => _.GetHashCode()); + } + + bool IEqualityComparer.Equals(T x, T y) => equalsFunc(x, y); + + int IEqualityComparer.GetHashCode(T obj) => getHashCodeFunc(obj); +} diff --git a/STROOP.Core/Utilities/GeneralUtilities.cs b/STROOP.Core/Utilities/GeneralUtilities.cs new file mode 100644 index 000000000..7fcf0a134 --- /dev/null +++ b/STROOP.Core/Utilities/GeneralUtilities.cs @@ -0,0 +1,84 @@ +using System.Reflection; + +namespace STROOP.Core.Utilities; + +public static class GeneralUtilities +{ + public static IEnumerable Yield(this T value) + { + yield return value; + } + + public static EqualityComparer GetEqualityComparer(Func equalsFunc, Func getHashCodeFunc = null) + => new EqualityComparer(equalsFunc, getHashCodeFunc); + + public static IEnumerable GetStroopTypes() + => AppDomain.CurrentDomain.GetAssemblies() + .Where(x => x.FullName?.StartsWith("STROOP") ?? false) + .SelectMany(x => x.GetTypes()); + + public static void ExecuteInitializers(params object[] args) where T : InitializerAttribute + { + foreach (Type? type in GetStroopTypes()) + foreach (MethodInfo? m in type.GetMethods(BindingFlags.Static | BindingFlags.NonPublic)) + if (m.GetParameters().Length == 0 && m.GetCustomAttribute() != null) + m.Invoke(null, args); + } + + public static List ConvertAndRemoveNull(this IEnumerable lstIn, Func converter) where TOut : class + { + List? lstOut = new List(); + foreach (TIn? obj in lstIn) + { + TOut? convertedObj = converter(obj); + if (convertedObj != null) + lstOut.Add(convertedObj); + } + + return lstOut; + } + + public static List ConvertAndRemoveNull(this System.Collections.IEnumerable lstIn, Func converter) where TOut : class + { + List? lstOut = new List(); + foreach (object? obj in lstIn) + { + TOut? convertedObj = converter(obj); + if (convertedObj != null) + lstOut.Add(convertedObj); + } + + return lstOut; + } + + public static IEnumerable ConvertAll(this IEnumerable lstIn, Func converter) + { + foreach (TIn? obj in lstIn) + yield return converter(obj); + } + + + public static T GetMeaningfulValue(Func> values, T fail, T @default) + { + T result = @default; + foreach (T? value in values()) + GetMeaningfulValue(ref result, value, fail); + return result; + } + + public static void GetMeaningfulValue(ref T result, T input, T fail) + { + if (!(result?.Equals(fail) ?? fail == null)) + if (result == null) + result = input; + else if (!(input?.Equals(result) ?? result == null)) + result = fail; + } + + public static Dictionary ReverseDictionary(Dictionary dictionary) + { + Dictionary reverseDictionary = new Dictionary(); + dictionary.ToList().ForEach(keyValuePair => { reverseDictionary.Add(keyValuePair.Value, keyValuePair.Key); }); + return reverseDictionary; + } +} diff --git a/STROOP.Core/Utilities/InitializerAttribute.cs b/STROOP.Core/Utilities/InitializerAttribute.cs new file mode 100644 index 000000000..a270b41d9 --- /dev/null +++ b/STROOP.Core/Utilities/InitializerAttribute.cs @@ -0,0 +1,4 @@ +namespace STROOP.Core.Utilities; + +[AttributeUsage(AttributeTargets.Method, Inherited = true, AllowMultiple = false)] +public abstract class InitializerAttribute : Attribute; diff --git a/STROOP.Core/Utilities/MoreMath.cs b/STROOP.Core/Utilities/MoreMath.cs new file mode 100644 index 000000000..cba926e30 --- /dev/null +++ b/STROOP.Core/Utilities/MoreMath.cs @@ -0,0 +1,853 @@ +namespace STROOP.Utilities +{ + public static class MoreMath + { + public static float EaseIn(float f) => 1 - 1 / (float)Math.Exp(f); + + public static int Sign(double value) + { + if (value == 0 || double.IsNaN(value)) return 0; + return value > 0 ? 1 : -1; + } + + public static int Min(params int[] values) + { + if (values.Length == 0) return 0; + int min = values[0]; + for (int i = 1; i < values.Length; i++) + { + if (values[i] < min) min = values[i]; + } + + return min; + } + + public static int Max(params int[] values) + { + if (values.Length == 0) return 0; + int max = values[0]; + for (int i = 1; i < values.Length; i++) + { + if (values[i] > max) max = values[i]; + } + + return max; + } + + public static double Min(params double[] values) + { + if (values.Length == 0) return 0; + double min = values[0]; + for (int i = 1; i < values.Length; i++) + { + if (values[i] < min) min = values[i]; + } + + return min; + } + + public static double Max(params double[] values) + { + if (values.Length == 0) return 0; + double max = values[0]; + for (int i = 1; i < values.Length; i++) + { + if (values[i] > max) max = values[i]; + } + + return max; + } + + public static double Average(params double[] values) + { + if (values.Length == 0) return 0; + double sum = 0; + for (int i = 0; i < values.Length; i++) + { + sum += values[i]; + } + + return sum / values.Length; + } + + public static double GetHypotenuse(double x, double y) + { + return Math.Sqrt(x * x + y * y); + } + + public static double GetHypotenuse(double x, double y, double z) + { + return Math.Sqrt(x * x + y * y + z * z); + } + + public static double GetDistanceBetween(double x1, double y1, double z1, double x2, double y2, double z2) + { + double dx, dy, dz; + dx = x1 - x2; + dy = y1 - y2; + dz = z1 - z2; + return Math.Sqrt(dx * dx + dy * dy + dz * dz); + } + + public static double GetDistanceBetween(double x1, double z1, double x2, double z2) + { + double dx, dz; + dx = x1 - x2; + dz = z1 - z2; + return Math.Sqrt(dx * dx + dz * dz); + } + + public static (double xDist, double zDist) GetComponentsFromVector(double magnitude, double angle) + { + double radians = AngleUnitsToRadians(angle); + double xComponent = Math.Sin(radians); + double zComponent = Math.Cos(radians); + return (magnitude * xComponent, magnitude * zComponent); + } + + public static (double xDist, double zDist) AddVectorToPoint( + double magnitude, double angle, double x1, double z1) + { + (double xDist, double zDist) = GetComponentsFromVector(magnitude, angle); + return (x1 + xDist, z1 + zDist); + } + + public static (double sidewaysDist, double forwardsDist) GetComponentsFromVectorRelatively( + double magnitude, double vectorAngle, double baseAngle) + { + double rotatedAngle = NormalizeAngleDouble(vectorAngle - baseAngle); + (double xComponent, double zComponent) = GetComponentsFromVector(magnitude, rotatedAngle); + return (-1 * xComponent, zComponent); + } + + public static (double sidewaysDist, double forwardsDist) GetSidewaysAndForwardsDist( + double x1, double z1, double x2, double z2, double baseAngle) + { + double hDist = GetDistanceBetween(x1, z1, x2, z2); + double angle = AngleTo_AngleUnits(x1, z1, x2, z2); + return GetComponentsFromVectorRelatively(hDist, angle, baseAngle); + } + + public static (double xDist, double zDist) GetAbsoluteComponents( + double sidewaysDist, double forwardsDist, double relativeAngle) + { + double relX = sidewaysDist; + double relZ = -1 * forwardsDist; + double relDist = GetHypotenuse(relX, relZ); + double relAngle = AngleTo_AngleUnits(relX, relZ); + double absAngle = relativeAngle + ReverseAngle(relAngle); + return GetComponentsFromVector(relDist, absAngle); + } + + public static (double newXPos, double newZPos) GetRelativelyOffsettedPosition( + double baseX, double baseZ, double baseAngle, double pointX, double pointZ, + double? goalSidewaysDistNullable, double? goalForwardsDistNullable) + { + double hdist = GetDistanceBetween(baseX, baseZ, pointX, pointZ); + double angle = AngleTo_AngleUnits(baseX, baseZ, pointX, pointZ); + (double currentSidewaysDist, double currentForwardsDist) = + GetComponentsFromVectorRelatively(hdist, angle, baseAngle); + + double goalSidewaysDist = goalSidewaysDistNullable ?? currentSidewaysDist; + double goalForwardsDist = goalForwardsDistNullable ?? currentForwardsDist; + + (double xDist, double zDist) = GetAbsoluteComponents(goalSidewaysDist, goalForwardsDist, baseAngle); + return (baseX + xDist, baseZ + zDist); + } + + public static (double magnitude, double angle) GetVectorFromComponents(double xDist, double zDist) + { + double magnitude = Math.Sqrt(xDist * xDist + zDist * zDist); + double angle = AngleTo_AngleUnits(0, 0, xDist, zDist); + return (magnitude, angle); + } + + public static (double magnitude, double angle) GetVectorFromCoordinates( + double xFrom, double zFrom, double xTo, double zTo, bool usePositiveMagnitude) + { + double xDist = xTo - xFrom; + double zDist = zTo - zFrom; + (double magnitude, double angle) = GetVectorFromComponents(xDist, zDist); + double adjustedMagnitude = usePositiveMagnitude ? magnitude : -1 * magnitude; + double adjustedAngle = usePositiveMagnitude ? angle : ReverseAngle(angle); + return (adjustedMagnitude, adjustedAngle); + } + + public static (double x, double y, double z) ScaleVector3D( + double xComp, double yComp, double zComp, double finalDist) + { + double magnitude = GetHypotenuse(xComp, yComp, zComp); + if (magnitude == 0) return (finalDist, 0, 0); + double multiplier = finalDist / magnitude; + return (xComp * multiplier, yComp * multiplier, zComp * multiplier); + } + + public static (double x, double z) ScaleVector2D( + double xComp, double zComp, double finalDist) + { + double magnitude = GetHypotenuse(xComp, zComp); + if (magnitude == 0) return (finalDist, 0); + double multiplier = finalDist / magnitude; + return (xComp * multiplier, zComp * multiplier); + } + + public static double ScaleVector1D( + double xComp, double finalDist) + { + return xComp >= 0 ? finalDist : -1 * finalDist; + } + + public static (double x, double y, double z) ExtrapolateLine3D( + double p1X, double p1Y, double p1Z, double p2X, double p2Y, double p2Z, double finalDist) + { + double diffX = p2X - p1X; + double diffY = p2Y - p1Y; + double diffZ = p2Z - p1Z; + (double scaledX, double scaledY, double scaledZ) = ScaleVector3D(diffX, diffY, diffZ, finalDist); + return (p1X + scaledX, p1Y + scaledY, p1Z + scaledZ); + } + + public static (double x, double z) ExtrapolateLine2D( + double p1X, double p1Z, double p2X, double p2Z, double finalDist) + { + double diffX = p2X - p1X; + double diffZ = p2Z - p1Z; + (double scaledX, double scaledZ) = ScaleVector2D(diffX, diffZ, finalDist); + return (p1X + scaledX, p1Z + scaledZ); + } + + public static double GetPositionAlongLine(double p1X, double p1Y, double p2X, double p2Y, double x) + { + double slope = (p2Y - p1Y) / (p2X - p1X); + return (x - p1X) * slope + p1Y; + } + + /** p2 is pivot. */ + public static (double x, double z) RotatePointAboutPointToAngle( + double p1X, double p1Z, double p2X, double p2Z, double finalAngle) + { + double dist = GetDistanceBetween(p1X, p1Z, p2X, p2Z); + (double xDiff, double zDiff) = GetComponentsFromVector(dist, finalAngle); + return (p2X + xDiff, p2Z + zDiff); + } + + /** p2 is pivot. */ + public static (double x, double z) RotatePointAboutPointAnAngularDistance( + double p1X, double p1Z, double p2X, double p2Z, double angularDistance) + { + double dist = GetDistanceBetween(p1X, p1Z, p2X, p2Z); + double angle = AngleTo_AngleUnits(p1X, p1Z, p2X, p2Z); + (double xDiff, double zDiff) = GetComponentsFromVector(dist, angle + angularDistance); + return (p2X + xDiff, p2Z + zDiff); + } + + public static double GetDistanceFromPointToLine( + double pX, double pZ, double v1X, double v1Z, double v2X, double v2Z) + { + double numerator = Math.Abs((v2Z - v1Z) * pX - (v2X - v1X) * pZ + v2X * v1Z - v2Z * v1X); + double denominator = GetDistanceBetween(v1X, v1Z, v2X, v2Z); + return numerator / denominator; + } + + public static bool IsPointInsideTriangle( + double pX, double pZ, double v1X, double v1Z, double v2X, double v2Z, double v3X, double v3Z) + { + bool leftOf12 = IsPointLeftOfLine(pX, pZ, v1X, v1Z, v2X, v2Z); + bool leftOf23 = IsPointLeftOfLine(pX, pZ, v2X, v2Z, v3X, v3Z); + bool leftOf31 = IsPointLeftOfLine(pX, pZ, v3X, v3Z, v1X, v1Z); + + bool rightOf12 = IsPointRightOfLine(pX, pZ, v1X, v1Z, v2X, v2Z); + bool rightOf23 = IsPointRightOfLine(pX, pZ, v2X, v2Z, v3X, v3Z); + bool rightOf31 = IsPointRightOfLine(pX, pZ, v3X, v3Z, v1X, v1Z); + + return (leftOf12 && leftOf23 && leftOf31) || (rightOf12 && rightOf23 && rightOf31); + } + + public static bool IsPointLeftOfLine( + double pX, double pZ, double v1X, double v1Z, double v2X, double v2Z) + { + return (v1Z - pZ) * (v2X - v1X) >= (v1X - pX) * (v2Z - v1Z); + } + + public static bool IsPointRightOfLine( + double pX, double pZ, double v1X, double v1Z, double v2X, double v2Z) + { + return (v1Z - pZ) * (v2X - v1X) <= (v1X - pX) * (v2Z - v1Z); + } + + public static double GetPlaneDistanceBetweenPoints( + double pointX, double pointY, double pointZ, double startX, double startY, double startZ, double endX, double endY, double endZ) + { + double startToPointX = pointX - startX; + double startToPointY = pointY - startY; + double startToPointZ = pointZ - startZ; + double startToEndX = endX - startX; + double startToEndY = endY - startY; + double startToEndZ = endZ - startZ; + + double dotProduct = GetDotProduct(startToPointX, startToPointY, startToPointZ, startToEndX, startToEndY, startToEndZ); + double prevToNextDist = GetDistanceBetween(startX, startY, startZ, endX, endY, endZ); + double planeDistance = dotProduct / prevToNextDist; + + return planeDistance; + } + + public static double ReflectValueAboutValue(double value, double pivot) + { + double diff = pivot - value; + return pivot + diff; + } + + public static double NormalizeAngleDouble(double angle) + { + return NonNegativeModulus(angle, 65536); + } + + public static double NormalizeAngleDoubleSigned(double angle) + { + return MaybeNegativeModulus(angle, 65536); + } + + public static ushort NormalizeAngleUshort(double angle) + { + double nonNegative = NormalizeAngleDouble(angle); + return (ushort)(Math.Round(nonNegative) % 65536); + } + + public static short NormalizeAngleShort(double angle) + { + ushort angleUshort = NormalizeAngleUshort(angle); + short angleShort; + if (angleUshort > 32767) + { + angleShort = (short)(angleUshort - 65536); + } + else + { + angleShort = (short)angleUshort; + } + + return angleShort; + } + + public static ushort NormalizeAngleTruncated(double angle) + { + angle = NormalizeAngleDouble(angle); + ushort angleUshort = (ushort)angle; + ushort angleTruncated = (ushort)(angleUshort - (angleUshort % 16)); + return angleTruncated; + } + + public static double NormalizeAngleUsingType(double angle, Type type) + { + if (type == typeof(short)) return MaybeNegativeModulus(angle, 1.0 + short.MaxValue - short.MinValue); + if (type == typeof(ushort)) return NonNegativeModulus(angle, 1.0 + ushort.MaxValue - ushort.MinValue); + if (type == typeof(int)) return MaybeNegativeModulus(angle, 1.0 + int.MaxValue - int.MinValue); + if (type == typeof(uint)) return NonNegativeModulus(angle, 1.0 + uint.MaxValue - uint.MinValue); + throw new ArgumentOutOfRangeException("Cannot call NormalizeAngleUsingType with type " + type); + } + + public static double NormalizeAngle45Degrees(double angle) + { + int divided = NormalizeAngleUshort(angle + 4096) / 8192; + return divided * 8192; + } + + public static double AngleTo_Radians(double xFrom, double zFrom, double xTo, double zTo) + { + return Math.Atan2(xTo - xFrom, zTo - zFrom); + } + + public static double AngleTo_Radians(double xTo, double zTo) + { + return AngleTo_Radians(0, 0, xTo, zTo); + } + + public static double AngleTo_AngleUnits(double xFrom, double zFrom, double xTo, double zTo) + { + return RadiansToAngleUnits(AngleTo_Radians(xFrom, zFrom, xTo, zTo)); + } + + public static double AngleTo_AngleUnits(double xTo, double zTo) + { + return AngleTo_AngleUnits(0, 0, xTo, zTo); + } + + public static double? AngleTo_AngleUnitsNullable(double xTo, double zTo) + { + if (xTo == 0 && zTo == 0) return null; + return AngleTo_AngleUnits(0, 0, xTo, zTo); + } + + public static ushort AngleTo_AngleUnitsRounded(double xFrom, double zFrom, double xTo, double zTo) + { + return RadiansToAngleUnitsRounded(AngleTo_Radians(xFrom, zFrom, xTo, zTo)); + } + + public static ushort AngleTo_AngleUnitsRounded(double xTo, double zTo) + { + return AngleTo_AngleUnitsRounded(0, 0, xTo, zTo); + } + + public static (double radius, double theta, double phi) EulerToSpherical_Radians(double x, double y, double z) + { + double radius = Math.Sqrt(x * x + y * y + z * z); + double theta = Math.Atan2(x, z); + double phi = radius == 0 ? 0 : Math.Asin(y / radius); + return (radius, theta, phi); + } + + public static (double radius, double theta, double phi) EulerToSpherical_AngleUnits(double x, double y, double z) + { + double radius, thetaRadians, phiRadians; + (radius, thetaRadians, phiRadians) = EulerToSpherical_Radians(x, y, z); + double thetaAngleUnits = RadiansToAngleUnits(thetaRadians); + double phiAngleUnits = RadiansToAngleUnits(phiRadians); + return (radius, thetaAngleUnits, phiAngleUnits); + } + + public static (double x, double y, double z) SphericalToEuler_Radians(double radius, double theta, double phi) + { + double x = radius * Math.Sin(theta) * Math.Cos(phi); + double y = radius * Math.Sin(phi); + double z = radius * Math.Cos(theta) * Math.Cos(phi); + return (x, y, z); + } + + public static (double x, double y, double z) SphericalToEuler_AngleUnits(double radius, double thetaAngleUnits, double phiAngleUnits) + { + double thetaRadians = AngleUnitsToRadians(thetaAngleUnits); + double phiRadians = AngleUnitsToRadians(phiAngleUnits); + return SphericalToEuler_Radians(radius, thetaRadians, phiRadians); + } + + public static (double radius, double theta, double height) EulerToCylindrical_Radians(double x, double y, double z) + { + double radius = Math.Sqrt(x * x + z * z); + double theta = Math.Atan2(x, z); + double height = y; + return (radius, theta, height); + } + + public static (double x, double y, double z) CylindricalToEuler_Radians(double radius, double theta, double height) + { + double x = radius * Math.Sin(theta); + double y = height; + double z = radius * Math.Cos(theta); + return (x, y, z); + } + + public static (double radius, double thetaAngleUnits, double height) EulerToCylindrical_AngleUnits(double x, double y, double z) + { + double radius, thetaRadians, height; + (radius, thetaRadians, height) = EulerToCylindrical_Radians(x, y, z); + double thetaAngleUnits = RadiansToAngleUnits(thetaRadians); + return (radius, thetaAngleUnits, height); + } + + public static (double x, double y, double z) CylindricalToEuler_AngleUnits(double radius, double thetaAngleUnits, double height) + { + double thetaRadians = AngleUnitsToRadians(thetaAngleUnits); + return CylindricalToEuler_Radians(radius, thetaRadians, height); + } + + public static (double radius, double thetaAngleUnits, double height) EulerToCylindricalAboutPivot( + double x, double y, double z, double pivotX, double pivotY, double pivotZ) + { + return EulerToCylindrical_AngleUnits(x - pivotX, y - pivotY, z - pivotZ); + } + + public static double GetPitch(double startX, double startY, double startZ, double endX, double endY, double endZ) + { + (double radius, double theta, double phi) = EulerToSpherical_AngleUnits(endX - startX, endY - startY, endZ - startZ); + return phi; + } + + public static double RadiansToAngleUnits(double radians) + { + double angleUnits = radians / (2 * Math.PI) * 65536; + return NonNegativeModulus(angleUnits, 65536); + } + + public static ushort RadiansToAngleUnitsRounded(double radians) + { + double angleUnits = radians / (2 * Math.PI) * 65536; + double nonNegative = NonNegativeModulus(angleUnits, 65536); + return (ushort)(Math.Round(nonNegative) % 65536); + } + + public static double AngleUnitsToRadians(double angleUnits) + { + double radians = angleUnits / 65536 * (2 * Math.PI); + return NonNegativeModulus(radians, 2 * Math.PI); + } + + public static double AngleUnitsToDegrees(double angleUnits) + { + double radians = angleUnits / 65536 * 360; + return NonNegativeModulus(radians, 360); + } + + public static double RotateAngleCCW(double angleUnits, double rotationDiff) + { + return NormalizeAngleDouble(angleUnits + rotationDiff); + } + + public static double RotateAngleCW(double angleUnits, double rotationDiff) + { + return RotateAngleCCW(angleUnits, -1 * rotationDiff); + } + + public static double ReverseAngle(double angleUnits) + { + return RotateAngleCCW(angleUnits, 32768); + } + + public static (double x, double y, double z) OffsetSpherically( + double x, double y, double z, double radiusChange, double thetaChangeAngleUnits, double phiChangeAngleUnits) + { + double oldRadius, oldTheta, oldPhi; + (oldRadius, oldTheta, oldPhi) = EulerToSpherical_AngleUnits(x, y, z); + + double newRadius = Math.Max(oldRadius + radiusChange, 0); + double newTheta = NonNegativeModulus(oldTheta + thetaChangeAngleUnits, 65536); + double newPhi = Clamp(NormalizeAngleDoubleSigned(oldPhi) + phiChangeAngleUnits, -16384, 16384); + + return SphericalToEuler_AngleUnits(newRadius, newTheta, newPhi); + } + + public static (double x, double y, double z) OffsetSphericallyAboutPivot( + double x, double y, double z, double radiusChange, double thetaChangeAngleUnits, double phiChangeAngleUnits, + double pivotX, double pivotY, double pivotZ) + { + double oldRelX = x - pivotX; + double oldRelY = y - pivotY; + double oldRelZ = z - pivotZ; + + double newRelX, newRelY, newRelZ; + (newRelX, newRelY, newRelZ) = + OffsetSpherically(oldRelX, oldRelY, oldRelZ, radiusChange, thetaChangeAngleUnits, phiChangeAngleUnits); + + return (newRelX + pivotX, newRelY + pivotY, newRelZ + pivotZ); + } + + public static double OffsetAngleUnitsCapped(double angleUnits, double change) + { + angleUnits = NonNegativeModulus(angleUnits, 65536); + angleUnits = Clamp(angleUnits + change, 0, 65536); + angleUnits = NonNegativeModulus(angleUnits, 65536); + return angleUnits; + } + + /** Gets the value in [0, modulus). */ + public static int NonNegativeModulus(int value, int modulus) + { + value %= modulus; + if (value < 0) value += modulus; + return value; + } + + /** Gets the value in [0, modulus). */ + public static double NonNegativeModulus(double value, double modulus) + { + value %= modulus; + if (value < 0) value += modulus; + return value; + } + + /** Gets the value in [-modulus/2, modulus/2). */ + public static double MaybeNegativeModulus(double value, double modulus) + { + value %= modulus; + if (value < 0) value += modulus; + if (value >= modulus / 2) value -= modulus; + return value; + } + + public static double GetUnsignedAngleDifference(double angle1, double angle2) + { + return NonNegativeModulus(angle2 - angle1, 65536); + } + + public static double GetAngleDifference(double angle1, double angle2) + { + return MaybeNegativeModulus(angle2 - angle1, 65536); + } + + public static double GetAngleDistance(double angle1, double angle2) + { + return Math.Abs(GetAngleDifference(angle1, angle2)); + } + + public static bool IsAngleBetweenAngles(double angle, double angleMin, double angleMax) + { + double effectiveAngle = NonNegativeModulus(angle - angleMin, 65536); + double effectiveRange = NonNegativeModulus(angleMax - angleMin, 65536); + return effectiveAngle <= effectiveRange; + } + + public static double Clamp(double value, double min, double max) + { + return Math.Min(Math.Max(value, min), max); + } + + public static int Clamp(int value, int min, int max) + { + return Math.Min(Math.Max(value, min), max); + } + + public static double TruncateToMultipleOf16(double value) + { + double divided = value / 16; + double truncated = Math.Floor(divided); + double multipled = truncated * 16; + return multipled; + } + + public static string GetPercentString(double count, double total, int decimalPlaces) + { + double percent = Math.Round(100 * count / total, decimalPlaces); + string percentString = percent.ToString("N" + decimalPlaces) + "%"; + return percentString; + } + + public static (double scaledX, double scaledZ) ScaleValues(double xValue, double zValue) + { + double magnitude = Math.Max(Math.Abs(xValue), Math.Abs(zValue)); + double totalMagnitude = Math.Sqrt(xValue * xValue + zValue * zValue); + double multiplier = totalMagnitude == 0 ? 1 : magnitude / totalMagnitude; + return (xValue * multiplier, zValue * multiplier); + } + + public static ushort getUphillAngle(double normX, double normY, double normZ) + { + var uphillRadians = Math.PI + Math.Atan2(normX, normZ); + if (normY < -0.01) + uphillRadians += Math.PI; + if (normX == 0 && normZ == 0) + uphillRadians = 0; + return RadiansToAngleUnitsRounded(uphillRadians); + } + + public static byte ApplyValueToMaskedByte(byte currentValue, byte mask, byte valueToSet) + { + byte maskedValueToSet = (byte)(valueToSet & mask); + byte unmaskedCurrentValue = (byte)(currentValue & ~mask); + byte newValue = (byte)(unmaskedCurrentValue | maskedValueToSet); + return newValue; + } + + public static byte ApplyValueToMaskedByte(byte currentValue, byte mask, bool useWholeMask) + { + return ApplyValueToMaskedByte(currentValue, mask, useWholeMask ? mask : (byte)0); + } + + public static double RotateAngleTowards(double angle1, double angle2, double cap) + { + angle1 = NormalizeAngleDouble(angle1); + angle2 = NormalizeAngleDouble(angle2); + double angle12Diff = NormalizeAngleDouble(angle1 - angle2); + double angle21Diff = NormalizeAngleDouble(angle2 - angle1); + double rotationDiff = Math.Min(cap, Math.Min(angle12Diff, angle21Diff)); + bool angle1Less = angle21Diff <= angle12Diff; + double newAngle = angle1 + (angle1Less ? 1 : -1) * rotationDiff; + return NormalizeAngleDouble(newAngle); + } + + public static double MoveNumberTowards(double start, double end, double cap) + { + bool startLessThanEnd = start < end; + double diff = Math.Abs(end - start); + double cappedDiff = Math.Min(diff, cap); + double moved = start + (startLessThanEnd ? 1 : -1) * cappedDiff; + return moved; + } + + public static double GetDotProduct(double v1X, double v1Y, double v1Z, double v2X, double v2Y, double v2Z) + { + return v1X * v2X + v1Y * v2Y + v1Z * v2Z; + } + + // Input angle stuff + + public static float GetEffectiveInputMagnitudeUncapped(int rawX, int rawY) + { + int effectiveX = rawX >= 8 ? rawX - 6 : rawX <= -8 ? rawX + 6 : 0; + int effectiveY = rawY >= 8 ? rawY - 6 : rawY <= -8 ? rawY + 6 : 0; + return (float)Math.Sqrt(effectiveX * effectiveX + effectiveY * effectiveY); + } + + public static float GetEffectiveInputMagnitude(int rawX, int rawY) + { + int effectiveX = rawX >= 8 ? rawX - 6 : rawX <= -8 ? rawX + 6 : 0; + int effectiveY = rawY >= 8 ? rawY - 6 : rawY <= -8 ? rawY + 6 : 0; + float hypotenuse = (float)Math.Sqrt(effectiveX * effectiveX + effectiveY * effectiveY); + return Math.Min(hypotenuse, 64f); + } + + public static float GetScaledInputMagnitude(int rawX, int rawY, bool squished) + { + float effectiveMagnitude = GetEffectiveInputMagnitude(rawX, rawY); + float scaled = (effectiveMagnitude / 64f) * (effectiveMagnitude / 64f) * 64f; + int divider = squished ? 8 : 2; + return scaled / divider; + } + + public static bool InputIsInDeadZone(int input) + { + return input > -8 && input < 8 && input != 0; + } + + /** relX = how much right, relY = how much up, relZ = how much towards the camera */ + public static (double x, double y, double z) TranslateRelatively( + double yaw, double pitch, double roll, double relX, double relY, double relZ) + { + (double fx, double fy, double fz) = SphericalToEuler_AngleUnits(relZ, yaw, pitch); + (double sx, double sy, double sz) = SphericalToEuler_AngleUnits(relX, yaw - 16384, 0); + (double vx, double vy, double vz) = SphericalToEuler_AngleUnits(relY, yaw, pitch - 16384); + return (fx + sx + vx, fy + sy + vy, fz + sz + vz); + } + + public static float GetNextFloatInterval(float value) + { + value = Math.Abs(value); + float interval = 262144; + while (true) + { + float testValue = value + (interval / 2); + if (value == testValue) return interval; + interval /= 2; + } + } + + public static float GetPreviousFloatInterval(float value) + { + value = Math.Abs(value); + float interval = 262144; + while (true) + { + float testValue = value - (interval / 2); + if (value == testValue) return interval; + interval /= 2; + } + } + + public static float GetNextFloat(float value) + { + return value + GetNextFloatInterval(value); + } + + public static float GetPreviousFloat(float value) + { + return value - GetPreviousFloatInterval(value); + } + + public static float MoveFloat(float value, int num) + { + int iters = Math.Abs(num); + for (int i = 0; i < iters; i++) + { + value = num > 0 ? GetNextFloat(value) : GetPreviousFloat(value); + } + + return value; + } + + public static float MoveFloatTowards(float value, float goal) + { + if (goal > value) return GetNextFloat(value); + if (goal < value) return GetPreviousFloat(value); + return value; + } + + public static (double x, double y, double z, double t) GetPlaneLineIntersection( + double planeX, double planeY, double planeZ, double planeYaw, double planePitch, + double x1, double y1, double z1, double x2, double y2, double z2) + { + // Ax + By + Cz = D + double yawRadians = AngleUnitsToRadians(planeYaw); + double pitchRadians = AngleUnitsToRadians(planePitch); + double A = Math.Sin(yawRadians) * Math.Cos(pitchRadians); + double B = Math.Sin(pitchRadians); + double C = Math.Cos(yawRadians) * Math.Cos(pitchRadians); + double D = A * planeX + B * planeY + C * planeZ; + + // x = x1 + xDiff * t + // y = y1 + yDiff * t + // z = z1 + zDiff * t + double xDiff = x2 - x1; + double yDiff = y2 - y1; + double zDiff = z2 - z1; + + // A * x + B * y + C * z = D + // A * (x1 + xDiff * t) + B * (y1 + yDiff * t) + C * (z1 + zDiff * t) = D + // A * x1 + A * xDiff * t + B * y1 + B * yDiff * t + C * z1 + C * zDiff * t = D + // A * xDiff * t + B * yDiff * t + C * zDiff * t = D - (A * x1) - (B * y1) - (C * z1) + // t * (A * xDiff + B * yDiff + C * zDiff) = D - (A * x1) - (B * y1) - (C * z1) + // t = (D - (A * x1) - (B * y1) - (C * z1)) / (A * xDiff + B * yDiff + C * zDiff) + double t = (D - (A * x1) - (B * y1) - (C * z1)) / (A * xDiff + B * yDiff + C * zDiff); + + return (x1 + xDiff * t, y1 + yDiff * t, z1 + zDiff * t, t); + } + + public static (double x, double y, double z, double t) GetPlaneLineIntersection( + double planeX, double planeY, double planeZ, double planeYaw, double planePitch, + double x1, double y1, double z1, double lineYaw, double linePitch) + { + // Ax + By + Cz = D + double yawRadians = AngleUnitsToRadians(planeYaw); + double pitchRadians = AngleUnitsToRadians(planePitch); + double A = Math.Sin(yawRadians) * Math.Cos(pitchRadians); + double B = Math.Sin(pitchRadians); + double C = Math.Cos(yawRadians) * Math.Cos(pitchRadians); + double D = A * planeX + B * planeY + C * planeZ; + + // x = x1 + xDiff * t + // y = y1 + yDiff * t + // z = z1 + zDiff * t + (double xDiff, double yDiff, double zDiff) = SphericalToEuler_AngleUnits(1, lineYaw, linePitch); + + // A * x + B * y + C * z = D + // A * (x1 + xDiff * t) + B * (y1 + yDiff * t) + C * (z1 + zDiff * t) = D + // A * x1 + A * xDiff * t + B * y1 + B * yDiff * t + C * z1 + C * zDiff * t = D + // A * xDiff * t + B * yDiff * t + C * zDiff * t = D - (A * x1) - (B * y1) - (C * z1) + // t * (A * xDiff + B * yDiff + C * zDiff) = D - (A * x1) - (B * y1) - (C * z1) + // t = (D - (A * x1) - (B * y1) - (C * z1)) / (A * xDiff + B * yDiff + C * zDiff) + double t = (D - (A * x1) - (B * y1) - (C * z1)) / (A * xDiff + B * yDiff + C * zDiff); + + return (x1 + xDiff * t, y1 + yDiff * t, z1 + zDiff * t, t); + } + + public static (double x, double y, double z) GetPlanePointAtPoint( + double planeX, double planeY, double planeZ, double planeYaw, double planePitch, + double px, double py, double pz) + { + (double qx, double qz) = AddVectorToPoint(1, planeYaw, planeX, planeZ); + (double rx, double ry, double rz, double t) = GetPlaneLineIntersection( + px, py, pz, planeYaw, planePitch, planeX, planeY, planeZ, qx, planeY, qz); + return (rx, ry, rz); + } + + public static double GetPlaneDistanceToPoint( + double planeX, double planeY, double planeZ, double planeYaw, double planePitch, + double px, double py, double pz) + { + return Math.Abs(GetPlaneDistanceToPointSigned( + planeX, planeY, planeZ, planeYaw, planePitch, px, py, pz)); + } + + public static double GetPlaneDistanceToPointSigned( + double planeX, double planeY, double planeZ, double planeYaw, double planePitch, + double px, double py, double pz) + { + // Ax + By + Cz = D + double yawRadians = AngleUnitsToRadians(planeYaw); + double pitchRadians = AngleUnitsToRadians(planePitch); + double A = Math.Sin(yawRadians) * Math.Cos(pitchRadians); + double B = Math.Sin(pitchRadians); + double C = Math.Cos(yawRadians) * Math.Cos(pitchRadians); + double D = A * planeX + B * planeY + C * planeZ; + return A * px + B * py + C * pz - D; + } + } +} diff --git a/STROOP.Core/Utilities/OrderComparer.cs b/STROOP.Core/Utilities/OrderComparer.cs new file mode 100644 index 000000000..f92f7e1b4 --- /dev/null +++ b/STROOP.Core/Utilities/OrderComparer.cs @@ -0,0 +1,10 @@ +namespace STROOP.Core.Utilities; + +public class OrderComparer : IComparer +{ + private Func func; + + public OrderComparer(Func func) => this.func = func; + + int IComparer.Compare(T x, T y) => func(x, y); +} diff --git a/STROOP.Core/Utilities/StringSymbolAttribute.cs b/STROOP.Core/Utilities/StringSymbolAttribute.cs new file mode 100644 index 000000000..1d9302a3d --- /dev/null +++ b/STROOP.Core/Utilities/StringSymbolAttribute.cs @@ -0,0 +1,17 @@ +using System.Reflection; + +namespace STROOP.Core.Utilities; + +/// +/// Denotes that a static string variable's value shall be initialized with its field name when is called on its declaring type. +/// +[AttributeUsage(AttributeTargets.Field)] +public class StringSymbolAttribute : Attribute +{ + public static void InitializeDeclaredStrings(Type t) + { + foreach (FieldInfo? field in t.GetFields(BindingFlags.Public | BindingFlags.Static)) + if (field.FieldType == typeof(string)) + field.SetValue(null, field.Name); + } +} diff --git a/STROOP.Core/Utilities/Wrapper.cs b/STROOP.Core/Utilities/Wrapper.cs new file mode 100644 index 000000000..75b363c9f --- /dev/null +++ b/STROOP.Core/Utilities/Wrapper.cs @@ -0,0 +1,12 @@ +namespace STROOP.Core.Utilities; + +public class Wrapper +{ + public T value; + + public Wrapper() + { + } + + public Wrapper(T value) => this.value = value; +} diff --git a/STROOP/Enums/AngleUnitType.cs b/STROOP.Variables/AngleUnitType.cs similarity index 81% rename from STROOP/Enums/AngleUnitType.cs rename to STROOP.Variables/AngleUnitType.cs index 1bddcd227..0a2fcb037 100644 --- a/STROOP/Enums/AngleUnitType.cs +++ b/STROOP.Variables/AngleUnitType.cs @@ -1,4 +1,4 @@ -namespace STROOP.Structs +namespace STROOP.Variables { public enum AngleUnitType { diff --git a/STROOP.Variables/CombinedValuesMeaning.cs b/STROOP.Variables/CombinedValuesMeaning.cs new file mode 100644 index 000000000..5cf10f8cf --- /dev/null +++ b/STROOP.Variables/CombinedValuesMeaning.cs @@ -0,0 +1,8 @@ +namespace STROOP.Variables; + +public enum CombinedValuesMeaning +{ + NoValue, + SameValue, + MultipleValues, +} diff --git a/STROOP.Variables/CommonVariableProperties.cs b/STROOP.Variables/CommonVariableProperties.cs new file mode 100644 index 000000000..3122e0128 --- /dev/null +++ b/STROOP.Variables/CommonVariableProperties.cs @@ -0,0 +1,18 @@ +using STROOP.Core.Utilities; + +namespace STROOP.Variables; + +public class CommonVariableProperties +{ + static CommonVariableProperties() => StringSymbolAttribute.InitializeDeclaredStrings(typeof(CommonVariableProperties)); + + [StringSymbol] + public static readonly string + useHex, + invertBool, + specialType, + roundingLimit, + display, + color, + displayPriority; +} diff --git a/STROOP.Variables/Coordinate.cs b/STROOP.Variables/Coordinate.cs new file mode 100644 index 000000000..d039e1c4a --- /dev/null +++ b/STROOP.Variables/Coordinate.cs @@ -0,0 +1,8 @@ +namespace STROOP.Variables; + +public enum Coordinate +{ + X, + Y, + Z, +}; diff --git a/STROOP.Variables/CustomVariable.cs b/STROOP.Variables/CustomVariable.cs new file mode 100644 index 000000000..35edb7d4e --- /dev/null +++ b/STROOP.Variables/CustomVariable.cs @@ -0,0 +1,48 @@ +namespace STROOP.Variables; + +public class CustomVariable : IVariable +{ + public Action ValueSet { get; set; } + public Action OnDelete { get; set; } + public string Subclass { get; } + public Type ClrType { get; } + + public string Color + { + set => SetValueByKey(CommonVariableProperties.color, value); + } + + public string Display + { + set => SetValueByKey(CommonVariableProperties.display, value); + } + + private Dictionary keyedValues = new Dictionary(); + + public CustomVariable(string subclass, Type clrType) + { + Subclass = subclass; + ClrType = clrType; + } + + public virtual string GetValueByKey(string key) + => keyedValues.GetValueOrDefault(key); + + public virtual bool SetValueByKey(string key, string value) + { + keyedValues[key] = value; + return true; + } +} + +public class CustomVariable : CustomVariable, IVariable +{ + public IVariable.ValueGetter getter { get; set; } + public IVariable.ValueSetter setter { get; set; } + + public CustomVariable(string subclass) : base(subclass, typeof(T)) + { + getter = SpecialVariableDefaults.DEFAULT_GETTER; + setter = SpecialVariableDefaults.DEFAULT_SETTER; + } +} diff --git a/STROOP.Variables/DescribedMemoryState.cs b/STROOP.Variables/DescribedMemoryState.cs new file mode 100644 index 000000000..35d199cdb --- /dev/null +++ b/STROOP.Variables/DescribedMemoryState.cs @@ -0,0 +1,25 @@ +namespace STROOP.Variables; + +public class DescribedMemoryState +{ + public readonly MemoryDescriptor descriptor; + + private Func> _fixedAddressGetter = null; + public bool fixedAddresses => _fixedAddressGetter != null; + + public DescribedMemoryState(MemoryDescriptor memoryDescriptor) => descriptor = memoryDescriptor; + + public IEnumerable GetAddressList() + => _fixedAddressGetter?.Invoke() ?? descriptor.GetAddressList(); + + public void ToggleFixedAddress(bool? fix) + { + bool doFix = fix ?? _fixedAddressGetter == null; + _fixedAddressGetter = null; + if (doFix) + { + IEnumerable capture = GetAddressList().ToList(); + _fixedAddressGetter = () => capture; + } + } +} diff --git a/STROOP.Variables/Formatting/MemoryDescriptorExtensions.cs b/STROOP.Variables/Formatting/MemoryDescriptorExtensions.cs new file mode 100644 index 000000000..8569d3370 --- /dev/null +++ b/STROOP.Variables/Formatting/MemoryDescriptorExtensions.cs @@ -0,0 +1,69 @@ +using STROOP.Core; +using STROOP.Utilities; +using STROOP.Variables.Utilities; + +namespace STROOP.Variables.Formatting; + +public static class MemoryDescriptorExtensions +{ + public static string GetTypeDescription(this MemoryDescriptor memoryDescriptor) + { + string maskString = ""; + if (memoryDescriptor.Mask != null) + maskString = " with mask " + HexUtilities.FormatValue(memoryDescriptor.Mask.Value, memoryDescriptor.NibbleCount.Value); + + string shiftString = ""; + if (memoryDescriptor.Shift != null) + shiftString = " right shifted by " + memoryDescriptor.Shift.Value; + + string byteCountString = ""; + if (memoryDescriptor.ByteCount.HasValue) + { + string pluralSuffix = memoryDescriptor.ByteCount.Value == 1 ? "" : "s"; + byteCountString = $" ({memoryDescriptor.ByteCount.Value} byte{pluralSuffix})"; + } + + return TypeUtilities.TypeToString[memoryDescriptor.ClrType] + maskString + shiftString + byteCountString; + } + + public static string GetBaseTypeOffsetDescription(this MemoryDescriptor memoryDescriptor) + => $"{memoryDescriptor.BaseAddressType} + {HexUtilities.FormatValue(memoryDescriptor.Offset)}"; + + public static string GetProcessAddressListString(this MemoryDescriptor memoryDescriptor) + { + List addressList = memoryDescriptor.GetAddressList(); + if (addressList.Count == 0) + return "(none)"; + + List processAddressList = memoryDescriptor.GetProcessAddressList().ConvertAll(address => address.ToUInt64()); + List stringList = processAddressList.ConvertAll(address => HexUtilities.FormatValue(address, address > 0xFFFFFFFFU ? 16 : 8)); + return string.Join(", ", stringList); + } + + public static string GetRamAddressListString(this MemoryDescriptor memoryDescriptor, bool addressArea = true) + { + List addressList = memoryDescriptor.GetAddressList(); + if (addressList.Count == 0) return "(none)"; + List ramAddressList = memoryDescriptor.GetRamAddressList(addressArea); + List stringList = ramAddressList.ConvertAll(address => HexUtilities.FormatValue(address, 8)); + return string.Join(", ", stringList); + } + + public static string GetBaseAddressListString(this MemoryDescriptor memoryDescriptor) + { + List baseAddresses = VariableUtilities.GetBaseAddresses(memoryDescriptor.BaseAddressType).ToList(); + if (baseAddresses.Count == 0) + return "(none)"; + List baseAddressesString = baseAddresses.ConvertAll(address => HexUtilities.FormatValue(address, 8)); + return string.Join(",", baseAddressesString); + } + + private static List GetProcessAddressList(this MemoryDescriptor memoryDescriptor) + { + List ramAddressList = memoryDescriptor.GetRamAddressList(false); + return ramAddressList.ConvertAll(address => ProcessStream.Instance.GetAbsoluteAddress(address, memoryDescriptor.ByteCount.Value)); + } + + private static List GetRamAddressList(this MemoryDescriptor memoryDescriptor, bool addressArea = true) + => memoryDescriptor.GetAddressList().ConvertAll(addr => addressArea ? addr | 0x80000000 : addr & 0x0FFFFFFF); +} diff --git a/STROOP.Variables/IVariable.cs b/STROOP.Variables/IVariable.cs new file mode 100644 index 000000000..e2e7ecd99 --- /dev/null +++ b/STROOP.Variables/IVariable.cs @@ -0,0 +1,63 @@ +namespace STROOP.Variables; + +/// +/// Represents a single semantic of information that can be read, and optionally set, implemented via the type-safe . +/// Note that a single may yield many (or zero) values when being read depending on its semantic. +/// Classes must not implement directly. Implement . +/// +public interface IVariable +{ + /// + /// Invoked when any value was successfully set on this . + /// + Action ValueSet { get; set; } + + /// + /// Invoked when this becomes meaningless. + /// + Action OnDelete { get; set; } + + /// + /// Associates an arbitrary key with an arbitrary value on this . + /// + /// The key to associate the value with. + /// The value to associate. + /// True if the association could be made. False otherwise. + bool SetValueByKey(string key, string value); + + /// + /// Retrieves the value associated with this an arbitrary key on this . + /// + /// The key. + /// The associated value, or null if no value is associated for the provided key. + string GetValueByKey(string key); + + string Subclass { get; } + + /// + /// The CLR (Common Language Runtime) Type by which to determine how to handle values .NET values interfacing with this variable. + /// + public Type ClrType { get; } +} + +/// +/// Represents a single semantic of information with type that can be read, and optionally set. +/// Note that a single may yield many (or zero) values when being read depending on its semantic. +/// +/// The type of information being retrieved and stored in this . +public interface IVariable : IVariable +{ + /// + /// Retrieves all values that this currently represents. + /// + public delegate IEnumerable ValueGetter(); + + /// + /// Attempts to set all underlying values that this currently represents to . + /// + /// An ordered enumerable of booleans, where each value indicates whether the respective underlying value was set. + public delegate IEnumerable ValueSetter(T value); + + ValueGetter getter { get; } + ValueSetter setter { get; } +} diff --git a/STROOP.Variables/MemoryDescriptor.cs b/STROOP.Variables/MemoryDescriptor.cs new file mode 100644 index 000000000..3ccc828b0 --- /dev/null +++ b/STROOP.Variables/MemoryDescriptor.cs @@ -0,0 +1,90 @@ +using STROOP.Variables.SM64MemoryLayout; +using STROOP.Variables.Utilities; + +namespace STROOP.Variables; + +public class MemoryDescriptor +{ + public readonly Type ClrType; + public readonly int? ByteCount; + public readonly bool? SignedType; + + public readonly string BaseAddressType; + + public readonly uint? OffsetUS; + public readonly uint? OffsetJP; + public readonly uint? OffsetSH; + public readonly uint? OffsetEU; + public readonly uint? OffsetDefault; + + public readonly uint? Mask; + public readonly int? Shift; + public readonly bool HandleMapping; + + public int? NibbleCount => ByteCount.HasValue ? (int?)(ByteCount.Value * 2) : null; + + public uint Offset + { + get + { + if (OffsetUS.HasValue || OffsetJP.HasValue || OffsetSH.HasValue || OffsetEU.HasValue) + { + if (HandleMapping) + return RomVersionConfig.SwitchMap( + OffsetUS ?? 0, + OffsetJP ?? 0, + OffsetSH ?? 0, + OffsetEU ?? 0); + else + return RomVersionConfig.SwitchOnly( + OffsetUS ?? 0, + OffsetJP ?? 0, + OffsetSH ?? 0, + OffsetEU ?? 0); + } + + if (OffsetDefault.HasValue) return OffsetDefault.Value; + return 0; + } + } + + public MemoryDescriptor(Type clrTypeName, string baseAddress, uint offset, uint? mask = null, int? shift = null) + : this(clrTypeName, baseAddress, null, null, null, null, offset, mask, shift, false) + { + } + + public MemoryDescriptor(Type clrType, string baseAddressType, + uint? offsetUS, uint? offsetJP, uint? offsetSH, uint? offsetEU, uint? offsetDefault, uint? mask, int? shift, bool handleMapping) + { + if (offsetDefault.HasValue && (offsetUS.HasValue || offsetJP.HasValue || offsetSH.HasValue || offsetEU.HasValue)) + { + throw new ArgumentOutOfRangeException("Can't have both a default offset value and a rom-specific offset value"); + } + + BaseAddressType = baseAddressType; + + OffsetUS = offsetUS; + OffsetJP = offsetJP; + OffsetSH = offsetSH; + OffsetEU = offsetEU; + OffsetDefault = offsetDefault; + + ClrType = clrType; + ByteCount = TypeUtilities.TypeSize[ClrType]; + SignedType = TypeUtilities.TypeSign[ClrType]; + + Mask = mask; + Shift = shift; + HandleMapping = handleMapping; + } + + public IMemoryVariable CreateVariable(string wrapper = "Number") + => (IMemoryVariable) + typeof(MemoryVariable<>) + .MakeGenericType(ClrType) + .GetConstructor(new Type[] { typeof(string), typeof(MemoryDescriptor) }) + .Invoke(new object[] { wrapper, this }); + + public List GetAddressList() + => VariableUtilities.GetBaseAddresses(BaseAddressType).Select(baseAddress => baseAddress + Offset).ToList(); +} diff --git a/STROOP.Variables/MemoryVariable.cs b/STROOP.Variables/MemoryVariable.cs new file mode 100644 index 000000000..45f78e68f --- /dev/null +++ b/STROOP.Variables/MemoryVariable.cs @@ -0,0 +1,76 @@ +using STROOP.Core; +using STROOP.Core.Utilities; + +namespace STROOP.Variables; + +public interface IMemoryVariable : IVariable +{ + MemoryDescriptor memoryDescriptor { get; } + DescribedMemoryState describedMemoryState { get; } +} + +public class MemoryVariable + : CustomVariable, IMemoryVariable, IVariable + where T : struct, IConvertible +{ + public MemoryDescriptor memoryDescriptor { get; } + public DescribedMemoryState describedMemoryState { get; } + + public MemoryVariable(string subclass, MemoryDescriptor memoryDescriptor) + : base(subclass, memoryDescriptor.ClrType) + { + this.memoryDescriptor = memoryDescriptor; + describedMemoryState = new DescribedMemoryState(memoryDescriptor); + getter = () => GetValues(describedMemoryState); + setter = (T value) => SetAll(describedMemoryState, value); + } + + public IVariable.ValueGetter getter { get; private set; } + public IVariable.ValueSetter setter { get; private set; } + + private static IEnumerable GetValues(DescribedMemoryState memoryState) + => memoryState.GetAddressList().ConvertAll(address => (T)ProcessStream.Instance.GetValue( + typeof(T), + address, + false, + memoryState.descriptor.Mask, + memoryState.descriptor.Shift + )); + + private static IEnumerable SetAll(DescribedMemoryState memoryState, T value) + => Static._memoryWriters.TryGetValue(typeof(T), out Static.MemoryWriter writer) + ? memoryState.GetAddressList().Select(address => writer(value, address, memoryState.descriptor)).ToArray() + : [false]; +} + +file static class Static +{ + internal delegate bool MemoryWriter(object value, uint address, MemoryDescriptor memoryDescriptor); + internal static readonly Dictionary _memoryWriters = new Dictionary(); + + static Static() + { + _memoryWriters[typeof(ulong)] = (value, address, descriptor) + => ProcessStream.Instance.SetValue((ulong)value, address, false, descriptor.Mask, descriptor.Shift); + _memoryWriters[typeof(uint)] = (value, address, descriptor) + => ProcessStream.Instance.SetValue((uint)value, address, false, descriptor.Mask, descriptor.Shift); + _memoryWriters[typeof(ushort)] = (value, address, descriptor) + => ProcessStream.Instance.SetValue((ushort)value, address, false, descriptor.Mask, descriptor.Shift); + _memoryWriters[typeof(byte)] = (value, address, descriptor) + => ProcessStream.Instance.SetValue((byte)value, address, false, descriptor.Mask, descriptor.Shift); + + _memoryWriters[typeof(long)] = (value, address, descriptor) + => ProcessStream.Instance.SetValue((long)value, address, false, descriptor.Mask, descriptor.Shift); + _memoryWriters[typeof(int)] = (value, address, descriptor) + => ProcessStream.Instance.SetValue((int)value, address, false, descriptor.Mask, descriptor.Shift); + _memoryWriters[typeof(short)] = (value, address, descriptor) + => ProcessStream.Instance.SetValue((short)value, address, false, descriptor.Mask, descriptor.Shift); + _memoryWriters[typeof(sbyte)] = (value, address, descriptor) + => ProcessStream.Instance.SetValue((byte)value, address, false, descriptor.Mask, descriptor.Shift); + + _memoryWriters[typeof(double)] = (value, address, descriptor) + => ProcessStream.Instance.SetValue((double)value, address, false, descriptor.Mask, descriptor.Shift); + _memoryWriters[typeof(float)] = (value, address, descriptor) + => ProcessStream.Instance.SetValue((float)value, address, false, descriptor.Mask, descriptor.Shift); + } +} diff --git a/STROOP.Variables/SM64MemoryLayout/BaseAddressType.cs b/STROOP.Variables/SM64MemoryLayout/BaseAddressType.cs new file mode 100644 index 000000000..d93f04395 --- /dev/null +++ b/STROOP.Variables/SM64MemoryLayout/BaseAddressType.cs @@ -0,0 +1,29 @@ +using STROOP.Core.Utilities; + +namespace STROOP.Variables.SM64MemoryLayout; + +public static class BaseAddressType +{ + static BaseAddressType() => StringSymbolAttribute.InitializeDeclaredStrings(typeof(BaseAddressType)); + + [StringSymbol] + public static string + None, + Relative, + Mario, + MarioObj, + Camera, + CameraStruct, + LakituStruct, + CameraModeInfo, + CameraModeTransition, + CameraSettings, + File, + MainSave, + Object, + ProcessGroup, + Coin, + Triangle, + Area, + GfxNode; +}; diff --git a/STROOP.Variables/SM64MemoryLayout/CameraConfig.cs b/STROOP.Variables/SM64MemoryLayout/CameraConfig.cs new file mode 100644 index 000000000..199055724 --- /dev/null +++ b/STROOP.Variables/SM64MemoryLayout/CameraConfig.cs @@ -0,0 +1,108 @@ +using STROOP.Core; + +namespace STROOP.Variables.SM64MemoryLayout; + +public static class CameraConfig +{ + public static uint StructAddress => RomVersionConfig.SwitchMap(StructAddressUS, StructAddressJP, StructAddressSH, StructAddressEU); + + public static readonly uint StructAddressUS = 0x8033C520; + public static readonly uint StructAddressJP = 0x8033B1B0; + public static readonly uint StructAddressSH = 0x8031EC78; + public static readonly uint StructAddressEU = 0x8030A7E0; + + public static uint CamStructAddress => ProcessStream.Instance.GetUInt32(RomVersionConfig.SwitchMap(0x8033cbd0, 0x8033b860)); + public static uint LakituStructAddress => RomVersionConfig.SwitchMap(0x8033c698, 0x8033b328); + public static uint ModeInfoAddress => RomVersionConfig.SwitchMap(0x8033c788, 0x8033b418, null, null); + public static uint ModeTransitionAddress => RomVersionConfig.SwitchMap(0x8033c5c0, 0x8033b250, null, null); + + + public static readonly uint XOffset = 0x184; + public static readonly uint YOffset = 0x188; + public static readonly uint ZOffset = 0x18C; + public static readonly uint FocusXOffset = 0x178; + public static readonly uint FocusYOffset = 0x17C; + public static readonly uint FocusZOffset = 0x180; + public static readonly uint FacingYawOffset = 0x1C6; + public static readonly uint FacingPitchOffset = 0x1C4; + public static readonly uint FacingRollOffset = 0x1C8; + public static readonly uint CentripetalAngleOffset = 0x1F4; + + public static readonly uint MarioCamPossibleOffset = 0x165; + public static readonly byte MarioCamPossibleMask = 0x04; + + public static uint FOVStructAddress => RomVersionConfig.SwitchMap(FOVStructAddressUS, FOVStructAddressJP, null, FOVStructAddressEU); + + public static readonly uint FOVStructAddressUS = 0x8033C5A0; + public static readonly uint FOVStructAddressJP = 0x8033B230; + public static readonly uint FOVStructAddressEU = 0x8030A920; + + public static uint FOVValueOffset = 0x4; + + public static uint SecondaryObjectAddress => RomVersionConfig.SwitchMap(SecondaryObjectAddressUS, SecondaryObjectAddressJP, null, SecondaryObjectAddressEU); + + public static readonly uint SecondaryObjectAddressUS = 0x8032DF30; + public static readonly uint SecondaryObjectAddressJP = 0x8032CFD0; + public static readonly uint SecondaryObjectAddressEU = 0x802FA110; + + + public static uint FovFunctionAwakeAddress => RomVersionConfig.SwitchMap(FovFunctionAwakeAddressUS, FovFunctionAwakeAddressJP, null, FovFunctionAwakeAddressEU); + + public static readonly uint FovFunctionAwakeAddressUS = 0x8029A7C8; + public static readonly uint FovFunctionAwakeAddressJP = 0x8029A0AC; + public static readonly uint FovFunctionAwakeAddressEU = 0x802849C8; + + public static uint FovFunctionSleepingAddress => RomVersionConfig.SwitchMap(FovFunctionSleepingAddressUS, FovFunctionSleepingAddressJP, null, FovFunctionSleepingAddressEU); + + public static readonly uint FovFunctionSleepingAddressUS = 0x8029A774; + public static readonly uint FovFunctionSleepingAddressJP = 0x8029A058; + public static readonly uint FovFunctionSleepingAddressEU = 0x80284974; + + public static uint FovFunctionUseDoorAddress => RomVersionConfig.SwitchMap(FovFunctionUseDoorAddressUS, FovFunctionUseDoorAddressJP, null, FovFunctionUseDoorAddressEU); + + public static readonly uint FovFunctionUseDoorAddressUS = 0x8029AA20; + public static readonly uint FovFunctionUseDoorAddressJP = 0x8029A304; + public static readonly uint FovFunctionUseDoorAddressEU = 0x80284B48; + + public static uint FovFunctionCollectStarAddress => RomVersionConfig.SwitchMap(FovFunctionCollectStarAddressUS, FovFunctionCollectStarAddressJP, null, FovFunctionCollectStarAddressEU); + + public static readonly uint FovFunctionCollectStarAddressUS = 0x8029A984; + public static readonly uint FovFunctionCollectStarAddressJP = 0x8029A268; + public static readonly uint FovFunctionCollectStarAddressEU = 0x80284AB8; + + public static uint FovFunctionAwakeValue => RomVersionConfig.SwitchMap(FovFunctionAwakeValueUS, FovFunctionAwakeValueJP); + + public static readonly uint FovFunctionAwakeValueUS = 0x0C0A2673; + public static readonly uint FovFunctionAwakeValueJP = 0x0C0A24F9; + + public static uint FovFunctionSleepingValue => RomVersionConfig.SwitchMap(FovFunctionSleepingValueUS, FovFunctionSleepingValueJP); + + public static readonly uint FovFunctionSleepingValueUS = 0x0C0A2673; + public static readonly uint FovFunctionSleepingValueJP = 0x0C0A24F9; + + public static uint FovFunctionUseDoorValue => RomVersionConfig.SwitchMap(FovFunctionUseDoorValueUS, FovFunctionUseDoorValueJP); + + public static readonly uint FovFunctionUseDoorValueUS = 0xE420C5A4; + public static readonly uint FovFunctionUseDoorValueJP = 0xE420B234; + + public static uint FovFunctionCollectStarValue => RomVersionConfig.SwitchMap(FovFunctionCollectStarValueUS, FovFunctionCollectStarValueJP); + + public static readonly uint FovFunctionCollectStarValueUS = 0x0C0A2673; + public static readonly uint FovFunctionCollectStarValueJP = 0x0C0A24F9; + + public static List FovFunctionAddresses => new List() + { + FovFunctionAwakeAddress, + FovFunctionSleepingAddress, + FovFunctionUseDoorAddress, + FovFunctionCollectStarAddress, + }; + + public static List FovFunctionValues => new List() + { + FovFunctionAwakeValue, + FovFunctionSleepingValue, + FovFunctionUseDoorValue, + FovFunctionCollectStarValue, + }; +} diff --git a/STROOP.Variables/SM64MemoryLayout/MappingConfig.cs b/STROOP.Variables/SM64MemoryLayout/MappingConfig.cs new file mode 100644 index 000000000..aac4c3540 --- /dev/null +++ b/STROOP.Variables/SM64MemoryLayout/MappingConfig.cs @@ -0,0 +1,168 @@ +using STROOP.Core; +using STROOP.Core.Utilities; +using System.Globalization; + +namespace STROOP.Variables.SM64MemoryLayout; + +public static class MappingConfig +{ + private static readonly Dictionary mappingUS = GetMappingDictionary(@"Mappings/MappingUS.map"); + private static readonly Dictionary mappingJP = GetMappingDictionary(@"Mappings/MappingJP.map"); + private static readonly Dictionary mappingUSReversed = GeneralUtilities.ReverseDictionary(mappingUS); + private static readonly Dictionary mappingJPReversed = GeneralUtilities.ReverseDictionary(mappingJP); + + private static Dictionary mappingCurrent = null; + private static Dictionary mappingCurrentReversed = null; + + private static List ReadFileLines(string filePath) + { + List lines = new List(); + string line; + + StreamReader file = new StreamReader(filePath); + while ((line = file.ReadLine()) != null) + { + lines.Add(line); + } + + file.Close(); + return lines; + } + + public static Dictionary GetMappingDictionary(string filePath) + { + Dictionary dictionary = new Dictionary(); + List lines = ReadFileLines(filePath); + foreach (string line in lines) + { + // splits by whitespace, see the #Remarks section of https://learn.microsoft.com/en-us/dotnet/api/system.string.split?view=net-8.0 + string[] parts = line.Split(null); + + if (parts.Length != 2) continue; + string part1 = parts[0]; + string part2 = parts[1]; + if (!part1.StartsWith("0x00000000")) continue; + string addressString = "0x" + part1.Substring(10); + uint address = uint.Parse(addressString, NumberStyles.HexNumber); + dictionary[address] = part2; + } + + return dictionary; + } + + public static void OpenMapping(string fileName) + { + mappingCurrent = GetMappingDictionary(fileName); + mappingCurrentReversed = GeneralUtilities.ReverseDictionary(mappingCurrent); + } + + public static void ClearMapping() + { + mappingCurrent = null; + mappingCurrentReversed = null; + } + + public static uint HandleMapping(uint address) + { + if (mappingCurrent == null) return address; + + Dictionary mappingOriginal; + switch (RomVersionConfig.Version) + { + case RomVersion.US: + mappingOriginal = mappingUS; + break; + case RomVersion.JP: + mappingOriginal = mappingJP; + break; + default: + throw new ArgumentOutOfRangeException(); + } + + if (!mappingOriginal.ContainsKey(address)) return address; + string name = mappingOriginal[address]; + if (!mappingCurrentReversed.ContainsKey(name)) return address; + return mappingCurrentReversed[name]; + } + + public static uint HandleReverseMapping(uint address) + { + if (mappingCurrent == null) return address; + + Dictionary mappingOriginalReversed; + switch (RomVersionConfig.Version) + { + case RomVersion.US: + mappingOriginalReversed = mappingUSReversed; + break; + case RomVersion.JP: + mappingOriginalReversed = mappingJPReversed; + break; + default: + throw new ArgumentOutOfRangeException(); + } + + if (!mappingCurrent.ContainsKey(address)) return address; + string name = mappingCurrent[address]; + if (!mappingOriginalReversed.ContainsKey(name)) return address; + return mappingOriginalReversed[name]; + } + + private static (Type type, string name) GetInfoIfUserAddedWord(string word) + { + if (_suffixes.Any(suff => word.EndsWith(suff)) && + _ignoredWords.All(ignored => word != ignored)) + { + string suffix = _suffixes.First(suff => word.EndsWith(suff)); + Type type = GetTypeFromSuffix(suffix); + string name = word.Substring(0, word.Length - suffix.Length); + return (type, name); + } + + return (null, null); + } + + private static List _suffixes = new List() + { + "_s8", + "_u8", + "_s16", + "_u16", + "_s32", + "_u32", + "_s64", + "_u64", + "_f32", + "_f64", + }; + + private static List _ignoredWords = new List() + { + "m64_read_u8", + "m64_read_s16", + "m64_read_compressed_u16", + "string_to_u32", + "approach_s32", + "approach_f32", + "random_u16", + "gd_clamp_f32", + }; + + private static Type GetTypeFromSuffix(string suffix) + { + switch (suffix.ToLower()) + { + case "_s8": return typeof(sbyte); + case "_u8": return typeof(byte); + case "_s16": return typeof(short); + case "_u16": return typeof(ushort); + case "_s32": return typeof(int); + case "_u32": return typeof(uint); + case "_s64": return typeof(long); + case "_u64": return typeof(ulong); + case "_f32": return typeof(float); + case "_f64": return typeof(double); + default: return null; + } + } +} diff --git a/STROOP.Variables/SM64MemoryLayout/MarioConfig.cs b/STROOP.Variables/SM64MemoryLayout/MarioConfig.cs new file mode 100644 index 000000000..f531793b6 --- /dev/null +++ b/STROOP.Variables/SM64MemoryLayout/MarioConfig.cs @@ -0,0 +1,72 @@ +namespace STROOP.Variables.SM64MemoryLayout; + +public static class MarioConfig +{ + public static uint StructAddress => RomVersionConfig.SwitchMap(StructAddressUS, StructAddressJP, StructAddressSH, StructAddressEU); + + public static readonly uint StructAddressUS = 0x8033B170; + public static readonly uint StructAddressJP = 0x80339E00; + public static readonly uint StructAddressSH = 0x8031D9C0; + public static readonly uint StructAddressEU = 0x80309430; + + public static readonly uint XOffset = 0x3C; + public static readonly uint YOffset = 0x40; + public static readonly uint ZOffset = 0x44; + + public static readonly uint XSpeedOffset = 0x48; + public static readonly uint YSpeedOffset = 0x4C; + public static readonly uint ZSpeedOffset = 0x50; + public static readonly uint HSpeedOffset = 0x54; + + public static readonly uint FacingYawOffset = 0x2E; + public static readonly uint FacingPitchOffset = 0x2C; + public static readonly uint FacingRollOffset = 0x30; + + public static readonly uint IntendedYawOffset = 0x24; + public static readonly uint IntendedPitchOffset = 0x22; + public static readonly uint IntendedRollOffset = 0x26; + + public static readonly uint MovingYawOffset = 0x38; + public static readonly uint ScaledMagnitudeOffset = 0x20; + + public static readonly uint SlidingSpeedXOffset = 0x58; + public static readonly uint SlidingSpeedZOffset = 0x5C; + public static readonly uint SlidingYawOffset = 0x38; + + public static readonly uint HolpXOffset = 0x258; + public static readonly uint HolpYOffset = 0x25C; + public static readonly uint HolpZOffset = 0x260; + public static readonly uint HolpTypeOffset = 0x24A; + + public static uint StoodOnObjectPointerAddress => RomVersionConfig.SwitchMap(StoodOnObjectPointerAddressUS, StoodOnObjectPointerAddressJP, StoodOnObjectPointerAddressSH, StoodOnObjectPointerAddressEU); + + public static readonly uint StoodOnObjectPointerAddressUS = 0x80330E34; + public static readonly uint StoodOnObjectPointerAddressJP = 0x8032FED4; + public static readonly uint StoodOnObjectPointerAddressSH = 0x80310564; + public static readonly uint StoodOnObjectPointerAddressEU = 0x802FCFF4; + + public static readonly uint InteractionObjectPointerOffset = 0x78; + public static readonly uint HeldObjectPointerOffset = 0x7C; + public static readonly uint UsedObjectPointerOffset = 0x80; + public static readonly uint RiddenObjectPointerOffset = 0x84; + + public static readonly uint WallTriangleOffset = 0x60; + public static readonly uint FloorTriangleOffset = 0x68; + public static readonly uint CeilingTriangleOffset = 0x64; + + public static readonly uint FloorYOffset = 0x70; + public static readonly uint CeilingYOffset = 0x6C; + + public static readonly uint FloorYawOffset = 0x74; + + public static readonly uint ActionOffset = 0x0C; + public static readonly uint PrevActionOffset = 0x10; + public static readonly uint FreeMovementAction = 0x0000130F; + public static readonly uint RidingShellAction = 0x20810446; + public static readonly uint IdleAction = 0x0C400201; + + public static readonly uint TwirlYawOffset = 0x3A; + public static readonly uint PeakHeightOffset = 0xBC; + public static readonly uint WaterLevelOffset = 0x76; + public static readonly uint AreaPointerOffset = 0x90; +} diff --git a/STROOP.Variables/SM64MemoryLayout/MarioObjectConfig.cs b/STROOP.Variables/SM64MemoryLayout/MarioObjectConfig.cs new file mode 100644 index 000000000..aad866899 --- /dev/null +++ b/STROOP.Variables/SM64MemoryLayout/MarioObjectConfig.cs @@ -0,0 +1,16 @@ +namespace STROOP.Variables.SM64MemoryLayout; + +public static class MarioObjectConfig +{ + public static uint PointerAddress => RomVersionConfig.SwitchMap(PointerAddressUS, PointerAddressJP, PointerAddressSH); + + public static readonly uint PointerAddressUS = 0x80361158; + public static readonly uint PointerAddressJP = 0x8035FDE8; + public static readonly uint PointerAddressSH = 0x80343318; + + public static readonly uint AnimationOffset = 0x38; + public static readonly uint AnimationTimerOffset = 0x40; + + public static readonly uint GraphicValue = 0x800F0860; + public static readonly uint BehaviorValue = 0x13002EC0; +} diff --git a/STROOP.Variables/SM64MemoryLayout/RomVersionConfig.cs b/STROOP.Variables/SM64MemoryLayout/RomVersionConfig.cs new file mode 100644 index 000000000..9747d070b --- /dev/null +++ b/STROOP.Variables/SM64MemoryLayout/RomVersionConfig.cs @@ -0,0 +1,80 @@ +using STROOP.Core; + +namespace STROOP.Variables.SM64MemoryLayout; + +public static class RomVersionConfig +{ + public static RomVersion Version = RomVersion.US; + + public static uint RomVersionTellAddress = 0x802F0000; + public static uint RomVersionTellValueUS = 0xC58400A4; + public static uint RomVersionTellValueJP = 0x27BD0020; + public static uint RomVersionTellValueSH = 0x8F250004; + public static uint RomVersionTellValueEU = 0x0C0BD4AC; + + public static RomVersion? GetRomVersionUsingTell() + { + uint tell = ProcessStream.Instance.GetUInt32(RomVersionTellAddress); + if (tell == RomVersionTellValueUS) return RomVersion.US; + if (tell == RomVersionTellValueJP) return RomVersion.JP; + if (tell == RomVersionTellValueSH) return RomVersion.SH; + if (tell == RomVersionTellValueEU) return RomVersion.EU; + return RomVersion.US; + } + + public static uint SwitchMap(uint? valUS = null, uint? valJP = null, uint? valSH = null, uint? valEU = null) + { + uint address = SwitchOnly(valUS, valJP, valSH, valEU); + address = MappingConfig.HandleMapping(address); + return address; + } + + public static uint SwitchReverseMap(uint? valUS = null, uint? valJP = null, uint? valSH = null, uint? valEU = null) + { + uint address = SwitchOnly(valUS, valJP, valSH, valEU); + address = MappingConfig.HandleReverseMapping(address); + return address; + } + + public static uint SwitchOnly(uint? valUS = null, uint? valJP = null, uint? valSH = null, uint? valEU = null) + { + switch (Version) + { + case RomVersion.US: + if (valUS.HasValue) return valUS.Value; + break; + case RomVersion.JP: + if (valJP.HasValue) return valJP.Value; + break; + case RomVersion.SH: + if (valSH.HasValue) return valSH.Value; + break; + case RomVersion.EU: + if (valEU.HasValue) return valEU.Value; + break; + } + + return 0; + } + + public static ushort Switch(ushort? valUS = null, ushort? valJP = null, ushort? valSH = null, ushort? valEU = null) + { + switch (Version) + { + case RomVersion.US: + if (valUS.HasValue) return valUS.Value; + break; + case RomVersion.JP: + if (valJP.HasValue) return valJP.Value; + break; + case RomVersion.SH: + if (valSH.HasValue) return valSH.Value; + break; + case RomVersion.EU: + if (valEU.HasValue) return valEU.Value; + break; + } + + return 0; + } +} diff --git a/STROOP.Variables/STROOP.Variables.csproj b/STROOP.Variables/STROOP.Variables.csproj new file mode 100644 index 000000000..281152e01 --- /dev/null +++ b/STROOP.Variables/STROOP.Variables.csproj @@ -0,0 +1,13 @@ + + + + net8.0 + enable + disable + + + + + + + diff --git a/STROOP.Variables/SpecialVariableDefaults.cs b/STROOP.Variables/SpecialVariableDefaults.cs new file mode 100644 index 000000000..41874e5e7 --- /dev/null +++ b/STROOP.Variables/SpecialVariableDefaults.cs @@ -0,0 +1,8 @@ +namespace STROOP.Variables; + +public static class SpecialVariableDefaults +{ + public static readonly IVariable.ValueGetter DEFAULT_GETTER = () => Array.Empty(); + public static readonly IVariable.ValueSetter DEFAULT_SETTER = _ => Array.Empty(); + public static readonly Func DEFAULT_SETTER_WITH_ADDRESS = (_, _) => false; +} diff --git a/STROOP.Variables/Utilities/ColorUtilities.cs b/STROOP.Variables/Utilities/ColorUtilities.cs new file mode 100644 index 000000000..54bfe200b --- /dev/null +++ b/STROOP.Variables/Utilities/ColorUtilities.cs @@ -0,0 +1,123 @@ +using STROOP.Core.Utilities; +using System.Drawing; + +namespace STROOP.Variables.Utilities +{ + public static class ColorUtilities + { + public static readonly Dictionary ColorToParamsDictionary = + new Dictionary() + { + ["Red"] = "#FFD7D7", + ["Orange"] = "#FFE2B7", + ["Yellow"] = "#FFFFD0", + ["Green"] = "#CFFFCC", + ["LightBlue"] = "#CCFFFA", + ["Blue"] = "#CADDFF", + ["Purple"] = "#E5CCFF", + ["Pink"] = "#FFCCFF", + ["Grey"] = "#D0D0D0", + }; + + public static readonly List ColorList = + ColorToParamsDictionary.Values.ToList() + .ConvertAll(html => ColorTranslator.FromHtml(html)); + + private static readonly Dictionary ParamsToColorDictionary = + GeneralUtilities.ReverseDictionary(ColorToParamsDictionary); + + public static Color GetColorFromString(string colorString) + { + if (colorString.Substring(0, 1) != "#") + colorString = ColorToParamsDictionary[colorString]; + return ColorTranslator.FromHtml(colorString); + } + + public static string ConvertColorToString(Color color) + { + string colorParams = ConvertColorToParams(color); + if (ParamsToColorDictionary.ContainsKey(colorParams)) + return ParamsToColorDictionary[colorParams]; + return colorParams; + } + + public static string ConvertColorToParams(Color color) + { + string r = String.Format("{0:X2}", color.R); + string g = String.Format("{0:X2}", color.G); + string b = String.Format("{0:X2}", color.B); + return "#" + r + g + b; + } + + public static Color LastCustomColor = SystemColors.Control; + + public static Color GetColorForVariable(int? inputtedNumber) + { + if (inputtedNumber.HasValue && + inputtedNumber.Value > 0 && + inputtedNumber.Value <= ColorList.Count) + { + return ColorList[inputtedNumber.Value - 1]; + } + + return SystemColors.Control; + } + + public static Color? GetColorForHighlight(int? inputtedNumber) + { + switch (inputtedNumber) + { + case 1: + return Color.Red; + case 2: + return Color.Orange; + case 3: + return Color.Yellow; + case 4: + return Color.Green; + case 5: + return Color.Blue; + case 6: + return Color.Purple; + case 7: + return Color.Pink; + case 8: + return Color.Brown; + case 9: + return Color.Black; + case 0: + return Color.White; + default: + return null; + } + } + + public static Color? ConvertDecimalToColor(List numbersNullable) + { + if (numbersNullable.Count != 3) return null; + if (numbersNullable.Any(number => !number.HasValue)) return null; + if (numbersNullable.Any(number => number.Value < 0 || number.Value > 255)) return null; + List numbers = numbersNullable.ConvertAll(number => number.Value); + return Color.FromArgb(numbers[0], numbers[1], numbers[2]); + } + + public static string ConvertColorToDecimal(Color color) + { + return color.R + "," + color.G + "," + color.B; + } + + public static Color InterpolateColor(Color c1, Color c2, double amount) + { + amount = Math.Max(0, Math.Min(1, amount)); + byte r = (byte)((c1.R * (1 - amount)) + c2.R * amount); + byte g = (byte)((c1.G * (1 - amount)) + c2.G * amount); + byte b = (byte)((c1.B * (1 - amount)) + c2.B * amount); + return Color.FromArgb(r, g, b); + } + + public static Color AddAlpha(Color color, byte alpha) + { + return Color.FromArgb(alpha, color.R, color.G, color.B); + } + } +} diff --git a/STROOP.Variables/Utilities/HexUtilities.cs b/STROOP.Variables/Utilities/HexUtilities.cs new file mode 100644 index 000000000..9e13d2d27 --- /dev/null +++ b/STROOP.Variables/Utilities/HexUtilities.cs @@ -0,0 +1,62 @@ +namespace STROOP.Variables.Utilities; + +public static class HexUtilities +{ + public static string FormatValue(object number, int? numDigits = null, bool usePrefix = true) + { + object numberFormatted = number; + + // Make sure it's a number + if (!TypeUtilities.IsNumber(numberFormatted)) + { + numberFormatted = double.TryParse((string)numberFormatted, out double result) ? result : null; + if (numberFormatted == null) return number.ToString(); + } + + // Convert floats/doubles into ints/uints + if (numberFormatted is float || numberFormatted is double) + { + if (numberFormatted is float floatValue) numberFormatted = Math.Round(floatValue); + else if (numberFormatted is double doubleValue) numberFormatted = Math.Round(doubleValue); + else + { + int? intValueNullable = int.TryParse((string)numberFormatted, out int intValue) ? intValue : null; + if (intValueNullable.HasValue) + numberFormatted = intValueNullable.Value; + else + { + uint? uintValueNullable = uint.TryParse((string)numberFormatted, out uint uintValue) ? uintValue : null; + if (uintValueNullable.HasValue) numberFormatted = uintValueNullable.Value; + } + } + } + + if (!TypeUtilities.IsIntegerNumber(numberFormatted)) return number.ToString(); + + string numDigitsString = numDigits.HasValue ? numDigits.Value.ToString() : ""; + string hexString = string.Format("{0:X" + numDigitsString + "}", numberFormatted); + string prefix = usePrefix ? "0x" : ""; + if (numDigits.HasValue) + { + hexString = StringUtilities.ExactLength(hexString, numDigits.Value, true, '0'); + } + + return prefix + hexString; + } + + public static string FormatMemory(object number, int? numDigits = null, bool usePrefix = true) + { + if (number is bool boolValue) + number = boolValue ? 1 : 0; + if (!TypeUtilities.IsNumber(number)) throw new ArgumentOutOfRangeException(); + + byte[] bytes = TypeUtilities.GetBytes(number); + List byteList = new List(bytes); + byteList.Reverse(); + List stringList = byteList.ConvertAll(b => string.Format("{0:X2}", b)); + string byteString = string.Join("", stringList); + if (numDigits.HasValue) byteString = StringUtilities.ExactLength(byteString, numDigits.Value, true, '0'); + string prefix = usePrefix ? "0x" : ""; + return prefix + byteString; + } +} diff --git a/STROOP.Variables/Utilities/InitializeBaseAddressAttribute.cs b/STROOP.Variables/Utilities/InitializeBaseAddressAttribute.cs new file mode 100644 index 000000000..fd3734a3d --- /dev/null +++ b/STROOP.Variables/Utilities/InitializeBaseAddressAttribute.cs @@ -0,0 +1,5 @@ +using STROOP.Core.Utilities; + +namespace STROOP.Variables.Utilities; + +public class InitializeBaseAddressAttribute : InitializerAttribute; diff --git a/STROOP.Variables/Utilities/InitializeSpecialAttribute.cs b/STROOP.Variables/Utilities/InitializeSpecialAttribute.cs new file mode 100644 index 000000000..dc1edfcf6 --- /dev/null +++ b/STROOP.Variables/Utilities/InitializeSpecialAttribute.cs @@ -0,0 +1,5 @@ +using STROOP.Core.Utilities; + +namespace STROOP.Variables.Utilities; + +public class InitializeSpecialAttribute : InitializerAttribute; diff --git a/STROOP/Utilities/ParsingUtilities.cs b/STROOP.Variables/Utilities/ParsingUtilities.cs similarity index 86% rename from STROOP/Utilities/ParsingUtilities.cs rename to STROOP.Variables/Utilities/ParsingUtilities.cs index 490e69a3f..29b0ff80e 100644 --- a/STROOP/Utilities/ParsingUtilities.cs +++ b/STROOP.Variables/Utilities/ParsingUtilities.cs @@ -1,11 +1,7 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using OpenTK; +using System.Globalization; using System.Text.RegularExpressions; -using OpenTK.Mathematics; -namespace STROOP.Utilities +namespace STROOP.Variables.Utilities { public static class ParsingUtilities { @@ -426,32 +422,32 @@ public static List ParseHexListNullable(string text) public static byte ParseByteRoundingWrapping(double value) { - return (byte)MoreMath.GetIntegerInRangeWrapped(value, 1.0 + byte.MaxValue - byte.MinValue, false); + return (byte)GetIntegerInRangeWrapped(value, 1.0 + byte.MaxValue - byte.MinValue, false); } public static sbyte ParseSByteRoundingWrapping(double value) { - return (sbyte)MoreMath.GetIntegerInRangeWrapped(value, 1.0 + sbyte.MaxValue - sbyte.MinValue, true); + return (sbyte)GetIntegerInRangeWrapped(value, 1.0 + sbyte.MaxValue - sbyte.MinValue, true); } public static short ParseShortRoundingWrapping(double value) { - return (short)MoreMath.GetIntegerInRangeWrapped(value, 1.0 + short.MaxValue - short.MinValue, true); + return (short)GetIntegerInRangeWrapped(value, 1.0 + short.MaxValue - short.MinValue, true); } public static ushort ParseUShortRoundingWrapping(double value) { - return (ushort)MoreMath.GetIntegerInRangeWrapped(value, 1.0 + ushort.MaxValue - ushort.MinValue, false); + return (ushort)GetIntegerInRangeWrapped(value, 1.0 + ushort.MaxValue - ushort.MinValue, false); } public static int ParseIntRoundingWrapping(double value) { - return (int)MoreMath.GetIntegerInRangeWrapped(value, 1.0 + int.MaxValue - int.MinValue, true); + return (int)GetIntegerInRangeWrapped(value, 1.0 + int.MaxValue - int.MinValue, true); } public static uint ParseUIntRoundingWrapping(double value) { - return (uint)MoreMath.GetIntegerInRangeWrapped(value, 1.0 + uint.MaxValue - uint.MinValue, false); + return (uint)GetIntegerInRangeWrapped(value, 1.0 + uint.MaxValue - uint.MinValue, false); } @@ -499,43 +495,32 @@ public static uint ParseUIntRoundingWrapping(double value) public static byte ParseByteRoundingCapping(double value) { - return (byte)MoreMath.GetIntegerInRangeCapped(value, 1.0 + byte.MaxValue - byte.MinValue, false); + return (byte)GetIntegerInRangeCapped(value, 1.0 + byte.MaxValue - byte.MinValue, false); } public static sbyte ParseSByteRoundingCapping(double value) { - return (sbyte)MoreMath.GetIntegerInRangeCapped(value, 1.0 + sbyte.MaxValue - sbyte.MinValue, true); + return (sbyte)GetIntegerInRangeCapped(value, 1.0 + sbyte.MaxValue - sbyte.MinValue, true); } public static short ParseShortRoundingCapping(double value) { - return (short)MoreMath.GetIntegerInRangeCapped(value, 1.0 + short.MaxValue - short.MinValue, true); + return (short)GetIntegerInRangeCapped(value, 1.0 + short.MaxValue - short.MinValue, true); } public static ushort ParseUShortRoundingCapping(double value) { - return (ushort)MoreMath.GetIntegerInRangeCapped(value, 1.0 + ushort.MaxValue - ushort.MinValue, false); + return (ushort)GetIntegerInRangeCapped(value, 1.0 + ushort.MaxValue - ushort.MinValue, false); } public static int ParseIntRoundingCapping(double value) { - return (int)MoreMath.GetIntegerInRangeCapped(value, 1.0 + int.MaxValue - int.MinValue, true); + return (int)GetIntegerInRangeCapped(value, 1.0 + int.MaxValue - int.MinValue, true); } public static uint ParseUIntRoundingCapping(double value) { - return (uint)MoreMath.GetIntegerInRangeCapped(value, 1.0 + uint.MaxValue - uint.MinValue, false); - } - - public static bool TryParseVector3(string text, out Vector3 value) - { - value = default(Vector3); - if (text == null) return false; - string[] split = text.Split(';'); - return (split.Length == 3 - && float.TryParse(split[0].Trim(), out value.X) - && float.TryParse(split[1].Trim(), out value.Y) - && float.TryParse(split[2].Trim(), out value.Z)); + return (uint)GetIntegerInRangeCapped(value, 1.0 + uint.MaxValue - uint.MinValue, false); } public static bool ParseByteString(string byteString, out byte[] result) @@ -556,5 +541,39 @@ public static bool ParseByteString(string byteString, out byte[] result) result = bytes; return true; } + + /** Rounds and then caps the value to be in [-range/2, range/2) if signed or [0, range) if unsigned. */ + static double GetIntegerInRangeCapped(double value, double range, bool signed) + { + value = Math.Round(value, MidpointRounding.AwayFromZero); + double min = signed ? -1 * range / 2 : 0; + double exclusiveMax = signed ? range / 2 : range; + double inclusiveMax = exclusiveMax - 1; + return Math.Min(Math.Max(value, min), inclusiveMax); + } + + /** Rounds and then wraps the value to be in [-range/2, range/2) if signed or [0, range) if unsigned. */ + public static double GetIntegerInRangeWrapped(double value, double range, bool signed) + { + value = Math.Round(value, MidpointRounding.AwayFromZero); + return signed ? MaybeNegativeModulus(value, range) : NonNegativeModulus(value, range); + } + + /** Gets the value in [-modulus/2, modulus/2). */ + static double MaybeNegativeModulus(double value, double modulus) + { + value %= modulus; + if (value < 0) value += modulus; + if (value >= modulus / 2) value -= modulus; + return value; + } + + /** Gets the value in [0, modulus). */ + static double NonNegativeModulus(double value, double modulus) + { + value %= modulus; + if (value < 0) value += modulus; + return value; + } } } diff --git a/STROOP.Variables/Utilities/StringUtilities.cs b/STROOP.Variables/Utilities/StringUtilities.cs new file mode 100644 index 000000000..9c3af2b98 --- /dev/null +++ b/STROOP.Variables/Utilities/StringUtilities.cs @@ -0,0 +1,47 @@ +namespace STROOP.Variables.Utilities; + +public static class StringUtilities +{ + public static string Cap(string stringValue, int length) + { + if (stringValue == null) return stringValue; + if (stringValue.Length <= length) return stringValue; + return stringValue.Substring(0, length); + } + + public static string ExactLength(string stringValue, int length, bool leftAppend, char appendChar) + { + if (stringValue == null) return stringValue; + if (stringValue.Length < length) + { + return leftAppend + ? stringValue.PadLeft(length, appendChar) + : stringValue.PadRight(length, appendChar); + } + + if (stringValue.Length > length) + { + return leftAppend + ? stringValue.Substring(stringValue.Length - length) + : stringValue.Substring(0, length); + } + + return stringValue; + } + + public static string FormatIntegerWithSign(int num) => (num > 0 ? "+" : "") + num; + + public static string Capitalize(string s) + { + if (string.IsNullOrEmpty(s)) return s; + return s.Substring(0, 1).ToUpper() + s.Substring(1); + } + + public static string Concat(IEnumerable ts, Func toString) + { + List strings = new List(); + foreach (T? t in ts) + strings.Add(toString(t)); + return string.Concat(strings); + } +} diff --git a/STROOP.Variables/Utilities/TypeUtilities.cs b/STROOP.Variables/Utilities/TypeUtilities.cs new file mode 100644 index 000000000..56a50557d --- /dev/null +++ b/STROOP.Variables/Utilities/TypeUtilities.cs @@ -0,0 +1,243 @@ +using System.Globalization; +using System.Text; + +namespace STROOP.Variables.Utilities; + +public static class TypeUtilities +{ + public static readonly Dictionary StringToType = new Dictionary() + { + { "byte", typeof(byte) }, + { "sbyte", typeof(sbyte) }, + { "short", typeof(short) }, + { "ushort", typeof(ushort) }, + { "int", typeof(int) }, + { "uint", typeof(uint) }, + { "long", typeof(long) }, + { "ulong", typeof(ulong) }, + { "float", typeof(float) }, + { "double", typeof(double) }, + }; + + public static readonly Dictionary TypeToString = new Dictionary() + { + { typeof(byte), "byte" }, + { typeof(sbyte), "sbyte" }, + { typeof(short), "short" }, + { typeof(ushort), "ushort" }, + { typeof(int), "int" }, + { typeof(uint), "uint" }, + { typeof(long), "long" }, + { typeof(ulong), "ulong" }, + { typeof(float), "float" }, + { typeof(double), "double" }, + }; + + public static readonly Dictionary TypeSize = new Dictionary() + { + { typeof(byte), 1 }, + { typeof(sbyte), 1 }, + { typeof(short), 2 }, + { typeof(ushort), 2 }, + { typeof(int), 4 }, + { typeof(uint), 4 }, + { typeof(long), 8 }, + { typeof(ulong), 8 }, + { typeof(float), 4 }, + { typeof(double), 8 }, + }; + + public static readonly Dictionary TypeSign = new Dictionary() + { + { typeof(byte), false }, + { typeof(sbyte), true }, + { typeof(short), true }, + { typeof(ushort), false }, + { typeof(int), true }, + { typeof(uint), false }, + { typeof(long), true }, + { typeof(ulong), false }, + { typeof(float), true }, + { typeof(double), true }, + }; + + public static readonly Dictionary UnsignedByteType = new Dictionary() + { + { 1, typeof(byte) }, + { 2, typeof(ushort) }, + { 4, typeof(uint) }, + { 8, typeof(ulong) }, + }; + + public static readonly List SimpleTypeList = + new List() + { + "byte", + "sbyte", + "short", + "ushort", + "int", + "uint", + "float", + }; + + public static readonly List InGameTypeList = + new List() + { + "byte", + "sbyte", + "short", + "ushort", + "int", + "uint", + "float", + "double", + }; + + public static object ConvertBytes(Type type, string hexString, bool littleEndian) + { + if (hexString == null) return null; + if (hexString.Length >= 2 && hexString.Substring(0, 2) == "0x") hexString = hexString.Substring(2); + hexString = StringUtilities.ExactLength(hexString, 2 * TypeSize[type], true, '0'); + + try + { + byte[] bytes = Enumerable.Range(0, hexString.Length) + .ToList() + .FindAll(i => i % 2 == 0) + .ConvertAll(i => Convert.ToByte(hexString.Substring(i, 2), 16)) + .ToArray(); + return ConvertBytes(type, bytes, 0, littleEndian); + } + catch (Exception) + { + return null; + } + } + + public static object ConvertBytes(Type type, byte[] allBytes, int startIndex, bool littleEndian) + { + int typeSize = TypeSize[type]; + int modValue = startIndex % 4; + int baseValue = startIndex - modValue; + int newModValue = modValue; + if (littleEndian) + { + if (typeSize == 2) newModValue = 2 - modValue; + if (typeSize == 1) newModValue = 3 - modValue; + } + + int newStartAddress = baseValue + newModValue; + + byte[] bytes = new byte[typeSize]; + for (int i = 0; i < typeSize; i++) + { + byte byteValue = allBytes[newStartAddress + i]; + int index = typeSize - 1 - i; + bytes[index] = byteValue; + } + + return ConvertBytes(type, bytes); + } + + public static object ConvertBytes(Type type, byte[] bytes) + { + if (type == typeof(byte)) return bytes[0]; + if (type == typeof(sbyte)) return (sbyte)bytes[0]; + if (type == typeof(short)) return BitConverter.ToInt16(bytes, 0); + if (type == typeof(ushort)) return BitConverter.ToUInt16(bytes, 0); + if (type == typeof(int)) return BitConverter.ToInt32(bytes, 0); + if (type == typeof(uint)) return BitConverter.ToUInt32(bytes, 0); + if (type == typeof(float)) return BitConverter.ToSingle(bytes, 0); + if (type == typeof(double)) return BitConverter.ToDouble(bytes, 0); + throw new ArgumentOutOfRangeException(); + } + + public static byte[] GetBytes(object obj, int? fixedLength = null, Encoding encoding = null) + { + byte[] bytes; + + if (obj is byte byteValue) bytes = new byte[] { byteValue }; + else if (obj is sbyte sbyteValue) bytes = new byte[] { (byte)sbyteValue }; + else if (obj is short shortValue) bytes = BitConverter.GetBytes(shortValue); + else if (obj is ushort ushortValue) bytes = BitConverter.GetBytes(ushortValue); + else if (obj is int intValue) bytes = BitConverter.GetBytes(intValue); + else if (obj is uint uintValue) bytes = BitConverter.GetBytes(uintValue); + else if (obj is float floatValue) bytes = BitConverter.GetBytes(floatValue); + else if (obj is double doubleValue) bytes = BitConverter.GetBytes(doubleValue); + else if (obj is string stringValue) + { + if (encoding == null) throw new ArgumentOutOfRangeException(); + bytes = encoding.GetBytes(stringValue); + } + else throw new ArgumentOutOfRangeException(); + + if (fixedLength.HasValue) + { + if (bytes.Length > fixedLength.Value) + { + bytes = bytes.Take(fixedLength.Value).ToArray(); + } + else if (bytes.Length < fixedLength.Value) + { + bytes = bytes.Concat(new byte[fixedLength.Value - bytes.Length]).ToArray(); + } + } + + return bytes; + } + + public static bool IsNumber(object obj) => obj is byte || + obj is sbyte || + obj is short || + obj is ushort || + obj is int || + obj is uint || + obj is long || + obj is ulong || + obj is float || + obj is double; + + public static bool IsIntegerNumber(object obj) => obj is byte || + obj is sbyte || + obj is short || + obj is ushort || + obj is int || + obj is uint || + obj is long || + obj is ulong; + + public static byte[] ConvertHexStringToByteArray(string stringValue, bool swapEndianness) + { + if (stringValue == null || stringValue.Length % 2 == 1) + { + throw new ArgumentOutOfRangeException("stringValue must have even length"); + } + + byte[] bytes = new byte[stringValue.Length / 2]; + for (int i = 0; i < bytes.Length; i++) + { + string byteString = stringValue.Substring(i * 2, 2); + byte byteValue = byte.Parse(byteString, NumberStyles.HexNumber); + int index = swapEndianness ? bytes.Length - 1 - i : i; + bytes[index] = byteValue; + } + + return bytes; + } + + public static bool IsSubtype(Type type1, Type type2) => type1 == type2 || type1.IsSubclassOf(type2); + + public static bool MatchesGenericType(Type genericType, Type typeToCheck) + { + Type? t = typeToCheck; + while (t != null) + { + if (t.IsGenericType && t.GetGenericTypeDefinition() == genericType) + return true; + t = t.BaseType; + } + + return false; + } +} diff --git a/STROOP.Variables/Utilities/VariableUtilities.cs b/STROOP.Variables/Utilities/VariableUtilities.cs new file mode 100644 index 000000000..bb1a959c4 --- /dev/null +++ b/STROOP.Variables/Utilities/VariableUtilities.cs @@ -0,0 +1,123 @@ +using STROOP.Variables.SM64MemoryLayout; +using STROOP.Variables.VariablePanel; + +namespace STROOP.Variables.Utilities; + +public static class IVariableViewExtensions +{ + public static IVariable WithKeyedValue(this IVariable view, string key, string value) + { + view.SetValueByKey(key, value); + return view; + } + + public static IEnumerable GetNumberValues(this IVariable view) where T : struct, IConvertible + { + if (view.TryGetNumberValues(out IEnumerable? result)) + return result; + throw new InvalidOperationException($"'{view.GetType().FullName}' is not a vaild number type."); + } + + public static bool TryGetNumberValues(this IVariable view, out IEnumerable result) + where T : struct, IConvertible + { + bool Get(out IEnumerable innerResult) + { + innerResult = null; + if (view is IVariable qView) + { + innerResult = qView.getter().Select(x => (T)Convert.ChangeType(x, typeof(T))); + return true; + } + + return false; + } + + return Get(out result) + || Get(out result) + || Get(out result) + || Get(out result) + || Get(out result) + || Get(out result) + || Get(out result) + || Get(out result) + || Get(out result) + || Get(out result) + ; + } + + public static IEnumerable TrySetValue(this IVariable view, T value) where T : IConvertible + { + IEnumerable Set() + { + Q convertedValue = default(Q); + try + { + convertedValue = (Q)Convert.ChangeType(value, typeof(Q)); + } + catch (Exception) + { + return null; + } + + if (view is IVariable qView) + return qView.setter(convertedValue); + return null; + } + + return Set() + ?? Set() + ?? Set() + ?? Set() + ?? Set() + ?? Set() + ?? Set() + ?? Set() + ?? Set() + ?? Set() + ?? Array.Empty() + ; + } + + public static (CombinedValuesMeaning meaning, T value) CombineValues(this IVariableCellData view) + { + T[]? values = view.GetValues(); + if (values.Length == 0) + return (CombinedValuesMeaning.NoValue, default(T)); + + T firstValue = values[0]; + for (int i = 1; i < values.Length; i++) + if (!Equals(values[i], firstValue)) + return (CombinedValuesMeaning.MultipleValues, default(T)); + + return (CombinedValuesMeaning.SameValue, firstValue); + } +} + +public static class VariableUtilities +{ + public static SortedDictionary>> baseAddressGetters = new SortedDictionary>>(); + + [InitializeBaseAddress] + private static void InitBaseAddresses() + { + baseAddressGetters[BaseAddressType.None] = GetBaseAddressListEmpty; + baseAddressGetters[BaseAddressType.Relative] = GetBaseAddressListZero; + } + + public static List ParseVariableGroupList(string stringValue) + => [..Array.ConvertAll(stringValue.Split('|', ','), s => s.Trim())]; + + public static readonly List BaseAddressListZero = [0]; + public static readonly List BaseAddressListEmpty = []; + private static List GetBaseAddressListZero() => BaseAddressListZero; + private static List GetBaseAddressListEmpty() => BaseAddressListEmpty; + + public static IEnumerable GetBaseAddresses(string baseAddressType) + => baseAddressGetters.TryGetValue(baseAddressType, out Func> result) ? result() : []; + + public static IEnumerable> GetNumberValues(IEnumerable cells) + where TCell : IVariableCell + => cells.OfType>().Where(x => x is not IVariableCellData) + .Select(x => x.GetValues().Select(y => (double)Convert.ChangeType(y, TypeCode.Double))); +} diff --git a/STROOP.Variables/VariableGroup.cs b/STROOP.Variables/VariableGroup.cs new file mode 100644 index 000000000..3c99693f8 --- /dev/null +++ b/STROOP.Variables/VariableGroup.cs @@ -0,0 +1,37 @@ +using STROOP.Core.Utilities; + +namespace STROOP.Variables; + +public static class VariableGroup +{ + static VariableGroup() => StringSymbolAttribute.InitializeDeclaredStrings(typeof(VariableGroup)); + + [StringSymbol] + public static string + Basic, + Intermediate, + Advanced, + ObjectSpecific, + Scheduler, + Snow, + WarpNode, + NoGroup, + Custom, + ProcessGroup, + Collision, + Movement, + Transformation, + Coordinate, + FloorCoordinate, + ExtendedLevelBoundaries, + HolpMario, + HolpPoint, + Trajectory, + Point, + Coin, + Hacks, + Rng, + Self, + QuarterFrameHack, + GhostHack; +}; diff --git a/STROOP.Variables/VariablePanel/Cells/VariableAddressCell.cs b/STROOP.Variables/VariablePanel/Cells/VariableAddressCell.cs new file mode 100644 index 000000000..e21a85b77 --- /dev/null +++ b/STROOP.Variables/VariablePanel/Cells/VariableAddressCell.cs @@ -0,0 +1,31 @@ +namespace STROOP.Variables.VariablePanel.Cells +{ + public abstract class VariableAddressCell : VariableNumberCell + where TUiContext : IUiContext + { + private static VariableCellSetting _viewAddressCellSetting = new VariableCellSetting( + "View Address", + (ctrl, obj) => + { + if (ctrl.varCellInternal is VariableAddressCell addressWrapper) + addressWrapper.ShowMemory(addressWrapper.view.getter().FirstOrDefault()); + + return false; + }); + + private VariableNumberCell baseCell; + + protected abstract void ShowMemory(uint address); + + public VariableAddressCell(VariableNumberCell baseCell) + : base((IVariable)baseCell.control.view, baseCell.control) + { + control.view.SetValueByKey(CommonVariableProperties.useHex, true.ToString()); + control.AddSetting(_viewAddressCellSetting); + } + + public override string GetClass() => "Address"; + + internal protected sealed override bool RoundToZero() => baseCell.RoundToZero(); + } +} diff --git a/STROOP/Controls/VariablePanel/Wrappers/WatchVariableAngleWrapper.cs b/STROOP.Variables/VariablePanel/Cells/VariableAngleCell.cs similarity index 60% rename from STROOP/Controls/VariablePanel/Wrappers/WatchVariableAngleWrapper.cs rename to STROOP.Variables/VariablePanel/Cells/VariableAngleCell.cs index 2015c087a..5a5040897 100644 --- a/STROOP/Controls/VariablePanel/Wrappers/WatchVariableAngleWrapper.cs +++ b/STROOP.Variables/VariablePanel/Cells/VariableAngleCell.cs @@ -1,26 +1,26 @@ -using System; -using System.Collections.Generic; -using STROOP.Core.Variables; -using STROOP.Structs; -using STROOP.Utilities; +using STROOP.Utilities; +using STROOP.Variables.Utilities; -namespace STROOP.Controls.VariablePanel +namespace STROOP.Variables.VariablePanel.Cells { - public class WatchVariableAngleWrapper : WatchVariableNumberWrapper where TNumber : struct, IConvertible + public abstract class VariableAngleCell + : VariableNumberCell + where TNumber : struct, IConvertible + where TUiContext : IUiContext { - public static readonly WatchVariableSetting DisplaySignedSetting = new WatchVariableSetting( + public static readonly VariableCellSetting DisplaySignedCellSetting = new VariableCellSetting( "Angle: Signed", - CreateBoolWithDefault>((wrapper, val) => wrapper._signed = val, wrapper => wrapper._defaultSigned), - ("Default", () => null, WrapperProperty>(wr => wr._signed == wr._defaultSigned)), - ("Unsigned", () => false, WrapperProperty>(wr => !wr._signed)), - ("Signed", () => true, WrapperProperty>(wr => wr._signed)) + CreateBoolWithDefault>((wrapper, val) => wrapper._signed = val, wrapper => wrapper._defaultSigned), + ("Default", () => null, WrapperProperty>(wr => wr._signed == wr._defaultSigned)), + ("Unsigned", () => false, WrapperProperty>(wr => !wr._signed)), + ("Signed", () => true, WrapperProperty>(wr => wr._signed)) ); - public static readonly WatchVariableSetting AngleUnitTypeSetting = new WatchVariableSetting( + public static readonly VariableCellSetting AngleUnitTypeCellSetting = new VariableCellSetting( "Angle: Units", (ctrl, obj) => { - if (ctrl.WatchVarWrapper is WatchVariableAngleWrapper num) + if (ctrl.varCellInternal is VariableAngleCell num) if (obj is AngleUnitType type) num._angleUnitType = type; else if (obj == null) @@ -31,45 +31,47 @@ public class WatchVariableAngleWrapper : WatchVariableNumberWrapper, Func)[]>)(() => + ((Func<(string, Func, Func, bool>)[]>)(() => { - var lst = new List<(string, Func, Func)>(); + var lst = new List<(string, Func, Func, bool>)>(); foreach (AngleUnitType angleUnitType in Enum.GetValues(typeof(AngleUnitType))) { string stringValue = angleUnitType.ToString(); if (stringValue == AngleUnitType.InGameUnits.ToString()) stringValue = "In-Game Units"; var value = angleUnitType; - lst.Add((stringValue, () => angleUnitType, WrapperProperty>(wr => wr._angleUnitType == angleUnitType))); + lst.Add((stringValue, () => angleUnitType, WrapperProperty>(wr => wr._angleUnitType == angleUnitType))); } return lst.ToArray(); }))() ); - public static readonly WatchVariableSetting TruncateToMultipleOf16Setting = new WatchVariableSetting( + public static readonly VariableCellSetting TruncateToMultipleOf16CellSetting = new VariableCellSetting( "Angle: Truncate to Multiple of 16", - CreateBoolWithDefault>((wrapper, val) => wrapper._truncateToMultipleOf16 = val, wrapper => wrapper._defaultTruncateToMultipleOf16), - ("Default", () => null, WrapperProperty>(wr => wr._truncateToMultipleOf16 == wr._defaultTruncateToMultipleOf16)), - ("Truncate to Multiple of 16", () => true, WrapperProperty>(wr => wr._truncateToMultipleOf16)), - ("Don't Truncate to Multiple of 16", () => false, WrapperProperty>(wr => !wr._truncateToMultipleOf16)) + CreateBoolWithDefault>((wrapper, val) => wrapper._truncateToMultipleOf16 = val, wrapper => wrapper._defaultTruncateToMultipleOf16), + ("Default", () => null, WrapperProperty>(wr => wr._truncateToMultipleOf16 == wr._defaultTruncateToMultipleOf16)), + ("Truncate to Multiple of 16", () => true, WrapperProperty>(wr => wr._truncateToMultipleOf16)), + ("Don't Truncate to Multiple of 16", () => false, WrapperProperty>(wr => !wr._truncateToMultipleOf16)) ); - public static readonly WatchVariableSetting ConstrainToOneRevolutionSetting = new WatchVariableSetting( + public static readonly VariableCellSetting ConstrainToOneRevolutionCellSetting = new VariableCellSetting( "Angle: Constrain to One Revolution", - CreateBoolWithDefault>((wrapper, val) => wrapper._constrainToOneRevolution = val, wrapper => wrapper._defaultConstrainToOneRevolution), - ("Default", () => null, WrapperProperty>(wr => wr._constrainToOneRevolution == wr._defaultConstrainToOneRevolution)), - ("Constrain to One Revolution", () => true, WrapperProperty>(wr => wr._constrainToOneRevolution)), - ("Don't Constrain to One Revolution", () => false, WrapperProperty>(wr => !wr._constrainToOneRevolution)) + CreateBoolWithDefault>((wrapper, val) => wrapper._constrainToOneRevolution = val, wrapper => wrapper._defaultConstrainToOneRevolution), + ("Default", () => null, WrapperProperty>(wr => wr._constrainToOneRevolution == wr._defaultConstrainToOneRevolution)), + ("Constrain to One Revolution", () => true, WrapperProperty>(wr => wr._constrainToOneRevolution)), + ("Don't Constrain to One Revolution", () => false, WrapperProperty>(wr => !wr._constrainToOneRevolution)) ); - public static readonly WatchVariableSetting ReverseSetting = new WatchVariableSetting( + public static readonly VariableCellSetting ReverseCellSetting = new VariableCellSetting( "Angle: Reverse", - CreateBoolWithDefault>((wrapper, val) => wrapper._reverse = val, wrapper => wrapper._defaultReverse), - ("Default", () => null, WrapperProperty>(wr => wr._reverse == wr._defaultReverse)), - ("Reverse", () => true, WrapperProperty>(wr => wr._reverse)), - ("Don't Reverse", () => false, WrapperProperty>(wr => !wr._reverse)) + CreateBoolWithDefault>((wrapper, val) => wrapper._reverse = val, wrapper => wrapper._defaultReverse), + ("Default", () => null, WrapperProperty>(wr => wr._reverse == wr._defaultReverse)), + ("Reverse", () => true, WrapperProperty>(wr => wr._reverse)), + ("Don't Reverse", () => false, WrapperProperty>(wr => !wr._reverse)) ); + private VariableNumberCell baseCell; + private readonly bool _defaultSigned; private bool _signed; @@ -99,14 +101,18 @@ private Type _effectiveType } } + protected abstract bool DisplayAsUnsigned(); + private readonly bool _isYaw; - private bool effectiveSigned => _signed && (!_isYaw || Structs.Configurations.SavedSettingsConfig.DisplayYawAnglesAsUnsigned); + private bool effectiveSigned => _signed && (!_isYaw || DisplayAsUnsigned()); - public WatchVariableAngleWrapper(NamedVariableCollection.IView watchVar, WatchVariableControl watchVarControl) - : base(watchVar, watchVarControl) + public VariableAngleCell(VariableNumberCell baseCell) + : base((IVariable)baseCell.control.view, baseCell.control) { - var displayType = (view as NamedVariableCollection.MemoryDescriptorView)?.memoryDescriptor.MemoryType ?? typeof(double); - if (TypeUtilities.StringToType.TryGetValue(watchVarControl.view.GetValueByKey(NamedVariableCollection.ViewProperties.display) ?? "", out var dType)) + this.baseCell = baseCell; + + var displayType = (view as IMemoryVariable)?.memoryDescriptor.ClrType ?? typeof(double); + if (TypeUtilities.StringToType.TryGetValue(control.view.GetValueByKey(CommonVariableProperties.display) ?? "", out var dType)) displayType = dType; _baseType = displayType; @@ -128,7 +134,7 @@ public WatchVariableAngleWrapper(NamedVariableCollection.IView watchVar _defaultReverse = false; _reverse = _defaultReverse; - if (bool.TryParse(watchVarControl.view.GetValueByKey("yaw"), out var isYaw)) + if (bool.TryParse(control.view.GetValueByKey("yaw"), out var isYaw)) _isYaw = isYaw; else _isYaw = DEFAULT_IS_YAW; @@ -136,13 +142,40 @@ public WatchVariableAngleWrapper(NamedVariableCollection.IView watchVar AddAngleContextMenuStripItems(); } + public override bool TryParseValue(string value, out TNumber result) + { + double? doubleValueNullable = ParsingUtilities.ParseDoubleNullable(value); + if (doubleValueNullable.HasValue) + { + double doubleValue = doubleValueNullable.Value; + + if (_reverse) + { + doubleValue += 32768; + } + + if (_truncateToMultipleOf16) + { + doubleValue = MoreMath.TruncateToMultipleOf16(doubleValue); + } + + doubleValue = MoreMath.NormalizeAngleUsingType(doubleValue, _effectiveType); + doubleValue = (doubleValue / 65536) * GetAngleUnitTypeMaxValue(); + + result = (TNumber)Convert.ChangeType(doubleValue, typeof(TNumber)); + return true; + } + + return base.TryParseValue(value, out result); + } + private void AddAngleContextMenuStripItems() { - _watchVarControl.AddSetting(DisplaySignedSetting); - _watchVarControl.AddSetting(AngleUnitTypeSetting); - _watchVarControl.AddSetting(TruncateToMultipleOf16Setting); - _watchVarControl.AddSetting(ConstrainToOneRevolutionSetting); - _watchVarControl.AddSetting(ReverseSetting); + control.AddSetting(DisplaySignedCellSetting); + control.AddSetting(AngleUnitTypeCellSetting); + control.AddSetting(TruncateToMultipleOf16CellSetting); + control.AddSetting(ConstrainToOneRevolutionCellSetting); + control.AddSetting(ReverseCellSetting); } private double GetAngleUnitTypeMaxValue(AngleUnitType? angleUnitTypeNullable = null) @@ -181,33 +214,6 @@ private double GetAngleUnitTypeAndMaybeSignedMinValue(AngleUnitType? angleUnitTy return signed ? -1 * maxValue / 2 : 0; } - public override bool TryParseValue(string value, out TNumber result) - { - double? doubleValueNullable = ParsingUtilities.ParseDoubleNullable(value); - if (doubleValueNullable.HasValue) - { - double doubleValue = doubleValueNullable.Value; - - if (_reverse) - { - doubleValue += 32768; - } - - if (_truncateToMultipleOf16) - { - doubleValue = MoreMath.TruncateToMultipleOf16(doubleValue); - } - - doubleValue = MoreMath.NormalizeAngleUsingType(doubleValue, _effectiveType); - doubleValue = (doubleValue / 65536) * GetAngleUnitTypeMaxValue(); - - result = (TNumber)Convert.ChangeType(doubleValue, typeof(TNumber)); - return true; - } - - return base.TryParseValue(value, out result); - } - public override string DisplayValue(TNumber value) { double doubleValue = (double)Convert.ChangeType(value, typeof(double)); @@ -234,6 +240,8 @@ protected object HandleAngleRoundingOut(object value) return doubleValue; } + internal protected sealed override bool RoundToZero() => baseCell.RoundToZero(); + protected override int? GetHexDigitCount() => TypeUtilities.TypeSize[_effectiveType] * 2; public override string GetClass() => "Angle"; diff --git a/STROOP.Variables/VariablePanel/Cells/VariableBooleanCell.cs b/STROOP.Variables/VariablePanel/Cells/VariableBooleanCell.cs new file mode 100644 index 000000000..22b56e330 --- /dev/null +++ b/STROOP.Variables/VariablePanel/Cells/VariableBooleanCell.cs @@ -0,0 +1,124 @@ +using STROOP.Utilities; +using STROOP.Variables.Utilities; + +namespace STROOP.Variables.VariablePanel.Cells +{ + public abstract class VariableBooleanCellBase + : VariableCell + where TUiContext : IUiContext + { + + public static readonly VariableCellSetting DisplayAsCheckboxCellSetting = new VariableCellSetting( + "Boolean: Display as Checkbox", + CreateBoolWithDefault>((wrapper, val) => wrapper._displayAsCheckbox = val, wrapper => wrapper._displayAsCheckbox), + ("Default", () => true, WrapperProperty>(wr => wr._displayAsCheckbox == true)), + ("Display as Checkbox", () => true, WrapperProperty>(wr => wr._displayAsCheckbox)), + ("Don't display as Checkbox", () => false, WrapperProperty>(wr => !wr._displayAsCheckbox)) + ); + + public static readonly VariableCellSetting DisplayAsInverted = new VariableCellSetting( + "Boolean: Display as Inverted", + CreateBoolWithDefault>((wrapper, val) => wrapper._displayAsInverted = val, wrapper => wrapper._displayAsInverted), + ("Default", () => false, WrapperProperty>(wr => wr._displayAsInverted == false)), + ("Display as Inverted", () => true, WrapperProperty>(wr => wr._displayAsInverted)), + ("Don't display as Inverted", () => false, WrapperProperty>(wr => !wr._displayAsInverted)) + ); + + private bool _displayAsCheckbox; + protected bool _displayAsInverted { get ; private set; } + + protected abstract T falseValue { get; } + protected abstract T trueValue { get; } + + public override void SingleClick(TUiContext uiContext) + { + if (_displayAsCheckbox) + Edit(uiContext); + } + + public override void DoubleClick(TUiContext uiContext) + { + if (!_displayAsCheckbox) + Edit(uiContext); + } + + public VariableBooleanCellBase(IVariable watchVar, VariableCellControl varCellControl) + : base(watchVar, varCellControl) + { + _displayAsCheckbox = true; + if (bool.TryParse(varCellControl.view.GetValueByKey(CommonVariableProperties.invertBool), out var invertBool)) + _displayAsInverted = invertBool; + else + _displayAsInverted = false; + + AddBooleanContextMenuStripItems(); + } + + private void AddBooleanContextMenuStripItems() + { + control.AddSetting(DisplayAsCheckboxCellSetting); + control.AddSetting(DisplayAsInverted); + } + + public override IVariableCellUi.CustomDraw CustomDrawOperation => _displayAsCheckbox ? DrawCheckbox : null; + + public override sealed void Edit(TUiContext uiContext) + { + if (_displayAsCheckbox) + { + if (lastValueMeaning != CombinedValuesMeaning.SameValue) + nextValue = falseValue; + else + nextValue = lastValue.Equals(falseValue) ? trueValue : falseValue; + } + else + base.Edit(uiContext); + } + + protected abstract void DrawCheckbox(TUiContext uiContext); + + private bool HandleInverting(bool boolValue) => boolValue != _displayAsInverted; + + public override string GetClass() => "Boolean"; + } + + public abstract class VariableBooleanCell + : VariableBooleanCellBase + where TUiContext : IUiContext + { + protected override bool falseValue => false; + + protected override bool trueValue => true; + + public VariableBooleanCell(IVariable watchVar, VariableCellControl varCellControl) + : base(watchVar, varCellControl) + { + } + + public override bool TryParseValue(string value, out bool result) + => bool.TryParse(value, out result); + + public override string DisplayValue(bool value) => value.ToString(); + } + + public abstract class VariableBooleanCell + : VariableBooleanCellBase + where TUiContext : IUiContext + where TNumber : struct, IConvertible + { + public VariableBooleanCell(IVariable watchVar, VariableCellControl varCellControl) + : base(watchVar, varCellControl) + { + } + + private static TNumber MaxValue = (TNumber)typeof(TNumber).GetField(nameof(MaxValue)).GetValue(null); + + protected override TNumber falseValue => (TNumber)Convert.ChangeType(0, typeof(TNumber)); + protected override TNumber trueValue => MaxValue; + + public override bool TryParseValue(string value, out TNumber result) + => ParsingUtilities.TryParseNumber(value, out result); + + public override string DisplayValue(TNumber value) => value.ToString(); + } +} diff --git a/STROOP/Controls/VariablePanel/Wrappers/WatchVariableNullableWrapper.cs b/STROOP.Variables/VariablePanel/Cells/VariableNullableCell.cs similarity index 52% rename from STROOP/Controls/VariablePanel/Wrappers/WatchVariableNullableWrapper.cs rename to STROOP.Variables/VariablePanel/Cells/VariableNullableCell.cs index 6174117db..5c1ed4764 100644 --- a/STROOP/Controls/VariablePanel/Wrappers/WatchVariableNullableWrapper.cs +++ b/STROOP.Variables/VariablePanel/Cells/VariableNullableCell.cs @@ -1,33 +1,29 @@ -using System; -using System.Linq; -using STROOP.Core.Variables; - -namespace STROOP.Controls.VariablePanel +namespace STROOP.Variables.VariablePanel.Cells { - class WatchVariableNullableWrapper : WatchVariableWrapper - where TBaseWrapper : WatchVariableWrapper + class VariableNullableCell + : VariableCell + where TUiContext : IUiContext + where TBaseWrapper : VariableCell where TBackingType : struct { private TBaseWrapper baseWrapper; - public WatchVariableNullableWrapper(NamedVariableCollection.IView var, WatchVariableControl control) - : base(var, control) + public VariableNullableCell(IVariable var, VariableCellControl cellControl) + : base(var, cellControl) { - var interfaceType = view.GetType().GetInterfaces().First(x => x.Name == $"{nameof(NamedVariableCollection.IView)}`1"); + var interfaceType = view.GetType().GetInterfaces().First(x => x.Name == $"{nameof(IVariable)}`1"); interfaceType = interfaceType.GetGenericTypeDefinition().MakeGenericType(interfaceType.GenericTypeArguments[0].GenericTypeArguments[0]); baseWrapper = (TBaseWrapper) typeof(TBaseWrapper) - .GetConstructor(new Type[] { interfaceType, typeof(WatchVariableControl) }) - .Invoke(new object[] - { - new NamedVariableCollection.CustomView(typeof(TBaseWrapper)) + .GetConstructor([ interfaceType, typeof(VariableCellControl) ]) + ?.Invoke([ + new CustomVariable(var.Subclass) { - Name = view.Name, - _getterFunction = () => view._getterFunction().Select(x => x.HasValue ? x.Value : default(TBackingType)).ToArray(), - _setterFunction = value => view._setterFunction(value), + getter = () => view.getter().Select(x => x.HasValue ? x.Value : default(TBackingType)).ToArray(), + setter = value => view.setter(value), }, - control - }); + cellControl, + ]); } public override sealed bool TryParseValue(string value, out TBackingType? result) diff --git a/STROOP/Controls/VariablePanel/Wrappers/WatchVariableNumberWrapper.cs b/STROOP.Variables/VariablePanel/Cells/VariableNumberCell.cs similarity index 68% rename from STROOP/Controls/VariablePanel/Wrappers/WatchVariableNumberWrapper.cs rename to STROOP.Variables/VariablePanel/Cells/VariableNumberCell.cs index 4e1b2ac42..330c60dd9 100644 --- a/STROOP/Controls/VariablePanel/Wrappers/WatchVariableNumberWrapper.cs +++ b/STROOP.Variables/VariablePanel/Cells/VariableNumberCell.cs @@ -1,26 +1,27 @@ -using System; -using System.Collections.Generic; -using STROOP.Core.Variables; -using STROOP.Structs.Configurations; -using STROOP.Utilities; +using STROOP.Utilities; +using STROOP.Variables.Utilities; -namespace STROOP.Controls.VariablePanel +namespace STROOP.Variables.VariablePanel.Cells { - public class WatchVariableNumberWrapper : WatchVariableWrapper where TNumber : struct, IConvertible + public abstract class VariableNumberCell + : VariableCell + , IVariableCellData + where TUiContext : IUiContext + where TNumber : struct, IConvertible { - static Func WrapperProperty(Func, bool> func) => + static Func, bool> WrapperProperty(Func, bool> func) => (ctrl) => { - if (ctrl.WatchVarWrapper is WatchVariableNumberWrapper wrapper) + if (ctrl.varCellInternal is VariableNumberCell wrapper) return func(wrapper); return false; }; - public static readonly WatchVariableSetting RoundToSetting = new WatchVariableSetting( + public static readonly VariableCellSetting RoundToCellSetting = new VariableCellSetting( "Round To", (ctrl, obj) => { - if (ctrl.WatchVarWrapper is WatchVariableNumberWrapper num) + if (ctrl.varCellInternal is VariableNumberCell num) if (obj is bool doRounding && doRounding == false) num._roundingLimit = -1; else if (obj is int roundingLimit) @@ -33,9 +34,9 @@ static Func WrapperProperty(Func, Func)[]>)(() => + ((Func<(string, Func, Func, bool>)[]>)(() => { - var lst = new List<(string, Func, Func)>(); + var lst = new List<(string, Func, Func, bool>)>(); lst.Add(("Default", () => null, WrapperProperty(wr => wr._roundingLimit == wr._defaultRoundingLimit))); lst.Add(("No Rounding", () => false, WrapperProperty(wr => wr._roundingLimit == -1))); for (int i = 0; i < 10; i++) @@ -48,11 +49,11 @@ static Func WrapperProperty(Func DisplayAsHexCellSetting = new VariableCellSetting( "Display as Hex", (ctrl, obj) => { - if (ctrl.WatchVarWrapper is WatchVariableNumberWrapper num) + if (ctrl.varCellInternal is VariableNumberCell num) if (obj is bool doHexDisplay) num.displayAsHex = doHexDisplay; else if (obj == null) @@ -84,10 +85,10 @@ static Func WrapperProperty(Func _setDisplayAsHex; - public WatchVariableNumberWrapper(NamedVariableCollection.IView watchVar, WatchVariableControl watchVarControl) - : base(watchVar, watchVarControl) + public VariableNumberCell(IVariable watchVar, VariableCellControl varCellControl) + : base(watchVar, varCellControl) { - if (int.TryParse(watchVarControl.view.GetValueByKey(NamedVariableCollection.ViewProperties.roundingLimit), out var roundingLimit)) + if (int.TryParse(varCellControl.view.GetValueByKey(CommonVariableProperties.roundingLimit), out var roundingLimit)) _defaultRoundingLimit = roundingLimit; else _defaultRoundingLimit = DEFAULT_ROUNDING_LIMIT; @@ -97,7 +98,7 @@ public WatchVariableNumberWrapper(NamedVariableCollection.IView watchVa throw new ArgumentOutOfRangeException(); _defaultDisplayAsHex = - bool.TryParse(watchVarControl.view.GetValueByKey(NamedVariableCollection.ViewProperties.useHex), out var viewSetting) + bool.TryParse(varCellControl.view.GetValueByKey(CommonVariableProperties.useHex), out var viewSetting) ? viewSetting : DEFAULT_DISPLAY_AS_HEX; displayAsHex = _displayAsHex = _defaultDisplayAsHex; @@ -105,11 +106,13 @@ public WatchVariableNumberWrapper(NamedVariableCollection.IView watchVa AddNumberContextMenuStripItems(); } + internal protected abstract bool RoundToZero(); + + protected virtual int? GetHexDigitCount() => (view as IMemoryVariable)?.memoryDescriptor.NibbleCount; + public override bool TryParseValue(string value, out TNumber result) => ParsingUtilities.TryParseNumber(value, out result); - protected virtual int? GetHexDigitCount() => (_view as NamedVariableCollection.MemoryDescriptorView)?.memoryDescriptor.NibbleCount; - protected string HandleRounding(TNumber unknownValue) { double value; @@ -122,8 +125,7 @@ protected string HandleRounding(TNumber unknownValue) double roundedValue = roundingLimit.HasValue ? Math.Round(value, roundingLimit.Value) : value; - if (SavedSettingsConfig.DontRoundValuesToZero && - roundedValue == 0 && value != 0) + if (!RoundToZero() && roundedValue == 0 && value != 0) { // Specially print values near zero string digitsString = roundingLimit?.ToString() ?? ""; @@ -135,10 +137,12 @@ protected string HandleRounding(TNumber unknownValue) private void AddNumberContextMenuStripItems() { - _watchVarControl.AddSetting(RoundToSetting); - _watchVarControl.AddSetting(DisplayAsHexSetting); + control.AddSetting(RoundToCellSetting); + control.AddSetting(DisplayAsHexCellSetting); } + IConvertible[] IVariableCellData.GetValues() => GetValues().Cast().ToArray(); + public override string GetClass() => "Number"; public override string DisplayValue(TNumber value) diff --git a/STROOP.Variables/VariablePanel/Cells/VariableObjectCell.cs b/STROOP.Variables/VariablePanel/Cells/VariableObjectCell.cs new file mode 100644 index 000000000..93a8a153b --- /dev/null +++ b/STROOP.Variables/VariablePanel/Cells/VariableObjectCell.cs @@ -0,0 +1,93 @@ +using STROOP.Variables.Utilities; + +namespace STROOP.Variables.VariablePanel.Cells +{ + public abstract class VariableObjectCell + : VariableAddressCell + where TUiContext : IUiContext + { + static VariableCellSetting _displayAsObjectCellSetting = new VariableCellSetting( + "Display as Object", + (ctrl, obj) => + { + if (ctrl.varCellInternal is VariableObjectCell objectWrapper) + if (obj is bool doDisplayAsObject) + objectWrapper._displayAsObject = doDisplayAsObject; + else + return false; + return true; + }, + ("Object", () => true, WrapperProperty>(o => o._displayAsObject)), + ("Address", () => true, WrapperProperty>(o => !o._displayAsObject)) + ); + + private static VariableCellSetting _selectObjectCellSetting = new VariableCellSetting( + "Select Object", + (ctrl, obj) => + { + if (ctrl.varCellInternal is VariableObjectCell objectCell) + { + var value = objectCell.CombineValues(); + if (value.meaning == CombinedValuesMeaning.SameValue) + objectCell.SelectObject(value.value); + } + + return false; + }); + + private bool _displayAsObject; + + public VariableObjectCell(VariableNumberCell baseCell) + : base(baseCell) + { + _displayAsObject = true; + + AddObjectContextMenuStripItems(); + } + + protected abstract uint GetUnusedSlotAddress(); + protected abstract void SelectObject(uint address); + protected abstract string GetDescriptiveSlotLabelFromAddress(uint address); + protected abstract uint? GetObjectAddressFromLabel(string label); + + private void AddObjectContextMenuStripItems() + { + control.AddSetting(_displayAsObjectCellSetting); + control.AddSetting(_selectObjectCellSetting); + } + + public override string GetClass() => "Object"; + + public override string DisplayValue(uint value) + => _displayAsObject ? GetDescriptiveSlotLabelFromAddress(value) : base.DisplayValue(value); + + public override bool TryParseValue(string value, out uint result) + { + string slotName = value.ToLower(); + + if (slotName == "(no object)" || slotName == "no object") + { + result = 0; + return true; + } + + if (slotName == "(unused object)" || slotName == "unused object") + { + result = GetUnusedSlotAddress(); + return true; + } + + if (slotName.StartsWith("slot")) + { + var addr = GetObjectAddressFromLabel(slotName.Remove(0, "slot".Length).Trim()); + if (addr != null) + { + result = addr.Value; + return true; + } + } + + return base.TryParseValue(value, out result); + } + } +} diff --git a/STROOP.Variables/VariablePanel/Cells/VariableSelectionCell.cs b/STROOP.Variables/VariablePanel/Cells/VariableSelectionCell.cs new file mode 100644 index 000000000..4edfed9cb --- /dev/null +++ b/STROOP.Variables/VariablePanel/Cells/VariableSelectionCell.cs @@ -0,0 +1,52 @@ +namespace STROOP.Variables.VariablePanel.Cells +{ + public abstract class VariableSelectionCell + : VariableCell + where TBaseWrapper : VariableCell + where TUiContext : IUiContext + { + public bool DisplaySingleOption = false; + + public List<(string name, Func func)> options = new List<(string, Func)>(); + + protected readonly TBaseWrapper baseWrapper; + protected bool isSingleOption => DisplaySingleOption && options.Count == 1; + + (string name, Func getter) selectedOption; + + public VariableSelectionCell(IVariable var, VariableCellControl cellControl) : base(var, cellControl) + { + var interfaceType = view.GetType().GetInterfaces().First(x => x.Name == $"{nameof(IVariable)}`1"); + baseWrapper = (TBaseWrapper) + typeof(TBaseWrapper) + .GetConstructor(new Type[] { interfaceType, typeof(VariableCellControl<>).MakeGenericType(typeof(TUiContext)) }) + .Invoke(new object[] { view, cellControl }); + view.ValueSet += () => selectedOption = (null, null); + } + + public override string GetClass() => $"Selection for {baseWrapper.GetClass()}"; + + public override void UpdateControls() => baseWrapper.UpdateControls(); + + protected void SetOption((string name, Func func) option) + { + view.setter(option.func()); + selectedOption = option; + } + + public void SelectOption(int index) => SetOption(options[index]); + + public void UpdateOption(int index) + { + if (selectedOption.Equals(options[index])) + { + view.setter(selectedOption.getter()); + selectedOption = options[index]; + } + } + + public override string DisplayValue(TBackingValue value) => baseWrapper.DisplayValue(value); + + public override bool TryParseValue(string value, out TBackingValue result) => baseWrapper.TryParseValue(value, out result); + } +} diff --git a/STROOP.Variables/VariablePanel/IVariablePanel.cs b/STROOP.Variables/VariablePanel/IVariablePanel.cs new file mode 100644 index 000000000..0bcdd0fe4 --- /dev/null +++ b/STROOP.Variables/VariablePanel/IVariablePanel.cs @@ -0,0 +1,29 @@ +namespace STROOP.Variables.VariablePanel; + +public interface IVariablePanel + where TUiContext : IUiContext +{ + bool IsSelected { get; } + void RemoveVariables(IEnumerable> variableCell); + IEnumerable> AddVariables(IEnumerable> vars); +} + +public static class IVariablePanelExtensions +{ + public static IEnumerable> AddVariables( + this IVariablePanel @this, + IEnumerable<(string name, IVariable variable)> vars + ) + where TUiContext : IUiContext + => @this.AddVariables(vars.Select( + var => new VariableCellControl(@this, var.variable) { VarName = var.name }.varCell + )); + + public static IVariableCellUi AddVariable(this IVariablePanel @this, (string name, IVariable variable) var) + where TUiContext : IUiContext + => @this.AddVariables([ var ]).First(); + + public static void RemoveVariable(this IVariablePanel @this, IVariableCellUi variableCell) + where TUiContext : IUiContext + => @this.RemoveVariables([ variableCell ]); +} diff --git a/STROOP.Variables/VariablePanel/VariableCell.cs b/STROOP.Variables/VariablePanel/VariableCell.cs new file mode 100644 index 000000000..138c1e1c8 --- /dev/null +++ b/STROOP.Variables/VariablePanel/VariableCell.cs @@ -0,0 +1,194 @@ +using STROOP.Variables.Formatting; +using STROOP.Variables.Utilities; + +namespace STROOP.Variables.VariablePanel +{ + public interface IUiContext + { + IValueEditBox CreateValueBox(string lastValue); + } + + public interface IValueEditBox + { + Action Accept { get; set; } + Action Cancel { get; set; } + void Dispose(); + } + + public interface IVariableCellUi + : IVariableCell + where TUiContext : IUiContext + { + public delegate void CustomDraw(TUiContext context); + + public CustomDraw CustomDrawOperation { get; } + + VariableCellControl control { get; } + + void SingleClick(TUiContext uiContext); + void DoubleClick(TUiContext uiContext); + } + + public interface IVariableCell + { + void Update(); + string GetValueText(); + string GetClass(); + bool TrySetValue(string value); + DescribedMemoryState memory { get ; } + List GetVarInfo(); + } + + public interface IVariableCellData + : IVariableCell + { + TValue[] GetValues(); + } + + public abstract class VariableCell(IVariable view, VariableCellControl cellControl) + : IVariableCell, IVariableCellData, IVariableCellUi + where TUiContext : IUiContext + { + protected static Func, object, bool> CreateBoolWithDefault( + Action setValue, + Func getDefault + ) where TWrapper : VariableCell => + (ctrl, obj) => + { + if (ctrl.varCellInternal is TWrapper num) + if (obj is bool b) + setValue(num, b); + else if (obj == null) + setValue(num, getDefault(num)); + else + return false; + else + return false; + return true; + }; + + protected static Func, bool> WrapperProperty(Func func) + where TWrapper : VariableCell => + (ctrl) => + { + if (ctrl.varCellInternal is TWrapper wrapper) + return func(wrapper); + return false; + }; + + + protected readonly IVariable view = view; + + protected Action editValueHandler; + protected IValueEditBox TextEditBox; + protected TBackingValue lastValue { get; private set; } + protected CombinedValuesMeaning lastValueMeaning { get; private set; } + + public VariableCellControl control => cellControl; + public DescribedMemoryState memory => (view as IMemoryVariable)?.describedMemoryState; + public virtual IVariableCellUi.CustomDraw CustomDrawOperation => null; + + + private bool hasNextValue = false; + private TBackingValue _nextValue; + + protected TBackingValue nextValue + { + get => _nextValue; + set + { + hasNextValue = true; + _nextValue = value; + } + } + + public abstract string GetClass(); + public virtual void SingleClick(TUiContext uiContext) { } + public virtual void DoubleClick(TUiContext uiContext) => Edit(uiContext); + + protected void OnValueSet() => view.ValueSet?.Invoke(); + + public TBackingValue[] GetValues() => view.getter().ToArray(); + + public void Update() + { + (lastValueMeaning, lastValue) = this.CombineValues(); + if (hasNextValue) + { + if (view.setter(nextValue).Aggregate(true, (a, b) => a && b)) + OnValueSet(); + hasNextValue = false; + } + + UpdateControls(); + control.Update(); + } + + public virtual void UpdateControls() { } + + public virtual void Edit(TUiContext uiContext) + { + if (editValueHandler != null) + editValueHandler(); + else + { + TextEditBox = uiContext.CreateValueBox(DisplayValue(lastValue)); + TextEditBox.Accept += text => + { + if (TryParseValue(text, out var nextValue)) + this.nextValue = nextValue; + TextEditBox.Dispose(); + }; + TextEditBox.Cancel += TextEditBox.Dispose; + } + } + + public string GetValueText() + { + var combinedValues = this.CombineValues(); + switch (combinedValues.meaning) + { + case CombinedValuesMeaning.NoValue: + return "(none)"; + case CombinedValuesMeaning.SameValue: + return DisplayValue(combinedValues.value); + case CombinedValuesMeaning.MultipleValues: + return "(multiple values)"; + default: + return ""; + } + } + + public bool TrySetValue(string value) + { + var success = TryParseValue(value, out var result); + if (success) + { + view.setter(result); + OnValueSet(); + } + + return success; + } + + public abstract bool TryParseValue(string value, out TBackingValue result); + + public abstract string DisplayValue(TBackingValue value); + + public List GetVarInfo() + { + var memoryDescriptor = (view as IMemoryVariable)?.memoryDescriptor; + return + [ + control.VarName, + GetClass(), + memoryDescriptor?.GetTypeDescription() ?? "special", + memoryDescriptor?.GetBaseTypeOffsetDescription(), + memoryDescriptor?.GetBaseAddressListString(), + memoryDescriptor?.GetProcessAddressListString(), + memoryDescriptor?.GetRamAddressListString(true), + memoryDescriptor?.GetProcessAddressListString(), + ]; + } + } +} diff --git a/STROOP/Controls/VariablePanel/WatchVariableControl.cs b/STROOP.Variables/VariablePanel/VariableCellControl.cs similarity index 57% rename from STROOP/Controls/VariablePanel/WatchVariableControl.cs rename to STROOP.Variables/VariablePanel/VariableCellControl.cs index 4b1708f75..8385ca360 100644 --- a/STROOP/Controls/VariablePanel/WatchVariableControl.cs +++ b/STROOP.Variables/VariablePanel/VariableCellControl.cs @@ -1,22 +1,21 @@ -using System; -using System.Collections.Generic; +using STROOP.Variables.Utilities; using System.Drawing; -using System.Linq; -using System.Windows.Forms; using System.Xml.Linq; -using STROOP.Core.Variables; -using STROOP.Structs; -using STROOP.Utilities; -namespace STROOP.Controls.VariablePanel +namespace STROOP.Variables.VariablePanel { - public partial class WatchVariableControl + public partial class VariableCellControl + where TUiContext : IUiContext { - public delegate int SortVariables(WatchVariableControl a, WatchVariableControl b); + public delegate int SortVariables(IVariableCellUi a, IVariableCellUi b); public static SortVariables SortNone = (a, b) => 0; - public static SortVariables SortByPriority = (a, b) => a.view.DislpayPriority.CompareTo(a.view.DislpayPriority); - public static SortVariables SortByName = (a, b) => a.VarName.CompareTo(b.VarName); + + public static SortVariables SortByPriority = (a, b) => + int.Parse(a.control.view.GetValueByKey(CommonVariableProperties.displayPriority) ?? "0") + .CompareTo(int.Parse(b.control.view.GetValueByKey(CommonVariableProperties.displayPriority) ?? "0")); + + public static SortVariables SortByName = (a, b) => a.control.VarName.CompareTo(b.control.VarName); public static readonly Color DEFAULT_COLOR = SystemColors.Control; public static readonly Color FAILURE_COLOR = Color.Red; @@ -26,15 +25,16 @@ public partial class WatchVariableControl public static readonly Color SELECTED_COLOR = Color.FromArgb(51, 153, 255); private static readonly int FLASH_DURATION_MS = 1000; - public readonly NamedVariableCollection.IView view; - public readonly WatchVariableWrapper WatchVarWrapper; + internal readonly IVariable view; public readonly List GroupList; - // Parent control - public readonly WatchVariablePanel containingPanel; + public readonly IVariablePanel containingPanel; + + internal readonly IVariableCell varCellInternal; + public IVariableCellUi varCell => (IVariableCellUi)varCellInternal; - private readonly Color _initialBaseColor; + public readonly Color _initialBaseColor; private Color _baseColor; public Color BaseColor @@ -70,16 +70,15 @@ public bool IsSelected set { _isSelected = value; } } - public WatchVariableControl(WatchVariablePanel panel, NamedVariableCollection.IView view) + public VariableCellControl(IVariablePanel panel, IVariable view) { this.view = view; this.containingPanel = panel; - view.OnDelete += () => containingPanel.RemoveVariable(this); + view.OnDelete += RemoveFromPanel; // Initialize main fields - VarName = view.Name; - GroupList = WatchVariableUtilities.ParseVariableGroupList(view.GetValueByKey("groupList") ?? "Custom"); + GroupList = VariableUtilities.ParseVariableGroupList(view.GetValueByKey("groupList") ?? "Custom"); RenameMode = false; IsSelected = false; @@ -98,57 +97,20 @@ public WatchVariableControl(WatchVariablePanel panel, NamedVariableCollection.IV _isFlashing = false; _flashStartTime = DateTime.Now; - if (!WatchVariableUtilities.TryCreateWrapper(view, this, out WatchVarWrapper)) + if (!VariableCellFactory.TryCreateWrapper(view, this, out varCellInternal)) BaseColor = Color.DarkRed; - AddSetting(DefaultSettings.BackgroundColorSetting); - AddSetting(DefaultSettings.HighlightColorSetting); - AddSetting(DefaultSettings.HighlightSetting); + AddSetting(DefaultSettings.BackgroundColorCellSetting); + AddSetting(DefaultSettings.HighlightColorCellSetting); + AddSetting(DefaultSettings.HighlightCellSetting); - if (view is NamedVariableCollection.IMemoryDescriptorView) + if (view is IMemoryVariable) { - AddSetting(DefaultSettings.FixAddressSetting); - // TODO: work out locking setting - //AddSetting(DefaultSettings.LockSetting); + AddSetting(DefaultSettings.FixAddressCellSetting); } } - void ShowMainContextMenu(object sender, MouseEventArgs e) - { - if (e.Button == MouseButtons.Right) - ShowContextMenu(); - } - - public void ShowContextMenu() - { - ContextMenuStrip ctx = new ContextMenuStrip(); - if (containingPanel != null) - { - var uniqueSettings = new HashSet(); - foreach (var selectedVar in containingPanel.GetSelectedVars()) - foreach (var setting in selectedVar.availableSettings) - uniqueSettings.Add(setting.Value); - - var sortedOptions = uniqueSettings.ToList(); - sortedOptions.Sort((a, b) => string.Compare(a.Name, b.Name)); - foreach (var setting in sortedOptions) - setting.CreateContextMenuEntry(ctx.Items, containingPanel.GetSelectedVars); - - ctx.Items.Add(new ToolStripSeparator()); - foreach (var item in WatchVariableSelectionUtilities.CreateSelectionToolStripItems(containingPanel.GetSelectedVars(), containingPanel)) - ctx.Items.Add(item); - } - - ctx.Show(System.Windows.Forms.Cursor.Position); - } - - public void UpdateControl() - { - WatchVarWrapper.Update(); - UpdateColor(); - } - - private void UpdateColor() + internal void Update() { Color selectedOrBaseColor = IsSelected ? SELECTED_COLOR : _baseColor; if (_isFlashing) @@ -191,11 +153,14 @@ public bool BelongsToAnyGroupOrHasNoGroup(List variableGroups) return GroupList.Count == 0 || BelongsToAnyGroup(variableGroups); } - Dictionary availableSettings = new Dictionary(); + Dictionary> availableSettings = new Dictionary>(); + + public IEnumerable> AvailableSettings() + => availableSettings.Values; - public void AddSetting(WatchVariableSetting setting) + public void AddSetting(VariableCellSetting cellSetting) { - availableSettings[setting.Name] = setting; + availableSettings[cellSetting.Name] = cellSetting; } public bool ApplySettings(string settingName, object settingValue) @@ -206,20 +171,11 @@ public bool ApplySettings(string settingName, object settingValue) } public void RemoveFromPanel() - { - if (containingPanel == null) return; - containingPanel.RemoveVariable(this); - } - - public void OpenPanelOptions(Point point) - { - if (containingPanel == null) return; - containingPanel.ContextMenuStrip.Show(point); - } + => containingPanel?.RemoveVariable(varCell); - public WatchVariableControl CreateCopy(WatchVariablePanel panel) + public VariableCellControl CreateCopy(IVariablePanel panel) { - var copy = new WatchVariableControl(panel, view); + var copy = new VariableCellControl(panel, view); copy.BaseColor = _baseColor; copy.VarName = VarName; copy.GroupList.Clear(); @@ -228,7 +184,7 @@ public WatchVariableControl CreateCopy(WatchVariablePanel panel) } public void ToggleFixedAddress(bool? fix) - => (view as NamedVariableCollection.IMemoryDescriptorView)?.describedMemoryState.ToggleFixedAddress(fix); + => (view as IMemoryVariable)?.describedMemoryState.ToggleFixedAddress(fix); public void ToggleHighlighted(Color? color = null) { @@ -244,8 +200,8 @@ public Type GetMemoryType() { if (viewType.IsGenericType) { - if (viewType.GetGenericTypeDefinition() == typeof(NamedVariableCollection.MemoryDescriptorView<>) - || viewType.GetGenericTypeDefinition() == typeof(NamedVariableCollection.XmlMemoryView<>)) + if (viewType.GetGenericTypeDefinition() == typeof(MemoryVariable<>) + || viewType.GetGenericTypeDefinition() == typeof(XmlMemoryVariable<>)) return viewType.GetGenericArguments()[0]; } @@ -257,8 +213,8 @@ public Type GetMemoryType() public bool SetValue(T value) { - if (view is NamedVariableCollection.IView compatibleView - && compatibleView._setterFunction(value).Aggregate(true, (a, b) => a && b)) + if (view is IVariable compatibleView + && compatibleView.setter(value).Aggregate(true, (a, b) => a && b)) return true; else if (value is IConvertible convertibleValue && view.TrySetValue(convertibleValue).Aggregate(true, (a, b) => a && b)) return true; @@ -269,13 +225,13 @@ public bool SetValue(T value) public XElement ToXml(bool useCurrentState = true) { Color? color = _baseColor == DEFAULT_COLOR ? (Color?)null : _baseColor; - if (view is NamedVariableCollection.XmlMemoryView xmlView) + if (view is IXmlMemoryVariable xmlView) return xmlView.GetXml(); return null; } - public List GetVarInfo() => WatchVarWrapper.GetVarInfo(); + public List GetVarInfo() => varCellInternal.GetVarInfo(); - public override string ToString() => WatchVarWrapper.ToString(); + public override string ToString() => varCellInternal.ToString(); } } diff --git a/STROOP.Variables/VariablePanel/VariableCellFactory.cs b/STROOP.Variables/VariablePanel/VariableCellFactory.cs new file mode 100644 index 000000000..faefffc53 --- /dev/null +++ b/STROOP.Variables/VariablePanel/VariableCellFactory.cs @@ -0,0 +1,160 @@ +using STROOP.Core.Utilities; +using STROOP.Variables.Utilities; +using STROOP.Variables.VariablePanel.Cells; +using System.Globalization; +using System.Text.RegularExpressions; +using System.Xml.Linq; + +namespace STROOP.Variables.VariablePanel +{ + public static class VariableCellFactory where TUiContext : IUiContext + { + private class VariableCellFallback(IVariable view, VariableCellControl cellControl) + : IVariableCell + , IVariableCellUi + { + public VariableCellControl control { get; } = cellControl; + public DescribedMemoryState memory => null; + public IVariableCellUi.CustomDraw CustomDrawOperation => null; + + List IVariableCell.GetVarInfo() => []; + + public string GetClass() => "INVALID VARIABLE"; + + public string GetValueText() => "INVALID VARIABLE"; + + public bool TrySetValue(string value) => false; + + public void SingleClick(TUiContext uiContext) { } + public void DoubleClick(TUiContext uiContext) { } + public void Update() { } + } + + static readonly Dictionary wrapperTypes = new Dictionary(); + + static readonly Regex VariableTypeNameRegex = new Regex("(?<=(^Variable))[a-zA-Z0-9]+(?=(Cell))", RegexOptions.Compiled); + + static VariableCellFactory() + { + GeneralUtilities.ExecuteInitializers(); + foreach (var t in GeneralUtilities.GetStroopTypes()) + { + var match = VariableTypeNameRegex.Match(t.Name); + if (match.Success) + if (!t.IsAbstract && t.IsPublic && TypeUtilities.MatchesGenericType(typeof(VariableCell<,>), t)) + wrapperTypes[match.Value] = t; + } + } + + internal static bool TryCreateWrapper( + IVariable view, + VariableCellControl cellControl, + out IVariableCell result, + Type wrapperType = null) + { + result = null; + var interfaceType = view.GetType().GetInterfaces().FirstOrDefault(x => x.Name == $"{nameof(IVariable)}`1"); + if (interfaceType == null) + { + result = new VariableCellFallback(view, cellControl); + return false; + } + + bool isNullable = view.ClrType.IsGenericType && view.ClrType.GetGenericTypeDefinition() == typeof(Nullable<>); + var genericArgument = isNullable ? view.ClrType.GetGenericArguments()[0] : view.ClrType; + if (wrapperType == null) + { + wrapperType = wrapperTypes[view.Subclass]; + if (wrapperType.IsGenericTypeDefinition) + wrapperType = wrapperType.MakeGenericType(genericArgument); + if (isNullable) + wrapperType = typeof(VariableNullableCell<,,>).MakeGenericType( + typeof(TUiContext), + wrapperType, + interfaceType.GenericTypeArguments[0].GenericTypeArguments[0] + ); + } + + // Try to create as a root cell + var constructor = wrapperType.GetConstructor([ interfaceType, typeof(VariableCellControl) ]); + if (constructor != null) + { + result = (IVariableCell)constructor.Invoke([ view, cellControl ]); + return true; + } + + // Try to create as a decorator cell + var decoratorCtor = wrapperType + .GetConstructors() + .Select(x => new { Parameters = x.GetParameters(), Ctor = x, }) + .SingleOrDefault(x => + x.Parameters.Length == 1 + && x.Parameters[0].ParameterType.GetInterfaces().Any(IsMatchingBaseCellType) + ); + if (decoratorCtor != null + && TryCreateWrapper(view, cellControl, out var baseWrapper, decoratorCtor.Parameters[0].ParameterType)) + { + result = (IVariableCell)decoratorCtor.Ctor.Invoke([ baseWrapper ]); + return true; + } + + // Could not construct a matching cell, yield a fallback + result = new VariableCellFallback(view, cellControl); + return false; + + bool IsMatchingBaseCellType(Type t) + => t.IsGenericType + && t.GetGenericTypeDefinition() == typeof(IVariableCellData<>) + && t.GetGenericArguments()[0] == interfaceType.GetGenericArguments()[0]; + } + + public static (string name, IVariable var) ParseXml(XElement element, VariableSpecialDictionary sepcialVariables) + { + switch (element.Name.LocalName) + { + case "Data": + var specialType = element.Attribute(XName.Get("specialType"))?.Value; + return (element.Value, + specialType != null + ? sepcialVariables.TryGetValue(specialType, out var specialFactory) + ? specialFactory(element.Attribute(XName.Get("groupList"))?.Value ?? "Special") + : null + : FromXml(element).view); + } + + return (null, null); + } + + public static (MemoryDescriptor descriptor, IMemoryVariable view) FromXml(XElement element) + { + string typeName = (element.Attribute(XName.Get("type"))?.Value); + string baseAddressType = element.Attribute(XName.Get("base")).Value; + uint? offsetUS = TryParseHex("offsetUS"); + uint? offsetJP = TryParseHex("offsetJP"); + uint? offsetSH = TryParseHex("offsetSH"); + uint? offsetEU = TryParseHex("offsetEU"); + uint? offsetDefault = TryParseHex("offset"); + uint? mask = TryParseHex("mask"); + int? shift = (int?)TryParseHex("shift"); + bool handleMapping = element.Attribute(XName.Get("handleMapping")) != null + && (bool.TryParse(element.Attribute(XName.Get("handleMapping")).Value, out var v) ? v : false); + + var memoryDescriptor = new MemoryDescriptor(TypeUtilities.StringToType[typeName], baseAddressType, offsetUS, offsetJP, offsetSH, offsetEU, offsetDefault, mask, shift, handleMapping); + var view = (IMemoryVariable) + typeof(XmlMemoryVariable<>) + .MakeGenericType(TypeUtilities.StringToType[typeName]) + .GetConstructor(new Type[] { typeof(MemoryDescriptor), typeof(XElement) }) + .Invoke(new object[] { memoryDescriptor, element }); + return (memoryDescriptor, view); + + uint? TryParseHex(string elementName) + => uint.TryParse( + element.Attribute(XName.Get(elementName))?.Value.Substring(2) ?? "", + NumberStyles.HexNumber, + null, + out var result) + ? result + : null; + } + } +} diff --git a/STROOP/Controls/VariablePanel/Wrappers/WatchVariableSetting.cs b/STROOP.Variables/VariablePanel/VariableCellSetting.cs similarity index 51% rename from STROOP/Controls/VariablePanel/Wrappers/WatchVariableSetting.cs rename to STROOP.Variables/VariablePanel/VariableCellSetting.cs index ca5c69352..5013ab7ac 100644 --- a/STROOP/Controls/VariablePanel/Wrappers/WatchVariableSetting.cs +++ b/STROOP.Variables/VariablePanel/VariableCellSetting.cs @@ -1,86 +1,38 @@ -using System; -using System.Collections.Generic; +using STROOP.Variables.Utilities; using System.Drawing; -using System.Windows.Forms; -using STROOP.Core.Variables; -using STROOP.Utilities; -namespace STROOP.Controls.VariablePanel +namespace STROOP.Variables.VariablePanel { - public class WatchVariableSetting + public class VariableCellSetting + where TUiContext : IUiContext { public readonly string Name; - public readonly Func SetterFunction; - public readonly (string name, Func valueGetter, Func isSelected)[] DropDownValues; + public readonly Func, object, bool> SetterFunction; + public readonly (string name, Func valueGetter, Func, bool> isSelected)[] DropDownValues; - /// Constructs a new WatchVariableSetting + /// Constructs a new VariableSetting /// The name of the setting as displayed in the DropdownBox - /// The function that applies a selected value to a WatchVariableControl. If no are provided, this will be called with + /// The function that applies a selected value to a VariableControl. If no are provided, this will be called with /// /// A list of tuples representing selectable values, where 'name' is a readable representation of the selection, 'valueGetter' is a function returning the value associated with the setter, and 'isSelected' yields whether this option can be seen as selected /// - public WatchVariableSetting( + public VariableCellSetting( string name, - Func setterFunction, - params (string name, Func valueGetter, Func isSelected)[] dropDownValues + Func, object, bool> setterFunction, + params (string name, Func valueGetter, Func, bool> isSelected)[] dropDownValues ) { this.Name = name; this.SetterFunction = setterFunction; this.DropDownValues = dropDownValues; } - - public void CreateContextMenuEntry(ToolStripItemCollection target, Func> getWatchVars) - { - string mainItemText = Name; - if (DropDownValues.Length > 0) - mainItemText += "..."; - - var optionsItem = new ToolStripMenuItem(mainItemText); - foreach (var option in DropDownValues) - { - var item = new ToolStripMenuItem(option.name); - var getter = option.valueGetter; - item.Click += (_, __) => - { - var value = getter(); - getWatchVars().ForEach(v => v.ApplySettings(Name, value)); - }; - - if (option.isSelected != null) - { - bool? firstValue = null; - CheckState state = CheckState.Unchecked; - foreach (var c in getWatchVars()) - { - bool selected = option.isSelected(c); - if (firstValue == null) - firstValue = selected; - else if (selected != firstValue) - state = CheckState.Indeterminate; - } - - if (state == CheckState.Indeterminate) - item.CheckState = CheckState.Indeterminate; - else - item.Checked = !firstValue.HasValue ? false : firstValue.Value; - } - - optionsItem.DropDownItems.Add(item); - } - - if (DropDownValues.Length == 0) - optionsItem.Click += (_, __) => getWatchVars().ForEach(v => v.ApplySettings(Name, null)); - - target.Add(optionsItem); - } } - partial class WatchVariableControl + partial class VariableCellControl { class DefaultSettings { - public static readonly WatchVariableSetting HighlightSetting = new WatchVariableSetting( + public static readonly VariableCellSetting HighlightCellSetting = new VariableCellSetting( "Highlight", (ctrl, obj) => { @@ -93,7 +45,7 @@ class DefaultSettings ("Don't Highlight", () => false, ctrl => !ctrl.Highlighted) ); - public static readonly WatchVariableSetting HighlightColorSetting = new WatchVariableSetting( + public static readonly VariableCellSetting HighlightColorCellSetting = new VariableCellSetting( "Highlight Color", (ctrl, obj) => { @@ -118,25 +70,11 @@ class DefaultSettings ("White", () => Color.White, ctrl => ctrl.HighlightColor == Color.White) ); - public static readonly WatchVariableSetting LockSetting = new WatchVariableSetting( - "Lock", - (ctrl, obj) => - { - if (obj is bool newLock && ctrl.view is NamedVariableCollection.IMemoryDescriptorView memoryDescriptorView) - return memoryDescriptorView.describedMemoryState.SetLocked(newLock, null); - else - return false; - }, - ("Lock", () => true, ctrl => (ctrl.view as NamedVariableCollection.IMemoryDescriptorView)?.describedMemoryState.locked ?? false), - ("Don't Lock", () => false, ctrl => !((ctrl.view as NamedVariableCollection.IMemoryDescriptorView)?.describedMemoryState.locked ?? true)) - ); - - - public static readonly WatchVariableSetting FixAddressSetting = new WatchVariableSetting( + public static readonly VariableCellSetting FixAddressCellSetting = new VariableCellSetting( "Fix Address", (ctrl, obj) => { - if (ctrl.view is NamedVariableCollection.IMemoryDescriptorView memoryDescriptorView) + if (ctrl.view is IMemoryVariable memoryDescriptorView) { if (obj is bool newFixAddress) memoryDescriptorView.describedMemoryState.ToggleFixedAddress(newFixAddress); @@ -147,14 +85,14 @@ class DefaultSettings return false; }, - ("Default", () => null, ctrl => !((ctrl.view as NamedVariableCollection.IMemoryDescriptorView)?.describedMemoryState.fixedAddresses ?? false)), - ("Fix Address", () => true, ctrl => (ctrl.view as NamedVariableCollection.IMemoryDescriptorView)?.describedMemoryState.fixedAddresses ?? false), - ("Don't Fix Address", () => false, ctrl => !((ctrl.view as NamedVariableCollection.IMemoryDescriptorView)?.describedMemoryState.fixedAddresses ?? true)) + ("Default", () => null, ctrl => !((ctrl.view as IMemoryVariable)?.describedMemoryState.fixedAddresses ?? false)), + ("Fix Address", () => true, ctrl => (ctrl.view as IMemoryVariable)?.describedMemoryState.fixedAddresses ?? false), + ("Don't Fix Address", () => false, ctrl => !((ctrl.view as IMemoryVariable)?.describedMemoryState.fixedAddresses ?? true)) ); private static readonly object RevertToDefaultColor = new object(); - public static readonly WatchVariableSetting BackgroundColorSetting = new WatchVariableSetting( + public static readonly VariableCellSetting BackgroundColorCellSetting = new VariableCellSetting( "Background Color", (ctrl, obj) => { @@ -165,9 +103,9 @@ class DefaultSettings else return false; return true; }, - ((Func<(string, Func, Func)[]>)(() => + ((Func<(string, Func, Func, bool>)[]>)(() => { - var lst = new List<(string, Func, Func)>(); + var lst = new List<(string, Func, Func, bool>)>(); lst.Add(("Default", () => RevertToDefaultColor, ctrl => ctrl.BaseColor == ctrl._initialBaseColor)); foreach (KeyValuePair pair in ColorUtilities.ColorToParamsDictionary) { @@ -178,7 +116,7 @@ class DefaultSettings } lst.Add(("Control (No Color)", () => SystemColors.Control, ctrl => ctrl.BaseColor == SystemColors.Control)); - lst.Add(("Custom Color", () => ColorUtilities.GetColorFromDialog(SystemColors.Control), null)); + // lst.Add(("Custom Color", () => ColorUtilities.GetColorFromDialog(SystemColors.Control), null)); return lst.ToArray(); }))() ); diff --git a/STROOP.Variables/VariableSpecialDictionary.cs b/STROOP.Variables/VariableSpecialDictionary.cs new file mode 100644 index 000000000..85ad56e3d --- /dev/null +++ b/STROOP.Variables/VariableSpecialDictionary.cs @@ -0,0 +1,43 @@ +using STROOP.Core.Utilities; +using STROOP.Variables.Utilities; + +namespace STROOP.Variables; + +public class VariableSpecialDictionary +{ + public static VariableSpecialDictionary Instance = new(); + + private readonly Dictionary> _dictionary; + + public VariableSpecialDictionary() => _dictionary = new Dictionary>(); + + public bool TryGetValue(string key, out Func variableFactory) + => _dictionary.TryGetValue(key, out variableFactory); + + public void Add(string key, IVariable.ValueGetter getter, IVariable.ValueSetter setter, string? subclass = null) + { + _dictionary[key] = groupList => + { + var result = new CustomVariable(subclass.DefaultIfNull()) + { + getter = getter, + setter = setter, + }; + result.SetValueByKey("groupList", groupList); + return result; + }; + } + + public void Add(string key, Func getter, Func setter, string? subclass = null) + => Add(key, () => getter().Yield(), value => setter(value).Yield(), subclass); + + public void Add(string key, string baseAddressType, Func getter, Func setter, string? subclass = null) + => Add(key, + () => VariableUtilities.GetBaseAddresses(baseAddressType).Select(x => getter(x)), + value => VariableUtilities.GetBaseAddresses(baseAddressType).Select(x => setter(value, x)), + subclass + ); + + public void Add(string key, Func getter, IVariable.ValueSetter setter, string? subclass = null) + => Add(key, () => getter().Yield(), setter, subclass); +} diff --git a/STROOP.Variables/VariableSubclass.cs b/STROOP.Variables/VariableSubclass.cs new file mode 100644 index 000000000..83889d208 --- /dev/null +++ b/STROOP.Variables/VariableSubclass.cs @@ -0,0 +1,33 @@ +using STROOP.Core.Utilities; + +namespace STROOP.Variables; + +public static class VariableSubclass +{ + static VariableSubclass() => StringSymbolAttribute.InitializeDeclaredStrings(typeof(VariableSubclass)); + + [StringSymbol] + public static string + Number, + String, + Angle, + Object, + Triangle, + Address, + Boolean; +} + +public static class VariableSubclassExtensions +{ + public static string DefaultIfNull(this string? subclass) + => subclass ?? typeof(T) switch + { + _ when typeof(T) == typeof(sbyte) || typeof(T) == typeof(short) || typeof(T) == typeof(int) || typeof(T) == typeof(long) => VariableSubclass.Number, + _ when typeof(T) == typeof(byte) || typeof(T) == typeof(ushort) || typeof(T) == typeof(uint) || typeof(T) == typeof(ulong) => VariableSubclass.Number, + _ when typeof(T) == typeof(float) || typeof(T) == typeof(double) => VariableSubclass.Number, + _ when typeof(T) == typeof(bool) => VariableSubclass.Boolean, + _ when typeof(T) == typeof(string) => VariableSubclass.String, + _ when typeof(T).IsGenericType && typeof(T).GetGenericTypeDefinition() == typeof(Nullable<>) => VariableSubclass.Number, + _ => throw new NotImplementedException("Figure out what to do with these types..."), + }; +} diff --git a/STROOP.Variables/XmlMemoryVariable.cs b/STROOP.Variables/XmlMemoryVariable.cs new file mode 100644 index 000000000..8470a4887 --- /dev/null +++ b/STROOP.Variables/XmlMemoryVariable.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Xml.Linq; + +namespace STROOP.Variables; + +public interface IXmlMemoryVariable +{ + XElement GetXml(); +} + +public class XmlMemoryVariable(MemoryDescriptor memoryDescriptor, XElement xElement) + : MemoryVariable(SubclassFromXml(xElement), memoryDescriptor) + , IXmlMemoryVariable + where T : struct, IConvertible +{ + static string SubclassFromXml(XElement xElement) + { + var subclassName = xElement.Attribute("subclass")?.Value; + return subclassName != null + ? (string?)typeof(VariableSubclass).GetFields( BindingFlags.Static | BindingFlags.Public) + .SingleOrDefault(x => x.Name == subclassName)?.GetValue(null) ?? VariableSubclass.Number + : VariableSubclass.Number; + } + + public override string GetValueByKey(string key) + => xElement.Attribute(key)?.Value; + + public override bool SetValueByKey(string key, string value) + { + xElement.SetAttributeValue(XName.Get(key), value); + return true; + } + + public XElement GetXml() => xElement; +} diff --git a/STROOP.Win32/NativeMethodWrappers.cs b/STROOP.Win32/NativeMethodWrappers.cs new file mode 100644 index 000000000..b0d480f16 --- /dev/null +++ b/STROOP.Win32/NativeMethodWrappers.cs @@ -0,0 +1,73 @@ +using System.Runtime.InteropServices; +using Windows.Win32; +using Windows.Win32.Foundation; +using Windows.Win32.System.Diagnostics.Debug; +using Windows.Win32.System.ProcessStatus; + +namespace STROOP.Win32; + +public static class NativeMethodWrappers +{ + public static unsafe bool ReadProcessMemory(IntPtr hProcess, UIntPtr lpBaseAddress, byte[] buffer) + { + var gcHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned); + UIntPtr lpNumberOfBytesRead; + try + { + return PInvoke.ReadProcessMemory( + (HANDLE)hProcess, + (void*)lpBaseAddress, + (void*)Marshal.UnsafeAddrOfPinnedArrayElement(buffer, 0), + (uint)buffer.Length, + &lpNumberOfBytesRead + ); + } + finally + { + gcHandle.Free(); + } + } + + public static unsafe bool WriteProcessMemory(IntPtr hProcess, UIntPtr lpBaseAddress, byte[] buffer) + { + UIntPtr numOfBytes = 0; + var gcHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned); + try + { + return PInvoke.WriteProcessMemory( + (HANDLE)hProcess, + (void*)lpBaseAddress, + (void*)Marshal.UnsafeAddrOfPinnedArrayElement(buffer, 0), + (UIntPtr)buffer.Length, + &numOfBytes); + } + finally + { + gcHandle.Free(); + } + } + + public static unsafe bool QueryWorkingSetEx(IntPtr hProcess, UIntPtr lpBaseAddress, out PSAPI_WORKING_SET_EX_INFORMATION wsInfo) + { + PSAPI_WORKING_SET_EX_INFORMATION tmp; + tmp.VirtualAddress = (HANDLE)lpBaseAddress; + uint setInfoSize = (uint)Marshal.SizeOf(typeof(PSAPI_WORKING_SET_EX_INFORMATION)); + var result = PInvoke.QueryWorkingSetEx((HANDLE)hProcess, &tmp, setInfoSize); + wsInfo = tmp; + return result; + } + + public static unsafe bool GetSymbolAddress(SafeHandle hProcess, string name, out ulong address) + { + const int MAX_NAME_LENGTH = 2000; + + // See https://learn.microsoft.com/en-us/windows/win32/debug/retrieving-symbol-information-by-name + var symbol = (SYMBOL_INFO*)Marshal.AllocHGlobal(Marshal.SizeOf() + MAX_NAME_LENGTH * sizeof(CHAR) + (sizeof(ulong) - 1) / sizeof(ulong)); + symbol->MaxNameLen = MAX_NAME_LENGTH; + symbol->SizeOfStruct = (uint)sizeof(SYMBOL_INFO); + var result = PInvoke.SymFromName(hProcess, name, symbol); + address = symbol->Address; + Marshal.FreeHGlobal((IntPtr)symbol); + return result; + } +} diff --git a/STROOP.Win32/NativeMethods.json b/STROOP.Win32/NativeMethods.json new file mode 100644 index 000000000..d1b171f72 --- /dev/null +++ b/STROOP.Win32/NativeMethods.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://aka.ms/CsWin32.schema.json", + "public": true +} diff --git a/STROOP.Win32/NativeMethods.txt b/STROOP.Win32/NativeMethods.txt new file mode 100644 index 000000000..7087d42e1 --- /dev/null +++ b/STROOP.Win32/NativeMethods.txt @@ -0,0 +1,26 @@ +OpenThread +SuspendThread +ResumeThread +CloseHandle +OpenProcess +ReadProcessMemory +WriteProcessMemory +QueryWorkingSetEx +SymInitialize +SymCleanup +SymFromName +IsWow64Process + +PSAPI_WORKING_SET_EX_INFORMATION +MEMORY_BASIC_INFORMATION + +CHARFORMAT2A +CFE_EFFECTS +CFM_MASK +SCF_* +EM_* +SendMessage + +GetAsyncKeyState +GetSystemMetrics +SYSTEM_METRICS_INDEX diff --git a/STROOP.Win32/STROOP.Win32.csproj b/STROOP.Win32/STROOP.Win32.csproj new file mode 100644 index 000000000..73254d5aa --- /dev/null +++ b/STROOP.Win32/STROOP.Win32.csproj @@ -0,0 +1,16 @@ + + + + net8.0 + enable + enable + STROOP.Win32 + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + diff --git a/STROOP.Win32/VirtualQueryEx.cs b/STROOP.Win32/VirtualQueryEx.cs new file mode 100644 index 000000000..82fb0eb7f --- /dev/null +++ b/STROOP.Win32/VirtualQueryEx.cs @@ -0,0 +1,34 @@ +using System.Runtime.InteropServices; + +namespace STROOP.Win32; + +/// +/// The VirtualQueryEx method cannot be generated via CsWin32 unless the C# project itself is compiled for a specific platform.
+/// Invoking it may thus cause a runtime exception on certain platforms, but as this is only used for the Dolphin IO, I'll accept this for now. +/// See https://github.com/microsoft/CsWin32/issues/722 for details. +///
+public static class VirtualQueryEx +{ + [Flags] + public enum MemoryType : uint + { + MEM_IMAGE = 0x1000000, + MEM_MAPPED = 0x40000, + MEM_PRIVATE = 0x20000, + } + + [StructLayout(LayoutKind.Sequential)] + public struct MemoryBasicInformation + { + public UIntPtr BaseAddress; + public IntPtr AllocationBase; + public uint AllocationProtect; + public IntPtr RegionSize; + public uint State; + public uint Protect; + public MemoryType Type; + } + + [DllImport("kernel32.dll", EntryPoint = "VirtualQueryEx")] + public static extern IntPtr Invoke(IntPtr hProcess, IntPtr lpAddress, out MemoryBasicInformation lpBuffer, IntPtr dwLength); +} diff --git a/STROOP.sln b/STROOP.sln index 2e86f4bae..aafba4587 100644 --- a/STROOP.sln +++ b/STROOP.sln @@ -5,11 +5,17 @@ VisualStudioVersion = 15.0.26228.9 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "STROOP", "STROOP\STROOP.csproj", "{D309A4ED-54AF-4BC7-83CA-BCD38543AEB3}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "STROOP.Core", "STROOP.Core\STROOP.Core.csproj", "{EF8C9D84-7DE6-421C-A3AD-688E9CD46125}" +EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{812871A5-4626-428A-B176-8BE13E3058FF}" ProjectSection(SolutionItems) = preProject .editorconfig = .editorconfig EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "STROOP.Variables", "STROOP.Variables\STROOP.Variables.csproj", "{D5CB8378-E26B-4808-839B-200083A13E3C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "STROOP.Win32", "STROOP.Win32\STROOP.Win32.csproj", "{590625A1-EC10-4656-8BD3-65BB7AAE004F}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -32,6 +38,42 @@ Global {D309A4ED-54AF-4BC7-83CA-BCD38543AEB3}.Release|x64.Build.0 = Release|x64 {D309A4ED-54AF-4BC7-83CA-BCD38543AEB3}.Release|x86.ActiveCfg = Release|x86 {D309A4ED-54AF-4BC7-83CA-BCD38543AEB3}.Release|x86.Build.0 = Release|x86 + {EF8C9D84-7DE6-421C-A3AD-688E9CD46125}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EF8C9D84-7DE6-421C-A3AD-688E9CD46125}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EF8C9D84-7DE6-421C-A3AD-688E9CD46125}.Debug|x64.ActiveCfg = Debug|Any CPU + {EF8C9D84-7DE6-421C-A3AD-688E9CD46125}.Debug|x64.Build.0 = Debug|Any CPU + {EF8C9D84-7DE6-421C-A3AD-688E9CD46125}.Debug|x86.ActiveCfg = Debug|Any CPU + {EF8C9D84-7DE6-421C-A3AD-688E9CD46125}.Debug|x86.Build.0 = Debug|Any CPU + {EF8C9D84-7DE6-421C-A3AD-688E9CD46125}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EF8C9D84-7DE6-421C-A3AD-688E9CD46125}.Release|Any CPU.Build.0 = Release|Any CPU + {EF8C9D84-7DE6-421C-A3AD-688E9CD46125}.Release|x64.ActiveCfg = Release|Any CPU + {EF8C9D84-7DE6-421C-A3AD-688E9CD46125}.Release|x64.Build.0 = Release|Any CPU + {EF8C9D84-7DE6-421C-A3AD-688E9CD46125}.Release|x86.ActiveCfg = Release|Any CPU + {EF8C9D84-7DE6-421C-A3AD-688E9CD46125}.Release|x86.Build.0 = Release|Any CPU + {D5CB8378-E26B-4808-839B-200083A13E3C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D5CB8378-E26B-4808-839B-200083A13E3C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D5CB8378-E26B-4808-839B-200083A13E3C}.Debug|x64.ActiveCfg = Debug|Any CPU + {D5CB8378-E26B-4808-839B-200083A13E3C}.Debug|x64.Build.0 = Debug|Any CPU + {D5CB8378-E26B-4808-839B-200083A13E3C}.Debug|x86.ActiveCfg = Debug|Any CPU + {D5CB8378-E26B-4808-839B-200083A13E3C}.Debug|x86.Build.0 = Debug|Any CPU + {D5CB8378-E26B-4808-839B-200083A13E3C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D5CB8378-E26B-4808-839B-200083A13E3C}.Release|Any CPU.Build.0 = Release|Any CPU + {D5CB8378-E26B-4808-839B-200083A13E3C}.Release|x64.ActiveCfg = Release|Any CPU + {D5CB8378-E26B-4808-839B-200083A13E3C}.Release|x64.Build.0 = Release|Any CPU + {D5CB8378-E26B-4808-839B-200083A13E3C}.Release|x86.ActiveCfg = Release|Any CPU + {D5CB8378-E26B-4808-839B-200083A13E3C}.Release|x86.Build.0 = Release|Any CPU + {590625A1-EC10-4656-8BD3-65BB7AAE004F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {590625A1-EC10-4656-8BD3-65BB7AAE004F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {590625A1-EC10-4656-8BD3-65BB7AAE004F}.Debug|x64.ActiveCfg = Debug|Any CPU + {590625A1-EC10-4656-8BD3-65BB7AAE004F}.Debug|x64.Build.0 = Debug|Any CPU + {590625A1-EC10-4656-8BD3-65BB7AAE004F}.Debug|x86.ActiveCfg = Debug|Any CPU + {590625A1-EC10-4656-8BD3-65BB7AAE004F}.Debug|x86.Build.0 = Debug|Any CPU + {590625A1-EC10-4656-8BD3-65BB7AAE004F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {590625A1-EC10-4656-8BD3-65BB7AAE004F}.Release|Any CPU.Build.0 = Release|Any CPU + {590625A1-EC10-4656-8BD3-65BB7AAE004F}.Release|x64.ActiveCfg = Release|Any CPU + {590625A1-EC10-4656-8BD3-65BB7AAE004F}.Release|x64.Build.0 = Release|Any CPU + {590625A1-EC10-4656-8BD3-65BB7AAE004F}.Release|x86.ActiveCfg = Release|Any CPU + {590625A1-EC10-4656-8BD3-65BB7AAE004F}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/STROOP/Calculators/AirMovementCalculator.cs b/STROOP/Calculators/AirMovementCalculator.cs index 3a89d2e47..98339266c 100644 --- a/STROOP/Calculators/AirMovementCalculator.cs +++ b/STROOP/Calculators/AirMovementCalculator.cs @@ -167,7 +167,7 @@ private static MarioState ComputeAirHSpeed(MarioState initialState, Input input) int maxSpeed = longJump ? 48 : 32; ushort marioAngle = initialState.MarioAngle; - ushort yawIntended = MoreMath.CalculateAngleFromInputs(input.X, input.Y, initialState.CameraAngle); + ushort yawIntended = STROOPMath.CalculateAngleFromInputs(input.X, input.Y, initialState.CameraAngle); int deltaAngleIntendedFacing = yawIntended - marioAngle; float inputScaledMagnitude = input.GetScaledMagnitude(); diff --git a/STROOP/Calculators/MarioState.cs b/STROOP/Calculators/MarioState.cs index 5ff281005..979f70954 100644 --- a/STROOP/Calculators/MarioState.cs +++ b/STROOP/Calculators/MarioState.cs @@ -1,4 +1,5 @@ using STROOP.Structs.Configurations; +using STROOP.Variables.SM64MemoryLayout; using System; using System.Collections.Generic; using System.Linq; diff --git a/STROOP/Calculators/MutableMarioState.cs b/STROOP/Calculators/MutableMarioState.cs index 454a97bbd..078b5ed5d 100644 --- a/STROOP/Calculators/MutableMarioState.cs +++ b/STROOP/Calculators/MutableMarioState.cs @@ -44,7 +44,7 @@ public MutableMarioState( SlidingSpeedZ = slidingSpeedZ; SlidingAngle = slidingAngle; MarioAngle = marioAngle; - IntendedAngle = MoreMath.CalculateAngleFromInputs(input.X, input.Y, cameraAngle); + IntendedAngle = STROOPMath.CalculateAngleFromInputs(input.X, input.Y, cameraAngle); IntendedMagnitude = input.GetScaledMagnitude(); } diff --git a/STROOP/Controls/CarretlessTextBox.cs b/STROOP/Controls/CarretlessTextBox.cs deleted file mode 100644 index 4b5c69fda..000000000 --- a/STROOP/Controls/CarretlessTextBox.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; -using System.Windows.Forms; -using System.Runtime.InteropServices; - -namespace STROOP -{ - public class CarretlessTextBox : TextBox - { - [DllImport("user32.dll")] - static extern bool HideCaret(IntPtr hWnd); - - [DllImport("user32.dll")] - static extern bool ShowCaret(IntPtr hWnd); - - public CarretlessTextBox() - { - } - - public void HideTheCaret() - { - HideCaret(Handle); - } - - public void ShowTheCaret() - { - ShowCaret(Handle); - } - } -} diff --git a/STROOP/Controls/ColorSelector.cs b/STROOP/Controls/ColorSelector.cs index 51f03d67f..7892336b0 100644 --- a/STROOP/Controls/ColorSelector.cs +++ b/STROOP/Controls/ColorSelector.cs @@ -3,6 +3,7 @@ using System.Drawing; using System.Windows.Forms; using STROOP.Utilities; +using STROOP.Variables.Utilities; namespace STROOP.Controls { @@ -34,7 +35,7 @@ public ColorSelector() panelColorSelector.Click += (sender, e) => { - Color? newColor = ColorUtilities.GetColorFromDialog(SelectedColor); + Color? newColor = ColorDialogUtilities.GetColorFromDialog(SelectedColor); if (newColor.HasValue) SelectedColor = newColor.Value; }; } @@ -46,7 +47,7 @@ public void AddColorChangeAction(Action action) private void SubmitColorText() { - Color? newColor = ColorUtilities.ConvertDecimalToColor(textBoxColorSelector.Text); + Color? newColor = ColorUtilities.ConvertDecimalToColor(ParsingUtilities.ParseIntList(textBoxColorSelector.Text)); if (newColor.HasValue) { SelectedColor = newColor.Value; diff --git a/STROOP/Controls/FileCoinScoreTextbox.cs b/STROOP/Controls/FileCoinScoreTextbox.cs index 99839339c..f142c19e6 100644 --- a/STROOP/Controls/FileCoinScoreTextbox.cs +++ b/STROOP/Controls/FileCoinScoreTextbox.cs @@ -1,4 +1,5 @@ using STROOP.Structs.Configurations; +using STROOP.Tabs; namespace STROOP { @@ -18,7 +19,7 @@ public override void Initialize(uint addressOffset) private byte GetCoinScoreFromMemory() { - return Config.Stream.GetByte(FileConfig.CurrentFileAddress + _addressOffset); + return Config.Stream.GetByte(FileTab.CurrentFileAddress + _addressOffset); } protected override void SubmitValue() @@ -30,7 +31,7 @@ protected override void SubmitValue() return; } - Config.Stream.SetValue(value, FileConfig.CurrentFileAddress + _addressOffset); + Config.Stream.SetValue(value, FileTab.CurrentFileAddress + _addressOffset); } protected override void ResetValue() diff --git a/STROOP/Controls/FileCourseLabel.cs b/STROOP/Controls/FileCourseLabel.cs index 8340793e3..8df79eebd 100644 --- a/STROOP/Controls/FileCourseLabel.cs +++ b/STROOP/Controls/FileCourseLabel.cs @@ -2,6 +2,7 @@ using System.Windows.Forms; using STROOP.Structs; using STROOP.Structs.Configurations; +using STROOP.Tabs; namespace STROOP { @@ -48,15 +49,15 @@ public void Initialize(uint addressOffset, byte mask, int courseIndex) private void SetValue(byte value) { byte maskedValue = (byte)(value & _mask); - byte oldByte = Config.Stream.GetByte(FileConfig.CurrentFileAddress + _addressOffset); + byte oldByte = Config.Stream.GetByte(FileTab.CurrentFileAddress + _addressOffset); byte unmaskedOldByte = (byte)(oldByte & ~_mask); byte newByte = (byte)(unmaskedOldByte | maskedValue); - Config.Stream.SetValue(newByte, FileConfig.CurrentFileAddress + _addressOffset); + Config.Stream.SetValue(newByte, FileTab.CurrentFileAddress + _addressOffset); } private byte GetValue() { - byte currentByte = Config.Stream.GetByte(FileConfig.CurrentFileAddress + _addressOffset); + byte currentByte = Config.Stream.GetByte(FileTab.CurrentFileAddress + _addressOffset); byte maskedCurrentByte = (byte)(currentByte & _mask); return maskedCurrentByte; } diff --git a/STROOP/Controls/FileHatLocationPictureBox.cs b/STROOP/Controls/FileHatLocationPictureBox.cs index 61ee07718..122a91301 100644 --- a/STROOP/Controls/FileHatLocationPictureBox.cs +++ b/STROOP/Controls/FileHatLocationPictureBox.cs @@ -3,6 +3,7 @@ using STROOP.Utilities; using STROOP.Structs; using STROOP.Structs.Configurations; +using STROOP.Tabs; namespace STROOP { @@ -27,8 +28,8 @@ public void Initialize(HatLocation definingHatLocation, Image onImage, Image off private HatLocation? GetCurrentHatLocation() { - byte hatLocationLevel = Config.Stream.GetByte(FileConfig.CurrentFileAddress + FileConfig.HatLocationLevelOffset); - byte hatLocationMode = (byte)(Config.Stream.GetByte(FileConfig.CurrentFileAddress + FileConfig.HatLocationModeOffset) & FileConfig.HatLocationModeMask); + byte hatLocationLevel = Config.Stream.GetByte(FileTab.CurrentFileAddress + FileConfig.HatLocationLevelOffset); + byte hatLocationMode = (byte)(Config.Stream.GetByte(FileTab.CurrentFileAddress + FileConfig.HatLocationModeOffset) & FileConfig.HatLocationModeMask); return hatLocationMode == FileConfig.HatLocationMarioMask ? HatLocation.Mario : hatLocationMode == FileConfig.HatLocationKleptoMask ? HatLocation.SSLKlepto : @@ -64,8 +65,8 @@ protected override void ClickAction(object sender, EventArgs e) case HatLocation.SSLGround: SetHatMode(FileConfig.HatLocationGroundMask); - Config.Stream.SetValue(FileConfig.HatLocationLevelSSLValue, FileConfig.CurrentFileAddress + FileConfig.HatLocationLevelOffset); - Config.Stream.SetValue(FileConfig.HatLocationAreaSSLValue, FileConfig.CurrentFileAddress + FileConfig.HatLocationAreaOffset); + Config.Stream.SetValue(FileConfig.HatLocationLevelSSLValue, FileTab.CurrentFileAddress + FileConfig.HatLocationLevelOffset); + Config.Stream.SetValue(FileConfig.HatLocationAreaSSLValue, FileTab.CurrentFileAddress + FileConfig.HatLocationAreaOffset); break; case HatLocation.SLSnowman: @@ -74,8 +75,8 @@ protected override void ClickAction(object sender, EventArgs e) case HatLocation.SLGround: SetHatMode(FileConfig.HatLocationGroundMask); - Config.Stream.SetValue(FileConfig.HatLocationLevelSLValue, FileConfig.CurrentFileAddress + FileConfig.HatLocationLevelOffset); - Config.Stream.SetValue(FileConfig.HatLocationAreaSLValue, FileConfig.CurrentFileAddress + FileConfig.HatLocationAreaOffset); + Config.Stream.SetValue(FileConfig.HatLocationLevelSLValue, FileTab.CurrentFileAddress + FileConfig.HatLocationLevelOffset); + Config.Stream.SetValue(FileConfig.HatLocationAreaSLValue, FileTab.CurrentFileAddress + FileConfig.HatLocationAreaOffset); break; case HatLocation.TTMUkiki: @@ -84,17 +85,17 @@ protected override void ClickAction(object sender, EventArgs e) case HatLocation.TTMGround: SetHatMode(FileConfig.HatLocationGroundMask); - Config.Stream.SetValue(FileConfig.HatLocationLevelTTMValue, FileConfig.CurrentFileAddress + FileConfig.HatLocationLevelOffset); - Config.Stream.SetValue(FileConfig.HatLocationAreaTTMValue, FileConfig.CurrentFileAddress + FileConfig.HatLocationAreaOffset); + Config.Stream.SetValue(FileConfig.HatLocationLevelTTMValue, FileTab.CurrentFileAddress + FileConfig.HatLocationLevelOffset); + Config.Stream.SetValue(FileConfig.HatLocationAreaTTMValue, FileTab.CurrentFileAddress + FileConfig.HatLocationAreaOffset); break; } } private void SetHatMode(byte hatModeByte) { - byte oldByte = Config.Stream.GetByte(FileConfig.CurrentFileAddress + FileConfig.HatLocationModeOffset); + byte oldByte = Config.Stream.GetByte(FileTab.CurrentFileAddress + FileConfig.HatLocationModeOffset); byte newByte = MoreMath.ApplyValueToMaskedByte(oldByte, FileConfig.HatLocationModeMask, hatModeByte); - Config.Stream.SetValue(newByte, FileConfig.CurrentFileAddress + FileConfig.HatLocationModeOffset); + Config.Stream.SetValue(newByte, FileTab.CurrentFileAddress + FileConfig.HatLocationModeOffset); } public override void UpdateImage() diff --git a/STROOP/Controls/FileHatPositionTextbox.cs b/STROOP/Controls/FileHatPositionTextbox.cs index eaf573a2f..5013e0c83 100644 --- a/STROOP/Controls/FileHatPositionTextbox.cs +++ b/STROOP/Controls/FileHatPositionTextbox.cs @@ -1,4 +1,5 @@ using STROOP.Structs.Configurations; +using STROOP.Tabs; namespace STROOP { @@ -18,7 +19,7 @@ public override void Initialize(uint addressOffset) private short GetHatLocationValueFromMemory() { - return Config.Stream.GetInt16(FileConfig.CurrentFileAddress + _addressOffset); + return Config.Stream.GetInt16(FileTab.CurrentFileAddress + _addressOffset); } protected override void SubmitValue() @@ -30,7 +31,7 @@ protected override void SubmitValue() return; } - Config.Stream.SetValue(value, FileConfig.CurrentFileAddress + _addressOffset); + Config.Stream.SetValue(value, FileTab.CurrentFileAddress + _addressOffset); } protected override void ResetValue() diff --git a/STROOP/Controls/FilePictureBox.cs b/STROOP/Controls/FilePictureBox.cs index bb9ddc5de..a3f7daf01 100644 --- a/STROOP/Controls/FilePictureBox.cs +++ b/STROOP/Controls/FilePictureBox.cs @@ -3,6 +3,7 @@ using System.Drawing; using STROOP.Utilities; using STROOP.Structs.Configurations; +using STROOP.Tabs; namespace STROOP { @@ -38,14 +39,14 @@ private void SetValue(bool boolValue) private void SetValue(byte value) { - byte oldByte = Config.Stream.GetByte(FileConfig.CurrentFileAddress + _addressOffset); + byte oldByte = Config.Stream.GetByte(FileTab.CurrentFileAddress + _addressOffset); byte newByte = MoreMath.ApplyValueToMaskedByte(oldByte, _mask, value); - Config.Stream.SetValue(newByte, FileConfig.CurrentFileAddress + _addressOffset); + Config.Stream.SetValue(newByte, FileTab.CurrentFileAddress + _addressOffset); } private byte GetValue() { - byte currentByte = Config.Stream.GetByte(FileConfig.CurrentFileAddress + _addressOffset); + byte currentByte = Config.Stream.GetByte(FileTab.CurrentFileAddress + _addressOffset); byte maskedCurrentByte = (byte)(currentByte & _mask); return maskedCurrentByte; } diff --git a/STROOP/Controls/InputDisplayPanel.cs b/STROOP/Controls/InputDisplayPanel.cs index 8a4f193bc..0dd228926 100644 --- a/STROOP/Controls/InputDisplayPanel.cs +++ b/STROOP/Controls/InputDisplayPanel.cs @@ -16,8 +16,6 @@ public class InputDisplayPanel : Panel InputDisplayTypeEnum _inputDisplayType; InputFrame _currentInputs = null; - object _gfxLock = new object(); - public InputDisplayPanel() { this.DoubleBuffered = true; diff --git a/STROOP/Controls/MainSaveTextbox.cs b/STROOP/Controls/MainSaveTextbox.cs index ac175f6d8..c40619864 100644 --- a/STROOP/Controls/MainSaveTextbox.cs +++ b/STROOP/Controls/MainSaveTextbox.cs @@ -1,5 +1,6 @@ using System.Windows.Forms; using STROOP.Structs.Configurations; +using STROOP.Tabs; namespace STROOP { @@ -41,12 +42,12 @@ public void Initialize(int level, int file) private uint GetValueFromMemory() { - return Config.Stream.GetUInt32(MainSaveConfig.CurrentMainSaveAddress + _offset, false, _mask, _shift); + return Config.Stream.GetUInt32(MainSaveTab.CurrentMainSaveAddress + _offset, false, _mask, _shift); } private void SetValueInMemory(uint value) { - Config.Stream.SetValue(value, MainSaveConfig.CurrentMainSaveAddress + _offset, false, _mask, _shift); + Config.Stream.SetValue(value, MainSaveTab.CurrentMainSaveAddress + _offset, false, _mask, _shift); } private void SubmitValue() diff --git a/STROOP/Controls/ObjectSlot.cs b/STROOP/Controls/ObjectSlot.cs index 0ebe84f03..ef6459ad4 100644 --- a/STROOP/Controls/ObjectSlot.cs +++ b/STROOP/Controls/ObjectSlot.cs @@ -1,4 +1,6 @@ -using System; +using STROOP.Core; +using STROOP.Core.Utilities; +using System; using System.Collections.Generic; using System.Windows.Forms; using System.Drawing; @@ -9,6 +11,8 @@ using System.Drawing.Drawing2D; using STROOP.Structs.Configurations; using STROOP.Models; +using STROOP.Variables.SM64MemoryLayout; +using STROOP.Variables.Utilities; using static STROOP.Managers.ObjectSlotsManager; using System.Windows.Input; using System.Xml.Linq; @@ -112,13 +116,6 @@ OverlayExpression GetHoveredExpression(Func - !LockConfig.LockingDisabled && WatchVariableLockManager.ContainsAnyLocksForObject(address)))); - - lst.Add(new Overlay("LockDisabled", GetAddressExpression((obj, address) => - LockConfig.LockingDisabled && WatchVariableLockManager.ContainsAnyLocksForObject(address)))); - - //TODO: Figure out what "LockReadOnly" is supposed to be Func shownOnMap = (obj, address) => AccessScope.content.GetTab().TracksObject(address); @@ -509,7 +506,7 @@ private void OnDrag(object sender, System.Windows.Forms.MouseEventArgs e) protected override void OnPaint(PaintEventArgs e) { - e.Graphics.InterpolationMode = InterpolationMode.NearestNeighbor; + e.Graphics.InterpolationMode = InterpolationMode.High; e.Graphics.CompositingQuality = CompositingQuality.HighSpeed; lock (_gfxLock) { diff --git a/STROOP/Controls/ObjectSlotFlowLayoutPanel.cs b/STROOP/Controls/ObjectSlotFlowLayoutPanel.cs index 27038c445..44ef00f69 100644 --- a/STROOP/Controls/ObjectSlotFlowLayoutPanel.cs +++ b/STROOP/Controls/ObjectSlotFlowLayoutPanel.cs @@ -1,6 +1,7 @@ using STROOP.Models; using STROOP.Structs.Configurations; using STROOP.Utilities; +using STROOP.Variables.Utilities; using System.Collections.Generic; using System.Linq; using System.Windows.Forms; diff --git a/STROOP/Controls/RichTextBoxEx.cs b/STROOP/Controls/RichTextBoxEx.cs index c2bbac1aa..2d371c1fd 100644 --- a/STROOP/Controls/RichTextBoxEx.cs +++ b/STROOP/Controls/RichTextBoxEx.cs @@ -3,115 +3,14 @@ using System.Drawing; using System.Windows.Forms; using System.Runtime.InteropServices; +using Windows.Win32; +using Windows.Win32.Foundation; +using Windows.Win32.UI.Controls.RichEdit; namespace STROOP.Controls { public class RichTextBoxEx : RichTextBox { - #region Interop-Defines - - [StructLayout(LayoutKind.Sequential)] - private struct CHARFORMAT2_STRUCT - { - public UInt32 cbSize; - public UInt32 dwMask; - public UInt32 dwEffects; - public Int32 yHeight; - public Int32 yOffset; - public Int32 crTextColor; - public byte bCharSet; - public byte bPitchAndFamily; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] - public char[] szFaceName; - - public UInt16 wWeight; - public UInt16 sSpacing; - public int crBackColor; // Color.ToArgb() -> int - public int lcid; - public int dwReserved; - public Int16 sStyle; - public Int16 wKerning; - public byte bUnderlineType; - public byte bAnimation; - public byte bRevAuthor; - public byte bReserved1; - } - - [DllImport("user32.dll", CharSet = CharSet.Auto)] - private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam); - - private const int WM_USER = 0x0400; - private const int EM_GETCHARFORMAT = WM_USER + 58; - private const int EM_SETCHARFORMAT = WM_USER + 68; - - private const int SCF_SELECTION = 0x0001; - private const int SCF_WORD = 0x0002; - private const int SCF_ALL = 0x0004; - - #region CHARFORMAT2 Flags - - private const UInt32 CFE_BOLD = 0x0001; - private const UInt32 CFE_ITALIC = 0x0002; - private const UInt32 CFE_UNDERLINE = 0x0004; - private const UInt32 CFE_STRIKEOUT = 0x0008; - private const UInt32 CFE_PROTECTED = 0x0010; - private const UInt32 CFE_LINK = 0x0020; - private const UInt32 CFE_AUTOCOLOR = 0x40000000; - private const UInt32 CFE_SUBSCRIPT = 0x00010000; /* Superscript and subscript are */ - private const UInt32 CFE_SUPERSCRIPT = 0x00020000; /* mutually exclusive */ - - private const int CFM_SMALLCAPS = 0x0040; /* (*) */ - private const int CFM_ALLCAPS = 0x0080; /* Displayed by 3.0 */ - private const int CFM_HIDDEN = 0x0100; /* Hidden by 3.0 */ - private const int CFM_OUTLINE = 0x0200; /* (*) */ - private const int CFM_SHADOW = 0x0400; /* (*) */ - private const int CFM_EMBOSS = 0x0800; /* (*) */ - private const int CFM_IMPRINT = 0x1000; /* (*) */ - private const int CFM_DISABLED = 0x2000; - private const int CFM_REVISED = 0x4000; - - private const int CFM_BACKCOLOR = 0x04000000; - private const int CFM_LCID = 0x02000000; - private const int CFM_UNDERLINETYPE = 0x00800000; /* Many displayed by 3.0 */ - private const int CFM_WEIGHT = 0x00400000; - private const int CFM_SPACING = 0x00200000; /* Displayed by 3.0 */ - private const int CFM_KERNING = 0x00100000; /* (*) */ - private const int CFM_STYLE = 0x00080000; /* (*) */ - private const int CFM_ANIMATION = 0x00040000; /* (*) */ - private const int CFM_REVAUTHOR = 0x00008000; - - - private const UInt32 CFM_BOLD = 0x00000001; - private const UInt32 CFM_ITALIC = 0x00000002; - private const UInt32 CFM_UNDERLINE = 0x00000004; - private const UInt32 CFM_STRIKEOUT = 0x00000008; - private const UInt32 CFM_PROTECTED = 0x00000010; - private const UInt32 CFM_LINK = 0x00000020; - private const UInt32 CFM_SIZE = 0x80000000; - private const UInt32 CFM_COLOR = 0x40000000; - private const UInt32 CFM_FACE = 0x20000000; - private const UInt32 CFM_OFFSET = 0x10000000; - private const UInt32 CFM_CHARSET = 0x08000000; - private const UInt32 CFM_SUBSCRIPT = CFE_SUBSCRIPT | CFE_SUPERSCRIPT; - private const UInt32 CFM_SUPERSCRIPT = CFM_SUBSCRIPT; - - private const byte CFU_UNDERLINENONE = 0x00000000; - private const byte CFU_UNDERLINE = 0x00000001; - private const byte CFU_UNDERLINEWORD = 0x00000002; /* (*) displayed as ordinary underline */ - private const byte CFU_UNDERLINEDOUBLE = 0x00000003; /* (*) displayed as ordinary underline */ - private const byte CFU_UNDERLINEDOTTED = 0x00000004; - private const byte CFU_UNDERLINEDASH = 0x00000005; - private const byte CFU_UNDERLINEDASHDOT = 0x00000006; - private const byte CFU_UNDERLINEDASHDOTDOT = 0x00000007; - private const byte CFU_UNDERLINEWAVE = 0x00000008; - private const byte CFU_UNDERLINETHICK = 0x00000009; - private const byte CFU_UNDERLINEHAIRLINE = 0x0000000A; /* (*) displayed as ordinary underline */ - - #endregion - - #endregion - public RichTextBoxEx() { // Otherwise, non-standard links get lost when user starts typing @@ -193,7 +92,7 @@ public void InsertLink(string text, string hyperlink, int position) /// true: set link style, false: clear link style public void SetSelectionLink(bool link) { - SetSelectionStyle(CFM_LINK, link ? CFE_LINK : 0); + SetSelectionStyle(CFM_MASK.CFM_LINK, link ? CFE_EFFECTS.CFE_LINK : 0); } /// @@ -202,39 +101,39 @@ public void SetSelectionLink(bool link) /// 0: link style not set, 1: link style set, -1: mixed public int GetSelectionLink() { - return GetSelectionStyle(CFM_LINK, CFE_LINK); + return GetSelectionStyle(CFM_MASK.CFM_LINK, CFE_EFFECTS.CFE_LINK); } - private void SetSelectionStyle(UInt32 mask, UInt32 effect) + private void SetSelectionStyle(CFM_MASK mask, CFE_EFFECTS effect) { - CHARFORMAT2_STRUCT cf = new CHARFORMAT2_STRUCT(); + CHARFORMATA cf = new CHARFORMATA(); cf.cbSize = (UInt32)Marshal.SizeOf(cf); cf.dwMask = mask; cf.dwEffects = effect; - IntPtr wpar = new IntPtr(SCF_SELECTION); - IntPtr lpar = Marshal.AllocCoTaskMem(Marshal.SizeOf(cf)); + WPARAM wpar = new WPARAM(PInvoke.SCF_SELECTION); + LPARAM lpar = Marshal.AllocCoTaskMem(Marshal.SizeOf(cf)); Marshal.StructureToPtr(cf, lpar, false); - IntPtr res = SendMessage(Handle, EM_SETCHARFORMAT, wpar, lpar); + IntPtr res = PInvoke.SendMessage((HWND)Handle, PInvoke.EM_SETCHARFORMAT, wpar, lpar); Marshal.FreeCoTaskMem(lpar); } - private int GetSelectionStyle(UInt32 mask, UInt32 effect) + private int GetSelectionStyle(CFM_MASK mask, CFE_EFFECTS effect) { - CHARFORMAT2_STRUCT cf = new CHARFORMAT2_STRUCT(); + CHARFORMATA cf = new CHARFORMATA(); cf.cbSize = (UInt32)Marshal.SizeOf(cf); - cf.szFaceName = new char[32]; + cf.szFaceName = new __CHAR_32(); - IntPtr wpar = new IntPtr(SCF_SELECTION); - IntPtr lpar = Marshal.AllocCoTaskMem(Marshal.SizeOf(cf)); + WPARAM wpar = new WPARAM(PInvoke.SCF_SELECTION); + LPARAM lpar = Marshal.AllocCoTaskMem(Marshal.SizeOf(cf)); Marshal.StructureToPtr(cf, lpar, false); - IntPtr res = SendMessage(Handle, EM_GETCHARFORMAT, wpar, lpar); + IntPtr res = PInvoke.SendMessage((HWND)Handle, PInvoke.EM_GETCHARFORMAT, wpar, lpar); - cf = (CHARFORMAT2_STRUCT)Marshal.PtrToStructure(lpar, typeof(CHARFORMAT2_STRUCT)); + cf = (CHARFORMATA)Marshal.PtrToStructure(lpar, typeof(CHARFORMATA)); int state; // dwMask holds the information which properties are consistent throughout the selection: diff --git a/STROOP/Controls/VarHackContainer.cs b/STROOP/Controls/VarHackContainer.cs index 9f1551e82..739f4c854 100644 --- a/STROOP/Controls/VarHackContainer.cs +++ b/STROOP/Controls/VarHackContainer.cs @@ -5,6 +5,7 @@ using STROOP.Utilities; using System.Xml.Linq; using STROOP.Structs.Configurations; +using STROOP.Variables.Utilities; namespace STROOP.Controls { diff --git a/STROOP/Controls/VarHackContainerDefaults.cs b/STROOP/Controls/VarHackContainerDefaults.cs index ea984eba8..b105006f3 100644 --- a/STROOP/Controls/VarHackContainerDefaults.cs +++ b/STROOP/Controls/VarHackContainerDefaults.cs @@ -1,4 +1,5 @@ using STROOP.Structs.Configurations; +using STROOP.Variables.SM64MemoryLayout; using System; namespace STROOP.Structs diff --git a/STROOP/Controls/VarHackFlowLayoutPanel.cs b/STROOP/Controls/VarHackFlowLayoutPanel.cs index 5f8b74126..b036514ef 100644 --- a/STROOP/Controls/VarHackFlowLayoutPanel.cs +++ b/STROOP/Controls/VarHackFlowLayoutPanel.cs @@ -1,4 +1,5 @@ -using STROOP.Forms; +using STROOP.Core; +using STROOP.Forms; using STROOP.Structs; using STROOP.Structs.Configurations; using System; diff --git a/STROOP/Controls/VariablePanel/Cells/VariableAddressCell.cs b/STROOP/Controls/VariablePanel/Cells/VariableAddressCell.cs new file mode 100644 index 000000000..c34b994c0 --- /dev/null +++ b/STROOP/Controls/VariablePanel/Cells/VariableAddressCell.cs @@ -0,0 +1,22 @@ +using STROOP.Core; +using STROOP.Structs.Configurations; +using STROOP.Utilities; +using STROOP.Variables.VariablePanel.Cells; + +namespace STROOP.Controls.VariablePanel.Cells; + +public class VariableAddressCell(VariableNumberCell baseCell) + : VariableAddressCell(baseCell) +{ + protected override void ShowMemory(uint address) + { + if (address == 0) + return; + + if (ObjectUtilities.IsObjectAddress(address)) + AccessScope.content.GetTab().SetObjectAddress(address); + else + AccessScope.content.GetTab().SetCustomAddress(address); + Config.TabControlMain.SelectedTab = Config.TabControlMain.TabPages["tabPageMemory"]; + } +} diff --git a/STROOP/Controls/VariablePanel/Cells/VariableAngleCell.cs b/STROOP/Controls/VariablePanel/Cells/VariableAngleCell.cs new file mode 100644 index 000000000..7ed6ef8ab --- /dev/null +++ b/STROOP/Controls/VariablePanel/Cells/VariableAngleCell.cs @@ -0,0 +1,12 @@ +using STROOP.Structs.Configurations; +using STROOP.Variables.VariablePanel.Cells; +using System; + +namespace STROOP.Controls.VariablePanel.Cells; + +public class VariableAngleCell(VariableNumberCell baseCell) + : VariableAngleCell(baseCell) + where TNumber : struct, IConvertible +{ + protected override bool DisplayAsUnsigned() => SavedSettingsConfig.DisplayYawAnglesAsUnsigned; +} diff --git a/STROOP/Controls/VariablePanel/Cells/VariableBooleanCell.cs b/STROOP/Controls/VariablePanel/Cells/VariableBooleanCell.cs new file mode 100644 index 000000000..2b7e03669 --- /dev/null +++ b/STROOP/Controls/VariablePanel/Cells/VariableBooleanCell.cs @@ -0,0 +1,42 @@ +using STROOP.Variables; +using STROOP.Variables.Utilities; +using STROOP.Variables.VariablePanel.Cells; +using System; +using System.Drawing; +using System.Windows.Forms; + +namespace STROOP.Controls.VariablePanel.Cells; + +public class VariableBooleanCell(IVariable watchVar, WinFormsVariableControl watchVarControl) + : VariableBooleanCell(watchVar, watchVarControl) + where TNumber : struct, IConvertible +{ + protected override void DrawCheckbox(WinFormsVariablePanelUiContext uiContext) + { + var combinedValues = this.CombineValues(); + CheckState state; + if (combinedValues.meaning != CombinedValuesMeaning.SameValue) + state = CheckState.Indeterminate; + else + state = (Convert.ToDecimal(combinedValues.value) != 0 ^ _displayAsInverted) ? CheckState.Checked : CheckState.Unchecked; + + Image checkboxImage; + switch (state) + { + case CheckState.Checked: + checkboxImage = Properties.Resources.checkbox_checked; + break; + case CheckState.Unchecked: + checkboxImage = Properties.Resources.checkbox_unchecked; + break; + default: + checkboxImage = Properties.Resources.checkbox_indeterminate; + break; + } + + var margin = 2; + var imgHeight = uiContext.drawRegion.Height - margin * 2; + uiContext.graphics.DrawImage(checkboxImage, uiContext.drawRegion.Right - imgHeight - margin * 2, uiContext.drawRegion.Top + margin, imgHeight, imgHeight); + + } +} diff --git a/STROOP/Controls/VariablePanel/Cells/VariableNumberCell.cs b/STROOP/Controls/VariablePanel/Cells/VariableNumberCell.cs new file mode 100644 index 000000000..cf703fc7d --- /dev/null +++ b/STROOP/Controls/VariablePanel/Cells/VariableNumberCell.cs @@ -0,0 +1,22 @@ +using STROOP.Structs.Configurations; +using STROOP.Utilities; +using STROOP.Variables; +using STROOP.Variables.Utilities; +using STROOP.Variables.VariablePanel; +using STROOP.Variables.VariablePanel.Cells; +using System; + +namespace STROOP.Controls.VariablePanel.Cells; + +public interface INumberVariableCell : IVariableCellData, IVariableCellUi; + +public class VariableNumberCell(IVariable view, WinFormsVariableControl control) + : VariableNumberCell(view, control) + , INumberVariableCell + where TNumber : struct, IConvertible +{ + protected sealed override bool RoundToZero() => !SavedSettingsConfig.DontRoundValuesToZero; + + public override bool TryParseValue(string value, out TNumber result) + => ParsingUtilities.TryParseNumber(value, out result); +} diff --git a/STROOP/Controls/VariablePanel/Cells/VariableObjectCell.cs b/STROOP/Controls/VariablePanel/Cells/VariableObjectCell.cs new file mode 100644 index 000000000..1af19c709 --- /dev/null +++ b/STROOP/Controls/VariablePanel/Cells/VariableObjectCell.cs @@ -0,0 +1,37 @@ +using STROOP.Core; +using STROOP.Structs; +using STROOP.Structs.Configurations; +using STROOP.Utilities; +using STROOP.Variables; +using STROOP.Variables.VariablePanel.Cells; + +namespace STROOP.Controls.VariablePanel.Cells; + +// TODO: refactor this such that it takes a NumberWrapper as a base wrapper, similar to selection wrappers, +// in order to avoid code duplication with RoundToZero +public class VariableObjectCell(VariableAddressCell baseCell) + : VariableObjectCell(baseCell) +{ + protected override uint GetUnusedSlotAddress() + => ObjectSlotsConfig.UnusedSlotAddress; + + protected override void SelectObject(uint address) + => Config.ObjectSlotsManager.SelectSlotByAddress(address); + + protected override string GetDescriptiveSlotLabelFromAddress(uint address) + => Config.ObjectSlotsManager.GetDescriptiveSlotLabelFromAddress(address, false); + + protected override uint? GetObjectAddressFromLabel(string label) => Config.ObjectSlotsManager.GetObjectFromLabel(label)?.Address; + + protected override void ShowMemory(uint address) + { + if (address == 0) + return; + + if (ObjectUtilities.IsObjectAddress(address)) + AccessScope.content.GetTab().SetObjectAddress(address); + else + AccessScope.content.GetTab().SetCustomAddress(address); + Config.TabControlMain.SelectedTab = Config.TabControlMain.TabPages["tabPageMemory"]; + } +} diff --git a/STROOP/Controls/VariablePanel/Cells/VariableSelectionCell.cs b/STROOP/Controls/VariablePanel/Cells/VariableSelectionCell.cs new file mode 100644 index 000000000..7eb1c1d3e --- /dev/null +++ b/STROOP/Controls/VariablePanel/Cells/VariableSelectionCell.cs @@ -0,0 +1,82 @@ +using STROOP.Structs.Configurations; +using STROOP.Utilities; +using STROOP.Variables; +using STROOP.Variables.VariablePanel; +using STROOP.Variables.VariablePanel.Cells; +using System.Drawing; +using System.Windows.Forms; + +namespace STROOP.Controls.VariablePanel.Cells; + +public class VariableSelectionCell(IVariable var, WinFormsVariableControl control) + : VariableSelectionCell(var, control) + where TBaseWrapper : VariableCell +{ + static StringFormat rightAlignFormat = new StringFormat() { Alignment = StringAlignment.Far }; + bool IsCursorHovering(WinFormsVariablePanelUiContext uiContext, out Rectangle drawRectangle) + { + int marginX = (int)SavedSettingsConfig.WatchVarPanelHorizontalMargin.value; + int marginY = (int)SavedSettingsConfig.WatchVarPanelVerticalMargin.value; + + Rectangle screenRect; + if (isSingleOption) + { + screenRect = uiContext.parent.RectangleToScreen(uiContext.drawRegion); + drawRectangle = uiContext.drawRegion; + } + else + { + var sideLength = uiContext.drawRegion.Height - marginY * 2; + drawRectangle = new Rectangle(uiContext.drawRegion.Left + marginX, uiContext.drawRegion.Top + marginY, sideLength, sideLength); + screenRect = uiContext.parent.RectangleToScreen(drawRectangle); + } + + return Cursor.Position.IsInsideRect(screenRect); + } + + public override void SingleClick(WinFormsVariablePanelUiContext uiContext) + { + base.SingleClick(uiContext); + if (IsCursorHovering(uiContext, out _)) + { + if (isSingleOption) + view.setter(options[0].func()); + else if (options.Count > 0) + { + var ctx = new ContextMenuStrip(); + foreach (var option_it in options) + { + var option_cap = option_it; + ctx.Items.AddHandlerToItem(option_cap.name, () => SetOption(option_cap)); + } + + ctx.Show(Cursor.Position); + } + } + else + baseWrapper.SingleClick(uiContext); + } + + public override IVariableCellUi.CustomDraw CustomDrawOperation => uiContext => + { + var g = uiContext.graphics; + baseWrapper.CustomDrawOperation?.Invoke(uiContext); + + int marginX = (int)SavedSettingsConfig.WatchVarPanelHorizontalMargin.value; + int marginY = (int)SavedSettingsConfig.WatchVarPanelVerticalMargin.value; + + if (isSingleOption) + g.FillRectangle(IsCursorHovering(uiContext, out var drawRect) ? Brushes.LightSlateGray : Brushes.Gray, drawRect); + + var txtPoint = new Point(uiContext.drawRegion.Right - marginX, uiContext.drawRegion.Top + marginY); + g.DrawString(isSingleOption ? options[0].name : GetValueText(), + uiContext.parent.Font, + control.IsSelected ? Brushes.White : Brushes.Black, + txtPoint, + rightAlignFormat); + + if (!isSingleOption) + g.DrawImage(IsCursorHovering(uiContext, out var drawRect) ? Properties.Resources.dropdown_box_hover : Properties.Resources.dropdown_box, drawRect); + }; + +} diff --git a/STROOP/Controls/VariablePanel/Wrappers/WatchVariableStringWrapper.cs b/STROOP/Controls/VariablePanel/Cells/VariableStringCell.cs similarity index 56% rename from STROOP/Controls/VariablePanel/Wrappers/WatchVariableStringWrapper.cs rename to STROOP/Controls/VariablePanel/Cells/VariableStringCell.cs index 061c44811..0ec23c779 100644 --- a/STROOP/Controls/VariablePanel/Wrappers/WatchVariableStringWrapper.cs +++ b/STROOP/Controls/VariablePanel/Cells/VariableStringCell.cs @@ -1,11 +1,12 @@ -using System; +using STROOP.Forms; +using STROOP.Variables; +using STROOP.Variables.VariablePanel; +using System; using System.Collections.Generic; -using STROOP.Core.Variables; -using STROOP.Forms; -namespace STROOP.Controls.VariablePanel +namespace STROOP.Controls.VariablePanel.Cells { - public class WatchVariableStringWrapper : WatchVariableWrapper + public class VariableStringCell : VariableCell { public static Dictionary specialTypeContextMenuHandlers = new Dictionary() { @@ -18,47 +19,30 @@ public class WatchVariableStringWrapper : WatchVariableWrapper ["AreaTerrainDescription"] = () => SelectionForm.ShowAreaTerrainDescriptionSelectionForm(), }; - static Dictionary settingsForSpecials = new Dictionary(); + static Dictionary settingsForSpecials = new Dictionary(); - public WatchVariableStringWrapper(NamedVariableCollection.IView watchVar, WatchVariableControl watchVarControl) + public VariableStringCell(IVariable watchVar, WinFormsVariableControl watchVarControl) : base(watchVar, watchVarControl) { - AddStringContextMenuStripItems(watchVarControl.view.GetValueByKey(NamedVariableCollection.ViewProperties.specialType)); + AddStringContextMenuStripItems(view.GetValueByKey(CommonVariableProperties.specialType)); } private void AddStringContextMenuStripItems(string specialType) { if (specialType != null && specialTypeContextMenuHandlers.TryGetValue(specialType, out editValueHandler)) { - WatchVariableSetting applicableSetting; + WinFormsVariableSetting applicableSetting; if (!settingsForSpecials.TryGetValue(specialType, out applicableSetting)) - settingsForSpecials[specialType] = applicableSetting = new WatchVariableSetting($"Select {specialType}...", + settingsForSpecials[specialType] = applicableSetting = new WinFormsVariableSetting($"Select {specialType}...", (ctrl, obj) => { editValueHandler(); return false; }); - _watchVarControl.AddSetting(applicableSetting); + control.AddSetting(applicableSetting); } } - public void AddContextMenuHandler(string name, Action handler, params string[] options) - { - var opts = new (string, Func, Func)[options.Length]; - for (int i = 0; i < options.Length; i++) - { - var optionName = options[i]; - opts[i] = (optionName, () => optionName, ctrl => false); - } - - WatchVariableSetting setting = new WatchVariableSetting(name, (ctrl, obj) => - { - handler((string)obj); - return false; - }, opts); - _watchVarControl.AddSetting(setting); - } - public override string GetClass() => "String"; public override string DisplayValue(string value) => value; diff --git a/STROOP/Controls/VariablePanel/Cells/VariableTriangleCell.cs b/STROOP/Controls/VariablePanel/Cells/VariableTriangleCell.cs new file mode 100644 index 000000000..ef41972ad --- /dev/null +++ b/STROOP/Controls/VariablePanel/Cells/VariableTriangleCell.cs @@ -0,0 +1,29 @@ +using STROOP.Core; +using STROOP.Variables; +using STROOP.Variables.Utilities; + +namespace STROOP.Controls.VariablePanel.Cells +{ + public class VariableTriangleCell : VariableAddressCell + { + static WinFormsVariableSetting SelectTriangleSetting = new WinFormsVariableSetting("Select Triangle", (ctrl, _) => + { + if (ctrl.varCell is VariableTriangleCell triangleWrapper) + { + var value = triangleWrapper.CombineValues(); + if (value.meaning == CombinedValuesMeaning.SameValue) + AccessScope.content.GetTab().SetCustomTriangleAddresses(value.value); + } + + return false; + }); + + public VariableTriangleCell(VariableNumberCell baseCell) + : base(baseCell) + { + control.AddSetting(SelectTriangleSetting); + } + + public override string GetClass() => "Triangle"; + } +} diff --git a/STROOP/Controls/VariablePanel/GlobalUsings.cs b/STROOP/Controls/VariablePanel/GlobalUsings.cs new file mode 100644 index 000000000..3972ca53e --- /dev/null +++ b/STROOP/Controls/VariablePanel/GlobalUsings.cs @@ -0,0 +1,4 @@ +global using WinFormsVariableControl = STROOP.Variables.VariablePanel.VariableCellControl; +global using WinFormsVariableSetting = STROOP.Variables.VariablePanel.VariableCellSetting; +global using IWinFormsVariableCell = STROOP.Variables.VariablePanel.IVariableCellUi; +global using VariablePrecursor = (string name, STROOP.Variables.IVariable var); diff --git a/STROOP/Controls/VariablePanel/VariableExtensions.cs b/STROOP/Controls/VariablePanel/VariableExtensions.cs new file mode 100644 index 000000000..3a1c3ca98 --- /dev/null +++ b/STROOP/Controls/VariablePanel/VariableExtensions.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.Windows.Forms; + +namespace STROOP.Controls.VariablePanel; + +public static class VariableExtensions +{ + public static void CreateContextMenuEntry(this WinFormsVariableSetting setting, ToolStripItemCollection target, Func> getWatchVars) + { + string mainItemText = setting.Name; + if (setting.DropDownValues.Length > 0) + mainItemText += "..."; + + var optionsItem = new ToolStripMenuItem(mainItemText); + foreach (var option in setting.DropDownValues) + { + var item = new ToolStripMenuItem(option.name); + var getter = option.valueGetter; + item.Click += (_, __) => + { + var value = getter(); + getWatchVars().ForEach(v => v.control.ApplySettings(setting.Name, value)); + }; + + if (option.isSelected != null) + { + bool? firstValue = null; + CheckState state = CheckState.Unchecked; + foreach (var c in getWatchVars()) + { + bool selected = option.isSelected(c.control); + if (firstValue == null) + firstValue = selected; + else if (selected != firstValue) + state = CheckState.Indeterminate; + } + + if (state == CheckState.Indeterminate) + item.CheckState = CheckState.Indeterminate; + else + item.Checked = !firstValue.HasValue ? false : firstValue.Value; + } + + optionsItem.DropDownItems.Add(item); + } + + if (setting.DropDownValues.Length == 0) + optionsItem.Click += (_, __) => getWatchVars().ForEach(v => v.control.ApplySettings(setting.Name, null)); + + target.Add(optionsItem); + } +} diff --git a/STROOP/Controls/VariablePanel/VariablePanel.IVariablePanelImplementation.cs b/STROOP/Controls/VariablePanel/VariablePanel.IVariablePanelImplementation.cs new file mode 100644 index 000000000..b602c0cad --- /dev/null +++ b/STROOP/Controls/VariablePanel/VariablePanel.IVariablePanelImplementation.cs @@ -0,0 +1,36 @@ +using STROOP.Variables.VariablePanel; +using System.Collections.Generic; + +namespace STROOP.Controls.VariablePanel; + +public partial class VariablePanel : IVariablePanel +{ + bool IVariablePanel.IsSelected => Focused; + + public IEnumerable AddVariables(IEnumerable cells) + { + if (!initialized) + DeferredInitialize(); + + var lst = new List(); + foreach (var cell in cells) + { + lst.Add(cell); + _allWatchVarControls.Add(cell); + if (ShouldShow(cell)) + _shownWatchVarControls.Add(cell); + } + + return lst; + } + + public void RemoveVariables(IEnumerable watchVarControls) + { + foreach (IWinFormsVariableCell watchVarControl in watchVarControls) + { + _reorderingWatchVarControls.Remove(watchVarControl); + _allWatchVarControls.Remove(watchVarControl); + _shownWatchVarControls.Remove(watchVarControl); + } + } +} diff --git a/STROOP/Controls/VariablePanel/VariablePanel.Renderer.cs b/STROOP/Controls/VariablePanel/VariablePanel.Renderer.cs new file mode 100644 index 000000000..3c317dafa --- /dev/null +++ b/STROOP/Controls/VariablePanel/VariablePanel.Renderer.cs @@ -0,0 +1,534 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Windows.Forms; +using OpenTK.Mathematics; +using STROOP.Controls.VariablePanel.Cells; +using STROOP.Core.Utilities; +using STROOP.Structs.Configurations; +using STROOP.Variables; +using STROOP.Variables.Utilities; + +namespace STROOP.Controls.VariablePanel; + +partial class VariablePanel +{ + [InitializeSpecial] + static void InitializeSpecial() + { + var target = VariableSpecialDictionary.Instance; + target.Add("WatchVarPanelNameWidth", () => SavedSettingsConfig.WatchVarPanelNameWidth.value, (uint value) => + { + SavedSettingsConfig.WatchVarPanelNameWidth.value = Math.Max(1, value); + return true; + }); + target.Add("WatchVarPanelValueWidth", () => SavedSettingsConfig.WatchVarPanelValueWidth.value, (uint value) => + { + SavedSettingsConfig.WatchVarPanelValueWidth.value = Math.Max(1, value); + return true; + }); + target.Add("WatchVarPanelXMargin", () => SavedSettingsConfig.WatchVarPanelHorizontalMargin.value, (uint value) => + { + SavedSettingsConfig.WatchVarPanelHorizontalMargin.value = (uint)Math.Max(1, value); + return true; + }); + target.Add("WatchVarPanelYMargin", () => SavedSettingsConfig.WatchVarPanelVerticalMargin.value, (uint value) => + { + SavedSettingsConfig.WatchVarPanelVerticalMargin.value = (uint)Math.Max(1, value); + return true; + }); + target.Add("WatchVarPanelBoldNames", () => SavedSettingsConfig.WatchVarPanelBoldNames.value, (bool value) => + { + SavedSettingsConfig.WatchVarPanelBoldNames.value = value; + return true; + }); + target.Add("WatchVarPanelFont", () => SavedSettingsConfig.WatchVarPanelFontOverride.value?.Name ?? "(default)", (string value) => false); + VariableStringCell.specialTypeContextMenuHandlers.Add("WatchVarPanelFont", () => + { + var dlg = new FontDialog(); + if (SavedSettingsConfig.WatchVarPanelFontOverride.value != null) + dlg.Font = SavedSettingsConfig.WatchVarPanelFontOverride; + try + { + if (dlg.ShowDialog() == DialogResult.OK) + SavedSettingsConfig.WatchVarPanelFontOverride.value = dlg.Font; + } + catch (ArgumentException ex) + { + // Apparently ACCEPTING a FontDialog can throw if the selected Font is not a TrueType-Font. + MessageBox.Show($"This font is not supported.\nHere's a scary error report:\n\n{ex.Message}"); + } + }); + } + + class Renderer : Control + { + class OnDemand where T : IDisposable + { + readonly Func factory; + Wrapper disposeContext, invalidateContext; + + public OnDemand(Wrapper disposeContext, Func factory, Wrapper invalidateContext = null) + { + this.factory = factory; + this.disposeContext = disposeContext; + this.invalidateContext = invalidateContext; + if (invalidateContext != null) + invalidateContext.value += InvalidateValue; + } + + T _value; + bool valueCreated = false; + + public T Value + { + get + { + if (!valueCreated) + { + _value = factory(); + valueCreated = true; + disposeContext.value += DisposeValue; + } + + return _value; + } + } + + void InvalidateValue() + { + _value?.Dispose(); + valueCreated = false; + } + + void DisposeValue() + { + disposeContext.value -= DisposeValue; + if (invalidateContext != null) + invalidateContext.value -= InvalidateValue; + _value?.Dispose(); + } + + public static implicit operator T(OnDemand obj) => obj.Value; + } + + class VariableControlRenderData + { + public Vector2 positionInGrid; + public Vector2 positionWhileMoving; + public bool moving = false; + public float nameTextOffset; + public float nameTextLength; + public string lastRenderedNameText; + } + + private static readonly Image _pinnedImage = Properties.Resources.img_pin; + + Dictionary renderDatas = new Dictionary(); + + VariableControlRenderData GetRenderData(WinFormsVariableControl ctrl) + { + VariableControlRenderData result; + if (!renderDatas.TryGetValue(ctrl, out result)) + renderDatas[ctrl] = result = new VariableControlRenderData(); + return result; + } + + static int idleRefreshMilliseconds = 250; + DateTime lastRefreshed; + + delegate void OnDemandCall(); + + Wrapper OnDispose = new Wrapper(), OnInvalidateFonts = new Wrapper(); + + BufferedGraphics bufferedGraphics = null; + + OnDemand boldFont; + OnDemand cellBorderPen, cellSeparatorPen, insertionMarkerPen; + OnDemand rightAlignFormat; + + VariablePanel target; + + public int borderMargin { get; private set; } = 2; + static int elementMarginTopBottom => (int)(uint)SavedSettingsConfig.WatchVarPanelVerticalMargin; + static int elementMarginLeftRight => (int)(uint)SavedSettingsConfig.WatchVarPanelHorizontalMargin; + public int elementHeight => (int)(Font.Height + 2 * elementMarginTopBottom); + + int elementNameWidth => target.elementNameWidth ?? (int)(uint)SavedSettingsConfig.WatchVarPanelNameWidth; + int elementValueWidth => target.elementValueWidth ?? (int)(uint)SavedSettingsConfig.WatchVarPanelValueWidth; + int elementWidth => (int)(elementNameWidth + elementValueWidth); + + public int GetMaxRows() + { + var effectiveHeight = target.Height - borderMargin * 2; + var totalVariableCount = target.GetCurrentlyVisibleCells().Count; + var knolz = Math.Max(1, effectiveHeight / elementHeight); + var numColumnsWithoutScrollbar = totalVariableCount / knolz; + if (totalVariableCount % knolz > 0) + numColumnsWithoutScrollbar++; + if (numColumnsWithoutScrollbar * (SavedSettingsConfig.WatchVarPanelNameWidth + SavedSettingsConfig.WatchVarPanelValueWidth) > + target.ClientRectangle.Width - 2 * borderMargin) + effectiveHeight -= SystemInformation.HorizontalScrollBarHeight; + return Math.Max(1, effectiveHeight / elementHeight); + } + + public Renderer(VariablePanel target) + { + this.target = target; + boldFont = new OnDemand( + OnDispose, + () => Font.FontFamily.IsStyleAvailable(FontStyle.Bold) ? new Font(Font, FontStyle.Bold) : Font, + OnInvalidateFonts); + + cellBorderPen = new OnDemand(OnDispose, () => new Pen(Color.Gray, 2)); + cellSeparatorPen = new OnDemand(OnDispose, () => new Pen(Color.Gray, 1)); + insertionMarkerPen = new OnDemand(OnDispose, () => new Pen(Color.Blue, 3)); + rightAlignFormat = new OnDemand(OnDispose, () => new StringFormat() { Alignment = StringAlignment.Far }); + } + + protected override void OnPaint(PaintEventArgs e) + { + base.OnPaint(e); + bufferedGraphics.Render(e.Graphics); + } + + public void Draw() + { + //Return if not focused and recently enough refreshed to save CPU + var form = FindForm(); + if (form != Form.ActiveForm && (DateTime.Now - lastRefreshed).TotalMilliseconds < idleRefreshMilliseconds) + return; + + var displayedWatchVars = target.GetCurrentlyVisibleCells(); + var varNameFont = SavedSettingsConfig.WatchVarPanelBoldNames ? boldFont : Font; + + lastRefreshed = DateTime.Now; + var searchForm = (form as StroopMainForm)?.searchVariableDialog; + bool SearchHighlight(string text) => searchForm?.IsMatch(text) ?? false; + + int maxRows = GetMaxRows(); + var newRect = new Rectangle(0, 0, ((displayedWatchVars.Count - 1) / maxRows + 1) * elementWidth + borderMargin * 2, maxRows * elementHeight + borderMargin * 2); + if (bufferedGraphics == null || Bounds.Width != newRect.Width || Bounds.Height != newRect.Height) + { + bufferedGraphics?.Dispose(); + target.HorizontalScroll.Value = 0; + Bounds = newRect; + bufferedGraphics = BufferedGraphicsManager.Current.Allocate(CreateGraphics(), new Rectangle(0, 0, ClientRectangle.Width, ClientRectangle.Height)); + bufferedGraphics.Graphics.TranslateTransform(borderMargin, borderMargin); + } + + var g = bufferedGraphics.Graphics; + var visibleRegion = new Rectangle( + target.HorizontalScroll.Value - borderMargin, + -borderMargin, + target.ClientRectangle.Width, + target.ClientRectangle.Height); + + void DrawFixImage(IWinFormsVariableCell cell, int baseX, int baseY) + { + var xCoord = baseX + 2; + var iconHeight = elementHeight - elementMarginTopBottom * 2; + if (cell.memory?.fixedAddresses ?? false) + g.DrawImage(_pinnedImage, + new Rectangle( + xCoord, + baseY + elementMarginTopBottom, + (int)(iconHeight * (_pinnedImage.Width / (float)_pinnedImage.Height)), + iconHeight) + ); + } + + void DrawGrid() + { + int x = 0, y = 0; + int iterator = 0; + var lastColumn = -1; + if (maxRows == 0) + return; + + var cursorPos = PointToClient(Cursor.Position); + cursorPos.X -= borderMargin; + cursorPos.Y -= borderMargin; + + void ResetIterators() + { + iterator = 0; + lastColumn = -1; + } + + void GetColumn(int offset, int width, bool clip = true) + { + y = iterator % maxRows; + x = iterator / maxRows; + if (x > lastColumn) + { + lastColumn = x; + if (clip) + g.Clip = new Region(new Rectangle(x * elementWidth + offset, 0, width, Height)); + } + + iterator++; + } + + g.ResetClip(); + ResetIterators(); + foreach (var cell in displayedWatchVars) + { + var ctrlData = GetRenderData(cell.control); + + GetColumn(0, elementNameWidth, false); + var yCoord = y * elementHeight; + ctrlData.positionInGrid = new Vector2(x * elementWidth, yCoord); + if (!ctrlData.moving) + ctrlData.positionWhileMoving = ctrlData.positionInGrid; + + //Skip if invisible + if (x * elementWidth > visibleRegion.Right || + (x + 1) * elementWidth < visibleRegion.Left || + yCoord > visibleRegion.Bottom || + yCoord + elementHeight < visibleRegion.Top) + continue; + + var c = cell.control.IsSelected ? Color.Blue : cell.control.currentColor; + if (c != Parent.BackColor) + using (var brush = new SolidBrush(c)) + g.FillRectangle(brush, x * elementWidth, yCoord, elementWidth, elementHeight); + } + + ResetIterators(); + foreach (var cell in displayedWatchVars) + { + GetColumn(0, elementNameWidth); + var yCoord = y * elementHeight; + + //Skip if invisible + if (x * elementWidth > visibleRegion.Right || + x * elementWidth + elementNameWidth < visibleRegion.Left || + yCoord > visibleRegion.Bottom || + yCoord + elementHeight < visibleRegion.Top) + continue; + + var txtPoint = new Point(x * elementWidth + elementMarginLeftRight, yCoord + elementMarginTopBottom); + var ctrlData = GetRenderData(cell.control); + + if (cursorPos.Y > yCoord && cursorPos.Y < yCoord + elementHeight && + cursorPos.X > x * elementWidth && cursorPos.X < x * elementWidth + elementNameWidth) //Cursor is hovering over the name field + { + if (ctrlData.lastRenderedNameText != cell.control.VarName) + { + var tmp = g.PageUnit; + g.PageUnit = GraphicsUnit.Pixel; + ctrlData.nameTextLength = g.MeasureString(cell.control.VarName, varNameFont).Width; + g.PageUnit = tmp; + ctrlData.lastRenderedNameText = cell.control.VarName; + } + + var overEdge = ctrlData.nameTextLength - (elementNameWidth - elementMarginLeftRight * 2); + if (overEdge > 0) + { + ctrlData.nameTextOffset += (float)Config.CoreLoop.lastFrameTime * elementHeight; + if (ctrlData.nameTextOffset > overEdge + elementHeight * 2) + ctrlData.nameTextOffset = 0; + txtPoint.X -= (int)Math.Max(0, Math.Min(overEdge, ctrlData.nameTextOffset - elementHeight)); + } + } + else + ctrlData.nameTextOffset = 0; + + g.DrawString(cell.control.VarName, varNameFont, cell.control.IsSelected ? Brushes.White : Brushes.Black, txtPoint); + } + + ResetIterators(); + foreach (var cell in displayedWatchVars) + { + GetColumn(elementNameWidth, elementValueWidth); + + //Skip if invisible + var yCoord = y * elementHeight; + if (x * elementWidth + elementNameWidth > visibleRegion.Right || + (x + 1) * elementWidth < visibleRegion.Left || + yCoord > visibleRegion.Bottom || + yCoord + elementHeight < visibleRegion.Top) + continue; + + if (cell.CustomDrawOperation != null) + cell.CustomDrawOperation( + new WinFormsVariablePanelUiContext(this, g, + new Rectangle( + x * elementWidth + elementNameWidth, + y * elementHeight, + elementValueWidth, + elementHeight)) + ); + else + { + var txtPoint = new Point((x + 1) * elementWidth - elementMarginLeftRight, yCoord + elementMarginTopBottom); + g.DrawString(cell.GetValueText(), Font, cell.control.IsSelected ? Brushes.White : Brushes.Black, txtPoint, rightAlignFormat); + } + + DrawFixImage(cell, x * elementWidth + elementNameWidth, yCoord); + } + + g.ResetClip(); + + var numRows = x == 0 ? (y + 1) : maxRows; + var maxY = numRows * elementHeight; + var maxX = elementWidth * (x + 1); + + if (y == maxRows - 1) + x++; + for (int dx = 0; dx <= x; dx++) + { + var xCoord = dx * elementWidth; + g.DrawLine(cellBorderPen, xCoord, 0, xCoord, maxY); + xCoord += elementNameWidth; + if (dx < x) + g.DrawLine(cellSeparatorPen, xCoord, 0, xCoord, maxY); + } + + if (y != maxRows - 1) + { + var yCoord = (y + 1) * elementHeight; + g.DrawLine(cellBorderPen, maxX, 0, maxX, yCoord); + var xCoord = maxX - elementWidth + elementNameWidth; + g.DrawLine(cellSeparatorPen, xCoord, 0, xCoord, yCoord); + } + + for (int dy = 0; dy <= numRows; dy++) + { + var yCoord = dy * elementHeight; + g.DrawLine(cellBorderPen, 0, yCoord, dy <= (y + 1) ? maxX : maxX - elementWidth, yCoord); + } + + ResetIterators(); + using (var highlightBrush = new SolidBrush(Color.FromArgb(0x40, Color.Blue))) + { + foreach (var ctrl in displayedWatchVars) + { + GetColumn(elementNameWidth, elementValueWidth, false); + if (ctrl.control.Highlighted) + using (var pen = new Pen(ctrl.control.HighlightColor, 3)) + g.DrawRectangle(pen, x * elementWidth, y * elementHeight, elementWidth, elementHeight); + if (SearchHighlight(ctrl.control.VarName)) + g.FillRectangle(highlightBrush, x * elementWidth + 2, y * elementHeight + 2, elementWidth - 4, elementHeight - 4); + } + } + } + + void DrawMovingVariables() + { + if (target._reorderingWatchVarControls.Count == 0) + return; + + var pt = PointToClient(Cursor.Position); + var cursorPosition = new Vector2(pt.X, pt.Y); + (var insertionIndex, _, _) = GetVariableAt(pt); + if (insertionIndex < 0) + insertionIndex = displayedWatchVars.Count; + var x = insertionIndex / maxRows; + var y = insertionIndex % maxRows; + g.DrawLine(insertionMarkerPen, x * elementWidth, y * elementHeight, (x + 1) * elementWidth, y * elementHeight); + + int i = 0; + foreach (var cell in target._reorderingWatchVarControls) + { + var ctrlData = GetRenderData(cell.control); + using (var brush = new SolidBrush(cell.control.currentColor)) + { + g.FillRectangle(brush, ctrlData.positionWhileMoving.X, ctrlData.positionWhileMoving.Y, elementWidth, elementHeight); + } + + var yCoord = (int)ctrlData.positionWhileMoving.Y + elementMarginTopBottom; + + + g.Clip = new Region( + new Rectangle( + (int)ctrlData.positionWhileMoving.X, + (int)ctrlData.positionWhileMoving.Y, + elementNameWidth, + elementHeight)); + var txtPoint = new Point((int)ctrlData.positionWhileMoving.X + elementMarginLeftRight, yCoord + elementMarginTopBottom); + g.DrawString(cell.control.VarName, varNameFont, Brushes.Black, txtPoint); + + var valueX = (int)ctrlData.positionWhileMoving.X + elementNameWidth; + g.Clip = new Region( + new Rectangle( + valueX, + (int)ctrlData.positionWhileMoving.Y, + elementValueWidth, + elementHeight)); + txtPoint = new Point((int)ctrlData.positionWhileMoving.X + elementWidth - elementMarginLeftRight, yCoord + elementMarginTopBottom); + g.DrawString(cell.GetValueText(), Font, Brushes.Black, txtPoint, rightAlignFormat); + DrawFixImage(cell, valueX, yCoord); + + g.ResetClip(); + + var xCoord = (int)ctrlData.positionWhileMoving.X + elementNameWidth; + g.DrawLine(cellSeparatorPen, xCoord, yCoord, xCoord, yCoord + elementHeight); + g.DrawRectangle(cellBorderPen, ctrlData.positionWhileMoving.X, ctrlData.positionWhileMoving.Y, elementWidth, elementHeight); + + var target = cursorPosition; + target.Y += elementHeight * i++; + ctrlData.positionWhileMoving += (target - ctrlData.positionWhileMoving) * Utilities.MoreMath.EaseIn(10 * (float)Config.CoreLoop.lastFrameTime); + if ((ctrlData.positionInGrid - ctrlData.positionWhileMoving).LengthSquared < 1) + ctrlData.moving = false; + else + ctrlData.moving = true; + } + } + + g.Clear(Parent.BackColor); + DrawGrid(); + DrawMovingVariables(); + + if (Controls.Count == 0) + bufferedGraphics.Render(); + } + + public Rectangle GetVariableControlBounds(int index) + { + var maxRows = GetMaxRows(); + var x = index / maxRows; + var y = index % maxRows; + return new Rectangle( + borderMargin + x * elementWidth + elementNameWidth, + borderMargin + y * elementHeight, + elementValueWidth, + elementHeight); + } + + public (int index, IWinFormsVariableCell cell, bool select) GetVariableAt(Point location) + { + location.X -= borderMargin; + location.Y -= borderMargin; + if (location.X < 0 || location.Y < 0) + return (-1, null, false); + var x = location.X / elementWidth; + var y = location.Y / elementHeight; + int maxRows = GetMaxRows(); + if (y >= maxRows) + return (-1, null, false); + int index = x * maxRows + y; + if (index < 0) + return (0, null, false); + var displayedWatchVars = target.GetCurrentlyVisibleCells(); + if (index < displayedWatchVars.Count) + return (index, displayedWatchVars[index], (location.X % elementWidth) < elementNameWidth); + + return (-1, null, false); + } + + protected override void Dispose(bool disposing) + { + if (disposing) + OnDispose.value?.DynamicInvoke(); + base.Dispose(disposing); + } + + protected override void OnFontChanged(EventArgs e) + { + base.OnFontChanged(e); + OnInvalidateFonts.value?.DynamicInvoke(); + } + } +} diff --git a/STROOP/Controls/VariablePanel/VariablePanel.WinForms.cs b/STROOP/Controls/VariablePanel/VariablePanel.WinForms.cs new file mode 100644 index 000000000..5070c254d --- /dev/null +++ b/STROOP/Controls/VariablePanel/VariablePanel.WinForms.cs @@ -0,0 +1,221 @@ +using STROOP.Controls.VariablePanel.Cells; +using STROOP.Forms; +using STROOP.Structs; +using STROOP.Structs.Configurations; +using STROOP.Utilities; +using STROOP.Variables; +using STROOP.Variables.Utilities; +using STROOP.Variables.VariablePanel; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Linq; +using System.Reflection; +using System.Windows.Forms; + +namespace STROOP.Controls.VariablePanel; + +public partial class VariablePanel +{ + public List customContextMenuItems = new List(); + + public override bool Focused => renderer.Focused; + + private string _varFilePath; + string _dataPath; + + [Category("Data"), Browsable(true)] + public string DataPath + { + get { return _dataPath; } + set { Initialize(_dataPath = value); } + } + + [Category("Layout"), Browsable(true)] public int? elementNameWidth { get; set; } = null; + [Category("Layout"), Browsable(true)] public int? elementValueWidth { get; set; } = null; + + protected override void OnScroll(ScrollEventArgs se) + { + base.OnScroll(se); + renderer.Draw(); + } + + private void ShowVarContextMenu() + { + ContextMenuStrip ctx = new ContextMenuStrip(); + + var uniqueSettings = GetSelectedVars().SelectMany(x => x.control.AvailableSettings()).ToHashSet(); + var sortedOptions = uniqueSettings.ToList(); + sortedOptions.Sort((a, b) => string.Compare(a.Name, b.Name)); + foreach (var setting in sortedOptions) + setting.CreateContextMenuEntry(ctx.Items, GetSelectedVars); + + ctx.Items.Add(new ToolStripSeparator()); + foreach (var item in VariableSelectionUtilities.CreateSelectionToolStripItems(GetSelectedVars(), this)) + ctx.Items.Add(item); + + ctx.Show(Cursor.Position); + } + + private void ShowContextMenu() + { + ToolStripMenuItem resetVariablesItem = new ToolStripMenuItem("Reset Variables"); + resetVariablesItem.Click += (sender, e) => ResetVariables(); + + ToolStripMenuItem clearAllButHighlightedItem = new ToolStripMenuItem("Clear All But Highlighted"); + clearAllButHighlightedItem.Click += (sender, e) => ClearAllButHighlightedVariables(); + + ToolStripMenuItem addCustomVariablesItem = new ToolStripMenuItem("Add Custom Variables"); + addCustomVariablesItem.Click += (sender, e) => + { + VariableCreationForm form = new VariableCreationForm(); + form.Initialize(this); + form.Show(); + }; + + ToolStripMenuItem addDummyVariableItem = new ToolStripMenuItem("Add Dummy Variable..."); + foreach (string typeString in TypeUtilities.InGameTypeList) + { + ToolStripMenuItem typeItem = new ToolStripMenuItem(typeString); + addDummyVariableItem.DropDownItems.Add(typeItem); + typeItem.Click += (sender, e) => + { + int numEntries = 1; + if (GlobalKeyboard.IsCtrlDown()) + { + string numEntriesString = DialogUtilities.GetStringFromDialog(labelText: "Enter Num Vars:"); + if (numEntriesString == null) return; + int parsed = ParsingUtilities.ParseInt(numEntriesString); + parsed = Math.Max(parsed, 0); + numEntries = parsed; + } + + for (int i = 0; i < numEntries; i++) + { + Type type = TypeUtilities.StringToType[typeString]; + var view = (CustomVariable)typeof(VariablePanel) + .GetMethod(nameof(CreateDummyVariable), BindingFlags.NonPublic | BindingFlags.Static) + .MakeGenericMethod(type) + .Invoke(null, []); + this.AddVariable(($"Dummy {i + 1}", view)); + } + }; + } + + ToolStripMenuItem addRelativeVariablesItem = null, removePointVariableItem = null; + var getSpecialFuncVars = getSpecialFuncVariables?.Invoke() ?? null; + var specificsCount = getSpecialFuncVars?.Count() ?? 0; + if (PositionAngle.HybridPositionAngle.pointPAs.Count > 0) + { + if (getSpecialFuncVars != null && specificsCount > 0) + { + void BindHandler(ToolStripMenuItem menuItem, PositionAngle.HybridPositionAngle targetPA, SpecialFuncVariables generator) => + menuItem.Click += (_, __) => this.AddVariables(generator(targetPA)); + + addRelativeVariablesItem = new ToolStripMenuItem("Add relative variables for..."); + if (specificsCount == 1) + addRelativeVariablesItem.Text = $"Add {getSpecialFuncVars.First().name} for..."; + foreach (var pa in PositionAngle.HybridPositionAngle.pointPAs) + { + var paItem = new ToolStripMenuItem(pa.name); + if (specificsCount == 1) + BindHandler(paItem, pa, getSpecialFuncVars.First().generateVariables); + else + foreach (var specialFunc in getSpecialFuncVars) + { + var specificsItem = new ToolStripMenuItem(specialFunc.name); + BindHandler(specificsItem, pa, specialFunc.generateVariables); + paItem.DropDownItems.Add(specificsItem); + } + + addRelativeVariablesItem.DropDownItems.Add(paItem); + } + } + + removePointVariableItem = new ToolStripMenuItem("Remove custom point ..."); + foreach (var customPA in PositionAngle.HybridPositionAngle.pointPAs) + { + var capture = customPA; + var subElement = new ToolStripMenuItem(customPA.name); + subElement.Click += (_, __) => + { + capture.first = () => PositionAngle.NaN; + capture.second = () => PositionAngle.NaN; + capture.OnDelete(); + PositionAngle.HybridPositionAngle.pointPAs.Remove(capture); + }; + removePointVariableItem.DropDownItems.Add(subElement); + } + } + + var addPointVariableItem = new ToolStripMenuItem("Add custom point..."); + addPointVariableItem.Click += (_, __) => + { + var ptCount = 1; + while (PositionAngle.HybridPositionAngle.pointPAs.Any(pa => pa.name.ToLower() == $"point{ptCount}")) + ptCount++; + var newName = DialogUtilities.GetStringFromDialog($"Point{ptCount}", "Enter name of new custom point", "Add custom point"); + if (newName?.Trim() != null) + PositionAngle.HybridPositionAngle.pointPAs.Add( + new PositionAngle.HybridPositionAngle(() => PositionAngle.Mario, () => PositionAngle.Mario, newName)); + }; + + ToolStripMenuItem openSaveClearItem = new ToolStripMenuItem("Open / Save / Clear ..."); + ControlUtilities.AddDropDownItems( + openSaveClearItem, + new List() { "Restore", "Open", "Open as Pop Out", "Save in Place", "Save As", "Clear" }, + new List() + { + () => OpenVariables(DialogUtilities.OpenXmlElements(FileType.StroopVariables, _dataPath)), + () => OpenVariables(), + () => OpenVariablesAsPopOut(), + () => SaveVariablesInPlace(), + () => SaveVariables(), + () => ClearVariables(), + }); + + ToolStripMenuItem doToAllVariablesItem = new ToolStripMenuItem("Do to all variables..."); + VariableSelectionUtilities.CreateSelectionToolStripItems(GetCurrentlyVisibleCells(), this) + .ForEach(item => doToAllVariablesItem.DropDownItems.Add(item)); + + filterVariablesItem.DropDown.MouseEnter += (sender, e) => { filterVariablesItem.DropDown.AutoClose = false; }; + filterVariablesItem.DropDown.MouseLeave += (sender, e) => + { + filterVariablesItem.DropDown.AutoClose = true; + filterVariablesItem.DropDown.Close(); + }; + + ToolStripItem searchVariablesItem = new ToolStripMenuItem("Search variables..."); + searchVariablesItem.Click += (_, __) => (FindForm() as StroopMainForm)?.ShowSearchDialog(); + + var strip = new ContextMenuStrip(); + strip.Items.Add(resetVariablesItem); + strip.Items.Add(clearAllButHighlightedItem); + strip.Items.Add(new ToolStripSeparator()); + if (addRelativeVariablesItem != null) + strip.Items.Add(addRelativeVariablesItem); + strip.Items.Add(addPointVariableItem); + strip.Items.Add(removePointVariableItem); + strip.Items.Add(addCustomVariablesItem); + strip.Items.Add(addDummyVariableItem); + strip.Items.Add(new ToolStripSeparator()); + strip.Items.Add(openSaveClearItem); + strip.Items.Add(doToAllVariablesItem); + strip.Items.Add(filterVariablesItem); + strip.Items.Add(searchVariablesItem); + if (customContextMenuItems.Count > 0) + { + strip.Items.Add(new ToolStripSeparator()); + foreach (var item in customContextMenuItems) + strip.Items.Add(item); + } + + strip.Show(System.Windows.Forms.Cursor.Position); + } + + // Prevent unwanted scrolling to the top left of the renderer child control + // For details, see https://stackoverflow.com/questions/419774/how-can-you-stop-a-winforms-panel-from-scrolling + protected override Point ScrollToControl(Control activeControl) + => DisplayRectangle.Location; +} diff --git a/STROOP/Controls/VariablePanel/VariablePanel.cs b/STROOP/Controls/VariablePanel/VariablePanel.cs new file mode 100644 index 000000000..c11bf7d5a --- /dev/null +++ b/STROOP/Controls/VariablePanel/VariablePanel.cs @@ -0,0 +1,596 @@ +using STROOP.Core; +using STROOP.Core.Utilities; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Reflection; +using System.Windows.Forms; +using System.Xml.Linq; +using STROOP.Forms; +using STROOP.Structs; +using STROOP.Structs.Configurations; +using STROOP.Utilities; +using STROOP.Variables; +using STROOP.Variables.Formatting; +using STROOP.Variables.Utilities; +using STROOP.Variables.VariablePanel; + +namespace STROOP.Controls.VariablePanel +{ + public partial class VariablePanel : UserControl + { + public delegate IEnumerable SpecialFuncVariables(PositionAngle.HybridPositionAngle input); + + static void ViewInMemoryTab(DescribedMemoryState memoryDescriptor) + { + List addressList = memoryDescriptor.GetAddressList().ToList(); + if (addressList.Count == 0) return; + uint address = addressList[0]; + var tab = AccessScope.content.GetTab(); + tab.UpdateOrInitialize(true); + Config.TabControlMain.SelectedTab = tab.Tab; + tab.SetCustomAddress(address); + tab.UpdateHexDisplay(); + } + + private static int numDummies = 0; + + public readonly Func> GetSelectedVars; + + public Func> getSpecialFuncVariables = null; + + bool initialized = false; + List deferredActions = new List(); + + private List _allWatchVarControls; + private List _hiddenSearchResults = []; + private List _reorderingWatchVarControls; + private HashSet _selectedWatchVarControls; + private SortedList _shownWatchVarControls; + + private List _allGroups; + private List _initialVisibleGroups; + private List _visibleGroups; + private List _filteringDropDownItems; + + private ToolStripMenuItem filterVariablesItem = new ToolStripMenuItem("Filter Variables..."); + private Renderer renderer; + private bool hasGroupsSet = false; + + public VariablePanel() + { + GetSelectedVars = () => new List(_selectedWatchVarControls); + + _allWatchVarControls = new List(); + _allGroups = new List(); + _initialVisibleGroups = new List(); + _visibleGroups = new List(); + + _selectedWatchVarControls = new HashSet(); + _reorderingWatchVarControls = new List(); + + renderer = new Renderer(this); + renderer.KeyDown += (_, args) => + { + if (GlobalKeyboard.IsCtrlDown() && args.KeyCode == Keys.F) + (FindForm() as StroopMainForm)?.ShowSearchDialog(); + }; + getSpecialFuncVariables = () => [ PositionAngle.HybridPositionAngle.GenerateBaseVariables ]; + UpdateSortOption(WinFormsVariableControl.SortByPriority); + } + + public void Initialize(string varFilePath = null) + { + AutoScroll = true; + + Controls.Add(renderer); + _varFilePath = varFilePath; + if (varFilePath != null && !System.IO.File.Exists(varFilePath)) + return; + deferredActions.Add(() => + { + SuspendLayout(); + + var controls = (_varFilePath != null ? XmlConfigParser.OpenVariableControlPrecursors(_varFilePath) : []) + .Select(precursor => new WinFormsVariableControl(this, precursor.var) { VarName = precursor.name }); + foreach (var watchVarControl in controls) + _allWatchVarControls.Add(watchVarControl.varCell); + + MouseDown += (_, __) => + { + if (__.Button == MouseButtons.Right) + ShowContextMenu(); + }; + + int lastSelectedEntry = -1; + int lastClicked = -1; + bool clickedName = false; + renderer.DoubleClick += (_, __) => + { + foreach (var selected in _selectedWatchVarControls) + { + if (clickedName) + ShowVarInfo(selected); + else if (lastClicked != -1) + selected.DoubleClick(new WinFormsVariablePanelUiContext( + renderer, + null, + renderer.GetVariableControlBounds(lastClicked)) + ); + break; + } + }; + renderer.Click += (_, __) => + { + if (lastClicked != -1) + foreach (var selected in _selectedWatchVarControls) + selected.SingleClick(new WinFormsVariablePanelUiContext( + renderer, + null, + renderer.GetVariableControlBounds(lastClicked)) + ); + }; + + renderer.MouseDown += (_, args) => + { + renderer.Focus(); + (int index, IWinFormsVariableCell cell, bool select) = renderer.GetVariableAt(args.Location); + lastClicked = index; + + bool ctrlHeld = GlobalKeyboard.IsCtrlDown(); + bool shiftHeld = GlobalKeyboard.IsShiftDown(); + clickedName = select | shiftHeld; + + if (_reorderingWatchVarControls.Count > 0) + { + if (args.Button == MouseButtons.Left) + { + var tmp = new List(); + foreach (var ctrl in _shownWatchVarControls) + if (!_reorderingWatchVarControls.Contains(ctrl)) + tmp.Add(ctrl); + tmp.AddRange(_reorderingWatchVarControls); + _shownWatchVarControls.Clear(); + foreach (var x in tmp) + _shownWatchVarControls.Add(x); + lastSelectedEntry = -1; + } + + _reorderingWatchVarControls.Clear(); + return; + } + + var numSelected = _selectedWatchVarControls.Count; + if (!ctrlHeld && (numSelected == 1 || args.Button != MouseButtons.Right)) + UnselectAllVariables(); + + if (shiftHeld) + { + int k = 0; + var low = Math.Min(lastSelectedEntry, index); + var high = Math.Max(lastSelectedEntry, index); + foreach (var ctrl in _shownWatchVarControls) + { + if (k >= low) + { + _selectedWatchVarControls.Add(ctrl); + ctrl.control.IsSelected = true; + } + + if (k >= high) + break; + k++; + } + } + else if (cell != null) + { + if (ctrlHeld && cell.control.IsSelected) + { + _selectedWatchVarControls.Remove(cell); + cell.control.IsSelected = false; + } + else + { + _selectedWatchVarControls.Add(cell); + cell.control.IsSelected = true; + } + } + + if (args.Button == MouseButtons.Left) + OnVariableClick(_selectedWatchVarControls.ToList()); + + if (args.Button == MouseButtons.Right) + { + if (cell != null) + ShowVarContextMenu(); + else + ShowContextMenu(); + } + + if (!shiftHeld || _selectedWatchVarControls.Count == 0) + if (cell != null && cell.control.IsSelected) + lastSelectedEntry = index; + }; + + _allGroups.AddRange(new List(new[] { VariableGroup.Custom })); + _initialVisibleGroups.AddRange(new List(new[] { VariableGroup.Custom })); + _visibleGroups.AddRange(new List(new[] { VariableGroup.Custom })); + if (!hasGroupsSet) + UpdateControlsBasedOnFilters(); + + ResumeLayout(); + }); + } + + public void DeferredInitialize() + { + foreach (var action in deferredActions) + action.Invoke(); + deferredActions.Clear(); + } + + public void UpdatePanel() + { + if (SavedSettingsConfig.WatchVarPanelFontOverride.value != null) + Font = SavedSettingsConfig.WatchVarPanelFontOverride; + else if (Font != SystemFonts.DefaultFont) + Font = SystemFonts.DefaultFont; + + var searchForm = (FindForm() as StroopMainForm)?.searchVariableDialog ?? null; + _hiddenSearchResults.Clear(); + var shownVars = new HashSet(_shownWatchVarControls); + var removeLater = new HashSet(); + foreach (var v in _allWatchVarControls) + { + if (!shownVars.Contains(v)) + { + if (ShouldShow(v)) + _shownWatchVarControls.Add(v); + else if (searchForm != null && searchForm.searchHidden && searchForm.IsMatch(v.control.VarName)) + _hiddenSearchResults.Add(v); + } + else if (!ShouldShow(v)) + removeLater.Add(v); + } + + foreach (var toBeRemoved in removeLater) + _shownWatchVarControls.Remove(toBeRemoved); + GetCurrentlyVisibleCells().ForEach(cell => cell.Update()); + renderer.Draw(); + } + + public void SetGroups( + List allVariableGroupsNullable, + List visibleVariableGroupsNullable + ) + { + if (Program.IsVisualStudioHostProcess()) return; + + hasGroupsSet = true; + deferredActions.Add(() => + { + _allGroups = allVariableGroupsNullable != null ? new List(allVariableGroupsNullable) : new List(); + + _visibleGroups = visibleVariableGroupsNullable != null ? new List(visibleVariableGroupsNullable) : new List(); + + _initialVisibleGroups.AddRange(_visibleGroups); + UpdateControlsBasedOnFilters(); + }); + } + + public void UpdateSortOption(WinFormsVariableControl.SortVariables newSortOption) + { + _shownWatchVarControls = new SortedList((a, b) => newSortOption(a, b)); + foreach (var shownVar in _allWatchVarControls.Where(ShouldShow)) + _shownWatchVarControls.Add(shownVar); + } + + public void BeginMoveSelected() + { + _reorderingWatchVarControls.Clear(); + _reorderingWatchVarControls.AddRange(_selectedWatchVarControls.Where(v => !_hiddenSearchResults.Contains(v))); + } + + private void OnVariableClick(List cells) + { + if (cells.Count == 0) + return; + + bool isShiftKeyHeld = GlobalKeyboard.IsShiftDown(); + bool isFKeyHeld = GlobalKeyboard.IsDown(Keys.F); + bool isHKeyHeld = GlobalKeyboard.IsDown(Keys.H); + bool isCKeyHeld = GlobalKeyboard.IsDown(Keys.C); + bool isBKeyHeld = GlobalKeyboard.IsDown(Keys.B); + bool isQKeyHeld = GlobalKeyboard.IsDown(Keys.Q); + bool isOKeyHeld = GlobalKeyboard.IsDown(Keys.O); + bool isNKeyHeld = GlobalKeyboard.IsDown(Keys.N); + bool isXKeyHeld = GlobalKeyboard.IsDown(Keys.X); + bool isDeletishKeyHeld = GlobalKeyboard.IsDeletishKeyDown(); + bool isBacktickHeld = GlobalKeyboard.IsDown(Keys.Oemtilde); + bool isZHeld = GlobalKeyboard.IsDown(Keys.Z); + bool isNumberHeld = GlobalKeyboard.IsNumberDown(); + + if (isShiftKeyHeld && isNumberHeld) + { + UnselectAllVariables(); + cells.ForEach(cell => cell.control.BaseColor = ColorUtilities.GetColorForVariable(GlobalKeyboard.GetCurrentlyInputtedNumber())); + } + //else if (isSKeyHeld) + //{ + // containingPanel.UnselectAllVariables(); + // AddToTab(Config.CustomManager); + //} + //else if (isMKeyHeld) + //{ + // containingPanel.UnselectAllVariables(); + // AddToTab(Config.MemoryManager); + //} + else if (isNKeyHeld) + { + var memory = cells.FirstOrDefault()?.memory; + if (memory != null) + { + UnselectAllVariables(); + ViewInMemoryTab(memory); + } + } + else if (isFKeyHeld) + { + UnselectAllVariables(); + cells.ForEach(watchVar => watchVar.control.ToggleFixedAddress(null)); + } + else if (isHKeyHeld) + { + UnselectAllVariables(); + cells.ForEach(watchVar => watchVar.control.ToggleHighlighted()); + } + else if (isNumberHeld) + { + UnselectAllVariables(); + Color? color = ColorUtilities.GetColorForHighlight(GlobalKeyboard.GetCurrentlyInputtedNumber()); + cells.ForEach(watchVar => watchVar.control.ToggleHighlighted(color)); + } + else if (isCKeyHeld) + { + UnselectAllVariables(); + var cell = cells.Last(); + new VariableControllerForm(cell.control.VarName, cell.control.varCell).Show(); + } + else if (isBKeyHeld) + { + var cell = cells.Last(); + if (cell.memory != null) + { + UnselectAllVariables(); + new VariableBitForm(cell.control.VarName, cell.memory.descriptor, true).Show(); + } + } + else if (isDeletishKeyHeld) + { + UnselectAllVariables(); + RemoveVariables(cells); + } + else if (isBacktickHeld) + { + UnselectAllVariables(); + AddToVarHackTab(cells); + } + else if (isZHeld) + { + UnselectAllVariables(); + cells.ForEach(cell => cell.control.SetValue(0)); + } + else if (isXKeyHeld) + { + BeginMoveSelected(); + } + else if (isQKeyHeld) + { + UnselectAllVariables(); + Color? newColor = ColorDialogUtilities.GetColorFromDialog(cells.First().control.BaseColor); + if (newColor.HasValue) + { + cells.ForEach(cell => cell.control.BaseColor = newColor.Value); + ColorUtilities.LastCustomColor = newColor.Value; + } + } + else if (isOKeyHeld) + { + UnselectAllVariables(); + cells.ForEach(cell => cell.control.BaseColor = ColorUtilities.LastCustomColor); + } + } + + private void AddToVarHackTab(List cells) + { + foreach (var cell in cells) + cell.control.FlashColor(WinFormsVariableControl.ADD_TO_VAR_HACK_TAB_COLOR); + MessageBox.Show("This feature is currently not implemented :("); + } + + private static CustomVariable CreateDummyVariable() where T : struct, IConvertible + { + throw new NotImplementedException(); + // T capturedValue = default(T); + // + // return new CustomVariableView(VariableUtilities.GetWrapperType(typeof(T))) + // { + // Name = $"Dummy {++numDummies} {StringUtilities.Capitalize(typeof(T).Name)}", + // _getterFunction = () => capturedValue.Yield(), + // _setterFunction = (T value) => + // { + // capturedValue = value; + // return true.Yield(); + // } + // }; + } + + private ToolStripMenuItem CreateFilterItem(string varGroup) + { + ToolStripMenuItem item = new ToolStripMenuItem(varGroup); + item.Click += (sender, e) => ToggleVarGroupVisibility(varGroup); + return item; + } + + private void ToggleVarGroupVisibility(string varGroup, bool? newVisibilityNullable = null) + { + // Toggle visibility if no visibility is provided + bool newVisibility = newVisibilityNullable ?? !_visibleGroups.Contains(varGroup); + if (newVisibility) // change to visible + _visibleGroups.Add(varGroup); + else // change to hidden + _visibleGroups.Remove(varGroup); + UpdateControlsBasedOnFilters(); + UpdateFilterItemCheckedStatuses(); + } + + private void UpdateFilterItemCheckedStatuses() + { + if (_allGroups.Count != _filteringDropDownItems.Count) throw new ArgumentOutOfRangeException(); + + for (int i = 0; i < _allGroups.Count; i++) + _filteringDropDownItems[i].Checked = _visibleGroups.Contains(_allGroups[i]); + } + + private void UpdateControlsBasedOnFilters() + { + _shownWatchVarControls.Clear(); + foreach (var shownVar in _allWatchVarControls.Where(ShouldShow)) + _shownWatchVarControls.Add(shownVar); + + filterVariablesItem.DropDownItems.Clear(); + _filteringDropDownItems = _allGroups.ConvertAll(varGroup => CreateFilterItem(varGroup)); + UpdateFilterItemCheckedStatuses(); + _filteringDropDownItems.ForEach(item => filterVariablesItem.DropDownItems.Add(item)); + } + + public void RemoveVariable(IWinFormsVariableCell varCellControl) => + RemoveVariables([varCellControl]); + + public void RemoveVariableGroup(string varGroup) + { + List watchVarControls = + _allWatchVarControls.FindAll( + watchVarControl => watchVarControl.control.BelongsToGroup(varGroup)); + RemoveVariables(watchVarControls); + } + + public void ShowOnlyVariableGroups(List visibleVarGroups) + { + foreach (string varGroup in _allGroups) + { + bool newVisibility = visibleVarGroups.Contains(varGroup); + ToggleVarGroupVisibility(varGroup, newVisibility); + } + } + + public void ClearVariables() + { + List watchVarControlListCopy = + new List(_allWatchVarControls); + RemoveVariables(watchVarControlListCopy); + } + + public void ClearAllButHighlightedVariables() + { + List nonHighlighted = _allWatchVarControls.FindAll(cell => !cell.control.Highlighted); + RemoveVariables(nonHighlighted); + _allWatchVarControls.ForEach(cell => cell.control.Highlighted = false); + } + + private void ResetVariables() + { + ClearVariables(); + _visibleGroups.Clear(); + _visibleGroups.AddRange(_initialVisibleGroups); + UpdateFilterItemCheckedStatuses(); + + this.AddVariables(_varFilePath != null ? XmlConfigParser.OpenVariableControlPrecursors(_varFilePath) : []); + } + + public void UnselectAllVariables() + { + foreach (var cell in _selectedWatchVarControls) + cell.control.IsSelected = false; + _selectedWatchVarControls.Clear(); + } + + public void OpenVariables() + { + List elements = DialogUtilities.OpenXmlElements(FileType.StroopVariables); + OpenVariables(elements); + } + + public void OpenVariablesAsPopOut() + { + List elements = DialogUtilities.OpenXmlElements(FileType.StroopVariables); + if (elements.Count == 0) return; + VariablePopOutForm form = new VariablePopOutForm(); + form.Initialize(elements + .Select(x => VariableCellFactory.ParseXml(x, VariableSpecialDictionary.Instance)) + .Where(x => x.var != null) + ); + form.ShowForm(); + } + + public void OpenVariables(List elements) + => this.AddVariables(elements.ConvertAll(x => VariableCellFactory.ParseXml(x, VariableSpecialDictionary.Instance))); + + public void SaveVariablesInPlace() + { + if (_varFilePath == null) return; + if (!DialogUtilities.AskQuestionAboutSavingVariableFileInPlace()) return; + SaveVariables(_varFilePath); + } + + public void SaveVariables(string fileName = null) + => DialogUtilities.SaveXmlElements( + FileType.StroopVariables, + "VarData", + GetCurrentlyVisibleCells().ConvertAll(cell => cell.control.ToXml()), + fileName + ); + + public List GetCurrentlyVisibleCells() + => [.._shownWatchVarControls, .._hiddenSearchResults]; + + public IEnumerable GetCurrentVariableMemoryDescriptors() + => GetCurrentlyVisibleCells().ConvertAndRemoveNull(control => control.memory?.descriptor); + + public List GetCurrentVariableValues() + => GetCurrentlyVisibleCells().ConvertAll(cell => cell.GetValueText()); + + public List GetCurrentVariableNames() + => GetCurrentlyVisibleCells().ConvertAll(cell => cell.control.VarName); + + private bool ShouldShow(IWinFormsVariableCell cell) + { + if (!hasGroupsSet || cell.control.alwaysVisible) + return true; + return cell.control.BelongsToAnyGroupOrHasNoGroup(_visibleGroups); + } + + private void ShowVarInfo(IWinFormsVariableCell cell) + { + var memoryDescriptor = cell.memory?.descriptor; + VariableViewerForm varInfo = + new VariableViewerForm( + name: cell.control.VarName, + clazz: cell.GetClass(), + type: memoryDescriptor?.GetTypeDescription() ?? "special", + baseTypeOffset: memoryDescriptor?.GetBaseTypeOffsetDescription() ?? "", + n64BaseAddress: memoryDescriptor?.GetBaseAddressListString() ?? "", + emulatorBaseAddress: memoryDescriptor?.GetProcessAddressListString() ?? "", + n64Address: memoryDescriptor?.GetRamAddressListString(true) ?? "", + emulatorAddress: memoryDescriptor?.GetProcessAddressListString() ?? ""); + varInfo.Show(); + } + + public override string ToString() + { + List varNames = _allWatchVarControls.ConvertAll(cell => cell.control.VarName); + return String.Join(",", varNames); + } + } +} diff --git a/STROOP/Controls/VariablePanel/VariablePanelValueEditBox.cs b/STROOP/Controls/VariablePanel/VariablePanelValueEditBox.cs new file mode 100644 index 000000000..458d2defd --- /dev/null +++ b/STROOP/Controls/VariablePanel/VariablePanelValueEditBox.cs @@ -0,0 +1,53 @@ +using STROOP.Variables.VariablePanel; +using System; +using System.Runtime.InteropServices; +using System.Windows.Forms; + +namespace STROOP.Controls.VariablePanel; + +public class VariablePanelValueEditBox : TextBox, IValueEditBox +{ + private readonly EventHandler _handleLostFocus; + private bool killed = false; + + internal VariablePanelValueEditBox() + { + bool updateValue = true; + KeyDown += (_, e) => + { + updateValue = true; + if (e.KeyCode == Keys.Enter) + Parent.Focus(); + else if (e.KeyCode == Keys.Escape) + { + updateValue = false; + Parent.Focus(); + } + }; + + _handleLostFocus = (_, e) => + { + if (killed) + return; + + if (updateValue) + Accept?.Invoke(Text); + else + Cancel(); + }; + + LostFocus += _handleLostFocus; + Focus(); + } + + public Action Accept { get; set; } + public Action Cancel { get; set; } + + protected override void Dispose(bool disposing) + { + killed = true; + LostFocus -= _handleLostFocus; + Parent!.Controls.Remove(this); + base.Dispose(disposing); + } +} diff --git a/STROOP/Controls/VariablePanel/WatchVariableFlowLayoutPanel.cs b/STROOP/Controls/VariablePanel/WatchVariableFlowLayoutPanel.cs deleted file mode 100644 index 47ee85db6..000000000 --- a/STROOP/Controls/VariablePanel/WatchVariableFlowLayoutPanel.cs +++ /dev/null @@ -1,889 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Drawing; -using System.Linq; -using System.Reflection; -using System.Windows.Forms; -using System.Xml.Linq; -using STROOP.Core.Variables; -using STROOP.Forms; -using STROOP.Structs; -using STROOP.Structs.Configurations; -using STROOP.Utilities; - -namespace STROOP.Controls.VariablePanel -{ - public partial class WatchVariablePanel : UserControl - { - public override bool Focused => renderer.Focused; - - public delegate void CustomDraw(Graphics g, Rectangle rect); - - [InitializeSpecial] - static void InitializeSpecial() - { - var target = WatchVariableSpecialUtilities.dictionary; - target.Add("WatchVarPanelNameWidth", () => SavedSettingsConfig.WatchVarPanelNameWidth.value, (uint value) => - { - SavedSettingsConfig.WatchVarPanelNameWidth.value = Math.Max(1, value); - return true; - }); - target.Add("WatchVarPanelValueWidth", () => SavedSettingsConfig.WatchVarPanelValueWidth.value, (uint value) => - { - SavedSettingsConfig.WatchVarPanelValueWidth.value = Math.Max(1, value); - return true; - }); - target.Add("WatchVarPanelXMargin", () => SavedSettingsConfig.WatchVarPanelHorizontalMargin.value, (uint value) => - { - SavedSettingsConfig.WatchVarPanelHorizontalMargin.value = (uint)Math.Max(1, value); - return true; - }); - target.Add("WatchVarPanelYMargin", () => SavedSettingsConfig.WatchVarPanelVerticalMargin.value, (uint value) => - { - SavedSettingsConfig.WatchVarPanelVerticalMargin.value = (uint)Math.Max(1, value); - return true; - }); - target.Add("WatchVarPanelBoldNames", () => SavedSettingsConfig.WatchVarPanelBoldNames.value, (bool value) => - { - SavedSettingsConfig.WatchVarPanelBoldNames.value = value; - return true; - }); - target.Add("WatchVarPanelFont", () => SavedSettingsConfig.WatchVarPanelFontOverride.value?.Name ?? "(default)", (string value) => false); - WatchVariableStringWrapper.specialTypeContextMenuHandlers.Add("WatchVarPanelFont", () => - { - var dlg = new FontDialog(); - if (SavedSettingsConfig.WatchVarPanelFontOverride.value != null) - dlg.Font = SavedSettingsConfig.WatchVarPanelFontOverride; - try - { - if (dlg.ShowDialog() == DialogResult.OK) - SavedSettingsConfig.WatchVarPanelFontOverride.value = dlg.Font; - } - catch (ArgumentException ex) - { - // Apparently ACCEPTING a FontDialog can throw if the selected Font is not a TrueType-Font. - MessageBox.Show($"This font is not supported.\nHere's a scary error report:\n\n{ex.Message}"); - } - }); - } - - public readonly Func> GetSelectedVars; - public List customContextMenuItems = new List(); - - public delegate IEnumerable SpecialFuncWatchVariables(PositionAngle.HybridPositionAngle input); - - public Func> getSpecialFuncWatchVariables = null; - - public bool initialized = false; - List deferredActions = new List(); - - private string _varFilePath; - - string _dataPath; - - [Category("Data"), Browsable(true)] - public string DataPath - { - get { return _dataPath; } - set { Initialize(_dataPath = value); } - } - - [Category("Layout"), Browsable(true)] public int? elementNameWidth { get; set; } = null; - [Category("Layout"), Browsable(true)] public int? elementValueWidth { get; set; } = null; - - public bool IsSelected => Focused; - - private List _allWatchVarControls; - private SortedList _shownWatchVarControls; - private List _hiddenSearchResults = new List(); - private List _allGroups; - private List _initialVisibleGroups; - private List _visibleGroups; - private List _filteringDropDownItems; - - private HashSet _selectedWatchVarControls; - private List _reorderingWatchVarControls; - - ToolStripMenuItem filterVariablesItem = new ToolStripMenuItem("Filter Variables..."); - - WatchVariablePanelRenderer renderer; - - public WatchVariableControl hoveringWatchVariableControl => renderer.GetVariableAt(renderer.PointToClient(System.Windows.Forms.Cursor.Position)).ctrl; - - public WatchVariablePanel() - { - GetSelectedVars = () => new List(_selectedWatchVarControls); - - _allWatchVarControls = new List(); - _allGroups = new List(); - _initialVisibleGroups = new List(); - _visibleGroups = new List(); - - _selectedWatchVarControls = new HashSet(); - _reorderingWatchVarControls = new List(); - - renderer = new WatchVariablePanelRenderer(this); - renderer.KeyDown += (_, args) => - { - if (GlobalKeyboard.IsCtrlDown() && args.KeyCode == Keys.F) - (FindForm() as StroopMainForm)?.ShowSearchDialog(); - }; - getSpecialFuncWatchVariables = () => new[] { PositionAngle.HybridPositionAngle.GenerateBaseVariables }; - UpdateSortOption(WatchVariableControl.SortByPriority); - } - - protected override void OnScroll(ScrollEventArgs se) - { - base.OnScroll(se); - renderer.Draw(); - } - - bool hasGroupsSet = false; - - public void SetGroups( - List allVariableGroupsNullable, - List visibleVariableGroupsNullable) - { - if (Program.IsVisualStudioHostProcess()) return; - - hasGroupsSet = true; - DeferActionToUpdate(nameof(SetGroups), () => - { - _allGroups = allVariableGroupsNullable != null ? new List(allVariableGroupsNullable) : new List(); - - _visibleGroups = visibleVariableGroupsNullable != null ? new List(visibleVariableGroupsNullable) : new List(); - - _initialVisibleGroups.AddRange(_visibleGroups); - UpdateControlsBasedOnFilters(); - }); - } - - public void Initialize(string varFilePath = null) - { - AutoScroll = true; - - Controls.Add(renderer); - _varFilePath = varFilePath; - if (varFilePath != null && !System.IO.File.Exists(varFilePath)) - return; - DeferActionToUpdate(nameof(Initialize), () => - { - SuspendLayout(); - - List precursors = _varFilePath == null - ? new List() - : XmlConfigParser.OpenWatchVariableControlPrecursors(_varFilePath); - - foreach (var watchVarControl in precursors.ConvertAll(precursor => new WatchVariableControl(this, precursor))) - _allWatchVarControls.Add(watchVarControl); - - MouseDown += (_, __) => - { - if (__.Button == MouseButtons.Right) - ShowContextMenu(); - }; - - int lastSelectedEntry = -1; - int lastClicked = -1; - bool clickedName = false; - renderer.DoubleClick += (_, __) => - { - foreach (var selected in _selectedWatchVarControls) - { - if (clickedName) - selected.WatchVarWrapper.ShowVarInfo(); - else if (lastClicked != -1) - selected.WatchVarWrapper.DoubleClick(renderer, renderer.GetVariableControlBounds(lastClicked)); - break; - } - }; - renderer.Click += (_, __) => - { - if (lastClicked != -1) - foreach (var selected in _selectedWatchVarControls) - selected.WatchVarWrapper.SingleClick(renderer, renderer.GetVariableControlBounds(lastClicked)); - }; - - renderer.MouseDown += (_, __) => - { - renderer.Focus(); - (int index, var var, var _select) = renderer.GetVariableAt(__.Location); - lastClicked = index; - - bool ctrlHeld = GlobalKeyboard.IsCtrlDown(); - bool shiftHeld = GlobalKeyboard.IsShiftDown(); - clickedName = _select | shiftHeld; - - if (_reorderingWatchVarControls.Count > 0) - { - if (__.Button == MouseButtons.Left) - { - var dings = new List(); - foreach (var ctrl in _shownWatchVarControls) - if (!_reorderingWatchVarControls.Contains(ctrl)) - dings.Add(ctrl); - dings.AddRange(_reorderingWatchVarControls); - _shownWatchVarControls.Clear(); - foreach (var ding in dings) - _shownWatchVarControls.Add(ding); - lastSelectedEntry = -1; - } - - _reorderingWatchVarControls.Clear(); - return; - } - - var numSelected = _selectedWatchVarControls.Count; - if (!ctrlHeld && (numSelected == 1 || __.Button != MouseButtons.Right)) - UnselectAllVariables(); - - if (shiftHeld) - { - int k = 0; - var low = Math.Min(lastSelectedEntry, index); - var high = Math.Max(lastSelectedEntry, index); - foreach (var ctrl in _shownWatchVarControls) - { - if (k >= low) - { - _selectedWatchVarControls.Add(ctrl); - ctrl.IsSelected = true; - } - - if (k >= high) - break; - k++; - } - } - else if (var != null) - { - if (ctrlHeld && var.IsSelected) - { - _selectedWatchVarControls.Remove(var); - var.IsSelected = false; - } - else - { - _selectedWatchVarControls.Add(var); - var.IsSelected = true; - } - } - - if (__.Button == MouseButtons.Left) - OnVariableClick(_selectedWatchVarControls.ToList()); - - if (__.Button == MouseButtons.Right) - { - if (var != null) - var.ShowContextMenu(); - else - ShowContextMenu(); - } - - if (!shiftHeld || _selectedWatchVarControls.Count == 0) - if (var != null && var.IsSelected) - lastSelectedEntry = index; - }; - - _allGroups.AddRange(new List(new[] { VariableGroup.Custom })); - _initialVisibleGroups.AddRange(new List(new[] { VariableGroup.Custom })); - _visibleGroups.AddRange(new List(new[] { VariableGroup.Custom })); - if (!hasGroupsSet) - UpdateControlsBasedOnFilters(); - - ResumeLayout(); - }); - } - - public void UpdateSortOption(WatchVariableControl.SortVariables newSortOption) - { - _shownWatchVarControls = new SortedList((a, b) => newSortOption(a, b)); - foreach (var shownVar in _allWatchVarControls.Where(_ => ShouldShow(_))) - _shownWatchVarControls.Add(shownVar); - } - - private void OnVariableClick(List watchVars) - { - if (watchVars.Count == 0) - return; - - bool isCtrlKeyHeld = GlobalKeyboard.IsCtrlDown(); - bool isShiftKeyHeld = GlobalKeyboard.IsShiftDown(); - bool isAltKeyHeld = GlobalKeyboard.IsAltDown(); - bool isFKeyHeld = GlobalKeyboard.IsDown(Keys.F); - bool isHKeyHeld = GlobalKeyboard.IsDown(Keys.H); - bool isLKeyHeld = GlobalKeyboard.IsDown(Keys.L); - bool isDKeyHeld = GlobalKeyboard.IsDown(Keys.D); - bool isRKeyHeld = GlobalKeyboard.IsDown(Keys.R); - bool isCKeyHeld = GlobalKeyboard.IsDown(Keys.C); - bool isBKeyHeld = GlobalKeyboard.IsDown(Keys.B); - bool isQKeyHeld = GlobalKeyboard.IsDown(Keys.Q); - bool isOKeyHeld = GlobalKeyboard.IsDown(Keys.O); - bool isMKeyHeld = GlobalKeyboard.IsDown(Keys.M); - bool isNKeyHeld = GlobalKeyboard.IsDown(Keys.N); - bool isPKeyHeld = GlobalKeyboard.IsDown(Keys.P); - bool isXKeyHeld = GlobalKeyboard.IsDown(Keys.X); - bool isSKeyHeld = GlobalKeyboard.IsDown(Keys.S); - bool isDeletishKeyHeld = GlobalKeyboard.IsDeletishKeyDown(); - bool isBacktickHeld = GlobalKeyboard.IsDown(Keys.Oemtilde); - bool isZHeld = GlobalKeyboard.IsDown(Keys.Z); - bool isMinusHeld = GlobalKeyboard.IsDown(Keys.OemMinus); - bool isPlusHeld = GlobalKeyboard.IsDown(Keys.Oemplus); - bool isNumberHeld = GlobalKeyboard.IsNumberDown(); - - if (isShiftKeyHeld && isNumberHeld) - { - UnselectAllVariables(); - watchVars.ForEach(watchVar => watchVar.BaseColor = ColorUtilities.GetColorForVariable()); - } - //else if (isSKeyHeld) - //{ - // containingPanel.UnselectAllVariables(); - // AddToTab(Config.CustomManager); - //} - //else if (isMKeyHeld) - //{ - // containingPanel.UnselectAllVariables(); - // AddToTab(Config.MemoryManager); - //} - else if (isNKeyHeld) - { - var memoryDescriptorView = watchVars.FirstOrDefault()?.view as NamedVariableCollection.IMemoryDescriptorView; - if (memoryDescriptorView != null) - { - UnselectAllVariables(); - memoryDescriptorView.describedMemoryState.ViewInMemoryTab(); - } - } - else if (isFKeyHeld) - { - UnselectAllVariables(); - watchVars.ForEach(watchVar => watchVar.ToggleFixedAddress(null)); - } - else if (isHKeyHeld) - { - UnselectAllVariables(); - watchVars.ForEach(watchVar => watchVar.ToggleHighlighted()); - } - else if (isNumberHeld) - { - UnselectAllVariables(); - Color? color = ColorUtilities.GetColorForHighlight(); - watchVars.ForEach(watchVar => watchVar.ToggleHighlighted(color)); - } - else if (isLKeyHeld) - { - var memoryDescriptorView = watchVars.FirstOrDefault()?.view as NamedVariableCollection.IMemoryDescriptorView; - if (memoryDescriptorView != null) - { - UnselectAllVariables(); - memoryDescriptorView.describedMemoryState.ToggleLocked(null); - } - } - else if (isDKeyHeld) - { - UnselectAllVariables(); - watchVars.ForEach(watchVar => watchVar.WatchVarWrapper.ToggleDisplay()); - } - else if (isCKeyHeld) - { - UnselectAllVariables(); - watchVars.Last().WatchVarWrapper.ShowControllerForm(); - } - else if (isBKeyHeld) - { - UnselectAllVariables(); - watchVars.Last().WatchVarWrapper.ShowBitForm(); - } - else if (isDeletishKeyHeld) - { - UnselectAllVariables(); - RemoveVariables(watchVars); - } - else if (isBacktickHeld) - { - UnselectAllVariables(); - AddToVarHackTab(watchVars); - } - else if (isZHeld) - { - UnselectAllVariables(); - watchVars.ForEach(watchVar => watchVar.SetValue(0)); - } - else if (isXKeyHeld) - { - BeginMoveSelected(); - } - else if (isQKeyHeld) - { - UnselectAllVariables(); - Color? newColor = ColorUtilities.GetColorFromDialog(watchVars.First().BaseColor); - if (newColor.HasValue) - { - watchVars.ForEach(watchVar => watchVar.BaseColor = newColor.Value); - ColorUtilities.LastCustomColor = newColor.Value; - } - } - else if (isOKeyHeld) - { - UnselectAllVariables(); - watchVars.ForEach(watchVar => watchVar.BaseColor = ColorUtilities.LastCustomColor); - } - } - - void AddToVarHackTab(List watchVars) - { - foreach (var watchVar in watchVars) - watchVar.FlashColor(WatchVariableControl.ADD_TO_VAR_HACK_TAB_COLOR); - MessageBox.Show("This feature is currently not implemented :("); - } - - public void DeferredInitialize() - { - foreach (var action in deferredActions) - action.Invoke(); - deferredActions.Clear(); - } - - private void DeferActionToUpdate(string name, Action action) - { - deferredActions.Add(action); - } - - private static int numDummies = 0; - - private static NamedVariableCollection.CustomView CreateDummyVariable() where T : struct, IConvertible - { - T capturedValue = default(T); - - return new NamedVariableCollection.CustomView(WatchVariableUtilities.GetWrapperType(typeof(T))) - { - Name = $"Dummy {++numDummies} {StringUtilities.Capitalize(typeof(T).Name)}", - _getterFunction = () => capturedValue.Yield(), - _setterFunction = (T value) => - { - capturedValue = value; - return true.Yield(); - } - }; - } - - private void ShowContextMenu() - { - ToolStripMenuItem resetVariablesItem = new ToolStripMenuItem("Reset Variables"); - resetVariablesItem.Click += (sender, e) => ResetVariables(); - - ToolStripMenuItem clearAllButHighlightedItem = new ToolStripMenuItem("Clear All But Highlighted"); - clearAllButHighlightedItem.Click += (sender, e) => ClearAllButHighlightedVariables(); - - ToolStripMenuItem addCustomVariablesItem = new ToolStripMenuItem("Add Custom Variables"); - addCustomVariablesItem.Click += (sender, e) => - { - VariableCreationForm form = new VariableCreationForm(); - form.Initialize(this); - form.Show(); - }; - - ToolStripMenuItem addMappingVariablesItem = new ToolStripMenuItem("Add Mapping Variables"); - addMappingVariablesItem.Click += (sender, e) => AddVariables(MappingConfig.GetVariables()); - - ToolStripMenuItem addDummyVariableItem = new ToolStripMenuItem("Add Dummy Variable..."); - foreach (string typeString in TypeUtilities.InGameTypeList) - { - ToolStripMenuItem typeItem = new ToolStripMenuItem(typeString); - addDummyVariableItem.DropDownItems.Add(typeItem); - typeItem.Click += (sender, e) => - { - int numEntries = 1; - if (GlobalKeyboard.IsCtrlDown()) - { - string numEntriesString = DialogUtilities.GetStringFromDialog(labelText: "Enter Num Vars:"); - if (numEntriesString == null) return; - int parsed = ParsingUtilities.ParseInt(numEntriesString); - parsed = Math.Max(parsed, 0); - numEntries = parsed; - } - - for (int i = 0; i < numEntries; i++) - { - Type type = TypeUtilities.StringToType[typeString]; - var view = (NamedVariableCollection.CustomView)typeof(WatchVariablePanel) - .GetMethod(nameof(CreateDummyVariable), BindingFlags.NonPublic | BindingFlags.Static) - .MakeGenericMethod(type) - .Invoke(null, Array.Empty()); - AddVariable(view); - } - }; - } - - ToolStripMenuItem addRelativeVariablesItem = null, removePointVariableItem = null; - var getSpecialFuncVars = getSpecialFuncWatchVariables?.Invoke() ?? null; - var specificsCount = getSpecialFuncVars?.Count() ?? 0; - if (PositionAngle.HybridPositionAngle.pointPAs.Count > 0) - { - if (getSpecialFuncVars != null && specificsCount > 0) - { - void BindHandler(ToolStripMenuItem menuItem, PositionAngle.HybridPositionAngle targetPA, SpecialFuncWatchVariables generator) => - menuItem.Click += (_, __) => AddVariables(generator(targetPA)); - - addRelativeVariablesItem = new ToolStripMenuItem("Add relative variables for..."); - if (specificsCount == 1) - addRelativeVariablesItem.Text = $"Add {getSpecialFuncVars.First().name} for..."; - foreach (var pa in PositionAngle.HybridPositionAngle.pointPAs) - { - var paItem = new ToolStripMenuItem(pa.name); - if (specificsCount == 1) - BindHandler(paItem, pa, getSpecialFuncVars.First().generateVariables); - else - foreach (var specialFunc in getSpecialFuncVars) - { - var specificsItem = new ToolStripMenuItem(specialFunc.name); - BindHandler(specificsItem, pa, specialFunc.generateVariables); - paItem.DropDownItems.Add(specificsItem); - } - - addRelativeVariablesItem.DropDownItems.Add(paItem); - } - } - - removePointVariableItem = new ToolStripMenuItem("Remove custom point ..."); - foreach (var customPA in PositionAngle.HybridPositionAngle.pointPAs) - { - var capture = customPA; - var subElement = new ToolStripMenuItem(customPA.name); - subElement.Click += (_, __) => - { - capture.first = () => PositionAngle.NaN; - capture.second = () => PositionAngle.NaN; - capture.OnDelete(); - PositionAngle.HybridPositionAngle.pointPAs.Remove(capture); - }; - removePointVariableItem.DropDownItems.Add(subElement); - } - } - - var addPointVariableItem = new ToolStripMenuItem("Add custom point..."); - addPointVariableItem.Click += (_, __) => - { - var ptCount = 1; - while (PositionAngle.HybridPositionAngle.pointPAs.Any(pa => pa.name.ToLower() == $"point{ptCount}")) - ptCount++; - var newName = DialogUtilities.GetStringFromDialog($"Point{ptCount}", "Enter name of new custom point", "Add custom point"); - if (newName?.Trim() != null) - PositionAngle.HybridPositionAngle.pointPAs.Add( - new PositionAngle.HybridPositionAngle(() => PositionAngle.Mario, () => PositionAngle.Mario, newName)); - }; - - ToolStripMenuItem openSaveClearItem = new ToolStripMenuItem("Open / Save / Clear ..."); - ControlUtilities.AddDropDownItems( - openSaveClearItem, - new List() { "Restore", "Open", "Open as Pop Out", "Save in Place", "Save As", "Clear" }, - new List() - { - () => OpenVariables(DialogUtilities.OpenXmlElements(FileType.StroopVariables, _dataPath)), - () => OpenVariables(), - () => OpenVariablesAsPopOut(), - () => SaveVariablesInPlace(), - () => SaveVariables(), - () => ClearVariables(), - }); - - ToolStripMenuItem doToAllVariablesItem = new ToolStripMenuItem("Do to all variables..."); - WatchVariableSelectionUtilities.CreateSelectionToolStripItems(GetCurrentVariableControls(), this) - .ForEach(item => doToAllVariablesItem.DropDownItems.Add(item)); - - filterVariablesItem.DropDown.MouseEnter += (sender, e) => { filterVariablesItem.DropDown.AutoClose = false; }; - filterVariablesItem.DropDown.MouseLeave += (sender, e) => - { - filterVariablesItem.DropDown.AutoClose = true; - filterVariablesItem.DropDown.Close(); - }; - - ToolStripItem searchVariablesItem = new ToolStripMenuItem("Search variables..."); - searchVariablesItem.Click += (_, __) => (FindForm() as StroopMainForm)?.ShowSearchDialog(); - - var strip = new ContextMenuStrip(); - strip.Items.Add(resetVariablesItem); - strip.Items.Add(clearAllButHighlightedItem); - strip.Items.Add(new ToolStripSeparator()); - if (addRelativeVariablesItem != null) - strip.Items.Add(addRelativeVariablesItem); - strip.Items.Add(addPointVariableItem); - strip.Items.Add(removePointVariableItem); - strip.Items.Add(addCustomVariablesItem); - strip.Items.Add(addMappingVariablesItem); - strip.Items.Add(addDummyVariableItem); - strip.Items.Add(new ToolStripSeparator()); - strip.Items.Add(openSaveClearItem); - strip.Items.Add(doToAllVariablesItem); - strip.Items.Add(filterVariablesItem); - strip.Items.Add(searchVariablesItem); - if (customContextMenuItems.Count > 0) - { - strip.Items.Add(new ToolStripSeparator()); - foreach (var item in customContextMenuItems) - strip.Items.Add(item); - } - - strip.Show(System.Windows.Forms.Cursor.Position); - } - - private ToolStripMenuItem CreateFilterItem(string varGroup) - { - ToolStripMenuItem item = new ToolStripMenuItem(varGroup.ToString()); - item.Click += (sender, e) => ToggleVarGroupVisibility(varGroup); - return item; - } - - public void BeginMoveSelected() - { - _reorderingWatchVarControls.Clear(); - _reorderingWatchVarControls.AddRange(_selectedWatchVarControls.Where(v => !_hiddenSearchResults.Contains(v))); - } - - private void ToggleVarGroupVisibility(string varGroup, bool? newVisibilityNullable = null) - { - // Toggle visibility if no visibility is provided - bool newVisibility = newVisibilityNullable ?? !_visibleGroups.Contains(varGroup); - if (newVisibility) // change to visible - _visibleGroups.Add(varGroup); - else // change to hidden - _visibleGroups.Remove(varGroup); - UpdateControlsBasedOnFilters(); - UpdateFilterItemCheckedStatuses(); - } - - private void UpdateFilterItemCheckedStatuses() - { - if (_allGroups.Count != _filteringDropDownItems.Count) throw new ArgumentOutOfRangeException(); - - for (int i = 0; i < _allGroups.Count; i++) - _filteringDropDownItems[i].Checked = _visibleGroups.Contains(_allGroups[i]); - } - - private void UpdateControlsBasedOnFilters() - { - _shownWatchVarControls.Clear(); - foreach (var shownVar in _allWatchVarControls.Where(_ => ShouldShow(_))) - _shownWatchVarControls.Add(shownVar); - - filterVariablesItem.DropDownItems.Clear(); - _filteringDropDownItems = _allGroups.ConvertAll(varGroup => CreateFilterItem(varGroup)); - UpdateFilterItemCheckedStatuses(); - _filteringDropDownItems.ForEach(item => filterVariablesItem.DropDownItems.Add(item)); - } - - public WatchVariableControl AddVariable(NamedVariableCollection.IView view) => - AddVariables(new[] { view }).First(); - - public IEnumerable AddVariables(IEnumerable watchVars) - { - if (!initialized) - DeferredInitialize(); - - var lst = new List(); - foreach (var view in watchVars) - { - var newControl = new WatchVariableControl(this, view); - lst.Add(newControl); - _allWatchVarControls.Add(newControl); - if (ShouldShow(newControl)) _shownWatchVarControls.Add(newControl); - } - - return lst; - } - - public void RemoveVariable(WatchVariableControl watchVarControl) => - RemoveVariables(new List() { watchVarControl }); - - public void RemoveVariables(IEnumerable watchVarControls) - { - foreach (WatchVariableControl watchVarControl in watchVarControls) - { - _reorderingWatchVarControls.Remove(watchVarControl); - _allWatchVarControls.Remove(watchVarControl); - _shownWatchVarControls.Remove(watchVarControl); - } - } - - public void RemoveVariableGroup(string varGroup) - { - List watchVarControls = - _allWatchVarControls.FindAll( - watchVarControl => watchVarControl.BelongsToGroup(varGroup)); - RemoveVariables(watchVarControls); - } - - public void ShowOnlyVariableGroup(string visibleVarGroup) => ShowOnlyVariableGroups(new List() { visibleVarGroup }); - - public void ShowOnlyVariableGroups(List visibleVarGroups) - { - foreach (string varGroup in _allGroups) - { - bool newVisibility = visibleVarGroups.Contains(varGroup); - ToggleVarGroupVisibility(varGroup, newVisibility); - } - } - - public void ClearVariables() - { - List watchVarControlListCopy = - new List(_allWatchVarControls); - RemoveVariables(watchVarControlListCopy); - } - - public void ClearAllButHighlightedVariables() - { - List nonHighlighted = - _allWatchVarControls.FindAll(control => !control.Highlighted); - RemoveVariables(nonHighlighted); - _allWatchVarControls.ForEach(control => control.Highlighted = false); - } - - private void ResetVariables() - { - ClearVariables(); - _visibleGroups.Clear(); - _visibleGroups.AddRange(_initialVisibleGroups); - UpdateFilterItemCheckedStatuses(); - - List views = _varFilePath == null - ? new List() - : XmlConfigParser.OpenWatchVariableControlPrecursors(_varFilePath); - AddVariables(views); - } - - public void UnselectAllVariables() - { - foreach (var control in _selectedWatchVarControls) - control.IsSelected = false; - _selectedWatchVarControls.Clear(); - } - - private List GetCurrentVarXmlElements(bool useCurrentState = true) => - GetCurrentVariableControls().ConvertAll(control => control.ToXml(useCurrentState)); - - public void OpenVariables() - { - List elements = DialogUtilities.OpenXmlElements(FileType.StroopVariables); - OpenVariables(elements); - } - - public void OpenVariablesAsPopOut() - { - List elements = DialogUtilities.OpenXmlElements(FileType.StroopVariables); - if (elements.Count == 0) return; - VariablePopOutForm form = new VariablePopOutForm(); - form.Initialize(elements.ConvertAndRemoveNull(element => NamedVariableCollection.ParseXml(element))); - form.ShowForm(); - } - - public void OpenVariables(List elements) - { - AddVariables(elements.ConvertAll(element => NamedVariableCollection.ParseXml(element))); - } - - public void SaveVariablesInPlace() - { - if (_varFilePath == null) return; - if (!DialogUtilities.AskQuestionAboutSavingVariableFileInPlace()) return; - SaveVariables(_varFilePath); - } - - public void SaveVariables(string fileName = null) - { - DialogUtilities.SaveXmlElements(FileType.StroopVariables, "VarData", GetCurrentVarXmlElements(), fileName); - } - - public List GetCurrentVariableControls() - { - var lst = new List(_shownWatchVarControls); - lst.AddRange(_hiddenSearchResults); - return lst; - } - - public IEnumerable GetCurrentVariablePrecursors() - => GetCurrentVariableControls().ConvertAndRemoveNull(control => (control.view as NamedVariableCollection.IMemoryDescriptorView)?.memoryDescriptor); - - public List GetCurrentVariableValues() => - GetCurrentVariableControls().ConvertAll(control => control.WatchVarWrapper.GetValueText()); - - public List GetCurrentVariableNames() => GetCurrentVariableControls().ConvertAll(control => control.VarName); - - public bool SetVariableValueByName(string name, T value) where T : IConvertible - { - WatchVariableControl control = GetCurrentVariableControls().FirstOrDefault(c => c.VarName == name); - if (control == null) return false; - return control.SetValue(value); - } - - public NamedVariableCollection.IView[] GetWatchVariablesByName(params string[] names) => - GetWatchVariableControlsByName(names).Select(x => x?.view ?? null).ToArray(); - - public WatchVariableControl[] GetWatchVariableControlsByName(params string[] names) - { - var result = new WatchVariableControl[names.Length]; - foreach (var var in _allWatchVarControls) - { - var index = Array.IndexOf(names, var.view.Name); - if (index != -1) - result[index] = var; - } - - return result; - } - - public void UpdatePanel() - { - if (SavedSettingsConfig.WatchVarPanelFontOverride.value != null) - Font = SavedSettingsConfig.WatchVarPanelFontOverride; - else if (Font != SystemFonts.DefaultFont) - Font = SystemFonts.DefaultFont; - - var searchForm = (FindForm() as StroopMainForm)?.searchVariableDialog ?? null; - _hiddenSearchResults.Clear(); - var shownVars = new HashSet(_shownWatchVarControls); - var removeLater = new HashSet(); - foreach (var v in _allWatchVarControls) - { - if (!shownVars.Contains(v)) - { - if (ShouldShow(v)) - _shownWatchVarControls.Add(v); - else if (searchForm != null && searchForm.searchHidden && searchForm.IsMatch(v.VarName)) - _hiddenSearchResults.Add(v); - } - else if (!ShouldShow(v)) - removeLater.Add(v); - } - - foreach (var toBeRemoved in removeLater) - _shownWatchVarControls.Remove(toBeRemoved); - GetCurrentVariableControls().ForEach(watchVarControl => watchVarControl.UpdateControl()); - renderer.Draw(); - } - - private bool ShouldShow(WatchVariableControl watchVarControl) - { - if (!hasGroupsSet || watchVarControl.alwaysVisible) - return true; - return watchVarControl.BelongsToAnyGroupOrHasNoGroup(_visibleGroups); - } - - public override string ToString() - { - List varNames = _allWatchVarControls.ConvertAll(control => control.VarName); - return String.Join(",", varNames); - } - - public void ColorVarsUsingFunction(Func getColor) - { - foreach (WatchVariableControl control in _allWatchVarControls) - control.BaseColor = getColor(control); - } - - public int GetAutoHeight(int numColumns = 1) => - (_shownWatchVarControls.Count + numColumns - 1) / numColumns * renderer.elementHeight + renderer.borderMargin * 2; - } -} diff --git a/STROOP/Controls/VariablePanel/WatchVariablePanelRenderer.cs b/STROOP/Controls/VariablePanel/WatchVariablePanelRenderer.cs deleted file mode 100644 index 753c4b650..000000000 --- a/STROOP/Controls/VariablePanel/WatchVariablePanelRenderer.cs +++ /dev/null @@ -1,522 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Windows.Forms; -using OpenTK.Mathematics; -using STROOP.Core.Variables; -using STROOP.Structs.Configurations; -using STROOP.Utilities; - -namespace STROOP.Controls.VariablePanel -{ - partial class WatchVariablePanel - { - class WatchVariablePanelRenderer : Control - { - class OnDemand where T : IDisposable - { - readonly Func factory; - Wrapper disposeContext, invalidateContext; - - public OnDemand(Wrapper disposeContext, Func factory, Wrapper invalidateContext = null) - { - this.factory = factory; - this.disposeContext = disposeContext; - this.invalidateContext = invalidateContext; - if (invalidateContext != null) - invalidateContext.value += InvalidateValue; - } - - T _value; - bool valueCreated = false; - - public T Value - { - get - { - if (!valueCreated) - { - _value = factory(); - valueCreated = true; - disposeContext.value += DisposeValue; - } - - return _value; - } - } - - void InvalidateValue() - { - _value?.Dispose(); - valueCreated = false; - } - - void DisposeValue() - { - disposeContext.value -= DisposeValue; - if (invalidateContext != null) - invalidateContext.value -= InvalidateValue; - _value?.Dispose(); - } - - public static implicit operator T(OnDemand obj) => obj.Value; - } - - class WatchVariableControlRenderData - { - public Vector2 positionInGrid; - public Vector2 positionWhileMoving; - public bool moving = false; - public float nameTextOffset; - public float nameTextLength; - public string lastRenderedNameText; - } - - private static readonly Image _lockedImage = Properties.Resources.img_lock; - private static readonly Image _someLockedImage = Properties.Resources.img_lock_grey; - private static readonly Image _disabledLockImage = Properties.Resources.lock_blue; - private static readonly Image _pinnedImage = Properties.Resources.img_pin; - - private static Image GetLockImageForCheckState(CheckState checkState) - { - Image image; - switch (checkState) - { - case CheckState.Unchecked: - return null; - case CheckState.Checked: - image = _lockedImage; - break; - case CheckState.Indeterminate: - image = _someLockedImage; - break; - default: - throw new ArgumentOutOfRangeException(); - } - - if (LockConfig.LockingDisabled) - image = _disabledLockImage; - return image; - } - - Dictionary renderDatas = new Dictionary(); - - WatchVariableControlRenderData GetRenderData(WatchVariableControl ctrl) - { - WatchVariableControlRenderData result; - if (!renderDatas.TryGetValue(ctrl, out result)) - renderDatas[ctrl] = result = new WatchVariableControlRenderData(); - return result; - } - - static int idleRefreshMilliseconds = 250; - DateTime lastRefreshed; - - delegate void OnDemandCall(); - - Wrapper OnDispose = new Wrapper(), OnInvalidateFonts = new Wrapper(); - - BufferedGraphics bufferedGraphics = null; - - OnDemand boldFont; - OnDemand cellBorderPen, cellSeparatorPen, insertionMarkerPen; - OnDemand rightAlignFormat; - - WatchVariablePanel target; - - public int borderMargin { get; private set; } = 2; - static int elementMarginTopBottom => (int)(uint)SavedSettingsConfig.WatchVarPanelVerticalMargin; - static int elementMarginLeftRight => (int)(uint)SavedSettingsConfig.WatchVarPanelHorizontalMargin; - public int elementHeight => (int)(Font.Height + 2 * elementMarginTopBottom); - - int elementNameWidth => target.elementNameWidth ?? (int)(uint)SavedSettingsConfig.WatchVarPanelNameWidth; - int elementValueWidth => target.elementValueWidth ?? (int)(uint)SavedSettingsConfig.WatchVarPanelValueWidth; - int elementWidth => (int)(elementNameWidth + elementValueWidth); - - public int GetMaxRows() - { - var effectiveHeight = target.Height - borderMargin * 2; - var totalVariableCount = target.GetCurrentVariableControls().Count; - var knolz = Math.Max(1, effectiveHeight / elementHeight); - var numColumnsWithoutScrollbar = totalVariableCount / knolz; - if (totalVariableCount % knolz > 0) - numColumnsWithoutScrollbar++; - if (numColumnsWithoutScrollbar * (SavedSettingsConfig.WatchVarPanelNameWidth + SavedSettingsConfig.WatchVarPanelValueWidth) > - target.ClientRectangle.Width - 2 * borderMargin) - effectiveHeight -= SystemInformation.HorizontalScrollBarHeight; - return Math.Max(1, effectiveHeight / elementHeight); - } - - public WatchVariablePanelRenderer(WatchVariablePanel target) - { - this.target = target; - boldFont = new OnDemand( - OnDispose, - () => Font.FontFamily.IsStyleAvailable(FontStyle.Bold) ? new Font(Font, FontStyle.Bold) : Font, - OnInvalidateFonts); - - cellBorderPen = new OnDemand(OnDispose, () => new Pen(Color.Gray, 2)); - cellSeparatorPen = new OnDemand(OnDispose, () => new Pen(Color.Gray, 1)); - insertionMarkerPen = new OnDemand(OnDispose, () => new Pen(Color.Blue, 3)); - rightAlignFormat = new OnDemand(OnDispose, () => new StringFormat() { Alignment = StringAlignment.Far }); - } - - protected override void OnPaint(PaintEventArgs e) - { - base.OnPaint(e); - bufferedGraphics.Render(e.Graphics); - } - - public void Draw() - { - //Return if not focused and recently enough refreshed to save CPU - var form = FindForm(); - if (form != Form.ActiveForm && (DateTime.Now - lastRefreshed).TotalMilliseconds < idleRefreshMilliseconds) - return; - - var displayedWatchVars = target.GetCurrentVariableControls(); - var varNameFont = SavedSettingsConfig.WatchVarPanelBoldNames ? boldFont : Font; - - lastRefreshed = DateTime.Now; - var searchForm = (form as StroopMainForm)?.searchVariableDialog; - bool SearchHighlight(string text) => searchForm?.IsMatch(text) ?? false; - - int maxRows = GetMaxRows(); - var newRect = new Rectangle(0, 0, ((displayedWatchVars.Count - 1) / maxRows + 1) * elementWidth + borderMargin * 2, maxRows * elementHeight + borderMargin * 2); - if (bufferedGraphics == null || Bounds.Width != newRect.Width || Bounds.Height != newRect.Height) - { - bufferedGraphics?.Dispose(); - target.HorizontalScroll.Value = 0; - Bounds = newRect; - bufferedGraphics = BufferedGraphicsManager.Current.Allocate(CreateGraphics(), new Rectangle(0, 0, ClientRectangle.Width, ClientRectangle.Height)); - bufferedGraphics.Graphics.TranslateTransform(borderMargin, borderMargin); - } - - var g = bufferedGraphics.Graphics; - var visibleRegion = new Rectangle( - target.HorizontalScroll.Value - borderMargin, - -borderMargin, - target.ClientRectangle.Width, - target.ClientRectangle.Height); - - void DrawLockAndFixImages(WatchVariableControl ctrl, int baseX, int baseY) - { - // TODO: work out locking feature - //var lockImg = GetLockImageForCheckState(ctrl.view.HasLocks()); - var xCoord = baseX + 2; - var iconHeight = elementHeight - elementMarginTopBottom * 2; - //if (lockImg != null) - //{ - // var iconWidth = (int)(iconHeight * (lockImg.Width / (float)lockImg.Height)); - // g.DrawImage(lockImg, - // new Rectangle( - // xCoord, - // baseY + elementMarginTopBottom, - // iconWidth, - // iconHeight) - // ); - // xCoord += iconWidth + 2; - //} - if (ctrl.view is NamedVariableCollection.IMemoryDescriptorView memoryDescriptorView && memoryDescriptorView.describedMemoryState.fixedAddresses) - g.DrawImage(_pinnedImage, - new Rectangle( - xCoord, - baseY + elementMarginTopBottom, - (int)(iconHeight * (_pinnedImage.Width / (float)_pinnedImage.Height)), - iconHeight) - ); - } - - void DrawGrid() - { - int x = 0, y = 0; - int iterator = 0; - var lastColumn = -1; - if (maxRows == 0) - return; - - var cursorPos = PointToClient(Cursor.Position); - cursorPos.X -= borderMargin; - cursorPos.Y -= borderMargin; - - void ResetIterators() - { - iterator = 0; - lastColumn = -1; - } - - void GetColumn(int offset, int width, bool clip = true) - { - y = iterator % maxRows; - x = iterator / maxRows; - if (x > lastColumn) - { - lastColumn = x; - if (clip) - g.Clip = new Region(new Rectangle(x * elementWidth + offset, 0, width, Height)); - } - - iterator++; - } - - g.ResetClip(); - ResetIterators(); - foreach (var ctrl in displayedWatchVars) - { - var ctrlData = GetRenderData(ctrl); - - GetColumn(0, elementNameWidth, false); - var yCoord = y * elementHeight; - ctrlData.positionInGrid = new Vector2(x * elementWidth, yCoord); - if (!ctrlData.moving) - ctrlData.positionWhileMoving = ctrlData.positionInGrid; - - //Skip if invisible - if (x * elementWidth > visibleRegion.Right || - (x + 1) * elementWidth < visibleRegion.Left || - yCoord > visibleRegion.Bottom || - yCoord + elementHeight < visibleRegion.Top) - continue; - - var c = ctrl.IsSelected ? Color.Blue : ctrl.currentColor; - if (c != Parent.BackColor) - using (var brush = new SolidBrush(c)) - g.FillRectangle(brush, x * elementWidth, yCoord, elementWidth, elementHeight); - } - - ResetIterators(); - foreach (var ctrl in displayedWatchVars) - { - GetColumn(0, elementNameWidth); - var yCoord = y * elementHeight; - - //Skip if invisible - if (x * elementWidth > visibleRegion.Right || - x * elementWidth + elementNameWidth < visibleRegion.Left || - yCoord > visibleRegion.Bottom || - yCoord + elementHeight < visibleRegion.Top) - continue; - - var txtPoint = new Point(x * elementWidth + elementMarginLeftRight, yCoord + elementMarginTopBottom); - var ctrlData = GetRenderData(ctrl); - - if (cursorPos.Y > yCoord && cursorPos.Y < yCoord + elementHeight && - cursorPos.X > x * elementWidth && cursorPos.X < x * elementWidth + elementNameWidth) //Cursor is hovering over the name field - { - if (ctrlData.lastRenderedNameText != ctrl.VarName) - { - var tmp = g.PageUnit; - g.PageUnit = GraphicsUnit.Pixel; - ctrlData.nameTextLength = g.MeasureString(ctrl.VarName, varNameFont).Width; - g.PageUnit = tmp; - ctrlData.lastRenderedNameText = ctrl.VarName; - } - - var overEdge = ctrlData.nameTextLength - (elementNameWidth - elementMarginLeftRight * 2); - if (overEdge > 0) - { - ctrlData.nameTextOffset += (float)Config.Stream.lastFrameTime * elementHeight; - if (ctrlData.nameTextOffset > overEdge + elementHeight * 2) - ctrlData.nameTextOffset = 0; - txtPoint.X -= (int)Math.Max(0, Math.Min(overEdge, ctrlData.nameTextOffset - elementHeight)); - } - } - else - ctrlData.nameTextOffset = 0; - - g.DrawString(ctrl.VarName, varNameFont, ctrl.IsSelected ? Brushes.White : Brushes.Black, txtPoint); - } - - ResetIterators(); - foreach (var ctrl in displayedWatchVars) - { - GetColumn(elementNameWidth, elementValueWidth); - - //Skip if invisible - var yCoord = y * elementHeight; - if (x * elementWidth + elementNameWidth > visibleRegion.Right || - (x + 1) * elementWidth < visibleRegion.Left || - yCoord > visibleRegion.Bottom || - yCoord + elementHeight < visibleRegion.Top) - continue; - - if (ctrl.WatchVarWrapper.CustomDrawOperation != null) - ctrl.WatchVarWrapper.CustomDrawOperation(g, - new Rectangle( - x * elementWidth + elementNameWidth, - y * elementHeight, - elementValueWidth, - elementHeight)); - else - { - var txtPoint = new Point((x + 1) * elementWidth - elementMarginLeftRight, yCoord + elementMarginTopBottom); - g.DrawString(ctrl.WatchVarWrapper.GetValueText(), Font, ctrl.IsSelected ? Brushes.White : Brushes.Black, txtPoint, rightAlignFormat); - } - - DrawLockAndFixImages(ctrl, x * elementWidth + elementNameWidth, yCoord); - } - - g.ResetClip(); - - var numRows = x == 0 ? (y + 1) : maxRows; - var maxY = numRows * elementHeight; - var maxX = elementWidth * (x + 1); - - if (y == maxRows - 1) - x++; - for (int dx = 0; dx <= x; dx++) - { - var xCoord = dx * elementWidth; - g.DrawLine(cellBorderPen, xCoord, 0, xCoord, maxY); - xCoord += elementNameWidth; - if (dx < x) - g.DrawLine(cellSeparatorPen, xCoord, 0, xCoord, maxY); - } - - if (y != maxRows - 1) - { - var yCoord = (y + 1) * elementHeight; - g.DrawLine(cellBorderPen, maxX, 0, maxX, yCoord); - var xCoord = maxX - elementWidth + elementNameWidth; - g.DrawLine(cellSeparatorPen, xCoord, 0, xCoord, yCoord); - } - - for (int dy = 0; dy <= numRows; dy++) - { - var yCoord = dy * elementHeight; - g.DrawLine(cellBorderPen, 0, yCoord, dy <= (y + 1) ? maxX : maxX - elementWidth, yCoord); - } - - ResetIterators(); - using (var highlightBrush = new SolidBrush(Color.FromArgb(0x40, Color.Blue))) - { - foreach (var ctrl in displayedWatchVars) - { - GetColumn(elementNameWidth, elementValueWidth, false); - if (ctrl.Highlighted) - using (var pen = new Pen(ctrl.HighlightColor, 3)) - g.DrawRectangle(pen, x * elementWidth, y * elementHeight, elementWidth, elementHeight); - if (SearchHighlight(ctrl.VarName)) - g.FillRectangle(highlightBrush, x * elementWidth + 2, y * elementHeight + 2, elementWidth - 4, elementHeight - 4); - } - } - } - - void DrawMovingVariables() - { - if (target._reorderingWatchVarControls.Count == 0) - return; - - var pt = PointToClient(Cursor.Position); - var cursorPosition = new Vector2(pt.X, pt.Y); - (var insertionIndex, _, _) = GetVariableAt(pt); - if (insertionIndex < 0) - insertionIndex = displayedWatchVars.Count; - var x = insertionIndex / maxRows; - var y = insertionIndex % maxRows; - g.DrawLine(insertionMarkerPen, x * elementWidth, y * elementHeight, (x + 1) * elementWidth, y * elementHeight); - - int i = 0; - foreach (var ctrl in target._reorderingWatchVarControls) - { - var ctrlData = GetRenderData(ctrl); - using (var brush = new SolidBrush(ctrl.currentColor)) - { - g.FillRectangle(brush, ctrlData.positionWhileMoving.X, ctrlData.positionWhileMoving.Y, elementWidth, elementHeight); - } - - var yCoord = (int)ctrlData.positionWhileMoving.Y + elementMarginTopBottom; - - - g.Clip = new Region( - new Rectangle( - (int)ctrlData.positionWhileMoving.X, - (int)ctrlData.positionWhileMoving.Y, - elementNameWidth, - elementHeight)); - var txtPoint = new Point((int)ctrlData.positionWhileMoving.X + elementMarginLeftRight, yCoord + elementMarginTopBottom); - g.DrawString(ctrl.VarName, varNameFont, Brushes.Black, txtPoint); - - var valueX = (int)ctrlData.positionWhileMoving.X + elementNameWidth; - g.Clip = new Region( - new Rectangle( - valueX, - (int)ctrlData.positionWhileMoving.Y, - elementValueWidth, - elementHeight)); - txtPoint = new Point((int)ctrlData.positionWhileMoving.X + elementWidth - elementMarginLeftRight, yCoord + elementMarginTopBottom); - g.DrawString(ctrl.WatchVarWrapper.GetValueText(), Font, Brushes.Black, txtPoint, rightAlignFormat); - DrawLockAndFixImages(ctrl, valueX, yCoord); - - g.ResetClip(); - - var xCoord = (int)ctrlData.positionWhileMoving.X + elementNameWidth; - g.DrawLine(cellSeparatorPen, xCoord, yCoord, xCoord, yCoord + elementHeight); - g.DrawRectangle(cellBorderPen, ctrlData.positionWhileMoving.X, ctrlData.positionWhileMoving.Y, elementWidth, elementHeight); - - var target = cursorPosition; - target.Y += elementHeight * i++; - ctrlData.positionWhileMoving += (target - ctrlData.positionWhileMoving) * Utilities.MoreMath.EaseIn(10 * (float)Structs.Configurations.Config.Stream.lastFrameTime); - if ((ctrlData.positionInGrid - ctrlData.positionWhileMoving).LengthSquared < 1) - ctrlData.moving = false; - else - ctrlData.moving = true; - } - } - - g.Clear(Parent.BackColor); - DrawGrid(); - DrawMovingVariables(); - - if (Controls.Count == 0) - bufferedGraphics.Render(); - } - - public Rectangle GetVariableControlBounds(int index) - { - var maxRows = GetMaxRows(); - var x = index / maxRows; - var y = index % maxRows; - return new Rectangle( - borderMargin + x * elementWidth + elementNameWidth, - borderMargin + y * elementHeight, - elementValueWidth, - elementHeight); - } - - public (int index, WatchVariableControl ctrl, bool select) GetVariableAt(Point location) - { - location.X -= borderMargin; - location.Y -= borderMargin; - if (location.X < 0 || location.Y < 0) - return (-1, null, false); - var x = location.X / elementWidth; - var y = location.Y / elementHeight; - int maxRows = GetMaxRows(); - if (y >= maxRows) - return (-1, null, false); - int index = x * maxRows + y; - if (index < 0) - return (0, null, false); - var displayedWatchVars = target.GetCurrentVariableControls(); - if (index < displayedWatchVars.Count) - return (index, displayedWatchVars[index], (location.X % elementWidth) < elementNameWidth); - - return (-1, null, false); - } - - protected override void Dispose(bool disposing) - { - if (disposing) - OnDispose.value?.DynamicInvoke(); - base.Dispose(disposing); - } - - protected override void OnFontChanged(EventArgs e) - { - base.OnFontChanged(e); - OnInvalidateFonts.value?.DynamicInvoke(); - } - } - } -} diff --git a/STROOP/Controls/VariablePanel/WinFormsVariablePanelUiContext.cs b/STROOP/Controls/VariablePanel/WinFormsVariablePanelUiContext.cs new file mode 100644 index 000000000..8f0d6bed4 --- /dev/null +++ b/STROOP/Controls/VariablePanel/WinFormsVariablePanelUiContext.cs @@ -0,0 +1,22 @@ +using STROOP.Variables.VariablePanel; +using System.Drawing; +using System.Windows.Forms; + +namespace STROOP.Controls.VariablePanel; + +public class WinFormsVariablePanelUiContext(Control parent, Graphics graphics, Rectangle drawRegion) : IUiContext +{ + public readonly Control parent = parent; + public readonly Graphics graphics = graphics; + public Rectangle drawRegion = drawRegion; + + public IValueEditBox CreateValueBox(string lastValue) + { + var textEditBox = new VariablePanelValueEditBox(); + textEditBox.Text = lastValue; + textEditBox.Bounds = drawRegion; + parent.Controls.Add(textEditBox); + textEditBox.Focus(); + return textEditBox; + } +} diff --git a/STROOP/Controls/VariablePanel/Wrappers/WatchVariableAddressWrapper.cs b/STROOP/Controls/VariablePanel/Wrappers/WatchVariableAddressWrapper.cs deleted file mode 100644 index c68d8e11f..000000000 --- a/STROOP/Controls/VariablePanel/Wrappers/WatchVariableAddressWrapper.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System.Linq; -using STROOP.Core.Variables; -using STROOP.Structs.Configurations; -using STROOP.Utilities; -using STROOP.Structs; - -namespace STROOP.Controls.VariablePanel -{ - public class WatchVariableAddressWrapper : WatchVariableNumberWrapper - { - static WatchVariableSetting ViewAddressSetting = new WatchVariableSetting( - "View Address", - (ctrl, obj) => - { - if (ctrl.WatchVarWrapper is WatchVariableAddressWrapper addressWrapper) - { - uint uintValue = (uint)addressWrapper.view._getterFunction().FirstOrDefault(); - if (uintValue == 0) return false; - if (ObjectUtilities.IsObjectAddress(uintValue)) - AccessScope.content.GetTab().SetObjectAddress(uintValue); - else - AccessScope.content.GetTab().SetCustomAddress(uintValue); - Config.TabControlMain.SelectedTab = Config.TabControlMain.TabPages["tabPageMemory"]; - } - - return false; - }); - - public WatchVariableAddressWrapper(NamedVariableCollection.IView watchVar, WatchVariableControl watchVarControl) - : base(watchVar.WithKeyedValue(NamedVariableCollection.ViewProperties.useHex, true), watchVarControl) - { - AddAddressContextMenuStripItems(); - } - - private void AddAddressContextMenuStripItems() - { - _watchVarControl.AddSetting(ViewAddressSetting); - } - - public override string GetClass() => "Address"; - } -} diff --git a/STROOP/Controls/VariablePanel/Wrappers/WatchVariableBooleanWrapper.cs b/STROOP/Controls/VariablePanel/Wrappers/WatchVariableBooleanWrapper.cs deleted file mode 100644 index 94157ac66..000000000 --- a/STROOP/Controls/VariablePanel/Wrappers/WatchVariableBooleanWrapper.cs +++ /dev/null @@ -1,153 +0,0 @@ -using System; -using System.Drawing; -using System.Windows.Forms; -using STROOP.Core.Variables; -using STROOP.Utilities; - -namespace STROOP.Controls.VariablePanel -{ - public abstract class WatchVariableBooleanWrapperBase : WatchVariableWrapper - { - public static readonly WatchVariableSetting DisplayAsCheckboxSetting = new WatchVariableSetting( - "Boolean: Display as Checkbox", - CreateBoolWithDefault>((wrapper, val) => wrapper._displayAsCheckbox = val, wrapper => wrapper._displayAsCheckbox), - ("Default", () => true, WrapperProperty>(wr => wr._displayAsCheckbox == true)), - ("Display as Checkbox", () => true, WrapperProperty>(wr => wr._displayAsCheckbox)), - ("Don't display as Checkbox", () => false, WrapperProperty>(wr => !wr._displayAsCheckbox)) - ); - - public static readonly WatchVariableSetting DisplayAsInverted = new WatchVariableSetting( - "Boolean: Display as Inverted", - CreateBoolWithDefault>((wrapper, val) => wrapper._displayAsInverted = val, wrapper => wrapper._displayAsInverted), - ("Default", () => false, WrapperProperty>(wr => wr._displayAsInverted == false)), - ("Display as Inverted", () => true, WrapperProperty>(wr => wr._displayAsInverted)), - ("Don't display as Inverted", () => false, WrapperProperty>(wr => !wr._displayAsInverted)) - ); - - private bool _displayAsCheckbox; - private bool _displayAsInverted; - - protected abstract T falseValue { get; } - protected abstract T trueValue { get; } - - public override void SingleClick(Control parent, Rectangle bounds) - { - if (_displayAsCheckbox) - Edit(parent, bounds); - } - - public override void DoubleClick(Control parent, Rectangle bounds) - { - if (!_displayAsCheckbox) - Edit(parent, bounds); - } - - public WatchVariableBooleanWrapperBase(NamedVariableCollection.IView watchVar, WatchVariableControl watchVarControl) - : base(watchVar, watchVarControl) - { - _displayAsCheckbox = true; - if (bool.TryParse(watchVarControl.view.GetValueByKey(NamedVariableCollection.ViewProperties.invertBool), out var invertBool)) - _displayAsInverted = invertBool; - else - _displayAsInverted = false; - - AddBooleanContextMenuStripItems(); - } - - private void AddBooleanContextMenuStripItems() - { - _watchVarControl.AddSetting(DisplayAsCheckboxSetting); - _watchVarControl.AddSetting(DisplayAsInverted); - } - - public override WatchVariablePanel.CustomDraw CustomDrawOperation => _displayAsCheckbox ? DrawCheckbox : (WatchVariablePanel.CustomDraw)null; - - public override sealed void Edit(Control parent, Rectangle bounds) - { - if (_displayAsCheckbox) - { - if (lastValueMeaning != CombinedValuesMeaning.SameValue) - nextValue = falseValue; - else - nextValue = lastValue.Equals(falseValue) ? trueValue : falseValue; - } - else - base.Edit(parent, bounds); - } - - void DrawCheckbox(Graphics g, Rectangle rect) - { - var combinedValues = CombineValues(); - CheckState state; - if (combinedValues.meaning != CombinedValuesMeaning.SameValue) - state = CheckState.Indeterminate; - else - state = (Convert.ToDecimal(combinedValues.value) != 0 ^ _displayAsInverted) ? CheckState.Checked : CheckState.Unchecked; - - Image checkboxImage; - switch (state) - { - case CheckState.Checked: - checkboxImage = Properties.Resources.checkbox_checked; - break; - case CheckState.Unchecked: - checkboxImage = Properties.Resources.checkbox_unchecked; - break; - default: - checkboxImage = Properties.Resources.checkbox_indeterminate; - break; - } - - var margin = 2; - var imgHeight = rect.Height - margin * 2; - g.DrawImage(checkboxImage, rect.Right - imgHeight - margin * 2, rect.Top + margin, imgHeight, imgHeight); - } - - protected CheckState ConvertValueToCheckState(object value) - { - double? doubleValueNullable = ParsingUtilities.ParseDoubleNullable(value); - if (!doubleValueNullable.HasValue) return CheckState.Unchecked; - double doubleValue = doubleValueNullable.Value; - return HandleInverting(doubleValue == 0) ? CheckState.Unchecked : CheckState.Checked; - } - - private bool HandleInverting(bool boolValue) => boolValue != _displayAsInverted; - - public override string GetClass() => "Boolean"; - } - - public class WatchVariableBooleanWrapper : WatchVariableBooleanWrapperBase - { - protected override bool falseValue => false; - - protected override bool trueValue => true; - - public WatchVariableBooleanWrapper(NamedVariableCollection.IView watchVar, WatchVariableControl watchVarControl) - : base(watchVar, watchVarControl) - { - } - - public override bool TryParseValue(string value, out bool result) - => bool.TryParse(value, out result); - - public override string DisplayValue(bool value) => value.ToString(); - } - - public class WatchVariableBooleanWrapper : WatchVariableBooleanWrapperBase where TNumber : struct, IConvertible - { - public WatchVariableBooleanWrapper(NamedVariableCollection.IView watchVar, WatchVariableControl watchVarControl) - : base(watchVar, watchVarControl) - { - } - - private static TNumber MaxValue = (TNumber)typeof(TNumber).GetField(nameof(MaxValue)).GetValue(null); - - protected override TNumber falseValue => (TNumber)Convert.ChangeType(0, typeof(TNumber)); - protected override TNumber trueValue => MaxValue; - - public override bool TryParseValue(string value, out TNumber result) - => ParsingUtilities.TryParseNumber(value, out result); - - public override string DisplayValue(TNumber value) => value.ToString(); - } -} diff --git a/STROOP/Controls/VariablePanel/Wrappers/WatchVariableObjectWrapper.cs b/STROOP/Controls/VariablePanel/Wrappers/WatchVariableObjectWrapper.cs deleted file mode 100644 index 22e4314e5..000000000 --- a/STROOP/Controls/VariablePanel/Wrappers/WatchVariableObjectWrapper.cs +++ /dev/null @@ -1,101 +0,0 @@ -using STROOP.Core.Variables; -using STROOP.Models; -using STROOP.Structs; -using STROOP.Structs.Configurations; -using STROOP.Utilities; - -namespace STROOP.Controls.VariablePanel -{ - public class WatchVariableObjectWrapper : WatchVariableAddressWrapper - { - static WatchVariableSetting DisplayAsObjectSetting = new WatchVariableSetting( - "Display as Object", - (ctrl, obj) => - { - if (ctrl.WatchVarWrapper is WatchVariableObjectWrapper objectWrapper) - if (obj is bool doDisplayAsObject) - objectWrapper._displayAsObject = doDisplayAsObject; - else - return false; - return true; - }, - ("Object", () => true, WrapperProperty(o => o._displayAsObject)), - ("Address", () => true, WrapperProperty(o => !o._displayAsObject)) - ); - - static WatchVariableSetting SelectObjectSetting = new WatchVariableSetting( - "Select Object", - (ctrl, obj) => - { - if (ctrl.WatchVarWrapper is WatchVariableObjectWrapper objectWrapper) - { - var value = objectWrapper.CombineValues(); - if (value.meaning == CombinedValuesMeaning.SameValue) - Config.ObjectSlotsManager.SelectSlotByAddress((uint)value.value); - } - - return false; - }); - - private bool _displayAsObject; - - public WatchVariableObjectWrapper(NamedVariableCollection.IView watchVar, WatchVariableControl watchVarControl) - : base(watchVar, watchVarControl) - { - _displayAsObject = true; - - AddObjectContextMenuStripItems(); - } - - private void AddObjectContextMenuStripItems() - { - _watchVarControl.AddSetting(DisplayAsObjectSetting); - _watchVarControl.AddSetting(SelectObjectSetting); - } - - public override string GetClass() => "Object"; - - public override string DisplayValue(uint value) - { - if (_displayAsObject) - { - uint? uintValueNullable = ParsingUtilities.ParseUIntNullable(value); - if (uintValueNullable.HasValue) - return Config.ObjectSlotsManager.GetDescriptiveSlotLabelFromAddress(uintValueNullable.Value, false); - } - - return base.DisplayValue(value); - } - - public override bool TryParseValue(string value, out uint result) - { - string slotName = value.ToLower(); - - if (slotName == "(no object)" || slotName == "no object") - { - result = 0; - return true; - } - - if (slotName == "(unused object)" || slotName == "unused object") - { - result = ObjectSlotsConfig.UnusedSlotAddress; - return true; - } - - if (slotName.StartsWith("slot")) - { - slotName = slotName.Remove(0, "slot".Length); - slotName = slotName.Trim(); - ObjectDataModel obj = Config.ObjectSlotsManager.GetObjectFromLabel(slotName); - if (obj != null) - { - result = obj.Address; - return true; - } - } - - return base.TryParseValue(value, out result); - } - } -} diff --git a/STROOP/Controls/VariablePanel/Wrappers/WatchVariableSelectionWrapper.cs b/STROOP/Controls/VariablePanel/Wrappers/WatchVariableSelectionWrapper.cs deleted file mode 100644 index 42edc9120..000000000 --- a/STROOP/Controls/VariablePanel/Wrappers/WatchVariableSelectionWrapper.cs +++ /dev/null @@ -1,126 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using System.Windows.Forms; -using STROOP.Core.Variables; -using STROOP.Structs.Configurations; -using STROOP.Utilities; - -namespace STROOP.Controls.VariablePanel -{ - public class WatchVariableSelectionWrapper : WatchVariableWrapper - where TBaseWrapper : WatchVariableWrapper - { - static StringFormat rightAlignFormat = new StringFormat() { Alignment = StringAlignment.Far }; - - public bool DisplaySingleOption = false; - - public List<(string name, Func func)> options = new List<(string, Func)>(); - - TBaseWrapper baseWrapper; - bool isSingleOption => DisplaySingleOption && options.Count == 1; - - (string name, Func getter) selectedOption; - - public WatchVariableSelectionWrapper(NamedVariableCollection.IView var, WatchVariableControl control) : base(var, control) - { - var interfaceType = view.GetType().GetInterfaces().First(x => x.Name == $"{nameof(NamedVariableCollection.IView)}`1"); - baseWrapper = (TBaseWrapper) - typeof(TBaseWrapper) - .GetConstructor(new Type[] { interfaceType, typeof(WatchVariableControl) }) - .Invoke(new object[] { view, control }); - _view.ValueSet += () => selectedOption = (null, null); - } - - public override string GetClass() => $"Selection for {baseWrapper.GetClass()}"; - - public override void UpdateControls() => baseWrapper.UpdateControls(); - - bool IsCursorHovering(Rectangle rect, out Rectangle drawRectangle) - { - int marginX = (int)SavedSettingsConfig.WatchVarPanelHorizontalMargin.value; - int marginY = (int)SavedSettingsConfig.WatchVarPanelVerticalMargin.value; - - Rectangle screenRect; - if (isSingleOption) - { - screenRect = _watchVarControl.containingPanel.RectangleToScreen(rect); - drawRectangle = rect; - } - else - { - var sideLength = rect.Height - marginY * 2; - drawRectangle = new Rectangle(rect.Left + marginX, rect.Top + marginY, sideLength, sideLength); - screenRect = _watchVarControl.containingPanel.RectangleToScreen(drawRectangle); - } - - return Cursor.Position.IsInsideRect(screenRect); - } - - public override void SingleClick(Control parentCtrl, Rectangle bounds) - { - base.SingleClick(parentCtrl, bounds); - if (IsCursorHovering(bounds, out var _)) - { - if (isSingleOption) - view._setterFunction(options[0].func()); - else if (options.Count > 0) - { - var ctx = new ContextMenuStrip(); - foreach (var option_it in options) - { - var option_cap = option_it; - ctx.Items.AddHandlerToItem(option_cap.name, () => SetOption(option_cap)); - } - - ctx.Show(Cursor.Position); - } - } - else - baseWrapper.SingleClick(parentCtrl, bounds); - } - - public override WatchVariablePanel.CustomDraw CustomDrawOperation => (g, rect) => - { - baseWrapper.CustomDrawOperation?.Invoke(g, rect); - - int marginX = (int)SavedSettingsConfig.WatchVarPanelHorizontalMargin.value; - int marginY = (int)SavedSettingsConfig.WatchVarPanelVerticalMargin.value; - - if (isSingleOption) - g.FillRectangle(IsCursorHovering(rect, out var drawRect) ? Brushes.LightSlateGray : Brushes.Gray, drawRect); - - var txtPoint = new Point(rect.Right - marginX, rect.Top + marginY); - g.DrawString(isSingleOption ? options[0].name : GetValueText(), - _watchVarControl.containingPanel.Font, - _watchVarControl.IsSelected ? Brushes.White : Brushes.Black, - txtPoint, - rightAlignFormat); - - if (!isSingleOption) - g.DrawImage(IsCursorHovering(rect, out var drawRect) ? Properties.Resources.dropdown_box_hover : Properties.Resources.dropdown_box, drawRect); - }; - - void SetOption((string name, Func func) option) - { - view._setterFunction(option.func()); - selectedOption = option; - } - - public void SelectOption(int index) => SetOption(options[index]); - - public void UpdateOption(int index) - { - if (selectedOption.Equals(options[index])) - { - view._setterFunction(selectedOption.getter()); - selectedOption = options[index]; - } - } - - public override string DisplayValue(TBackingValue value) => baseWrapper.DisplayValue(value); - - public override bool TryParseValue(string value, out TBackingValue result) => baseWrapper.TryParseValue(value, out result); - } -} diff --git a/STROOP/Controls/VariablePanel/Wrappers/WatchVariableTriangleWrapper.cs b/STROOP/Controls/VariablePanel/Wrappers/WatchVariableTriangleWrapper.cs deleted file mode 100644 index 73be9c516..000000000 --- a/STROOP/Controls/VariablePanel/Wrappers/WatchVariableTriangleWrapper.cs +++ /dev/null @@ -1,33 +0,0 @@ -using STROOP.Core.Variables; -using STROOP.Utilities; - -namespace STROOP.Controls.VariablePanel -{ - public class WatchVariableTriangleWrapper : WatchVariableAddressWrapper - { - static WatchVariableSetting SelectTriangleSetting = new WatchVariableSetting("Select Triangle", (ctrl, _) => - { - if (ctrl.WatchVarWrapper is WatchVariableTriangleWrapper triangleWrapper) - { - var value = triangleWrapper.CombineValues(); - if (value.meaning == CombinedValuesMeaning.SameValue) - AccessScope.content.GetTab().SetCustomTriangleAddresses((uint)value.value); - } - - return false; - }); - - public WatchVariableTriangleWrapper(NamedVariableCollection.IView watchVar, WatchVariableControl watchVarControl) - : base(watchVar, watchVarControl) - { - AddTriangleContextMenuStripItems(); - } - - private void AddTriangleContextMenuStripItems() - { - _watchVarControl.AddSetting(SelectTriangleSetting); - } - - public override string GetClass() => "Triangle"; - } -} diff --git a/STROOP/Controls/VariablePanel/Wrappers/WatchVariableWrapper.cs b/STROOP/Controls/VariablePanel/Wrappers/WatchVariableWrapper.cs deleted file mode 100644 index c3a9ae09d..000000000 --- a/STROOP/Controls/VariablePanel/Wrappers/WatchVariableWrapper.cs +++ /dev/null @@ -1,268 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using System.Windows.Forms; -using STROOP.Core.Variables; -using STROOP.Forms; - -namespace STROOP.Controls.VariablePanel -{ - public enum CombinedValuesMeaning - { - NoValue, - SameValue, - MultipleValues, - } - - public abstract class WatchVariableWrapper - { - public readonly NamedVariableCollection.IView _view; - - public event Action ValueSet = () => { }; - - protected readonly WatchVariableControl _watchVarControl; - protected CarretlessTextBox textBox = null; - protected Action editValueHandler; - - public virtual WatchVariablePanel.CustomDraw CustomDrawOperation => null; - - protected WatchVariableWrapper(NamedVariableCollection.IView watchVar, WatchVariableControl watchVarControl) - { - _view = watchVar; - _watchVarControl = watchVarControl; - } - - public void ShowControllerForm() - { - new VariableControllerForm(_watchVarControl.VarName, this).Show(); - } - - public void ShowVarInfo() - { - var memoryDescriptor = (_view as NamedVariableCollection.IMemoryDescriptorView)?.memoryDescriptor; - VariableViewerForm varInfo = - new VariableViewerForm( - name: _watchVarControl.VarName, - clazz: GetClass(), - type: memoryDescriptor?.GetTypeDescription() ?? "special", - baseTypeOffset: memoryDescriptor?.GetBaseTypeOffsetDescription() ?? "", - n64BaseAddress: memoryDescriptor?.GetBaseAddressListString() ?? "", - emulatorBaseAddress: memoryDescriptor?.GetProcessAddressListString() ?? "", - n64Address: memoryDescriptor?.GetRamAddressListString(true) ?? "", - emulatorAddress: memoryDescriptor?.GetProcessAddressListString() ?? ""); - varInfo.Show(); - } - - public List GetVarInfo() - { - var memoryDescriptor = (_view as NamedVariableCollection.MemoryDescriptorView)?.memoryDescriptor; - return new List() - { - _watchVarControl.VarName, - GetClass(), - memoryDescriptor?.GetTypeDescription() ?? "special", - memoryDescriptor?.GetBaseTypeOffsetDescription(), - memoryDescriptor?.GetBaseAddressListString(), - memoryDescriptor?.GetProcessAddressListString(), - memoryDescriptor?.GetRamAddressListString(true), - memoryDescriptor?.GetProcessAddressListString(), - }; - } - - public static List GetVarInfoLabels() - { - return new List() - { - "Name", - "Class", - "Type", - "BaseType + Offset", - "N64 Base Address", - "Emulator Base Address", - "N64 Address", - "Emulator Address", - }; - } - - public void ShowBitForm() - { - if (_view is NamedVariableCollection.IMemoryDescriptorView compatible) - new VariableBitForm(compatible.Name, compatible.memoryDescriptor, true).Show(); - } - - public abstract bool TrySetValue(string value); - - public virtual void SingleClick(Control parentCtrl, Rectangle bounds) - { - } - - public virtual void DoubleClick(Control parentCtrl, Rectangle bounds) => Edit(parentCtrl, bounds); - - public abstract void Edit(Control parent, Rectangle bounds); - public abstract string GetClass(); - public abstract string GetValueText(); - public abstract void Update(); - - public virtual void ToggleDisplay() - { - } - - protected void OnValueSet() - { - ValueSet(); - _view.ValueSet?.Invoke(); - } - } - - public abstract class WatchVariableWrapper : WatchVariableWrapper - { - protected static Func CreateBoolWithDefault( - Action setValue, - Func getDefault - ) where TWrapper : WatchVariableWrapper => - (ctrl, obj) => - { - if (ctrl.WatchVarWrapper is TWrapper num) - if (obj is bool b) - setValue(num, b); - else if (obj == null) - setValue(num, getDefault(num)); - else - return false; - else - return false; - return true; - }; - - protected static Func WrapperProperty(Func func) where TWrapper : WatchVariableWrapper => - (ctrl) => - { - if (ctrl.WatchVarWrapper is TWrapper wrapper) - return func(wrapper); - return false; - }; - - public NamedVariableCollection.IView view => (NamedVariableCollection.IView)_view; - - protected TBackingValue lastValue { get; private set; } - protected CombinedValuesMeaning lastValueMeaning { get; private set; } - - private bool hasNextValue = false; - private TBackingValue _nextValue; - - protected TBackingValue nextValue - { - get => _nextValue; - set - { - hasNextValue = true; - _nextValue = value; - } - } - - protected WatchVariableWrapper(NamedVariableCollection.IView watchVar, WatchVariableControl watchVarControl) - : base(watchVar, watchVarControl) - { - } - - public (CombinedValuesMeaning meaning, TBackingValue value) CombineValues() - { - var values = view._getterFunction().ToArray(); - if (values.Length == 0) return (CombinedValuesMeaning.NoValue, default(TBackingValue)); - TBackingValue firstValue = values[0]; - for (int i = 1; i < values.Length; i++) - if (!Equals(values[i], firstValue)) - return (CombinedValuesMeaning.MultipleValues, default(TBackingValue)); - return (CombinedValuesMeaning.SameValue, firstValue); - } - - public override sealed void Update() - { - (lastValueMeaning, lastValue) = CombineValues(); - if (hasNextValue) - { - if (view._setterFunction(nextValue).Aggregate(true, (a, b) => a && b)) - OnValueSet(); - hasNextValue = false; - } - - UpdateControls(); - } - - public virtual void UpdateControls() - { - } - - public override void Edit(Control parent, Rectangle bounds) - { - if (editValueHandler != null) - editValueHandler(); - else - { - textBox = new CarretlessTextBox(); - textBox.Bounds = bounds; - textBox.Text = DisplayValue(lastValue); - - bool updateValue = true; - textBox.Multiline = false; - textBox.KeyDown += (_, e) => - { - updateValue = true; - if (e.KeyCode == Keys.Enter) - textBox.Parent.Focus(); - else if (e.KeyCode == Keys.Escape) - { - updateValue = false; - textBox.Parent.Focus(); - } - }; - EventHandler HandleLostFocus = null; - HandleLostFocus = (_, e) => - { - if (updateValue && TryParseValue(textBox.Text, out var nextValue)) - this.nextValue = nextValue; - textBox.LostFocus -= HandleLostFocus; - textBox.Parent.Controls.Remove(textBox); - textBox.Dispose(); - }; - - textBox.LostFocus += HandleLostFocus; - parent.Controls.Add(textBox); - textBox.Focus(); - } - } - - public override sealed string GetValueText() - { - var combinedValues = CombineValues(); - switch (combinedValues.meaning) - { - case CombinedValuesMeaning.NoValue: - return "(none)"; - case CombinedValuesMeaning.SameValue: - return DisplayValue(combinedValues.value); - case CombinedValuesMeaning.MultipleValues: - return "(multiple values)"; - default: - return ""; - } - } - - public override sealed bool TrySetValue(string value) - { - var success = TryParseValue(value, out var result); - if (success) - { - view._setterFunction(result); - OnValueSet(); - } - - return success; - } - - public abstract bool TryParseValue(string value, out TBackingValue result); - - public abstract string DisplayValue(TBackingValue value); - } -} diff --git a/STROOP/Core/WatchVariables/DescribedMemoryState.cs b/STROOP/Core/WatchVariables/DescribedMemoryState.cs deleted file mode 100644 index 631bd0f80..000000000 --- a/STROOP/Core/WatchVariables/DescribedMemoryState.cs +++ /dev/null @@ -1,105 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using STROOP.Structs.Configurations; -using STROOP.Utilities; - -namespace STROOP.Core.Variables -{ - public class DescribedMemoryState - { - public readonly MemoryDescriptor descriptor; - - public bool locked => HasLocks() != System.Windows.Forms.CheckState.Unchecked; - Dictionary locks = new Dictionary(); - - private Func> _fixedAddressGetter = null; - public bool fixedAddresses => _fixedAddressGetter != null; - - public DescribedMemoryState(MemoryDescriptor memoryDescriptor) - { - this.descriptor = memoryDescriptor; - } - - public IEnumerable GetAddressList() - => _fixedAddressGetter?.Invoke() ?? descriptor.GetBaseAddressList().Select(x => x + descriptor.Offset); - - public void ToggleFixedAddress(bool? fix) - { - bool doFix = fix ?? _fixedAddressGetter == null; - _fixedAddressGetter = null; - if (doFix) - { - var capture = GetAddressList(); - _fixedAddressGetter = () => capture; - } - } - - public void ToggleLocked(bool? locked) - { - // TODO: work out locking feature - } - - public void ViewInMemoryTab() - { - List addressList = GetAddressList().ToList(); - if (addressList.Count == 0) return; - uint address = addressList[0]; - var tab = AccessScope.content.GetTab(); - tab.UpdateOrInitialize(true); - Config.TabControlMain.SelectedTab = tab.Tab; - tab.SetCustomAddress(address); - tab.UpdateHexDisplay(); - } - - public bool SetLocked(bool locked, List addresses) - { - // TODO: work out locking feature - //var addressList = addresses ?? GetAddressList(null); - //if (!locked) - // foreach (var address in addressList) - // locks.Remove(address); - //else - //{ - // WatchVariableLockManager.AddLocks(this); - // if (view is IVariableView compatibleView) - // { - // var setter = compatibleView._setterFunction; - // foreach (var address in addressList) - // locks[address] = new Wrapper<(SetterFunction setter, object value)>(((SetterFunction>)setter, compatibleView._getterFunction(new[] { address }).FirstOrDefault())); - // } - //} - return false; - } - - public void ClearLocks() => locks.Clear(); - - public bool InvokeLocks() - { - return false; - - if (locks.Count == 0) - return false; - //foreach (var l in locks) - // l.Value.value.setter(l.Value.value.value, l.Key); - return true; - } - - public System.Windows.Forms.CheckState HasLocks() - { - bool? firstLockValue = null; - foreach (var addr in GetAddressList()) - { - var v = locks.TryGetValue(addr, out _); - if (firstLockValue == null) - firstLockValue = v; - else if (v != firstLockValue) - return System.Windows.Forms.CheckState.Indeterminate; - } - - if (!firstLockValue.HasValue) - return System.Windows.Forms.CheckState.Unchecked; - return firstLockValue.Value ? System.Windows.Forms.CheckState.Checked : System.Windows.Forms.CheckState.Unchecked; - } - } -} diff --git a/STROOP/Core/WatchVariables/MemoryDescriptor.cs b/STROOP/Core/WatchVariables/MemoryDescriptor.cs deleted file mode 100644 index 94b07b8e6..000000000 --- a/STROOP/Core/WatchVariables/MemoryDescriptor.cs +++ /dev/null @@ -1,207 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using STROOP.Utilities; -using STROOP.Structs; -using STROOP.Structs.Configurations; -using System.Xml.Linq; - -namespace STROOP.Core.Variables -{ - public class MemoryDescriptor - { - public static (MemoryDescriptor descriptor, NamedVariableCollection.XmlMemoryView view) FromXml(XElement element) - { - string typeName = (element.Attribute(XName.Get("type"))?.Value); - string baseAddressType = element.Attribute(XName.Get("base")).Value; - uint? offsetUS = ParsingUtilities.ParseHexNullable(element.Attribute(XName.Get("offsetUS"))?.Value); - uint? offsetJP = ParsingUtilities.ParseHexNullable(element.Attribute(XName.Get("offsetJP"))?.Value); - uint? offsetSH = ParsingUtilities.ParseHexNullable(element.Attribute(XName.Get("offsetSH"))?.Value); - uint? offsetEU = ParsingUtilities.ParseHexNullable(element.Attribute(XName.Get("offsetEU"))?.Value); - uint? offsetDefault = ParsingUtilities.ParseHexNullable(element.Attribute(XName.Get("offset"))?.Value); - uint? mask = element.Attribute(XName.Get("mask")) != null ? ParsingUtilities.ParseHexNullable(element.Attribute(XName.Get("mask")).Value) : null; - int? shift = element.Attribute(XName.Get("shift")) != null ? int.Parse(element.Attribute(XName.Get("shift")).Value) : (int?)null; - bool handleMapping = (element.Attribute(XName.Get("handleMapping")) != null) ? bool.Parse(element.Attribute(XName.Get("handleMapping")).Value) : true; - - var memoryDescriptor = new MemoryDescriptor(TypeUtilities.StringToType[typeName], baseAddressType, offsetUS, offsetJP, offsetSH, offsetEU, offsetDefault, mask, shift, handleMapping); - var view = (NamedVariableCollection.XmlMemoryView) - typeof(NamedVariableCollection.XmlMemoryView<>) - .MakeGenericType(memoryDescriptor.MemoryType) - .GetConstructor(new Type[] { typeof(MemoryDescriptor), typeof(XElement) }) - .Invoke(new object[] { memoryDescriptor, element }); - return (memoryDescriptor, view); - } - - public readonly Type MemoryType; - public readonly int? ByteCount; - public readonly bool? SignedType; - - public readonly string BaseAddressType; - - public readonly uint? OffsetUS; - public readonly uint? OffsetJP; - public readonly uint? OffsetSH; - public readonly uint? OffsetEU; - public readonly uint? OffsetDefault; - - public readonly uint? Mask; - public readonly int? Shift; - public readonly bool HandleMapping; - - public int? NibbleCount => ByteCount.HasValue ? (int?)(ByteCount.Value * 2) : null; - - public bool UseAbsoluteAddressing - { - get => BaseAddressType == Structs.BaseAddressType.Absolute; - } - - public uint Offset - { - get - { - if (OffsetUS.HasValue || OffsetJP.HasValue || OffsetSH.HasValue || OffsetEU.HasValue) - { - if (HandleMapping) - return RomVersionConfig.SwitchMap( - OffsetUS ?? 0, - OffsetJP ?? 0, - OffsetSH ?? 0, - OffsetEU ?? 0); - else - return RomVersionConfig.SwitchOnly( - OffsetUS ?? 0, - OffsetJP ?? 0, - OffsetSH ?? 0, - OffsetEU ?? 0); - } - - if (OffsetDefault.HasValue) return OffsetDefault.Value; - return 0; - } - } - - public List GetBaseAddressList() => WatchVariableUtilities.GetBaseAddresses(BaseAddressType).ToList(); - - public List GetAddressList(List addresses = null) - { - var baseAddresses = addresses ?? GetBaseAddressList(); - uint offset = Offset; - return baseAddresses.ConvertAll(baseAddress => baseAddress + offset).ToList(); - } - - public MemoryDescriptor(Type memoryTypeName, string baseAddress, uint offset, uint? mask = null, int? shift = null) - : this(memoryTypeName, baseAddress, null, null, null, null, offset, mask, shift, false) - { - } - - public NamedVariableCollection.MemoryDescriptorView CreateView(string wrapper = "Number") - => (NamedVariableCollection.MemoryDescriptorView) - typeof(NamedVariableCollection.MemoryDescriptorView<>) - .MakeGenericType(MemoryType) - .GetConstructor(new Type[] { typeof(MemoryDescriptor), typeof(string) }) - .Invoke(new object[] { this, wrapper }); - - private MemoryDescriptor(Type memoryType, string baseAddressType, - uint? offsetUS, uint? offsetJP, uint? offsetSH, uint? offsetEU, uint? offsetDefault, uint? mask, int? shift, bool handleMapping) - { - if (offsetDefault.HasValue && (offsetUS.HasValue || offsetJP.HasValue || offsetSH.HasValue || offsetEU.HasValue)) - { - throw new ArgumentOutOfRangeException("Can't have both a default offset value and a rom-specific offset value"); - } - - BaseAddressType = baseAddressType; - - OffsetUS = offsetUS; - OffsetJP = offsetJP; - OffsetSH = offsetSH; - OffsetEU = offsetEU; - OffsetDefault = offsetDefault; - - MemoryType = memoryType; - ByteCount = TypeUtilities.TypeSize[MemoryType]; - SignedType = TypeUtilities.TypeSign[MemoryType]; - - Mask = mask; - Shift = shift; - HandleMapping = handleMapping; - } - - public string GetTypeDescription() - { - string maskString = ""; - if (Mask != null) - { - maskString = " with mask " + HexUtilities.FormatValue(Mask.Value, NibbleCount.Value); - } - - string shiftString = ""; - if (Shift != null) - { - shiftString = " right shifted by " + Shift.Value; - } - - string byteCountString = ""; - if (ByteCount.HasValue) - { - string pluralSuffix = ByteCount.Value == 1 ? "" : "s"; - byteCountString = string.Format(" ({0} byte{1})", ByteCount.Value, pluralSuffix); - } - - return TypeUtilities.TypeToString[MemoryType] + maskString + shiftString + byteCountString; - } - - public string GetBaseTypeOffsetDescription() => $"{BaseAddressType} + {HexUtilities.FormatValue(Offset)}"; - - public string GetProcessAddressListString(List addresses = null) - { - List addressList = GetAddressList(addresses); - if (addressList.Count == 0) return "(none)"; - List processAddressList = GetProcessAddressList(addresses).ConvertAll(address => address.ToUInt64()); - List stringList = processAddressList.ConvertAll(address => HexUtilities.FormatValue(address, address > 0xFFFFFFFFU ? 16 : 8)); - return string.Join(", ", stringList); - } - - private List GetProcessAddressList(List addresses = null) - { - List ramAddressList = GetRamAddressList(false, addresses); - return ramAddressList.ConvertAll(address => Config.Stream.GetAbsoluteAddress(address, ByteCount.Value)); - } - - public string GetRamAddressListString(bool addressArea = true, List addresses = null) - { - List addressList = GetAddressList(addresses); - if (addressList.Count == 0) return "(none)"; - List ramAddressList = GetRamAddressList(addressArea, addresses); - List stringList = ramAddressList.ConvertAll(address => HexUtilities.FormatValue(address, 8)); - return string.Join(", ", stringList); - } - - private List GetRamAddressList(bool addressArea = true, List addresses = null) - { - List addressList = GetAddressList(addresses); - return addressList.ConvertAll(address => GetRamAddress(address, addressArea)); - } - - private uint GetRamAddress(uint addr, bool addressArea = true) - { - UIntPtr addressPtr = new UIntPtr(addr); - uint address; - - if (UseAbsoluteAddressing) - address = EndiannessUtilities.SwapAddressEndianness( - Config.Stream.GetRelativeAddress(addressPtr, ByteCount.Value), ByteCount.Value); - else - address = addressPtr.ToUInt32(); - - return addressArea ? address | 0x80000000 : address & 0x0FFFFFFF; - } - - public string GetBaseAddressListString(List addresses = null) - { - var baseAddresses = addresses ?? GetBaseAddressList(); - if (baseAddresses.Count == 0) return "(none)"; - List baseAddressesString = baseAddresses.ConvertAll(address => HexUtilities.FormatValue(address, 8)); - return string.Join(",", baseAddressesString); - } - } -} diff --git a/STROOP/Core/WatchVariables/NamedVariableGroup.cs b/STROOP/Core/WatchVariables/NamedVariableGroup.cs deleted file mode 100644 index 72398e45d..000000000 --- a/STROOP/Core/WatchVariables/NamedVariableGroup.cs +++ /dev/null @@ -1,219 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Xml.Linq; -using STROOP.Structs.Configurations; -using STROOP.Utilities; - -namespace STROOP.Core.Variables -{ - public class NamedVariableCollection - { - private static IEnumerable GetValues(DescribedMemoryState memoryState) where T : struct, IConvertible - => memoryState.GetAddressList().ConvertAll(address => (T)Config.Stream.GetValue( - typeof(T), - address, - memoryState.descriptor.UseAbsoluteAddressing, - memoryState.descriptor.Mask, - memoryState.descriptor.Shift - )); - - private static IEnumerable SetAll(DescribedMemoryState memoryState, T value) where T : struct, IConvertible - => memoryState.GetAddressList().Select(address => Config.Stream.SetValueRoundingWrapping( - typeof(T), - value, - address, - memoryState.descriptor.UseAbsoluteAddressing, - memoryState.descriptor.Mask, - memoryState.descriptor.Shift - )).ToArray(); - - public delegate IEnumerable GetterFunction(); - - public delegate IEnumerable SetterFunction(T value); - - public static class ViewProperties - { - static ViewProperties() => StringUtilities.InitializeDeclaredStrings(typeof(ViewProperties)); - - [DeclaredString] - public static readonly string - useHex, - invertBool, - specialType, - roundingLimit, - display, - color; - } - - public interface IView - { - Action ValueSet { get; set; } - Action OnDelete { get; set; } - string Name { get; } - bool SetValueByKey(string key, object value); - string GetValueByKey(string key); - Type GetWrapperType(); - int DislpayPriority { get; } - } - - public interface IView : IView - { - GetterFunction _getterFunction { get; } - SetterFunction _setterFunction { get; } - } - - public interface IMemoryDescriptorView : IView - { - MemoryDescriptor memoryDescriptor { get; } - DescribedMemoryState describedMemoryState { get; } - } - - public class CustomView : IView - { - public Action ValueSet { get; set; } - public Action OnDelete { get; set; } - public string Name { get; set; } - - public string Color - { - set { SetValueByKey(ViewProperties.color, value); } - } - - public string Display - { - set { SetValueByKey(ViewProperties.display, value); } - } - - public int DislpayPriority { get; } - - Dictionary keyedValues = new Dictionary(); - - protected readonly Type wrapperType; - public Type GetWrapperType() => wrapperType; - - public CustomView(Type wrapperType) - { - if (wrapperType == null) - System.Diagnostics.Debugger.Break(); - this.wrapperType = wrapperType; - } - - public virtual string GetValueByKey(string key) - { - if (keyedValues.TryGetValue(key, out var result)) - return result; - return null; - } - - public virtual bool SetValueByKey(string key, object value) - { - keyedValues[key] = value.ToString(); - return true; - } - } - - public class CustomView : CustomView, IView - { - public GetterFunction _getterFunction { get; set; } - public SetterFunction _setterFunction { get; set; } - - public CustomView(Type wrapperType) : base(wrapperType) - { - _getterFunction = WatchVariableSpecialUtilities.Defaults.DEFAULT_GETTER; - _setterFunction = WatchVariableSpecialUtilities.Defaults.DEFAULT_SETTER; - } - } - - public class MemoryDescriptorView : CustomView, IMemoryDescriptorView - { - public MemoryDescriptor memoryDescriptor { get; } - public DescribedMemoryState describedMemoryState { get; } - - public MemoryDescriptorView(MemoryDescriptor memoryDescriptor, string wrapper) - : base(WatchVariableUtilities.GetWrapperType(memoryDescriptor.MemoryType, wrapper)) - { - this.memoryDescriptor = memoryDescriptor; - this.describedMemoryState = new DescribedMemoryState(memoryDescriptor); - } - } - - public class MemoryDescriptorView : MemoryDescriptorView, IView where T : struct, IConvertible - { - public MemoryDescriptorView(MemoryDescriptor memoryDescriptor, string wrapper = "Number") - : base(memoryDescriptor, wrapper) - { - _getterFunction = () => GetValues(describedMemoryState); - _setterFunction = (T value) => SetAll(describedMemoryState, value); - } - - public GetterFunction _getterFunction { get; private set; } - public SetterFunction _setterFunction { get; private set; } - } - - public class XmlMemoryView : IMemoryDescriptorView - { - public Action ValueSet { get; set; } - public Action OnDelete { get; set; } - public string Name { get; private set; } - int IView.DislpayPriority => 0; - - readonly string wrapper; - readonly XElement xElement; - public MemoryDescriptor memoryDescriptor { get; } - public DescribedMemoryState describedMemoryState { get; } - - public XmlMemoryView(MemoryDescriptor memoryDescriptor, XElement xElement) - { - this.xElement = xElement; - this.memoryDescriptor = memoryDescriptor; - this.describedMemoryState = new DescribedMemoryState(memoryDescriptor); - Name = xElement.Value; - wrapper = xElement.Attribute(XName.Get("subclass"))?.Value ?? "Number"; - } - - public Type GetWrapperType() => WatchVariableUtilities.GetWrapperType(memoryDescriptor.MemoryType, wrapper); - public string GetValueByKey(string key) => xElement.Attribute(key)?.Value ?? null; - - public bool SetValueByKey(string key, object value) - { - xElement.SetAttributeValue(XName.Get(key), value.ToString()); - return true; - } - - public XElement GetXml() => xElement; - } - - public class XmlMemoryView : XmlMemoryView, IView where T : struct, IConvertible - { - public XmlMemoryView(MemoryDescriptor memoryDescriptor, XElement xElement) - : base(memoryDescriptor, xElement) - { - _getterFunction = () => GetValues(describedMemoryState); - _setterFunction = (T value) => SetAll(describedMemoryState, value); - } - - public GetterFunction _getterFunction { get; private set; } - public SetterFunction _setterFunction { get; private set; } - } - - public static IView ParseXml(XElement element) - { - switch (element.Name.LocalName) - { - case "Data": - var specialType = element.Attribute(XName.Get("specialType"))?.Value; - if (specialType != null) - { - if (WatchVariableSpecialUtilities.dictionary.TryGetValue(specialType, out var value)) - return value; - return null; - } - - return MemoryDescriptor.FromXml(element).view; - } - - return null; - } - } -} diff --git a/STROOP/Core/WatchVariables/WatchVariableSpecialDictionary.cs b/STROOP/Core/WatchVariables/WatchVariableSpecialDictionary.cs deleted file mode 100644 index 1bd9b50c8..000000000 --- a/STROOP/Core/WatchVariables/WatchVariableSpecialDictionary.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using STROOP.Utilities; - -namespace STROOP.Core.Variables -{ - public class WatchVariableSpecialDictionary - { - private readonly Dictionary _dictionary; - - public WatchVariableSpecialDictionary() - { - _dictionary = new Dictionary(); - } - - public bool TryGetValue(string key, out NamedVariableCollection.IView getterSetter) - => _dictionary.TryGetValue(key, out getterSetter); - - public void Add(string key, NamedVariableCollection.GetterFunction getter, NamedVariableCollection.SetterFunction setter, Type wrapperType = null) - { - _dictionary[key] = new NamedVariableCollection.CustomView(wrapperType ?? WatchVariableUtilities.GetWrapperType(typeof(T))) - { - Name = key, - _getterFunction = getter, - _setterFunction = setter, - }; - } - - public void Add(string key, Func getter, Func setter, Type wrapperType = null) - => Add(key, () => getter().Yield(), value => setter(value).Yield(), wrapperType); - - public void Add(string key, string baseAddressType, Func getter, Func setter, Type wrapperType = null) - => Add(key, - () => WatchVariableUtilities.GetBaseAddresses(baseAddressType).Select(x => getter(x)), - value => WatchVariableUtilities.GetBaseAddresses(baseAddressType).Select(x => setter(value, x)), - wrapperType - ); - - public void Add(string key, Func getter, NamedVariableCollection.SetterFunction setter, Type wrapperType = null) - { - _dictionary[key] = new NamedVariableCollection.CustomView(wrapperType ?? WatchVariableUtilities.GetWrapperType(typeof(T))) - { - Name = key, - _getterFunction = () => getter().Yield(), - _setterFunction = setter, - }; - } - } -} diff --git a/STROOP/Enums/BaseAddressTypeEnum.cs b/STROOP/Enums/BaseAddressTypeEnum.cs deleted file mode 100644 index 9d24b0f23..000000000 --- a/STROOP/Enums/BaseAddressTypeEnum.cs +++ /dev/null @@ -1,29 +0,0 @@ -namespace STROOP.Structs -{ - public static class BaseAddressType - { - static BaseAddressType() => Utilities.StringUtilities.InitializeDeclaredStrings(typeof(BaseAddressType)); - - [Utilities.DeclaredString] - public static string - None, - Absolute, - Relative, - Mario, - MarioObj, - Camera, - CameraStruct, - LakituStruct, - CameraModeInfo, - CameraModeTransition, - CameraSettings, - File, - MainSave, - Object, - ProcessGroup, - Coin, - Triangle, - Area, - GfxNode; - }; -} diff --git a/STROOP/Enums/BinaryMathOperation.cs b/STROOP/Enums/BinaryOperationName.cs similarity index 82% rename from STROOP/Enums/BinaryMathOperation.cs rename to STROOP/Enums/BinaryOperationName.cs index cd2e805d9..49148e790 100644 --- a/STROOP/Enums/BinaryMathOperation.cs +++ b/STROOP/Enums/BinaryOperationName.cs @@ -1,6 +1,6 @@ namespace STROOP.Structs { - public enum BinaryMathOperation + public enum BinaryOperationName { Add, Subtract, diff --git a/STROOP/Enums/Coordinate.cs b/STROOP/Enums/Coordinate.cs deleted file mode 100644 index 567658d0b..000000000 --- a/STROOP/Enums/Coordinate.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace STROOP.Structs -{ - public enum Coordinate - { - X, - Y, - Z, - }; -} diff --git a/STROOP/Enums/CopyTypeEnum.cs b/STROOP/Enums/CopyTypeEnum.cs deleted file mode 100644 index 6d8fec591..000000000 --- a/STROOP/Enums/CopyTypeEnum.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace STROOP.Structs -{ - public enum CopyTypeEnum - { - CopyWithCommas, - CopyWithSpaces, - CopyWithTabs, - CopyWithLineBreaks, - CopyWithCommasAndSpaces, - CopyWithNames, - - //CopyAsTable, - CopyForCode, - CopyForBruteforcerJson, - } -} diff --git a/STROOP/Enums/EndiannessType.cs b/STROOP/Enums/EndiannessType.cs deleted file mode 100644 index 3f256fe2f..000000000 --- a/STROOP/Enums/EndiannessType.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace STROOP.Structs -{ - public enum EndiannessType - { - Big, - Little - } -} diff --git a/STROOP/Enums/RomVersion.cs b/STROOP/Enums/RomVersion.cs deleted file mode 100644 index 9143098a2..000000000 --- a/STROOP/Enums/RomVersion.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace STROOP.Structs -{ - public enum RomVersion - { - US, - JP, - SH, - EU, - }; -} diff --git a/STROOP/Enums/RomVersionSelection.cs b/STROOP/Enums/RomVersionSelection.cs deleted file mode 100644 index e0ea2c581..000000000 --- a/STROOP/Enums/RomVersionSelection.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace STROOP.Structs -{ - public enum RomVersionSelection - { - AUTO, - AUTO_US, - AUTO_JP, - AUTO_SH, - AUTO_EU, - US, - JP, - SH, - EU, - }; -} diff --git a/STROOP/Enums/VariableGroup.cs b/STROOP/Enums/VariableGroup.cs deleted file mode 100644 index 6a147981d..000000000 --- a/STROOP/Enums/VariableGroup.cs +++ /dev/null @@ -1,36 +0,0 @@ -namespace STROOP.Structs -{ - public static class VariableGroup - { - static VariableGroup() => Utilities.StringUtilities.InitializeDeclaredStrings(typeof(VariableGroup)); - - [Utilities.DeclaredString] - public static string - Basic, - Intermediate, - Advanced, - ObjectSpecific, - Scheduler, - Snow, - WarpNode, - NoGroup, - Custom, - ProcessGroup, - Collision, - Movement, - Transformation, - Coordinate, - FloorCoordinate, - ExtendedLevelBoundaries, - HolpMario, - HolpPoint, - Trajectory, - Point, - Coin, - Hacks, - Rng, - Self, - QuarterFrameHack, - GhostHack; - }; -} diff --git a/STROOP/Enums/WatchVariableSubclass.cs b/STROOP/Enums/WatchVariableSubclass.cs deleted file mode 100644 index 39e9e0bdd..000000000 --- a/STROOP/Enums/WatchVariableSubclass.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace STROOP.Structs -{ - public enum WatchVariableSubclass - { - Number, - String, - Angle, - Object, - Triangle, - Address, - Boolean, - }; -} diff --git a/STROOP/Exceptions/DolphinNotRunningGameException.cs b/STROOP/Exceptions/DolphinNotRunningGameException.cs deleted file mode 100644 index 71e7824cf..000000000 --- a/STROOP/Exceptions/DolphinNotRunningGameException.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; - -namespace STROOP.Exceptions -{ - public class DolphinNotRunningGameException : Exception - { - public DolphinNotRunningGameException() - : base("Dolphin running, but emulator hasn't started") - { - } - } -} diff --git a/STROOP/Forms/ActionForm.cs b/STROOP/Forms/ActionForm.cs index 68d9267a8..d14b1795f 100644 --- a/STROOP/Forms/ActionForm.cs +++ b/STROOP/Forms/ActionForm.cs @@ -1,5 +1,6 @@ using STROOP.Structs; using STROOP.Utilities; +using STROOP.Variables.Utilities; using System.Collections.Generic; using System.Linq; using System.Windows.Forms; diff --git a/STROOP/Forms/SelectionForm.cs b/STROOP/Forms/SelectionForm.cs index bd0aa7372..5b9ece45a 100644 --- a/STROOP/Forms/SelectionForm.cs +++ b/STROOP/Forms/SelectionForm.cs @@ -1,6 +1,9 @@ -using STROOP.Structs; +using STROOP.Core; +using STROOP.Structs; using STROOP.Structs.Configurations; +using STROOP.Tabs; using STROOP.Utilities; +using STROOP.Variables.SM64MemoryLayout; using System; using System.Collections.Generic; using System.Windows.Forms; @@ -190,7 +193,7 @@ public static void ShowAreaTerrainDescriptionSelectionForm() { Config.Stream.SetValue( terrainType.Value, - AreaConfig.SelectedAreaAddress + AreaConfig.TerrainTypeOffset); + AreaTab.SelectedAreaAddress + AreaConfig.TerrainTypeOffset); } }); selectionForm.Show(); diff --git a/STROOP/Forms/StroopMainForm.Designer.cs b/STROOP/Forms/StroopMainForm.Designer.cs index 2904aaca4..4ff0f6ec8 100644 --- a/STROOP/Forms/StroopMainForm.Designer.cs +++ b/STROOP/Forms/StroopMainForm.Designer.cs @@ -74,8 +74,7 @@ private void InitializeComponent() this.labelSortMethod = new System.Windows.Forms.Label(); this.comboBoxSortMethod = new System.Windows.Forms.ComboBox(); this.labelSlotSize = new System.Windows.Forms.Label(); - this.checkBoxObjLockLabels = new System.Windows.Forms.CheckBox(); - this.WatchVariablePanelObjects = new STROOP.Controls.ObjectSlotFlowLayoutPanel(); + this.VariablePanelObjects = new STROOP.Controls.ObjectSlotFlowLayoutPanel(); this.trackBarObjSlotSize = new System.Windows.Forms.TrackBar(); this.panelConnect.SuspendLayout(); this.contextMenuStripProcessesList.SuspendLayout(); @@ -88,9 +87,9 @@ private void InitializeComponent() this.groupBoxObjects.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.trackBarObjSlotSize)).BeginInit(); this.SuspendLayout(); - // + // // labelProcessSelect - // + // this.labelProcessSelect.AutoSize = true; this.labelProcessSelect.Location = new System.Drawing.Point(145, 15); this.labelProcessSelect.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); @@ -98,9 +97,9 @@ private void InitializeComponent() this.labelProcessSelect.Size = new System.Drawing.Size(78, 13); this.labelProcessSelect.TabIndex = 1; this.labelProcessSelect.Text = "Connected To:"; - // + // // labelVersionNumber - // + // this.labelVersionNumber.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.labelVersionNumber.AutoSize = true; this.labelVersionNumber.Location = new System.Drawing.Point(868, 15); @@ -109,9 +108,9 @@ private void InitializeComponent() this.labelVersionNumber.TabIndex = 5; this.labelVersionNumber.Text = "version"; this.labelVersionNumber.TextAlign = System.Drawing.ContentAlignment.TopRight; - // + // // buttonDisconnect - // + // this.buttonDisconnect.Location = new System.Drawing.Point(11, 11); this.buttonDisconnect.Margin = new System.Windows.Forms.Padding(2); this.buttonDisconnect.Name = "buttonDisconnect"; @@ -120,9 +119,9 @@ private void InitializeComponent() this.buttonDisconnect.Text = "Disconnect"; this.buttonDisconnect.UseVisualStyleBackColor = true; this.buttonDisconnect.Click += new System.EventHandler(this.buttonDisconnect_Click); - // + // // panelConnect - // + // this.panelConnect.Controls.Add(this.buttonRefreshAndConnect); this.panelConnect.Controls.Add(this.buttonBypass); this.panelConnect.Controls.Add(this.buttonProcessOptions); @@ -136,9 +135,9 @@ private void InitializeComponent() this.panelConnect.Name = "panelConnect"; this.panelConnect.Size = new System.Drawing.Size(947, 741); this.panelConnect.TabIndex = 17; - // + // // buttonRefreshAndConnect - // + // this.buttonRefreshAndConnect.Anchor = System.Windows.Forms.AnchorStyles.None; this.buttonRefreshAndConnect.Location = new System.Drawing.Point(476, 417); this.buttonRefreshAndConnect.Name = "buttonRefreshAndConnect"; @@ -147,9 +146,9 @@ private void InitializeComponent() this.buttonRefreshAndConnect.Text = "Refresh && Connect"; this.buttonRefreshAndConnect.UseVisualStyleBackColor = true; this.buttonRefreshAndConnect.Click += new System.EventHandler(this.buttonRefreshAndConnect_Click); - // + // // buttonBypass - // + // this.buttonBypass.Anchor = System.Windows.Forms.AnchorStyles.None; this.buttonBypass.Location = new System.Drawing.Point(359, 417); this.buttonBypass.Name = "buttonBypass"; @@ -158,9 +157,9 @@ private void InitializeComponent() this.buttonBypass.Text = "Bypass"; this.buttonBypass.UseVisualStyleBackColor = true; this.buttonBypass.Click += new System.EventHandler(this.buttonBypass_Click); - // + // // buttonProcessOptions - // + // this.buttonProcessOptions.Anchor = System.Windows.Forms.AnchorStyles.None; this.buttonProcessOptions.Location = new System.Drawing.Point(511, 460); this.buttonProcessOptions.Name = "buttonProcessOptions"; @@ -169,9 +168,9 @@ private void InitializeComponent() this.buttonProcessOptions.Text = "Options"; this.buttonProcessOptions.UseVisualStyleBackColor = true; this.buttonProcessOptions.Click += new System.EventHandler(this.buttonProcessOptions_Click); - // + // // buttonOpenSavestate - // + // this.buttonOpenSavestate.Anchor = System.Windows.Forms.AnchorStyles.None; this.buttonOpenSavestate.Location = new System.Drawing.Point(359, 460); this.buttonOpenSavestate.Name = "buttonOpenSavestate"; @@ -180,9 +179,9 @@ private void InitializeComponent() this.buttonOpenSavestate.Text = "Open Savestate"; this.buttonOpenSavestate.UseVisualStyleBackColor = true; this.buttonOpenSavestate.Click += new System.EventHandler(this.buttonOpenSavestate_Click); - // + // // buttonRefresh - // + // this.buttonRefresh.Anchor = System.Windows.Forms.AnchorStyles.None; this.buttonRefresh.Location = new System.Drawing.Point(359, 376); this.buttonRefresh.Name = "buttonRefresh"; @@ -191,9 +190,9 @@ private void InitializeComponent() this.buttonRefresh.Text = "Refresh"; this.buttonRefresh.UseVisualStyleBackColor = true; this.buttonRefresh.Click += new System.EventHandler(this.buttonRefresh_Click); - // + // // labelNotConnected - // + // this.labelNotConnected.Anchor = System.Windows.Forms.AnchorStyles.None; this.labelNotConnected.AutoSize = true; this.labelNotConnected.Font = new System.Drawing.Font("Microsoft Sans Serif", 16F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); @@ -202,9 +201,9 @@ private void InitializeComponent() this.labelNotConnected.Size = new System.Drawing.Size(157, 26); this.labelNotConnected.TabIndex = 2; this.labelNotConnected.Text = "Not Connected"; - // + // // buttonConnect - // + // this.buttonConnect.Anchor = System.Windows.Forms.AnchorStyles.None; this.buttonConnect.Location = new System.Drawing.Point(476, 376); this.buttonConnect.Name = "buttonConnect"; @@ -213,9 +212,9 @@ private void InitializeComponent() this.buttonConnect.Text = "Connect"; this.buttonConnect.UseVisualStyleBackColor = true; this.buttonConnect.Click += new System.EventHandler(this.buttonConnect_Click); - // + // // listBoxProcessesList - // + // this.listBoxProcessesList.Anchor = System.Windows.Forms.AnchorStyles.None; this.listBoxProcessesList.FormattingEnabled = true; this.listBoxProcessesList.Location = new System.Drawing.Point(359, 275); @@ -223,34 +222,34 @@ private void InitializeComponent() this.listBoxProcessesList.Size = new System.Drawing.Size(229, 95); this.listBoxProcessesList.TabIndex = 0; this.listBoxProcessesList.DoubleClick += new System.EventHandler(this.listBoxProcessesList_DoubleClick); - // + // // contextMenuStripProcessesList - // + // this.contextMenuStripProcessesList.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this.itemShowSimilarProcesses}); this.contextMenuStripProcessesList.Name = "contextMenuStripProcessesList"; this.contextMenuStripProcessesList.Size = new System.Drawing.Size(197, 26); this.contextMenuStripProcessesList.Opening += new System.ComponentModel.CancelEventHandler(this.contextMenuStripProcessesList_Opening); - // + // // itemShowSimilarProcesses - // + // this.itemShowSimilarProcesses.CheckOnClick = true; this.itemShowSimilarProcesses.Name = "itemShowSimilarProcesses"; this.itemShowSimilarProcesses.Size = new System.Drawing.Size(196, 22); this.itemShowSimilarProcesses.Text = "Show Similar Processes"; this.itemShowSimilarProcesses.CheckedChanged += new System.EventHandler(this.itemShowSimilarProcesses_CheckedChanged); - // + // // labelFpsCounter - // + // this.labelFpsCounter.AutoSize = true; this.labelFpsCounter.Location = new System.Drawing.Point(88, 15); this.labelFpsCounter.Name = "labelFpsCounter"; this.labelFpsCounter.Size = new System.Drawing.Size(39, 13); this.labelFpsCounter.TabIndex = 18; this.labelFpsCounter.Text = "FPS: 0"; - // + // // comboBoxRomVersion - // + // this.comboBoxRomVersion.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.comboBoxRomVersion.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; this.comboBoxRomVersion.Location = new System.Drawing.Point(479, 11); @@ -258,9 +257,9 @@ private void InitializeComponent() this.comboBoxRomVersion.Name = "comboBoxRomVersion"; this.comboBoxRomVersion.Size = new System.Drawing.Size(79, 21); this.comboBoxRomVersion.TabIndex = 22; - // + // // comboBoxReadWriteMode - // + // this.comboBoxReadWriteMode.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.comboBoxReadWriteMode.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; this.comboBoxReadWriteMode.Location = new System.Drawing.Point(562, 11); @@ -268,9 +267,9 @@ private void InitializeComponent() this.comboBoxReadWriteMode.Name = "comboBoxReadWriteMode"; this.comboBoxReadWriteMode.Size = new System.Drawing.Size(75, 21); this.comboBoxReadWriteMode.TabIndex = 22; - // + // // labelDebugText - // + // this.labelDebugText.AutoSize = true; this.labelDebugText.BackColor = System.Drawing.Color.White; this.labelDebugText.Location = new System.Drawing.Point(271, 15); @@ -280,17 +279,17 @@ private void InitializeComponent() this.labelDebugText.TabIndex = 1; this.labelDebugText.Text = "Debug Text"; this.labelDebugText.Visible = false; - // + // // openFileDialogSt - // + // this.openFileDialogSt.Filter = "ST files |*.st;*.savestate|All files|*"; - // + // // saveFileDialogSt - // + // this.saveFileDialogSt.Filter = "ST files |*.st;*.savestate"; - // + // // pictureBoxCog - // + // this.pictureBoxCog.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.pictureBoxCog.BackgroundImage = global::STROOP.Properties.Resources.cog; this.pictureBoxCog.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom; @@ -300,9 +299,9 @@ private void InitializeComponent() this.pictureBoxCog.Size = new System.Drawing.Size(20, 20); this.pictureBoxCog.TabIndex = 23; this.pictureBoxCog.TabStop = false; - // + // // buttonShowTopPane - // + // this.buttonShowTopPane.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.buttonShowTopPane.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("buttonShowTopPane.BackgroundImage"))); this.buttonShowTopPane.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; @@ -313,9 +312,9 @@ private void InitializeComponent() this.buttonShowTopPane.TabIndex = 19; this.buttonShowTopPane.UseVisualStyleBackColor = true; this.buttonShowTopPane.Click += new System.EventHandler(this.buttonShowTopPanel_Click); - // + // // buttonShowTopBottomPane - // + // this.buttonShowTopBottomPane.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.buttonShowTopBottomPane.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("buttonShowTopBottomPane.BackgroundImage"))); this.buttonShowTopBottomPane.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; @@ -326,9 +325,9 @@ private void InitializeComponent() this.buttonShowTopBottomPane.TabIndex = 20; this.buttonShowTopBottomPane.UseVisualStyleBackColor = true; this.buttonShowTopBottomPane.Click += new System.EventHandler(this.buttonShowTopBottomPanel_Click); - // + // // buttonShowBottomPane - // + // this.buttonShowBottomPane.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.buttonShowBottomPane.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("buttonShowBottomPane.BackgroundImage"))); this.buttonShowBottomPane.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; @@ -339,9 +338,9 @@ private void InitializeComponent() this.buttonShowBottomPane.TabIndex = 20; this.buttonShowBottomPane.UseVisualStyleBackColor = true; this.buttonShowBottomPane.Click += new System.EventHandler(this.buttonShowBottomPanel_Click); - // + // // buttonShowRightPane - // + // this.buttonShowRightPane.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.buttonShowRightPane.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("buttonShowRightPane.BackgroundImage"))); this.buttonShowRightPane.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; @@ -352,9 +351,9 @@ private void InitializeComponent() this.buttonShowRightPane.TabIndex = 19; this.buttonShowRightPane.UseVisualStyleBackColor = true; this.buttonShowRightPane.Click += new System.EventHandler(this.buttonShowRightPanel_Click); - // + // // buttonShowLeftRightPane - // + // this.buttonShowLeftRightPane.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.buttonShowLeftRightPane.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("buttonShowLeftRightPane.BackgroundImage"))); this.buttonShowLeftRightPane.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; @@ -365,9 +364,9 @@ private void InitializeComponent() this.buttonShowLeftRightPane.TabIndex = 20; this.buttonShowLeftRightPane.UseVisualStyleBackColor = true; this.buttonShowLeftRightPane.Click += new System.EventHandler(this.buttonShowLeftRightPanel_Click); - // + // // buttonTabAdd - // + // this.buttonTabAdd.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.buttonTabAdd.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("buttonTabAdd.BackgroundImage"))); this.buttonTabAdd.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; @@ -378,9 +377,9 @@ private void InitializeComponent() this.buttonTabAdd.TabIndex = 20; this.buttonTabAdd.UseVisualStyleBackColor = true; this.buttonTabAdd.Click += new System.EventHandler(this.buttonTabAdd_Click); - // + // // buttonMoveTabLeft - // + // this.buttonMoveTabLeft.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.buttonMoveTabLeft.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("buttonMoveTabLeft.BackgroundImage"))); this.buttonMoveTabLeft.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; @@ -391,9 +390,9 @@ private void InitializeComponent() this.buttonMoveTabLeft.TabIndex = 20; this.buttonMoveTabLeft.UseVisualStyleBackColor = true; this.buttonMoveTabLeft.Click += new System.EventHandler(this.buttonMoveTabLeft_Click); - // + // // buttonMoveTabRight - // + // this.buttonMoveTabRight.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.buttonMoveTabRight.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("buttonMoveTabRight.BackgroundImage"))); this.buttonMoveTabRight.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; @@ -404,9 +403,9 @@ private void InitializeComponent() this.buttonMoveTabRight.TabIndex = 20; this.buttonMoveTabRight.UseVisualStyleBackColor = true; this.buttonMoveTabRight.Click += new System.EventHandler(this.buttonMoveTabRight_Click); - // + // // buttonShowLeftPane - // + // this.buttonShowLeftPane.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.buttonShowLeftPane.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("buttonShowLeftPane.BackgroundImage"))); this.buttonShowLeftPane.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; @@ -417,37 +416,37 @@ private void InitializeComponent() this.buttonShowLeftPane.TabIndex = 20; this.buttonShowLeftPane.UseVisualStyleBackColor = true; this.buttonShowLeftPane.Click += new System.EventHandler(this.buttonShowLeftPanel_Click); - // + // // splitContainerMain - // - this.splitContainerMain.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) + // + this.splitContainerMain.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.splitContainerMain.FixedPanel = System.Windows.Forms.FixedPanel.Panel1; this.splitContainerMain.Location = new System.Drawing.Point(12, 36); this.splitContainerMain.Margin = new System.Windows.Forms.Padding(2); this.splitContainerMain.Name = "splitContainerMain"; this.splitContainerMain.Orientation = System.Windows.Forms.Orientation.Horizontal; - // + // // splitContainerMain.Panel1 - // + // this.splitContainerMain.Panel1.Controls.Add(this.tabControlMain); this.splitContainerMain.Panel1MinSize = 0; - // + // // splitContainerMain.Panel2 - // + // this.splitContainerMain.Panel2.Controls.Add(this.groupBoxObjects); this.splitContainerMain.Panel2MinSize = 0; this.splitContainerMain.Size = new System.Drawing.Size(927, 698); this.splitContainerMain.SplitterDistance = 491; this.splitContainerMain.SplitterWidth = 3; this.splitContainerMain.TabIndex = 4; - // + // // tabControlMain - // + // this.tabControlMain.AllowDrop = true; - this.tabControlMain.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) + this.tabControlMain.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.tabControlMain.Controls.Add(this.tabPage1); this.tabControlMain.Cursor = System.Windows.Forms.Cursors.Default; @@ -458,18 +457,18 @@ private void InitializeComponent() this.tabControlMain.SelectedIndex = 0; this.tabControlMain.Size = new System.Drawing.Size(923, 489); this.tabControlMain.TabIndex = 3; - // + // // tabPage1 - // + // this.tabPage1.Location = new System.Drawing.Point(4, 22); this.tabPage1.Name = "tabPage1"; this.tabPage1.Size = new System.Drawing.Size(915, 463); this.tabPage1.TabIndex = 0; this.tabPage1.Text = "Dummy"; this.tabPage1.UseVisualStyleBackColor = true; - // + // // groupBoxObjects - // + // this.groupBoxObjects.Controls.Add(this.comboBoxSelectionMethod); this.groupBoxObjects.Controls.Add(this.labelSelectionMethod); this.groupBoxObjects.Controls.Add(this.comboBoxLabelMethod); @@ -477,8 +476,7 @@ private void InitializeComponent() this.groupBoxObjects.Controls.Add(this.labelSortMethod); this.groupBoxObjects.Controls.Add(this.comboBoxSortMethod); this.groupBoxObjects.Controls.Add(this.labelSlotSize); - this.groupBoxObjects.Controls.Add(this.checkBoxObjLockLabels); - this.groupBoxObjects.Controls.Add(this.WatchVariablePanelObjects); + this.groupBoxObjects.Controls.Add(this.VariablePanelObjects); this.groupBoxObjects.Controls.Add(this.trackBarObjSlotSize); this.groupBoxObjects.Dock = System.Windows.Forms.DockStyle.Fill; this.groupBoxObjects.Location = new System.Drawing.Point(0, 0); @@ -489,9 +487,9 @@ private void InitializeComponent() this.groupBoxObjects.TabIndex = 2; this.groupBoxObjects.TabStop = false; this.groupBoxObjects.Text = "Objects"; - // + // // comboBoxSelectionMethod - // + // this.comboBoxSelectionMethod.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.comboBoxSelectionMethod.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; this.comboBoxSelectionMethod.Location = new System.Drawing.Point(456, 15); @@ -499,9 +497,9 @@ private void InitializeComponent() this.comboBoxSelectionMethod.Name = "comboBoxSelectionMethod"; this.comboBoxSelectionMethod.Size = new System.Drawing.Size(82, 21); this.comboBoxSelectionMethod.TabIndex = 13; - // + // // labelSelectionMethod - // + // this.labelSelectionMethod.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.labelSelectionMethod.AutoSize = true; this.labelSelectionMethod.Location = new System.Drawing.Point(362, 18); @@ -509,9 +507,9 @@ private void InitializeComponent() this.labelSelectionMethod.Size = new System.Drawing.Size(93, 13); this.labelSelectionMethod.TabIndex = 12; this.labelSelectionMethod.Text = "Selection Method:"; - // + // // comboBoxLabelMethod - // + // this.comboBoxLabelMethod.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.comboBoxLabelMethod.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; this.comboBoxLabelMethod.Location = new System.Drawing.Point(623, 15); @@ -519,9 +517,9 @@ private void InitializeComponent() this.comboBoxLabelMethod.Name = "comboBoxLabelMethod"; this.comboBoxLabelMethod.Size = new System.Drawing.Size(102, 21); this.comboBoxLabelMethod.TabIndex = 13; - // + // // labelLabelMethod - // + // this.labelLabelMethod.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.labelLabelMethod.AutoSize = true; this.labelLabelMethod.Location = new System.Drawing.Point(547, 18); @@ -529,9 +527,9 @@ private void InitializeComponent() this.labelLabelMethod.Size = new System.Drawing.Size(75, 13); this.labelLabelMethod.TabIndex = 12; this.labelLabelMethod.Text = "Label Method:"; - // + // // labelSortMethod - // + // this.labelSortMethod.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.labelSortMethod.AutoSize = true; this.labelSortMethod.Location = new System.Drawing.Point(738, 18); @@ -540,9 +538,9 @@ private void InitializeComponent() this.labelSortMethod.Size = new System.Drawing.Size(68, 13); this.labelSortMethod.TabIndex = 5; this.labelSortMethod.Text = "Sort Method:"; - // + // // comboBoxSortMethod - // + // this.comboBoxSortMethod.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.comboBoxSortMethod.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; this.comboBoxSortMethod.Location = new System.Drawing.Point(807, 15); @@ -550,41 +548,30 @@ private void InitializeComponent() this.comboBoxSortMethod.Name = "comboBoxSortMethod"; this.comboBoxSortMethod.Size = new System.Drawing.Size(113, 21); this.comboBoxSortMethod.TabIndex = 4; - // + // // labelSlotSize - // + // this.labelSlotSize.AutoSize = true; this.labelSlotSize.Location = new System.Drawing.Point(110, 19); this.labelSlotSize.Name = "labelSlotSize"; this.labelSlotSize.Size = new System.Drawing.Size(51, 13); this.labelSlotSize.TabIndex = 11; this.labelSlotSize.Text = "Slot Size:"; - // - // checkBoxObjLockLabels - // - this.checkBoxObjLockLabels.AutoSize = true; - this.checkBoxObjLockLabels.Location = new System.Drawing.Point(4, 18); - this.checkBoxObjLockLabels.Margin = new System.Windows.Forms.Padding(2); - this.checkBoxObjLockLabels.Name = "checkBoxObjLockLabels"; - this.checkBoxObjLockLabels.Size = new System.Drawing.Size(84, 17); - this.checkBoxObjLockLabels.TabIndex = 7; - this.checkBoxObjLockLabels.Text = "Lock Labels"; - this.checkBoxObjLockLabels.UseVisualStyleBackColor = true; - // - // WatchVariablePanelObjects - // - this.WatchVariablePanelObjects.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) + // + // VariablePanelObjects + // + this.VariablePanelObjects.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.WatchVariablePanelObjects.AutoScroll = true; - this.WatchVariablePanelObjects.Location = new System.Drawing.Point(4, 45); - this.WatchVariablePanelObjects.Margin = new System.Windows.Forms.Padding(2); - this.WatchVariablePanelObjects.Name = "WatchVariablePanelObjects"; - this.WatchVariablePanelObjects.Size = new System.Drawing.Size(919, 155); - this.WatchVariablePanelObjects.TabIndex = 0; - // + this.VariablePanelObjects.AutoScroll = true; + this.VariablePanelObjects.Location = new System.Drawing.Point(4, 45); + this.VariablePanelObjects.Margin = new System.Windows.Forms.Padding(2); + this.VariablePanelObjects.Name = "VariablePanelObjects"; + this.VariablePanelObjects.Size = new System.Drawing.Size(919, 155); + this.VariablePanelObjects.TabIndex = 0; + // // trackBarObjSlotSize - // + // this.trackBarObjSlotSize.Location = new System.Drawing.Point(167, 15); this.trackBarObjSlotSize.Maximum = 100; this.trackBarObjSlotSize.Minimum = 15; @@ -594,9 +581,9 @@ private void InitializeComponent() this.trackBarObjSlotSize.TickFrequency = 10; this.trackBarObjSlotSize.Value = 36; this.trackBarObjSlotSize.ValueChanged += new System.EventHandler(this.trackBarObjSlotSize_ValueChanged); - // + // // StroopMainForm - // + // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(947, 741); @@ -647,9 +634,8 @@ private void InitializeComponent() private System.Windows.Forms.GroupBox groupBoxObjects; internal System.Windows.Forms.ComboBox comboBoxSortMethod; private System.Windows.Forms.Label labelSortMethod; - internal ObjectSlotFlowLayoutPanel WatchVariablePanelObjects; + internal ObjectSlotFlowLayoutPanel VariablePanelObjects; private BetterSplitContainer splitContainerMain; - internal System.Windows.Forms.CheckBox checkBoxObjLockLabels; private System.Windows.Forms.Label labelVersionNumber; private System.Windows.Forms.TrackBar trackBarObjSlotSize; private System.Windows.Forms.Label labelSlotSize; diff --git a/STROOP/Forms/StroopMainForm.cs b/STROOP/Forms/StroopMainForm.cs index 38db52aee..dc89f6a62 100644 --- a/STROOP/Forms/StroopMainForm.cs +++ b/STROOP/Forms/StroopMainForm.cs @@ -1,4 +1,6 @@ -using System; +using STROOP.Core; +using STROOP.Core.GameMemoryAccess; +using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; @@ -14,14 +16,17 @@ using STROOP.Structs.Configurations; using STROOP.Forms; using STROOP.Models; -using STROOP.Core.Variables; +using STROOP.Variables; +using STROOP.Variables.SM64MemoryLayout; +using System.Reflection; +using System.Threading; namespace STROOP { public partial class StroopMainForm : Form { // STROOP VERSION NAME - const string _version = "Refactor 0.7.2"; + const string _version = "Refactor 0.8.0"; public event Action Updating; @@ -37,11 +42,12 @@ public partial class StroopMainForm : Form public readonly SearchVariableDialog searchVariableDialog; + CancellationTokenSource _formClosing = new CancellationTokenSource(); + public StroopMainForm(bool isMainForm) { this.searchVariableDialog = new SearchVariableDialog(this); this.isMainForm = isMainForm; - GlobalKeyboard.AddForm(this); InitializeComponent(); InitTabs(); ObjectSlotsManager = new ObjectSlotsManager(this, tabControlMain); @@ -93,7 +99,41 @@ private bool AttachToProcess(Process process) MessageBox.Show("Ambiguous emulator type", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); } - return Config.Stream.SwitchProcess(process, emulators[0]); + return SwitchProcess(process, emulators[0]); + } + + + public bool OpenSTFile(string fileName) + { + StFileIO fileIO = new StFileIO(fileName); + return ProcessStream.Instance.SwitchIO(fileIO); + } + + public bool SwitchProcess(Process newProcess, Emulator emulator) + { + IEmuRamIO newIo = null; + try + { + newIo = newProcess != null + ? (IEmuRamIO)Activator.CreateInstance( + emulator.IOType, + BindingFlags.Default, + null, + [newProcess, emulator], + null + ) + : null; + var messages = newIo?.GetLastMessages() ?? string.Empty; + if (string.Empty != messages) + MessageBox.Show(messages, "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + } + catch (DolphinNotRunningGameException e) + { + MessageBox.Show(e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + return false; + } + + return ProcessStream.Instance.SwitchIO(newIo); } private void InitTabs() @@ -135,7 +175,8 @@ private void StroopMainForm_Load(object sender, EventArgs e) Config.Stream.OnDisconnect += _sm64Stream_OnDisconnect; Config.Stream.WarnReadonlyOff += _sm64Stream_WarnReadonlyOff; - comboBoxRomVersion.DataSource = Enum.GetValues(typeof(RomVersionSelection)); + comboBoxRomVersion.Items.AddRange(["AUTO", .. Enum.GetNames()]); + comboBoxRomVersion.SelectedItem = "AUTO"; comboBoxReadWriteMode.DataSource = Enum.GetValues(typeof(ReadWriteMode)); SetUpContextMenuStrips(); @@ -164,7 +205,11 @@ protected override void OnShown(EventArgs e) BringToFront(); Activate(); using (new AccessScope(this)) - Config.Stream.Run(); + Config.CoreLoop.Run( + _formClosing.Token, + Application.DoEvents, + () => RefreshRateConfig.RefreshRateInterval + ); } private void InitializeTabRemoval() @@ -211,7 +256,13 @@ private void SetUpContextMenuStrips() }, new List() { - () => MappingConfig.OpenMapping(), + () => + { + OpenFileDialog openFileDialog = DialogUtilities.CreateOpenFileDialog(FileType.Mapping); + DialogResult result = openFileDialog.ShowDialog(); + if (result == DialogResult.OK) + MappingConfig.OpenMapping(openFileDialog.FileName); + }, () => MappingConfig.ClearMapping(), () => GetTab().InjectHitboxViewCode(), () => Config.Stream.SetValue(MarioConfig.FreeMovementAction, MarioConfig.StructAddress + MarioConfig.ActionOffset), @@ -221,7 +272,7 @@ private void SetUpContextMenuStrips() () => { string varFilePath = @"Config/MhsData.xml"; - List precursors = XmlConfigParser.OpenWatchVariableControlPrecursors(varFilePath); + List precursors = XmlConfigParser.OpenVariableControlPrecursors(varFilePath); VariablePopOutForm form = new VariablePopOutForm(); form.Initialize(precursors); form.ShowForm(); @@ -352,7 +403,7 @@ public void OnUpdate() { using (new AccessScope(this)) { - labelFpsCounter.Text = "FPS: " + (int?)Config.Stream?.FpsInPractice ?? ""; + labelFpsCounter.Text = "FPS: " + (int?)Config.CoreLoop?.FpsInPractice ?? ""; if (Config.Stream != null) { UpdateGlobalConfig(); @@ -366,7 +417,6 @@ public void OnUpdate() foreach (TabPage page in tabControlMain.TabPages) Tabs.STROOPTab.UpdateTab(page, tabControlMain.SelectedTab == page); - WatchVariableLockManager.Update(); TriangleDataModel.ClearCache(); Updating?.Invoke(); } @@ -375,7 +425,18 @@ public void OnUpdate() private void UpdateGlobalConfig() { // Rom Version - RomVersionConfig.UpdateRomVersion(comboBoxRomVersion); + if ((comboBoxRomVersion.SelectedItem as string)?.StartsWith("AUTO") ?? false) + { + var autoVersion = RomVersionConfig.GetRomVersionUsingTell(); + if (autoVersion != null) + { + RomVersionConfig.Version = autoVersion.Value; + comboBoxRomVersion.Items[0] = $"AUTO ({autoVersion})"; + comboBoxRomVersion.SelectedItem = comboBoxRomVersion.Items[0]; + } + } + else if (Enum.TryParse(comboBoxRomVersion.SelectedItem as string ?? "", out var explicitVersion)) + RomVersionConfig.Version = explicitVersion; // Readonly / Read+Write Config.Stream.Readonly = (ReadWriteMode)comboBoxReadWriteMode.SelectedItem == ReadWriteMode.ReadOnly; @@ -552,7 +613,7 @@ private void buttonBypass_Click(object sender, EventArgs e) private void buttonDisconnect_Click(object sender, EventArgs e) { - Task.Run(() => Config.Stream.SwitchProcess(null, null)); + Task.Run(() => SwitchProcess(null, null)); buttonRefresh_Click(this, new EventArgs()); panelConnect.Visible = true; } @@ -590,9 +651,9 @@ await Task.Run(() => } }); - WatchVariablePanelObjects.SuspendLayout(); + VariablePanelObjects.SuspendLayout(); ObjectSlotsManager.ChangeSlotSize(size); - WatchVariablePanelObjects.ResumeLayout(); + VariablePanelObjects.ResumeLayout(); _objSlotResizing = false; } @@ -604,7 +665,7 @@ private void buttonOpenSavestate_Click(object sender, EventArgs e) { try { - Config.Stream.OpenSTFile(openFileDialogSt.FileName); + OpenSTFile(openFileDialogSt.FileName); } catch { @@ -659,11 +720,8 @@ protected override void OnFormClosing(FormClosingEventArgs e) if (isMainForm) { - if (Config.Stream != null) - { - Config.Stream.Dispose(); - Config.Stream = null; - } + _formClosing.Cancel(); + Config.Stream?.Dispose(); } } } diff --git a/STROOP/Forms/TriangleListForm.cs b/STROOP/Forms/TriangleListForm.cs index 2e3119124..14deb5e46 100644 --- a/STROOP/Forms/TriangleListForm.cs +++ b/STROOP/Forms/TriangleListForm.cs @@ -1,7 +1,9 @@ -using STROOP.Tabs.MapTab; +using STROOP.Core; +using STROOP.Tabs.MapTab; using STROOP.Models; using STROOP.Structs; using STROOP.Utilities; +using STROOP.Variables.Utilities; using System; using System.Collections.Generic; using System.Linq; diff --git a/STROOP/Forms/VariableBitForm.cs b/STROOP/Forms/VariableBitForm.cs index ec8c7d6cb..445900ff6 100644 --- a/STROOP/Forms/VariableBitForm.cs +++ b/STROOP/Forms/VariableBitForm.cs @@ -8,7 +8,9 @@ using System.Windows.Forms; using STROOP.Utilities; using STROOP.Models; -using STROOP.Core.Variables; +using STROOP.Variables; +using STROOP.Variables.Formatting; +using STROOP.Variables.Utilities; namespace STROOP.Forms { @@ -79,9 +81,9 @@ public void UpdateForm() } List values = _addressGetter().Select(address => Config.Stream.GetValue( - _memoryDescriptor.MemoryType, + _memoryDescriptor.ClrType, address, - _memoryDescriptor.UseAbsoluteAddressing, + false, _memoryDescriptor.Mask, _memoryDescriptor.Shift ) @@ -102,9 +104,9 @@ public void UpdateForm() if (_showFloatComponents && value is float floatValue) { - _textBoxDecValue.Text = MoreMath.GetFloatSign(floatValue).ToString(); - _textBoxHexValue.Text = MoreMath.GetFloatExponent(floatValue).ToString(); - _textBoxBinaryValue.Text = MoreMath.GetFloatMantissa(floatValue).ToString(); + _textBoxDecValue.Text = STROOPMath.GetFloatSign(floatValue).ToString(); + _textBoxHexValue.Text = STROOPMath.GetFloatExponent(floatValue).ToString(); + _textBoxBinaryValue.Text = STROOPMath.GetFloatMantissa(floatValue).ToString(); } else { @@ -117,15 +119,15 @@ public void UpdateForm() public void SetValueInMemory() { byte[] bytes = _reversedBytes.ConvertAll(b => b.GetByteValue()).ToArray(); - if (TypeUtilities.ConvertBytes(_memoryDescriptor.MemoryType, bytes) is IConvertible validValue) + if (TypeUtilities.ConvertBytes(_memoryDescriptor.ClrType, bytes) is IConvertible validValue) foreach (var address in _addressGetter()) - Config.Stream.SetValue(_memoryDescriptor.MemoryType, validValue, address, _memoryDescriptor.UseAbsoluteAddressing, _memoryDescriptor.Mask, _memoryDescriptor.Shift); + Config.Stream.SetValue(_memoryDescriptor.ClrType, validValue, address, false, _memoryDescriptor.Mask, _memoryDescriptor.Shift); } private void DoColoring() { // Color specially the differents parts of a float - if (_memoryDescriptor.MemoryType == typeof(float)) + if (_memoryDescriptor.ClrType == typeof(float)) { Color signColor = Color.LightBlue; Color exponentColor = Color.Pink; diff --git a/STROOP/Forms/VariableControllerForm.Designer.cs b/STROOP/Forms/VariableControllerForm.Designer.cs index 738c0b20f..6cd3dce2f 100644 --- a/STROOP/Forms/VariableControllerForm.Designer.cs +++ b/STROOP/Forms/VariableControllerForm.Designer.cs @@ -33,7 +33,6 @@ private void InitializeComponent() this._buttonGet = new System.Windows.Forms.Button(); this._buttonAdd = new System.Windows.Forms.Button(); this._buttonSet = new System.Windows.Forms.Button(); - this._checkBoxLock = new System.Windows.Forms.CheckBox(); this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); this._checkBoxFixAddress = new System.Windows.Forms.CheckBox(); this._textBoxGetSet = new STROOP.BetterTextbox(); @@ -42,9 +41,9 @@ private void InitializeComponent() this._textBoxVarName = new STROOP.BetterTextbox(); this.tableLayoutPanel1.SuspendLayout(); this.SuspendLayout(); - // + // // _buttonSubtract - // + // this._buttonSubtract.Dock = System.Windows.Forms.DockStyle.Fill; this._buttonSubtract.Font = new System.Drawing.Font("Microsoft Sans Serif", 14.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this._buttonSubtract.Location = new System.Drawing.Point(0, 52); @@ -54,9 +53,9 @@ private void InitializeComponent() this._buttonSubtract.TabIndex = 0; this._buttonSubtract.Text = "-"; this._buttonSubtract.UseVisualStyleBackColor = true; - // + // // _buttonGet - // + // this._buttonGet.Dock = System.Windows.Forms.DockStyle.Fill; this._buttonGet.Font = new System.Drawing.Font("Microsoft Sans Serif", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this._buttonGet.Location = new System.Drawing.Point(0, 78); @@ -66,9 +65,9 @@ private void InitializeComponent() this._buttonGet.TabIndex = 0; this._buttonGet.Text = "Get"; this._buttonGet.UseVisualStyleBackColor = true; - // + // // _buttonAdd - // + // this._buttonAdd.Dock = System.Windows.Forms.DockStyle.Fill; this._buttonAdd.Font = new System.Drawing.Font("Microsoft Sans Serif", 14.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this._buttonAdd.Location = new System.Drawing.Point(132, 52); @@ -78,9 +77,9 @@ private void InitializeComponent() this._buttonAdd.TabIndex = 0; this._buttonAdd.Text = "+"; this._buttonAdd.UseVisualStyleBackColor = true; - // + // // _buttonSet - // + // this._buttonSet.Dock = System.Windows.Forms.DockStyle.Fill; this._buttonSet.Font = new System.Drawing.Font("Microsoft Sans Serif", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this._buttonSet.Location = new System.Drawing.Point(132, 78); @@ -90,26 +89,14 @@ private void InitializeComponent() this._buttonSet.TabIndex = 0; this._buttonSet.Text = "Set"; this._buttonSet.UseVisualStyleBackColor = true; - // - // _checkBoxLock - // - this._checkBoxLock.Anchor = System.Windows.Forms.AnchorStyles.Left; - this._checkBoxLock.AutoSize = true; - this._checkBoxLock.Location = new System.Drawing.Point(135, 30); - this._checkBoxLock.Name = "_checkBoxLock"; - this._checkBoxLock.Size = new System.Drawing.Size(50, 17); - this._checkBoxLock.TabIndex = 38; - this._checkBoxLock.Text = "Lock"; - this._checkBoxLock.UseVisualStyleBackColor = true; - // + // // tableLayoutPanel1 - // + // this.tableLayoutPanel1.ColumnCount = 3; this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 29.04243F)); this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 41.91515F)); this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 29.04242F)); this.tableLayoutPanel1.Controls.Add(this._checkBoxFixAddress, 0, 1); - this.tableLayoutPanel1.Controls.Add(this._checkBoxLock, 2, 1); this.tableLayoutPanel1.Controls.Add(this._buttonSet, 2, 3); this.tableLayoutPanel1.Controls.Add(this._buttonAdd, 2, 2); this.tableLayoutPanel1.Controls.Add(this._buttonGet, 0, 3); @@ -129,9 +116,9 @@ private void InitializeComponent() this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); this.tableLayoutPanel1.Size = new System.Drawing.Size(188, 107); this.tableLayoutPanel1.TabIndex = 39; - // + // // _checkBoxFixAddress - // + // this._checkBoxFixAddress.Anchor = System.Windows.Forms.AnchorStyles.Right; this._checkBoxFixAddress.AutoSize = true; this._checkBoxFixAddress.Location = new System.Drawing.Point(3, 30); @@ -140,9 +127,9 @@ private void InitializeComponent() this._checkBoxFixAddress.TabIndex = 39; this._checkBoxFixAddress.Text = "Fix Addr"; this._checkBoxFixAddress.UseVisualStyleBackColor = true; - // + // // _textBoxGetSet - // + // this._textBoxGetSet.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); this._textBoxGetSet.BackColor = System.Drawing.Color.White; this._textBoxGetSet.Location = new System.Drawing.Point(57, 82); @@ -151,9 +138,9 @@ private void InitializeComponent() this._textBoxGetSet.TabIndex = 9; this._textBoxGetSet.Text = "200"; this._textBoxGetSet.TextAlign = System.Windows.Forms.HorizontalAlignment.Center; - // + // // _textBoxAddSubtract - // + // this._textBoxAddSubtract.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); this._textBoxAddSubtract.BackColor = System.Drawing.Color.White; this._textBoxAddSubtract.Location = new System.Drawing.Point(57, 55); @@ -163,9 +150,9 @@ private void InitializeComponent() this._textBoxAddSubtract.TabIndex = 9; this._textBoxAddSubtract.Text = "100"; this._textBoxAddSubtract.TextAlign = System.Windows.Forms.HorizontalAlignment.Center; - // + // // _textBoxCurrentValue - // + // this._textBoxCurrentValue.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); this._textBoxCurrentValue.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(220)))), ((int)(((byte)(255)))), ((int)(((byte)(255))))); this._textBoxCurrentValue.Location = new System.Drawing.Point(57, 29); @@ -175,9 +162,9 @@ private void InitializeComponent() this._textBoxCurrentValue.TabIndex = 9; this._textBoxCurrentValue.Text = "0x12345678"; this._textBoxCurrentValue.TextAlign = System.Windows.Forms.HorizontalAlignment.Center; - // + // // _textBoxVarName - // + // this._textBoxVarName.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); this._textBoxVarName.BackColor = System.Drawing.SystemColors.Control; this._textBoxVarName.BorderStyle = System.Windows.Forms.BorderStyle.None; @@ -189,9 +176,9 @@ private void InitializeComponent() this._textBoxVarName.TabIndex = 9; this._textBoxVarName.Text = "Variable Name"; this._textBoxVarName.TextAlign = System.Windows.Forms.HorizontalAlignment.Center; - // + // // VariableControllerForm - // + // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(188, 107); @@ -218,9 +205,8 @@ private void InitializeComponent() private System.Windows.Forms.Button _buttonGet; private System.Windows.Forms.Button _buttonAdd; private System.Windows.Forms.Button _buttonSet; - private System.Windows.Forms.CheckBox _checkBoxLock; private BetterTextbox _textBoxVarName; private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; private System.Windows.Forms.CheckBox _checkBoxFixAddress; } -} \ No newline at end of file +} diff --git a/STROOP/Forms/VariableControllerForm.cs b/STROOP/Forms/VariableControllerForm.cs index 327c03ee4..c5eab3fcf 100644 --- a/STROOP/Forms/VariableControllerForm.cs +++ b/STROOP/Forms/VariableControllerForm.cs @@ -2,11 +2,12 @@ using System.Collections.Generic; using System.Drawing; using System.Windows.Forms; -using STROOP.Core.Variables; -using STROOP.Controls.VariablePanel; +using STROOP.Core.Utilities; using STROOP.Structs; using STROOP.Structs.Configurations; using STROOP.Utilities; +using STROOP.Variables; +using STROOP.Variables.Utilities; namespace STROOP.Forms { @@ -17,21 +18,21 @@ public partial class VariableControllerForm : Form, IUpdatableForm private static readonly Color COLOR_PURPLE = Color.FromArgb(200, 190, 230); private readonly List _varNames; - private readonly List _watchVarWrappers; + private readonly List _cells; private readonly List _variableMemoryStates; - public VariableControllerForm(string varName, WatchVariableWrapper watchVarWrapper) : - this(new List() { varName }, new List() { watchVarWrapper }) + public VariableControllerForm(string varName, IWinFormsVariableCell watchVarCell) : + this([varName], [watchVarCell]) { } - public VariableControllerForm(List varNames, List watchVarWrappers) + public VariableControllerForm(List varNames, List cells) { _varNames = varNames; - _watchVarWrappers = watchVarWrappers; + _cells = cells; - // TODO: Create and correctly use own DescribedMemoryState? - _variableMemoryStates = _watchVarWrappers.ConvertAndRemoveNull(x => (x._view as NamedVariableCollection.IMemoryDescriptorView)?.describedMemoryState); + // TODO: Copy described memory states rather than referencing the same thing? + _variableMemoryStates = _cells.ConvertAndRemoveNull(cell => cell.memory); InitializeComponent(); FormManager.AddForm(this); @@ -75,25 +76,14 @@ public VariableControllerForm(List varNames, List _checkBoxFixAddress.Click += (s, e) => ToggleFixedAddress(); - // TODO: work out locking feature - //_checkBoxLock.Click += (s, e) => - //{ - // List lockedBools = new List(); - // for (int i = 0; i < _watchVarWrappers.Count; i++) - // lockedBools.Add(_watchVarWrappers[i]._view.locked); - // bool anyLocked = lockedBools.Any(b => b); - // for (int i = 0; i < _watchVarWrappers.Count; i++) - // _watchVarWrappers[i].ToggleLocked(!anyLocked, _fixedAddressLists[i]); - //}; - UpdateFixedCheckState(); } private string GetValues() { List values = new List(); - for (int i = 0; i < _watchVarWrappers.Count; i++) - values.Add(_watchVarWrappers[i].GetValueText()); + for (int i = 0; i < _cells.Count; i++) + values.Add(_cells[i].GetValueText()); return String.Join(",", values); } @@ -104,8 +94,8 @@ private void SetValues() using (Config.Stream.Suspend()) { - for (int i = 0; i < _watchVarWrappers.Count; i++) - _watchVarWrappers[i].TrySetValue(values[i % values.Count]); + for (int i = 0; i < _cells.Count; i++) + _cells[i].TrySetValue(values[i % values.Count]); } } @@ -133,11 +123,6 @@ private Color GetColorForCheckState(CheckState checkState) public void UpdateForm() { _textBoxCurrentValue.Text = GetValues(); - List lockedBools = new List(); - // TODO: work out locking feature - //for (int i = 0; i < _watchVarWrappers.Count; i++) - // lockedBools.Add(_watchVarWrappers[i]._view.locked); - _checkBoxLock.CheckState = BoolUtilities.GetCheckState(lockedBools); } public void ToggleFixedAddress() diff --git a/STROOP/Forms/VariableCreationForm.cs b/STROOP/Forms/VariableCreationForm.cs index 246d957fc..47a629b03 100644 --- a/STROOP/Forms/VariableCreationForm.cs +++ b/STROOP/Forms/VariableCreationForm.cs @@ -3,9 +3,11 @@ using System.Linq; using System.Windows.Forms; using STROOP.Controls.VariablePanel; -using STROOP.Core.Variables; -using STROOP.Structs; using STROOP.Utilities; +using STROOP.Variables; +using STROOP.Variables.SM64MemoryLayout; +using STROOP.Variables.Utilities; +using STROOP.Variables.VariablePanel; namespace STROOP.Forms { @@ -16,7 +18,7 @@ public partial class VariableCreationForm : Form public VariableCreationForm() { InitializeComponent(); - var baseTypeValues = WatchVariableUtilities.baseAddressGetters.Keys.ToArray(); + var baseTypeValues = VariableUtilities.baseAddressGetters.Keys.ToArray(); comboBoxTypeValue.DataSource = TypeUtilities.InGameTypeList; comboBoxBaseValue.DataSource = baseTypeValues; comboBoxTypeValue.SelectedIndex = TypeUtilities.InGameTypeList.IndexOf("int"); @@ -38,24 +40,18 @@ public VariableCreationForm() }); } - public void Initialize(WatchVariablePanel varPanel) + public void Initialize(VariablePanel varPanel) { - buttonAddVariable.Click += (sender, e) => varPanel.AddVariable(CreateWatchVariableControl()); + buttonAddVariable.Click += (sender, e) => varPanel.AddVariable(CreateVariable()); } - private NamedVariableCollection.IView CreateWatchVariableControl() + private VariablePrecursor CreateVariable() { string memoryTypeString = comboBoxTypeValue.SelectedItem.ToString(); string baseAddressType = (string)comboBoxBaseValue.SelectedItem; uint offset = ParsingUtilities.ParseHexNullable(textBoxOffsetValue.Text) ?? 0; - var memoryType = TypeUtilities.StringToType[memoryTypeString]; - - var isAbsolute = baseAddressType == BaseAddressType.Absolute; - - var result = new MemoryDescriptor(TypeUtilities.StringToType[memoryTypeString], baseAddressType, offset).CreateView(); - result.Name = textBoxNameValue.Text; - return result; + return (textBoxNameValue.Text, new MemoryDescriptor(TypeUtilities.StringToType[memoryTypeString], baseAddressType, offset).CreateVariable()); } } } diff --git a/STROOP/Forms/VariablePopOutForm.Designer.cs b/STROOP/Forms/VariablePopOutForm.Designer.cs index 7609d376a..e0762f451 100644 --- a/STROOP/Forms/VariablePopOutForm.Designer.cs +++ b/STROOP/Forms/VariablePopOutForm.Designer.cs @@ -30,24 +30,24 @@ private void InitializeComponent() { this.components = new System.ComponentModel.Container(); System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(VariablePopOutForm)); - this._watchVariablePanel = new STROOP.Controls.VariablePanel.WatchVariablePanel(); + this._variablePanel = new STROOP.Controls.VariablePanel.VariablePanel(); this.SuspendLayout(); // // _watchVariablePanel // - this._watchVariablePanel.Dock = System.Windows.Forms.DockStyle.Fill; - this._watchVariablePanel.Location = new System.Drawing.Point(2, 2); - this._watchVariablePanel.Margin = new System.Windows.Forms.Padding(0); - this._watchVariablePanel.Name = "_watchVariablePanel"; - this._watchVariablePanel.Size = new System.Drawing.Size(280, 170); - this._watchVariablePanel.TabIndex = 3; + this._variablePanel.Dock = System.Windows.Forms.DockStyle.Fill; + this._variablePanel.Location = new System.Drawing.Point(2, 2); + this._variablePanel.Margin = new System.Windows.Forms.Padding(0); + this._variablePanel.Name = "_variablePanel"; + this._variablePanel.Size = new System.Drawing.Size(280, 170); + this._variablePanel.TabIndex = 3; // // VariablePopOutForm // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(284, 174); - this.Controls.Add(this._watchVariablePanel); + this.Controls.Add(this._variablePanel); this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); this.MaximizeBox = false; this.MaximumSize = new System.Drawing.Size(10000, 10000); @@ -62,6 +62,6 @@ private void InitializeComponent() #endregion - private STROOP.Controls.VariablePanel.WatchVariablePanel _watchVariablePanel; + private STROOP.Controls.VariablePanel.VariablePanel _variablePanel; } } \ No newline at end of file diff --git a/STROOP/Forms/VariablePopOutForm.cs b/STROOP/Forms/VariablePopOutForm.cs index e88db080e..fdf441f87 100644 --- a/STROOP/Forms/VariablePopOutForm.cs +++ b/STROOP/Forms/VariablePopOutForm.cs @@ -1,8 +1,10 @@ using System.Collections.Generic; using System.Windows.Forms; using STROOP.Controls.VariablePanel; -using STROOP.Core.Variables; using STROOP.Structs; +using STROOP.Variables; +using STROOP.Variables.VariablePanel; +using System.Linq; namespace STROOP.Forms { @@ -11,7 +13,7 @@ public partial class VariablePopOutForm : Form, IUpdatableForm public static int? WIDTH = null; public static int? HEIGHT = null; - public WatchVariablePanel panel => _watchVariablePanel; + public VariablePanel panel => _variablePanel; private bool _borderless = false; private bool _isDragging = false; @@ -40,12 +42,28 @@ public VariablePopOutForm() }; } - public void Initialize(List vars) + public void Initialize(IEnumerable views) { // initialize panel - _watchVariablePanel.Initialize(); - _watchVariablePanel.DeferredInitialize(); - _watchVariablePanel.AddVariables(vars); + _variablePanel.Initialize(); + _variablePanel.DeferredInitialize(); + _variablePanel.AddVariables(views); + + InitInternal(); + } + + public void Initialize(IEnumerable vars) + { + // initialize panel + _variablePanel.Initialize(); + _variablePanel.DeferredInitialize(); + _variablePanel.AddVariables(vars); + + InitInternal(); + } + + void InitInternal() + { // add borderless item to panel ToolStripMenuItem itemBorderless = new ToolStripMenuItem("Borderless"); @@ -56,7 +74,7 @@ public void Initialize(List vars) FormBorderStyle = _borderless ? FormBorderStyle.None : FormBorderStyle.Sizable; }; itemBorderless.Checked = _borderless; - _watchVariablePanel.customContextMenuItems.Add(itemBorderless); + _variablePanel.customContextMenuItems.Add(itemBorderless); // add always on top item to panel ToolStripMenuItem itemAlwaysOnTop = new ToolStripMenuItem("Always On Top"); @@ -67,27 +85,27 @@ public void Initialize(List vars) TopMost = _alwaysOnTop; }; itemBorderless.Checked = _alwaysOnTop; - _watchVariablePanel.customContextMenuItems.Add(itemAlwaysOnTop); + _variablePanel.customContextMenuItems.Add(itemAlwaysOnTop); // add close item to panel ToolStripMenuItem itemClose = new ToolStripMenuItem("Close"); itemClose.Click += (sender, e) => Close(); - _watchVariablePanel.customContextMenuItems.Add(itemClose); + _variablePanel.customContextMenuItems.Add(itemClose); // make panel draggable when borderless - _watchVariablePanel.MouseDown += (sender, e) => + _variablePanel.MouseDown += (sender, e) => { if (!_borderless) return; _isDragging = true; _dragX = e.X; _dragY = e.Y; }; - _watchVariablePanel.MouseUp += (sender, e) => + _variablePanel.MouseUp += (sender, e) => { if (!_borderless) return; _isDragging = false; }; - _watchVariablePanel.MouseMove += (sender, e) => + _variablePanel.MouseMove += (sender, e) => { if (!_borderless) return; if (_isDragging) @@ -99,7 +117,7 @@ public void Initialize(List vars) public void UpdateForm() { - _watchVariablePanel.UpdatePanel(); + _variablePanel.UpdatePanel(); } public void ShowForm() => Show(); diff --git a/STROOP/Interfaces/IUpdatable.cs b/STROOP/Interfaces/IUpdatable.cs deleted file mode 100644 index 8e9047428..000000000 --- a/STROOP/Interfaces/IUpdatable.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace STROOP.Interfaces -{ - public interface IUpdatable - { - void Update(); - } -} diff --git a/STROOP/M64/M64Header.cs b/STROOP/M64/M64Header.cs index 1f2a4f582..670816cf5 100644 --- a/STROOP/M64/M64Header.cs +++ b/STROOP/M64/M64Header.cs @@ -5,6 +5,7 @@ using STROOP.Structs; using System.ComponentModel; using STROOP.Utilities; +using STROOP.Variables.Utilities; namespace STROOP.M64 { diff --git a/STROOP/M64/M64Utilities.cs b/STROOP/M64/M64Utilities.cs index 0137604b7..dab6c2fd6 100644 --- a/STROOP/M64/M64Utilities.cs +++ b/STROOP/M64/M64Utilities.cs @@ -4,6 +4,7 @@ using STROOP.Structs; using System.ComponentModel; using STROOP.Utilities; +using STROOP.Variables.Utilities; using System.Windows.Forms; using System.Drawing; diff --git a/STROOP/Managers/InjectionManager.cs b/STROOP/Managers/InjectionManager.cs index 988f7b207..c0fb08e56 100644 --- a/STROOP/Managers/InjectionManager.cs +++ b/STROOP/Managers/InjectionManager.cs @@ -1,4 +1,5 @@ -using System; +using STROOP.Core; +using System; using System.Linq; using System.Threading.Tasks; using STROOP.Structs; diff --git a/STROOP/Managers/ObjectSlotsManager.cs b/STROOP/Managers/ObjectSlotsManager.cs index 52b9109f7..1359c5366 100644 --- a/STROOP/Managers/ObjectSlotsManager.cs +++ b/STROOP/Managers/ObjectSlotsManager.cs @@ -1,4 +1,5 @@ -using System; +using STROOP.Core.Utilities; +using System; using System.Collections.Generic; using System.Linq; using System.Windows.Forms; @@ -7,6 +8,9 @@ using System.Drawing; using STROOP.Structs.Configurations; using STROOP.Models; +using STROOP.Variables; +using STROOP.Variables.SM64MemoryLayout; +using STROOP.Variables.Utilities; using System.Collections.ObjectModel; namespace STROOP.Managers @@ -47,6 +51,23 @@ public enum SelectionMethodType Closest }; + [InitializeBaseAddress] + static void InitializeBaseAddress() + { + VariableUtilities.baseAddressGetters[BaseAddressType.Object] = () => Config.ObjectSlotsManager.SelectedSlotsAddresses; + VariableUtilities.baseAddressGetters[BaseAddressType.ProcessGroup] = () => + Config.ObjectSlotsManager.SelectedObjects.ConvertAll(obj => obj.CurrentProcessGroup ?? uint.MaxValue); + + VariableUtilities.baseAddressGetters["Graphics"] = () => + Config.ObjectSlotsManager.SelectedSlotsAddresses.ConvertAll(objAddress => Config.Stream.GetUInt32(objAddress + ObjectConfig.BehaviorGfxOffset)); + + VariableUtilities.baseAddressGetters["Animation"] = () => + Config.ObjectSlotsManager.SelectedSlotsAddresses.ConvertAll(objAddress => Config.Stream.GetUInt32(objAddress + ObjectConfig.AnimationOffset)); + + VariableUtilities.baseAddressGetters["Waypoint"] = () => + Config.ObjectSlotsManager.SelectedSlotsAddresses.ConvertAll(objAddress => Config.Stream.GetUInt32(objAddress + ObjectConfig.WaypointOffset)); + } + public uint? HoveredObjectAddress; public List ObjectSlots; @@ -87,7 +108,7 @@ public ObjectSlotsManager(StroopMainForm mainForm, TabControl tabControlMain) var objectSlot = new ObjectSlot(this, i, new Size(DefaultSlotSize, DefaultSlotSize)); objectSlot.Click += (sender, e) => OnSlotClick(sender, e); ObjectSlots.Add(objectSlot); - mainForm.WatchVariablePanelObjects.Controls.Add(objectSlot); + mainForm.VariablePanelObjects.Controls.Add(objectSlot); } ; @@ -220,9 +241,6 @@ public void Update() LabelMethod = (SlotLabelType)mainForm.comboBoxLabelMethod.SelectedItem; SortMethod = (SortMethodType)mainForm.comboBoxSortMethod.SelectedItem; - // Lock label update - LabelsLocked = mainForm.checkBoxObjLockLabels.Checked; - // Processing sort order IEnumerable sortedObjects; switch (SortMethod) diff --git a/STROOP/Managers/WatchVariableLockManager.cs b/STROOP/Managers/WatchVariableLockManager.cs deleted file mode 100644 index 7c5965695..000000000 --- a/STROOP/Managers/WatchVariableLockManager.cs +++ /dev/null @@ -1,46 +0,0 @@ -using STROOP.Core.Variables; -using STROOP.Structs.Configurations; -using System.Collections.Generic; - -namespace STROOP.Structs -{ - public static class WatchVariableLockManager - { - private static HashSet _lockList = new HashSet(); - - public static void AddLocks(NamedVariableCollection.IView variable) - { - _lockList.Add(variable); - } - - public static void RemoveAllLocks() - { - // TODO: work out locking feature - //foreach (var l in _lockList) - // l.ClearLocks(); - //_lockList.Clear(); - } - - public static void Update() - { - // TODO: work out locking feature - //if (LockConfig.LockingDisabled || _lockList.Count == 0) return; - //using (Config.Stream.Suspend()) - //{ - // var removeList = new List(); - // foreach (var varLock in _lockList) - // { - // if (!varLock.InvokeLocks()) - // removeList.Add(varLock); - // } - // foreach (var remove in removeList) - // _lockList.Remove(remove); - //} - } - - public static bool ContainsAnyLocksForObject(uint baseAddress) - { - return false; - } - }; -} diff --git a/STROOP/Models/ByteModel.cs b/STROOP/Models/ByteModel.cs index 5e942e313..b0f1a4c4a 100644 --- a/STROOP/Models/ByteModel.cs +++ b/STROOP/Models/ByteModel.cs @@ -2,6 +2,7 @@ using System.Windows.Forms; using STROOP.Utilities; using STROOP.Forms; +using STROOP.Variables.Utilities; namespace STROOP.Models { diff --git a/STROOP/Models/CameraDataModel.cs b/STROOP/Models/CameraDataModel.cs index 426b07221..aa3707ec5 100644 --- a/STROOP/Models/CameraDataModel.cs +++ b/STROOP/Models/CameraDataModel.cs @@ -1,4 +1,5 @@ using STROOP.Structs.Configurations; +using STROOP.Variables.SM64MemoryLayout; namespace STROOP.Models { diff --git a/STROOP/Models/MarioDataModel.cs b/STROOP/Models/MarioDataModel.cs index 20c9b2991..b99cf47b6 100644 --- a/STROOP/Models/MarioDataModel.cs +++ b/STROOP/Models/MarioDataModel.cs @@ -4,6 +4,7 @@ using STROOP.Structs; using STROOP.Structs.Configurations; using STROOP.Utilities; +using STROOP.Variables.SM64MemoryLayout; namespace STROOP.Models { diff --git a/STROOP/Models/ObjectDataModel.cs b/STROOP/Models/ObjectDataModel.cs index 51af73076..69df64c01 100644 --- a/STROOP/Models/ObjectDataModel.cs +++ b/STROOP/Models/ObjectDataModel.cs @@ -1,6 +1,8 @@ using STROOP.Structs; using STROOP.Structs.Configurations; using STROOP.Utilities; +using STROOP.Variables.SM64MemoryLayout; +using STROOP.Variables.Utilities; using System; namespace STROOP.Models diff --git a/STROOP/Models/TriangleDataModel.cs b/STROOP/Models/TriangleDataModel.cs index 3cc735b71..243176842 100644 --- a/STROOP/Models/TriangleDataModel.cs +++ b/STROOP/Models/TriangleDataModel.cs @@ -4,6 +4,8 @@ using STROOP.Structs.Configurations; using STROOP.Utilities; using STROOP.Structs; +using STROOP.Variables.SM64MemoryLayout; +using STROOP.Variables.Utilities; namespace STROOP.Models { diff --git a/STROOP/Program.cs b/STROOP/Program.cs index 71dbd70f3..708b46e08 100644 --- a/STROOP/Program.cs +++ b/STROOP/Program.cs @@ -1,4 +1,5 @@ -using STROOP.Forms; +using STROOP.Core; +using STROOP.Forms; using System; using System.Drawing; using System.Reflection; @@ -94,7 +95,7 @@ static void Initialize(out StroopMainForm mainForm) () => tmpMainForm = new StroopMainForm(true) ), ("Creating Process Stream", - () => Config.Stream = new ProcessStream(tmpMainForm.OnUpdate) + () => ProcessStream.Instance = new ProcessStream(tmpMainForm.OnUpdate) ) ); mainForm = tmpMainForm; diff --git a/STROOP/Properties/Resources.Designer.cs b/STROOP/Properties/Resources.Designer.cs index beea84d17..e9e783f1a 100644 --- a/STROOP/Properties/Resources.Designer.cs +++ b/STROOP/Properties/Resources.Designer.cs @@ -10,8 +10,8 @@ namespace STROOP.Properties { using System; - - + + /// /// Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw. /// @@ -23,15 +23,15 @@ namespace STROOP.Properties { [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resources { - + private static global::System.Resources.ResourceManager resourceMan; - + private static global::System.Globalization.CultureInfo resourceCulture; - + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal Resources() { } - + /// /// Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird. /// @@ -45,7 +45,7 @@ internal Resources() { return resourceMan; } } - + /// /// Überschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle /// Ressourcenzuordnungen, die diese stark typisierte Ressourcenklasse verwenden. @@ -59,7 +59,7 @@ internal Resources() { resourceCulture = value; } } - + /// /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. /// @@ -69,7 +69,7 @@ internal static System.Drawing.Bitmap checkbox_checked { return ((System.Drawing.Bitmap)(obj)); } } - + /// /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. /// @@ -79,7 +79,7 @@ internal static System.Drawing.Bitmap checkbox_indeterminate { return ((System.Drawing.Bitmap)(obj)); } } - + /// /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. /// @@ -89,7 +89,7 @@ internal static System.Drawing.Bitmap checkbox_unchecked { return ((System.Drawing.Bitmap)(obj)); } } - + /// /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. /// @@ -99,7 +99,7 @@ internal static System.Drawing.Bitmap cog { return ((System.Drawing.Bitmap)(obj)); } } - + /// /// Sucht eine lokalisierte Ressource vom Typ System.Byte[]. /// @@ -109,7 +109,7 @@ internal static byte[] decompile_py { return ((byte[])(obj)); } } - + /// /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. /// @@ -119,7 +119,7 @@ internal static System.Drawing.Bitmap Down_Arrow { return ((System.Drawing.Bitmap)(obj)); } } - + /// /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. /// @@ -129,7 +129,7 @@ internal static System.Drawing.Bitmap dropdown_box { return ((System.Drawing.Bitmap)(obj)); } } - + /// /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. /// @@ -139,7 +139,7 @@ internal static System.Drawing.Bitmap dropdown_box_hover { return ((System.Drawing.Bitmap)(obj)); } } - + /// /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. /// @@ -149,7 +149,7 @@ internal static System.Drawing.Bitmap image_clockwise { return ((System.Drawing.Bitmap)(obj)); } } - + /// /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. /// @@ -159,7 +159,7 @@ internal static System.Drawing.Bitmap image_counterclockwise { return ((System.Drawing.Bitmap)(obj)); } } - + /// /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. /// @@ -169,7 +169,7 @@ internal static System.Drawing.Bitmap image_down { return ((System.Drawing.Bitmap)(obj)); } } - + /// /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. /// @@ -179,7 +179,7 @@ internal static System.Drawing.Bitmap image_downleft { return ((System.Drawing.Bitmap)(obj)); } } - + /// /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. /// @@ -189,7 +189,7 @@ internal static System.Drawing.Bitmap image_downright { return ((System.Drawing.Bitmap)(obj)); } } - + /// /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. /// @@ -199,7 +199,7 @@ internal static System.Drawing.Bitmap image_eye_closed { return ((System.Drawing.Bitmap)(obj)); } } - + /// /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. /// @@ -209,7 +209,7 @@ internal static System.Drawing.Bitmap image_eye_closed2 { return ((System.Drawing.Bitmap)(obj)); } } - + /// /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. /// @@ -219,7 +219,7 @@ internal static System.Drawing.Bitmap image_eye_open { return ((System.Drawing.Bitmap)(obj)); } } - + /// /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. /// @@ -229,7 +229,7 @@ internal static System.Drawing.Bitmap image_eye_open2 { return ((System.Drawing.Bitmap)(obj)); } } - + /// /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. /// @@ -239,7 +239,7 @@ internal static System.Drawing.Bitmap image_left { return ((System.Drawing.Bitmap)(obj)); } } - + /// /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. /// @@ -249,7 +249,7 @@ internal static System.Drawing.Bitmap image_minus { return ((System.Drawing.Bitmap)(obj)); } } - + /// /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. /// @@ -259,7 +259,7 @@ internal static System.Drawing.Bitmap image_plus { return ((System.Drawing.Bitmap)(obj)); } } - + /// /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. /// @@ -269,7 +269,7 @@ internal static System.Drawing.Bitmap image_right { return ((System.Drawing.Bitmap)(obj)); } } - + /// /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. /// @@ -279,7 +279,7 @@ internal static System.Drawing.Bitmap image_up { return ((System.Drawing.Bitmap)(obj)); } } - + /// /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. /// @@ -289,7 +289,7 @@ internal static System.Drawing.Bitmap image_upleft { return ((System.Drawing.Bitmap)(obj)); } } - + /// /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. /// @@ -299,7 +299,7 @@ internal static System.Drawing.Bitmap image_upright { return ((System.Drawing.Bitmap)(obj)); } } - + /// /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. /// @@ -309,7 +309,7 @@ internal static System.Drawing.Bitmap img_arrow_down { return ((System.Drawing.Bitmap)(obj)); } } - + /// /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. /// @@ -319,7 +319,7 @@ internal static System.Drawing.Bitmap img_arrow_left { return ((System.Drawing.Bitmap)(obj)); } } - + /// /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. /// @@ -329,7 +329,7 @@ internal static System.Drawing.Bitmap img_arrow_right { return ((System.Drawing.Bitmap)(obj)); } } - + /// /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. /// @@ -339,7 +339,7 @@ internal static System.Drawing.Bitmap img_arrow_up { return ((System.Drawing.Bitmap)(obj)); } } - + /// /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. /// @@ -349,7 +349,7 @@ internal static System.Drawing.Bitmap img_double_arrow_down { return ((System.Drawing.Bitmap)(obj)); } } - + /// /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. /// @@ -359,7 +359,7 @@ internal static System.Drawing.Bitmap img_double_arrow_left { return ((System.Drawing.Bitmap)(obj)); } } - + /// /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. /// @@ -369,7 +369,7 @@ internal static System.Drawing.Bitmap img_double_arrow_right { return ((System.Drawing.Bitmap)(obj)); } } - + /// /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. /// @@ -379,7 +379,7 @@ internal static System.Drawing.Bitmap img_double_arrow_up { return ((System.Drawing.Bitmap)(obj)); } } - + /// /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. /// @@ -389,27 +389,7 @@ internal static System.Drawing.Bitmap img_home { return ((System.Drawing.Bitmap)(obj)); } } - - /// - /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. - /// - internal static System.Drawing.Bitmap img_lock { - get { - object obj = ResourceManager.GetObject("img_lock", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - - /// - /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. - /// - internal static System.Drawing.Bitmap img_lock_grey { - get { - object obj = ResourceManager.GetObject("img_lock_grey", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - + /// /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. /// @@ -419,7 +399,7 @@ internal static System.Drawing.Bitmap img_pin { return ((System.Drawing.Bitmap)(obj)); } } - + /// /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. /// @@ -429,17 +409,7 @@ internal static System.Drawing.Bitmap Left_Arrow { return ((System.Drawing.Bitmap)(obj)); } } - - /// - /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. - /// - internal static System.Drawing.Bitmap lock_blue { - get { - object obj = ResourceManager.GetObject("lock_blue", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - + /// /// Sucht eine lokalisierte Ressource vom Typ System.Byte[]. /// @@ -449,7 +419,7 @@ internal static byte[] python_xshd { return ((byte[])(obj)); } } - + /// /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. /// @@ -459,7 +429,7 @@ internal static System.Drawing.Bitmap Red_X { return ((System.Drawing.Bitmap)(obj)); } } - + /// /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. /// @@ -469,7 +439,7 @@ internal static System.Drawing.Bitmap Right_Arrow { return ((System.Drawing.Bitmap)(obj)); } } - + /// /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. /// diff --git a/STROOP/Properties/Resources.resx b/STROOP/Properties/Resources.resx index 001197d32..f008160d1 100644 --- a/STROOP/Properties/Resources.resx +++ b/STROOP/Properties/Resources.resx @@ -121,12 +121,6 @@ ..\EmbeddedResources\pin.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\EmbeddedResources\lock_grey.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\EmbeddedResources\lock.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - ..\EmbeddedResources\arrow-down.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a @@ -226,9 +220,6 @@ ..\Resources\cog.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\lock_blue.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - ..\EmbeddedResources\checkbox-checked.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a diff --git a/STROOP/STROOP.csproj b/STROOP/STROOP.csproj index 6258cd068..76291479a 100644 --- a/STROOP/STROOP.csproj +++ b/STROOP/STROOP.csproj @@ -13,7 +13,6 @@ - @@ -29,7 +28,7 @@ - + @@ -54,9 +53,6 @@ Component - - Component - Component @@ -69,7 +65,7 @@ Component - + UserControl @@ -123,7 +119,7 @@ Component - + UserControl @@ -291,5 +287,9 @@ Designer + + + + diff --git a/STROOP/Structs/ActionTable.cs b/STROOP/Structs/ActionTable.cs index 10a2e61e3..7068b5901 100644 --- a/STROOP/Structs/ActionTable.cs +++ b/STROOP/Structs/ActionTable.cs @@ -1,4 +1,5 @@ using STROOP.Structs.Configurations; +using STROOP.Variables.SM64MemoryLayout; using System.Collections.Generic; using System.Linq; diff --git a/STROOP/Structs/AnimationTable.cs b/STROOP/Structs/AnimationTable.cs index 8cd4adac8..52a4878c7 100644 --- a/STROOP/Structs/AnimationTable.cs +++ b/STROOP/Structs/AnimationTable.cs @@ -1,4 +1,5 @@ using STROOP.Structs.Configurations; +using STROOP.Variables.SM64MemoryLayout; using System.Collections.Generic; using System.Linq; diff --git a/STROOP/Structs/Configurations/AreaConfig.cs b/STROOP/Structs/Configurations/AreaConfig.cs index 96e31c6c3..31f1b1051 100644 --- a/STROOP/Structs/Configurations/AreaConfig.cs +++ b/STROOP/Structs/Configurations/AreaConfig.cs @@ -1,11 +1,11 @@ -using STROOP.Utilities; +using STROOP.Core; +using STROOP.Utilities; +using STROOP.Variables.SM64MemoryLayout; namespace STROOP.Structs.Configurations { public static class AreaConfig { - public static uint SelectedAreaAddress => AccessScope.content.GetTab().SelectedAreaAddress; - public static uint AreaStartAddress { get => RomVersionConfig.SwitchMap(AreaStartAddressUS, AreaStartAddressJP, 0, AreaStartAddressEU); diff --git a/STROOP/Structs/Configurations/CamHackConfig.cs b/STROOP/Structs/Configurations/CamHackConfig.cs index fadecf34b..87e41f8e7 100644 --- a/STROOP/Structs/Configurations/CamHackConfig.cs +++ b/STROOP/Structs/Configurations/CamHackConfig.cs @@ -1,4 +1,6 @@ -namespace STROOP.Structs.Configurations +using STROOP.Variables.SM64MemoryLayout; + +namespace STROOP.Structs.Configurations { public static class CamHackConfig { diff --git a/STROOP/Structs/Configurations/CameraConfig.cs b/STROOP/Structs/Configurations/CameraConfig.cs deleted file mode 100644 index b54229aa5..000000000 --- a/STROOP/Structs/Configurations/CameraConfig.cs +++ /dev/null @@ -1,154 +0,0 @@ -using System.Collections.Generic; - -namespace STROOP.Structs.Configurations -{ - public static class CameraConfig - { - public static uint StructAddress - { - get => RomVersionConfig.SwitchMap(StructAddressUS, StructAddressJP, StructAddressSH, StructAddressEU); - } - - public static readonly uint StructAddressUS = 0x8033C520; - public static readonly uint StructAddressJP = 0x8033B1B0; - public static readonly uint StructAddressSH = 0x8031EC78; - public static readonly uint StructAddressEU = 0x8030A7E0; - - public static uint CamStructAddress => Config.Stream.GetUInt32(RomVersionConfig.SwitchMap(0x8033cbd0, 0x8033b860)); - public static uint LakituStructAddress => RomVersionConfig.SwitchMap(0x8033c698, 0x8033b328); - public static uint ModeInfoAddress => RomVersionConfig.SwitchMap(0x8033c788, 0x8033b418, null, null); - public static uint ModeTransitionAddress => RomVersionConfig.SwitchMap(0x8033c5c0, 0x8033b250, null, null); - - - public static readonly uint XOffset = 0x184; - public static readonly uint YOffset = 0x188; - public static readonly uint ZOffset = 0x18C; - public static readonly uint FocusXOffset = 0x178; - public static readonly uint FocusYOffset = 0x17C; - public static readonly uint FocusZOffset = 0x180; - public static readonly uint FacingYawOffset = 0x1C6; - public static readonly uint FacingPitchOffset = 0x1C4; - public static readonly uint FacingRollOffset = 0x1C8; - public static readonly uint CentripetalAngleOffset = 0x1F4; - - public static readonly uint MarioCamPossibleOffset = 0x165; - public static readonly byte MarioCamPossibleMask = 0x04; - - public static uint FOVStructAddress - { - get => RomVersionConfig.SwitchMap(FOVStructAddressUS, FOVStructAddressJP, null, FOVStructAddressEU); - } - - public static readonly uint FOVStructAddressUS = 0x8033C5A0; - public static readonly uint FOVStructAddressJP = 0x8033B230; - public static readonly uint FOVStructAddressEU = 0x8030A920; - - public static uint FOVValueOffset = 0x4; - - public static uint SecondaryObjectAddress - { - get => RomVersionConfig.SwitchMap(SecondaryObjectAddressUS, SecondaryObjectAddressJP, null, SecondaryObjectAddressEU); - } - - public static readonly uint SecondaryObjectAddressUS = 0x8032DF30; - public static readonly uint SecondaryObjectAddressJP = 0x8032CFD0; - public static readonly uint SecondaryObjectAddressEU = 0x802FA110; - - - public static uint FovFunctionAwakeAddress - { - get => RomVersionConfig.SwitchMap(FovFunctionAwakeAddressUS, FovFunctionAwakeAddressJP, null, FovFunctionAwakeAddressEU); - } - - public static readonly uint FovFunctionAwakeAddressUS = 0x8029A7C8; - public static readonly uint FovFunctionAwakeAddressJP = 0x8029A0AC; - public static readonly uint FovFunctionAwakeAddressEU = 0x802849C8; - - public static uint FovFunctionSleepingAddress - { - get => RomVersionConfig.SwitchMap(FovFunctionSleepingAddressUS, FovFunctionSleepingAddressJP, null, FovFunctionSleepingAddressEU); - } - - public static readonly uint FovFunctionSleepingAddressUS = 0x8029A774; - public static readonly uint FovFunctionSleepingAddressJP = 0x8029A058; - public static readonly uint FovFunctionSleepingAddressEU = 0x80284974; - - public static uint FovFunctionUseDoorAddress - { - get => RomVersionConfig.SwitchMap(FovFunctionUseDoorAddressUS, FovFunctionUseDoorAddressJP, null, FovFunctionUseDoorAddressEU); - } - - public static readonly uint FovFunctionUseDoorAddressUS = 0x8029AA20; - public static readonly uint FovFunctionUseDoorAddressJP = 0x8029A304; - public static readonly uint FovFunctionUseDoorAddressEU = 0x80284B48; - - public static uint FovFunctionCollectStarAddress - { - get => RomVersionConfig.SwitchMap(FovFunctionCollectStarAddressUS, FovFunctionCollectStarAddressJP, null, FovFunctionCollectStarAddressEU); - } - - public static readonly uint FovFunctionCollectStarAddressUS = 0x8029A984; - public static readonly uint FovFunctionCollectStarAddressJP = 0x8029A268; - public static readonly uint FovFunctionCollectStarAddressEU = 0x80284AB8; - - public static uint FovFunctionAwakeValue - { - get => RomVersionConfig.SwitchMap(FovFunctionAwakeValueUS, FovFunctionAwakeValueJP); - } - - public static readonly uint FovFunctionAwakeValueUS = 0x0C0A2673; - public static readonly uint FovFunctionAwakeValueJP = 0x0C0A24F9; - - public static uint FovFunctionSleepingValue - { - get => RomVersionConfig.SwitchMap(FovFunctionSleepingValueUS, FovFunctionSleepingValueJP); - } - - public static readonly uint FovFunctionSleepingValueUS = 0x0C0A2673; - public static readonly uint FovFunctionSleepingValueJP = 0x0C0A24F9; - - public static uint FovFunctionUseDoorValue - { - get => RomVersionConfig.SwitchMap(FovFunctionUseDoorValueUS, FovFunctionUseDoorValueJP); - } - - public static readonly uint FovFunctionUseDoorValueUS = 0xE420C5A4; - public static readonly uint FovFunctionUseDoorValueJP = 0xE420B234; - - public static uint FovFunctionCollectStarValue - { - get => RomVersionConfig.SwitchMap(FovFunctionCollectStarValueUS, FovFunctionCollectStarValueJP); - } - - public static readonly uint FovFunctionCollectStarValueUS = 0x0C0A2673; - public static readonly uint FovFunctionCollectStarValueJP = 0x0C0A24F9; - - public static List FovFunctionAddresses - { - get - { - return new List() - { - FovFunctionAwakeAddress, - FovFunctionSleepingAddress, - FovFunctionUseDoorAddress, - FovFunctionCollectStarAddress, - }; - } - } - - public static List FovFunctionValues - { - get - { - return new List() - { - FovFunctionAwakeValue, - FovFunctionSleepingValue, - FovFunctionUseDoorValue, - FovFunctionCollectStarValue, - }; - } - } - } -} diff --git a/STROOP/Structs/Configurations/Config.cs b/STROOP/Structs/Configurations/Config.cs index c8189e3d6..9645e061a 100644 --- a/STROOP/Structs/Configurations/Config.cs +++ b/STROOP/Structs/Configurations/Config.cs @@ -1,4 +1,5 @@ -using STROOP.Managers; +using STROOP.Core; +using STROOP.Managers; using STROOP.Utilities; using System; using System.Collections.Generic; @@ -10,8 +11,9 @@ public static class Config { public static uint RamSize => 0x800000; + public static ProcessStream Stream => ProcessStream.Instance; + public static CoreLoop CoreLoop = new CoreLoop(); public static List Emulators = new List(); - public static ProcessStream Stream; public static FileImageGui FileImageGui = new FileImageGui(); public static ObjectAssociations ObjectAssociations; public static StroopMainForm StroopMainForm => AccessScope.content; diff --git a/STROOP/Structs/Configurations/DebugConfig.cs b/STROOP/Structs/Configurations/DebugConfig.cs index bb29ed208..b3f16d0aa 100644 --- a/STROOP/Structs/Configurations/DebugConfig.cs +++ b/STROOP/Structs/Configurations/DebugConfig.cs @@ -1,4 +1,6 @@ -namespace STROOP.Structs.Configurations +using STROOP.Variables.SM64MemoryLayout; + +namespace STROOP.Structs.Configurations { public static class DebugConfig { diff --git a/STROOP/Structs/Configurations/FileConfig.cs b/STROOP/Structs/Configurations/FileConfig.cs index 559731f57..8d1d46613 100644 --- a/STROOP/Structs/Configurations/FileConfig.cs +++ b/STROOP/Structs/Configurations/FileConfig.cs @@ -1,11 +1,9 @@ -using STROOP.Utilities; +using STROOP.Variables.SM64MemoryLayout; namespace STROOP.Structs.Configurations { public static class FileConfig { - public static uint CurrentFileAddress => AccessScope.content.GetTab().getFileAddress(); - public static uint FileStructAddress { get => RomVersionConfig.SwitchMap(FileStructAddressUS, FileStructAddressJP, FileStructAddressSH, FileStructAddressEU); diff --git a/STROOP/Structs/Configurations/HudConfig.cs b/STROOP/Structs/Configurations/HudConfig.cs index 2ab239ab2..e58d6262b 100644 --- a/STROOP/Structs/Configurations/HudConfig.cs +++ b/STROOP/Structs/Configurations/HudConfig.cs @@ -1,4 +1,6 @@ -namespace STROOP.Structs.Configurations +using STROOP.Variables.SM64MemoryLayout; + +namespace STROOP.Structs.Configurations { public static class HudConfig { diff --git a/STROOP/Structs/Configurations/InputConfig.cs b/STROOP/Structs/Configurations/InputConfig.cs index acca6c1a6..ec1629bb6 100644 --- a/STROOP/Structs/Configurations/InputConfig.cs +++ b/STROOP/Structs/Configurations/InputConfig.cs @@ -1,4 +1,6 @@ -namespace STROOP.Structs.Configurations +using STROOP.Variables.SM64MemoryLayout; + +namespace STROOP.Structs.Configurations { public static class InputConfig { diff --git a/STROOP/Structs/Configurations/LockConfig.cs b/STROOP/Structs/Configurations/LockConfig.cs deleted file mode 100644 index 1c149b5a9..000000000 --- a/STROOP/Structs/Configurations/LockConfig.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace STROOP.Structs.Configurations -{ - public static class LockConfig - { - public static bool LockingDisabled = false; - } -} diff --git a/STROOP/Structs/Configurations/MainSaveConfig.cs b/STROOP/Structs/Configurations/MainSaveConfig.cs index d13ff4846..7ca1c05fd 100644 --- a/STROOP/Structs/Configurations/MainSaveConfig.cs +++ b/STROOP/Structs/Configurations/MainSaveConfig.cs @@ -1,11 +1,11 @@ -using STROOP.Utilities; +using STROOP.Core; +using STROOP.Utilities; +using STROOP.Variables.SM64MemoryLayout; namespace STROOP.Structs.Configurations { public static class MainSaveConfig { - public static uint CurrentMainSaveAddress => AccessScope.content.GetTab().CurrentMainSaveAddress; - public static uint MainSaveStructAddress { get => RomVersionConfig.SwitchMap(MainSaveStructAddressUS, MainSaveStructAddressJP); diff --git a/STROOP/Structs/Configurations/MappingConfig.cs b/STROOP/Structs/Configurations/MappingConfig.cs deleted file mode 100644 index 9bddad559..000000000 --- a/STROOP/Structs/Configurations/MappingConfig.cs +++ /dev/null @@ -1,183 +0,0 @@ -using STROOP.Core.Variables; -using STROOP.Utilities; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Windows.Forms; - -namespace STROOP.Structs.Configurations -{ - public static class MappingConfig - { - private static readonly Dictionary mappingUS = GetMappingDictionary(@"Mappings/MappingUS.map"); - private static readonly Dictionary mappingJP = GetMappingDictionary(@"Mappings/MappingJP.map"); - private static readonly Dictionary mappingUSReversed = DictionaryUtilities.ReverseDictionary(mappingUS); - private static readonly Dictionary mappingJPReversed = DictionaryUtilities.ReverseDictionary(mappingJP); - - private static Dictionary mappingCurrent = null; - private static Dictionary mappingCurrentReversed = null; - - public static Dictionary GetMappingDictionary(string filePath) - { - Dictionary dictionary = new Dictionary(); - List lines = DialogUtilities.ReadFileLines(filePath); - foreach (string line in lines) - { - List parts = ParsingUtilities.ParseStringList(line, false); - if (parts.Count != 2) continue; - string part1 = parts[0]; - string part2 = parts[1]; - if (!part1.StartsWith("0x00000000")) continue; - string addressString = "0x" + part1.Substring(10); - uint? addressNullable = ParsingUtilities.ParseHexNullable(addressString); - if (!addressNullable.HasValue) continue; - uint address = addressNullable.Value; - dictionary[address] = part2; - } - - return dictionary; - } - - public static void OpenMapping() - { - OpenFileDialog openFileDialog = DialogUtilities.CreateOpenFileDialog(FileType.Mapping); - DialogResult result = openFileDialog.ShowDialog(); - if (result != DialogResult.OK) return; - string fileName = openFileDialog.FileName; - mappingCurrent = GetMappingDictionary(fileName); - mappingCurrentReversed = DictionaryUtilities.ReverseDictionary(mappingCurrent); - } - - public static void ClearMapping() - { - mappingCurrent = null; - mappingCurrentReversed = null; - } - - public static uint HandleMapping(uint address) - { - if (mappingCurrent == null) return address; - - Dictionary mappingOriginal; - switch (RomVersionConfig.Version) - { - case RomVersion.US: - mappingOriginal = mappingUS; - break; - case RomVersion.JP: - mappingOriginal = mappingJP; - break; - default: - throw new ArgumentOutOfRangeException(); - } - - if (!mappingOriginal.ContainsKey(address)) return address; - string name = mappingOriginal[address]; - if (!mappingCurrentReversed.ContainsKey(name)) return address; - return mappingCurrentReversed[name]; - } - - public static uint HandleReverseMapping(uint address) - { - if (mappingCurrent == null) return address; - - Dictionary mappingOriginalReversed; - switch (RomVersionConfig.Version) - { - case RomVersion.US: - mappingOriginalReversed = mappingUSReversed; - break; - case RomVersion.JP: - mappingOriginalReversed = mappingJPReversed; - break; - default: - throw new ArgumentOutOfRangeException(); - } - - if (!mappingCurrent.ContainsKey(address)) return address; - string name = mappingCurrent[address]; - if (!mappingOriginalReversed.ContainsKey(name)) return address; - return mappingOriginalReversed[name]; - } - - /** - * Gets user added variables from the mapping, - * assuming they're suffixed with "_f32", "_s16", etc. - */ - public static IEnumerable GetVariables() - { - if (mappingCurrent == null) return new NamedVariableCollection.IView[0]; - - var controls = new List(); - // TODO: get back the mapping feature, but cooler - //foreach (uint address in mappingCurrent.Keys) - //{ - // string stringValue = mappingCurrent[address]; - // (Type type, string name) = GetInfoIfUserAddedWord(stringValue); - // if (type == null) continue; - // string typeString = TypeUtilities.TypeToString[type]; - - // controls.Add(new MemoryDescriptor(name, type)); - //} - return controls; - } - - private static (Type type, string name) GetInfoIfUserAddedWord(string word) - { - if (_suffixes.Any(suff => word.EndsWith(suff)) && - _ignoredWords.All(ignored => word != ignored)) - { - string suffix = _suffixes.First(suff => word.EndsWith(suff)); - Type type = GetTypeFromSuffix(suffix); - string name = word.Substring(0, word.Length - suffix.Length); - return (type, name); - } - - return (null, null); - } - - private static List _suffixes = new List() - { - "_s8", - "_u8", - "_s16", - "_u16", - "_s32", - "_u32", - "_s64", - "_u64", - "_f32", - "_f64", - }; - - private static List _ignoredWords = new List() - { - "m64_read_u8", - "m64_read_s16", - "m64_read_compressed_u16", - "string_to_u32", - "approach_s32", - "approach_f32", - "random_u16", - "gd_clamp_f32", - }; - - private static Type GetTypeFromSuffix(string suffix) - { - switch (suffix.ToLower()) - { - case "_s8": return typeof(sbyte); - case "_u8": return typeof(byte); - case "_s16": return typeof(short); - case "_u16": return typeof(ushort); - case "_s32": return typeof(int); - case "_u32": return typeof(uint); - case "_s64": return typeof(long); - case "_u64": return typeof(ulong); - case "_f32": return typeof(float); - case "_f64": return typeof(double); - default: return null; - } - } - } -} diff --git a/STROOP/Structs/Configurations/MarioConfig.cs b/STROOP/Structs/Configurations/MarioConfig.cs deleted file mode 100644 index 1dab92173..000000000 --- a/STROOP/Structs/Configurations/MarioConfig.cs +++ /dev/null @@ -1,81 +0,0 @@ -using STROOP.Structs.Configurations; - -namespace STROOP.Structs -{ - public static class MarioConfig - { - public static uint StructAddress - { - get => RomVersionConfig.SwitchMap(StructAddressUS, StructAddressJP, StructAddressSH, StructAddressEU); - } - - public static readonly uint StructAddressUS = 0x8033B170; - public static readonly uint StructAddressJP = 0x80339E00; - public static readonly uint StructAddressSH = 0x8031D9C0; - public static readonly uint StructAddressEU = 0x80309430; - - public static readonly uint XOffset = 0x3C; - public static readonly uint YOffset = 0x40; - public static readonly uint ZOffset = 0x44; - - public static readonly uint XSpeedOffset = 0x48; - public static readonly uint YSpeedOffset = 0x4C; - public static readonly uint ZSpeedOffset = 0x50; - public static readonly uint HSpeedOffset = 0x54; - - public static readonly uint FacingYawOffset = 0x2E; - public static readonly uint FacingPitchOffset = 0x2C; - public static readonly uint FacingRollOffset = 0x30; - - public static readonly uint IntendedYawOffset = 0x24; - public static readonly uint IntendedPitchOffset = 0x22; - public static readonly uint IntendedRollOffset = 0x26; - - public static readonly uint MovingYawOffset = 0x38; - public static readonly uint ScaledMagnitudeOffset = 0x20; - - public static readonly uint SlidingSpeedXOffset = 0x58; - public static readonly uint SlidingSpeedZOffset = 0x5C; - public static readonly uint SlidingYawOffset = 0x38; - - public static readonly uint HolpXOffset = 0x258; - public static readonly uint HolpYOffset = 0x25C; - public static readonly uint HolpZOffset = 0x260; - public static readonly uint HolpTypeOffset = 0x24A; - - public static uint StoodOnObjectPointerAddress - { - get => RomVersionConfig.SwitchMap(StoodOnObjectPointerAddressUS, StoodOnObjectPointerAddressJP, StoodOnObjectPointerAddressSH, StoodOnObjectPointerAddressEU); - } - - public static readonly uint StoodOnObjectPointerAddressUS = 0x80330E34; - public static readonly uint StoodOnObjectPointerAddressJP = 0x8032FED4; - public static readonly uint StoodOnObjectPointerAddressSH = 0x80310564; - public static readonly uint StoodOnObjectPointerAddressEU = 0x802FCFF4; - - public static readonly uint InteractionObjectPointerOffset = 0x78; - public static readonly uint HeldObjectPointerOffset = 0x7C; - public static readonly uint UsedObjectPointerOffset = 0x80; - public static readonly uint RiddenObjectPointerOffset = 0x84; - - public static readonly uint WallTriangleOffset = 0x60; - public static readonly uint FloorTriangleOffset = 0x68; - public static readonly uint CeilingTriangleOffset = 0x64; - - public static readonly uint FloorYOffset = 0x70; - public static readonly uint CeilingYOffset = 0x6C; - - public static readonly uint FloorYawOffset = 0x74; - - public static readonly uint ActionOffset = 0x0C; - public static readonly uint PrevActionOffset = 0x10; - public static readonly uint FreeMovementAction = 0x0000130F; - public static readonly uint RidingShellAction = 0x20810446; - public static readonly uint IdleAction = 0x0C400201; - - public static readonly uint TwirlYawOffset = 0x3A; - public static readonly uint PeakHeightOffset = 0xBC; - public static readonly uint WaterLevelOffset = 0x76; - public static readonly uint AreaPointerOffset = 0x90; - } -} diff --git a/STROOP/Structs/Configurations/MarioObjectConfig.cs b/STROOP/Structs/Configurations/MarioObjectConfig.cs deleted file mode 100644 index ce43cd740..000000000 --- a/STROOP/Structs/Configurations/MarioObjectConfig.cs +++ /dev/null @@ -1,22 +0,0 @@ -using STROOP.Structs.Configurations; - -namespace STROOP.Structs -{ - public static class MarioObjectConfig - { - public static uint PointerAddress - { - get => RomVersionConfig.SwitchMap(PointerAddressUS, PointerAddressJP, PointerAddressSH); - } - - public static readonly uint PointerAddressUS = 0x80361158; - public static readonly uint PointerAddressJP = 0x8035FDE8; - public static readonly uint PointerAddressSH = 0x80343318; - - public static readonly uint AnimationOffset = 0x38; - public static readonly uint AnimationTimerOffset = 0x40; - - public static readonly uint GraphicValue = 0x800F0860; - public static readonly uint BehaviorValue = 0x13002EC0; - } -} diff --git a/STROOP/Structs/Configurations/MiscConfig.cs b/STROOP/Structs/Configurations/MiscConfig.cs index 0d0c24930..05bdb5d71 100644 --- a/STROOP/Structs/Configurations/MiscConfig.cs +++ b/STROOP/Structs/Configurations/MiscConfig.cs @@ -1,4 +1,5 @@ using STROOP.Structs.Configurations; +using STROOP.Variables.SM64MemoryLayout; namespace STROOP.Structs { diff --git a/STROOP/Structs/Configurations/ObjectConfig.cs b/STROOP/Structs/Configurations/ObjectConfig.cs index 8d8a5379f..eb5061e4a 100644 --- a/STROOP/Structs/Configurations/ObjectConfig.cs +++ b/STROOP/Structs/Configurations/ObjectConfig.cs @@ -1,4 +1,5 @@ using STROOP.Structs.Configurations; +using STROOP.Variables.SM64MemoryLayout; namespace STROOP.Structs { diff --git a/STROOP/Structs/Configurations/ObjectSlotsConfig.cs b/STROOP/Structs/Configurations/ObjectSlotsConfig.cs index aa474567c..6c0b7c742 100644 --- a/STROOP/Structs/Configurations/ObjectSlotsConfig.cs +++ b/STROOP/Structs/Configurations/ObjectSlotsConfig.cs @@ -2,6 +2,7 @@ using System.Linq; using System.Drawing; using STROOP.Structs.Configurations; +using STROOP.Variables.SM64MemoryLayout; namespace STROOP.Structs { diff --git a/STROOP/Structs/Configurations/RomVersionConfig.cs b/STROOP/Structs/Configurations/RomVersionConfig.cs deleted file mode 100644 index 6694faf59..000000000 --- a/STROOP/Structs/Configurations/RomVersionConfig.cs +++ /dev/null @@ -1,135 +0,0 @@ -using System; -using System.Windows.Forms; - -namespace STROOP.Structs.Configurations -{ - public static class RomVersionConfig - { - public static RomVersion Version = RomVersion.US; - - public static uint RomVersionTellAddress = 0x802F0000; - public static uint RomVersionTellValueUS = 0xC58400A4; - public static uint RomVersionTellValueJP = 0x27BD0020; - public static uint RomVersionTellValueSH = 0x8F250004; - public static uint RomVersionTellValueEU = 0x0C0BD4AC; - - public static void UpdateRomVersion(ComboBox comboBoxRomVersion) - { - RomVersionSelection romVersionSelection = (RomVersionSelection)comboBoxRomVersion.SelectedItem; - switch (romVersionSelection) - { - case RomVersionSelection.AUTO: - case RomVersionSelection.AUTO_US: - case RomVersionSelection.AUTO_JP: - case RomVersionSelection.AUTO_SH: - case RomVersionSelection.AUTO_EU: - RomVersion? autoRomVersionNullable = GetRomVersionUsingTell(); - if (!autoRomVersionNullable.HasValue) return; - RomVersion autoRomVersion = autoRomVersionNullable.Value; - Version = autoRomVersion; - if (!comboBoxRomVersion.DroppedDown) - { - switch (autoRomVersion) - { - case RomVersion.US: - comboBoxRomVersion.SelectedItem = RomVersionSelection.AUTO_US; - break; - case RomVersion.JP: - comboBoxRomVersion.SelectedItem = RomVersionSelection.AUTO_JP; - break; - case RomVersion.SH: - comboBoxRomVersion.SelectedItem = RomVersionSelection.AUTO_SH; - break; - case RomVersion.EU: - comboBoxRomVersion.SelectedItem = RomVersionSelection.AUTO_EU; - break; - default: - throw new ArgumentOutOfRangeException(); - } - } - - break; - case RomVersionSelection.US: - Version = RomVersion.US; - break; - case RomVersionSelection.JP: - Version = RomVersion.JP; - break; - case RomVersionSelection.SH: - Version = RomVersion.SH; - break; - case RomVersionSelection.EU: - Version = RomVersion.EU; - break; - default: - throw new ArgumentOutOfRangeException(); - } - } - - private static RomVersion? GetRomVersionUsingTell() - { - uint tell = Config.Stream.GetUInt32(RomVersionTellAddress); - if (tell == RomVersionTellValueUS) return RomVersion.US; - if (tell == RomVersionTellValueJP) return RomVersion.JP; - if (tell == RomVersionTellValueSH) return RomVersion.SH; - if (tell == RomVersionTellValueEU) return RomVersion.EU; - return RomVersion.US; - } - - public static uint SwitchMap(uint? valUS = null, uint? valJP = null, uint? valSH = null, uint? valEU = null) - { - uint address = SwitchOnly(valUS, valJP, valSH, valEU); - address = MappingConfig.HandleMapping(address); - return address; - } - - public static uint SwitchReverseMap(uint? valUS = null, uint? valJP = null, uint? valSH = null, uint? valEU = null) - { - uint address = SwitchOnly(valUS, valJP, valSH, valEU); - address = MappingConfig.HandleReverseMapping(address); - return address; - } - - public static uint SwitchOnly(uint? valUS = null, uint? valJP = null, uint? valSH = null, uint? valEU = null) - { - switch (Version) - { - case RomVersion.US: - if (valUS.HasValue) return valUS.Value; - break; - case RomVersion.JP: - if (valJP.HasValue) return valJP.Value; - break; - case RomVersion.SH: - if (valSH.HasValue) return valSH.Value; - break; - case RomVersion.EU: - if (valEU.HasValue) return valEU.Value; - break; - } - - return 0; - } - - public static ushort Switch(ushort? valUS = null, ushort? valJP = null, ushort? valSH = null, ushort? valEU = null) - { - switch (Version) - { - case RomVersion.US: - if (valUS.HasValue) return valUS.Value; - break; - case RomVersion.JP: - if (valJP.HasValue) return valJP.Value; - break; - case RomVersion.SH: - if (valSH.HasValue) return valSH.Value; - break; - case RomVersion.EU: - if (valEU.HasValue) return valEU.Value; - break; - } - - return 0; - } - } -} diff --git a/STROOP/Structs/Configurations/SnowConfig.cs b/STROOP/Structs/Configurations/SnowConfig.cs index 9b6ad7540..92d7fcb77 100644 --- a/STROOP/Structs/Configurations/SnowConfig.cs +++ b/STROOP/Structs/Configurations/SnowConfig.cs @@ -1,4 +1,5 @@ using STROOP.Structs.Configurations; +using STROOP.Variables.SM64MemoryLayout; namespace STROOP.Structs { diff --git a/STROOP/Structs/Configurations/SpecialConfig.cs b/STROOP/Structs/Configurations/SpecialConfig.cs index 1a87af4a6..f2590d6d5 100644 --- a/STROOP/Structs/Configurations/SpecialConfig.cs +++ b/STROOP/Structs/Configurations/SpecialConfig.cs @@ -1,4 +1,5 @@ -using STROOP.Models; +using STROOP.Core; +using STROOP.Models; using STROOP.Utilities; using System; using System.Collections.Generic; diff --git a/STROOP/Structs/Configurations/TriangleConfig.cs b/STROOP/Structs/Configurations/TriangleConfig.cs index dbf63e092..585611fb2 100644 --- a/STROOP/Structs/Configurations/TriangleConfig.cs +++ b/STROOP/Structs/Configurations/TriangleConfig.cs @@ -1,4 +1,6 @@ -namespace STROOP.Structs.Configurations +using STROOP.Variables.SM64MemoryLayout; + +namespace STROOP.Structs.Configurations { public static class TriangleConfig { diff --git a/STROOP/Structs/Configurations/TtcObjectConfig.cs b/STROOP/Structs/Configurations/TtcObjectConfig.cs index 6c838f274..2239c6dce 100644 --- a/STROOP/Structs/Configurations/TtcObjectConfig.cs +++ b/STROOP/Structs/Configurations/TtcObjectConfig.cs @@ -1,4 +1,5 @@ using STROOP.Structs.Configurations; +using STROOP.Variables.SM64MemoryLayout; namespace STROOP.Structs { diff --git a/STROOP/Structs/Emulator.cs b/STROOP/Structs/Emulator.cs deleted file mode 100644 index 5d827790e..000000000 --- a/STROOP/Structs/Emulator.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; - -namespace STROOP.Structs -{ - 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; - } -} diff --git a/STROOP/Structs/Gui/ObjectSlotManagerGui.cs b/STROOP/Structs/Gui/ObjectSlotManagerGui.cs index 8452ff45a..38fa48a6f 100644 --- a/STROOP/Structs/Gui/ObjectSlotManagerGui.cs +++ b/STROOP/Structs/Gui/ObjectSlotManagerGui.cs @@ -5,11 +5,10 @@ namespace STROOP.Structs { public class ObjectSlotManagerGui { - public CheckBox checkBoxObjLockLabels; public TabControl tabControlMain; public ComboBox comboBoxSortMethod; public ComboBox comboBoxLabelMethod; public ComboBox comboBoxSelectionMethod; - public ObjectSlotFlowLayoutPanel WatchVariablePanelObjects; + public ObjectSlotFlowLayoutPanel VariablePanelObjects; } } diff --git a/STROOP/Structs/InitializeSpecialAttribute.cs b/STROOP/Structs/InitializeSpecialAttribute.cs deleted file mode 100644 index 13a903679..000000000 --- a/STROOP/Structs/InitializeSpecialAttribute.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; - -namespace STROOP.Utilities -{ - [AttributeUsage(AttributeTargets.Method, Inherited = true, AllowMultiple = false)] - public abstract class InitializerAttribute : Attribute - { - } - - public class InitializeSpecialAttribute : InitializerAttribute - { - } - - public class InitializeBaseAddressAttribute : InitializerAttribute - { - } -} diff --git a/STROOP/Structs/ObjectAssociations.cs b/STROOP/Structs/ObjectAssociations.cs index 81ead8b13..33837d038 100644 --- a/STROOP/Structs/ObjectAssociations.cs +++ b/STROOP/Structs/ObjectAssociations.cs @@ -5,7 +5,8 @@ using STROOP.Utilities; using STROOP.Extensions; using STROOP.Structs.Configurations; -using STROOP.Core.Variables; +using STROOP.Variables; +using STROOP.Variables.SM64MemoryLayout; namespace STROOP.Structs { @@ -210,15 +211,8 @@ public string GetObjectName(BehaviorCriteria behaviorCriteria) return assoc.Name; } - public IEnumerable GetWatchVarControls(BehaviorCriteria behaviorCriteria) - { - var assoc = FindObjectAssociation(behaviorCriteria); - - if (assoc == null) - return Array.Empty(); - - else return assoc.Precursors; - } + public IEnumerable GetVariablePrecursors(BehaviorCriteria behaviorCriteria) + => FindObjectAssociation(behaviorCriteria)?.Precursors ?? []; public uint AlignJPBehavior(uint segmented) { diff --git a/STROOP/Structs/ObjectBehaviorAssociation.cs b/STROOP/Structs/ObjectBehaviorAssociation.cs index 2d2d18774..0c64a0188 100644 --- a/STROOP/Structs/ObjectBehaviorAssociation.cs +++ b/STROOP/Structs/ObjectBehaviorAssociation.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using System.Drawing; -using STROOP.Core.Variables; +using STROOP.Variables; namespace STROOP.Structs { @@ -17,7 +17,7 @@ public class ObjectBehaviorAssociation public Lazy TransparentImage; public Lazy MapImage; public PushHitbox PushHitbox; - public List Precursors = new List(); + public List Precursors = new List(); public bool MeetsCriteria(BehaviorCriteria behaviorCriteria) { diff --git a/STROOP/Structs/PendulumSwingTable.cs b/STROOP/Structs/PendulumSwingTable.cs index b1189ac8a..631e177ab 100644 --- a/STROOP/Structs/PendulumSwingTable.cs +++ b/STROOP/Structs/PendulumSwingTable.cs @@ -1,5 +1,6 @@ using STROOP.Ttc; using STROOP.Utilities; +using STROOP.Variables.Utilities; using System; using System.Collections.Generic; @@ -173,8 +174,8 @@ public List GetSuccessors() { return new List() { - new PendulumSwing((int)WatchVariableSpecialUtilities.GetPendulumAmplitude(Amplitude, 13), 13, this, PrimaryIndex, SecondaryIndex + 1), - new PendulumSwing((int)WatchVariableSpecialUtilities.GetPendulumAmplitude(Amplitude, 42), 42, this, PrimaryIndex, SecondaryIndex + 1), + new PendulumSwing((int)VariableSpecialUtilities.GetPendulumAmplitude(Amplitude, 13), 13, this, PrimaryIndex, SecondaryIndex + 1), + new PendulumSwing((int)VariableSpecialUtilities.GetPendulumAmplitude(Amplitude, 42), 42, this, PrimaryIndex, SecondaryIndex + 1), }; } diff --git a/STROOP/Structs/PushHitbox.cs b/STROOP/Structs/PushHitbox.cs index 977cb651c..77102cc1c 100644 --- a/STROOP/Structs/PushHitbox.cs +++ b/STROOP/Structs/PushHitbox.cs @@ -1,4 +1,5 @@ using STROOP.Structs.Configurations; +using STROOP.Variables.SM64MemoryLayout; namespace STROOP.Structs { diff --git a/STROOP/Structs/RomHack.cs b/STROOP/Structs/RomHack.cs index 6b8fc8dfa..7575a111e 100644 --- a/STROOP/Structs/RomHack.cs +++ b/STROOP/Structs/RomHack.cs @@ -1,5 +1,7 @@ -using STROOP.Structs.Configurations; +using STROOP.Core; +using STROOP.Structs.Configurations; using STROOP.Utilities; +using STROOP.Variables.Utilities; using System; using System.Collections.Generic; using System.IO; diff --git a/STROOP/TTC/TTCCog.cs b/STROOP/TTC/TTCCog.cs index c88d53ed1..a1c21133e 100644 --- a/STROOP/TTC/TTCCog.cs +++ b/STROOP/TTC/TTCCog.cs @@ -23,7 +23,7 @@ public class TtcCog : TtcObject public int _endingYaw { - get => WatchVariableSpecialUtilities.GetCogEndingYaw( + get => VariableSpecialUtilities.GetCogEndingYaw( MoreMath.NormalizeAngleUshort(_angle), _currentAngularVelocity, _targetAngularVelocity); } diff --git a/STROOP/TTC/TTCPendulum.cs b/STROOP/TTC/TTCPendulum.cs index 5223d5fb6..95ae3f66c 100644 --- a/STROOP/TTC/TTCPendulum.cs +++ b/STROOP/TTC/TTCPendulum.cs @@ -103,7 +103,7 @@ public override List GetFields() public int GetAmplitude() { - return (int)WatchVariableSpecialUtilities.GetPendulumAmplitude( + return (int)VariableSpecialUtilities.GetPendulumAmplitude( _accelerationDirection, _accelerationMagnitude, _angularVelocity, _angle); } @@ -124,7 +124,7 @@ public string GetSwingIndexExtended() public int GetCountdown() { - return WatchVariableSpecialUtilities.GetPendulumCountdown( + return VariableSpecialUtilities.GetPendulumCountdown( _accelerationDirection, _accelerationMagnitude, _angularVelocity, _angle, _waitingTimer); } diff --git a/STROOP/TTC/TtcPendulum2.cs b/STROOP/TTC/TtcPendulum2.cs index 1ac6cc600..3428df3eb 100644 --- a/STROOP/TTC/TtcPendulum2.cs +++ b/STROOP/TTC/TtcPendulum2.cs @@ -98,7 +98,7 @@ public override List GetFields() public int GetAmplitude() { - return (int)WatchVariableSpecialUtilities.GetPendulumAmplitude( + return (int)VariableSpecialUtilities.GetPendulumAmplitude( _accelerationDirection, _accelerationMagnitude, _angularVelocity, _angle); } @@ -114,7 +114,7 @@ public string GetSwingIndexExtended() public int GetCountdown() { - return WatchVariableSpecialUtilities.GetPendulumCountdown( + return VariableSpecialUtilities.GetPendulumCountdown( _accelerationDirection, _accelerationMagnitude, _angularVelocity, _angle, _waitingTimer); } diff --git a/STROOP/TTC/TtcSaveState.cs b/STROOP/TTC/TtcSaveState.cs index 492e0aa7b..5ab4d4bcf 100644 --- a/STROOP/TTC/TtcSaveState.cs +++ b/STROOP/TTC/TtcSaveState.cs @@ -1,6 +1,7 @@ using STROOP.Structs; using STROOP.Structs.Configurations; using STROOP.Utilities; +using STROOP.Variables.Utilities; using System; using System.Collections.Generic; using System.Linq; diff --git a/STROOP/TTC/TtcSaveStateByteIterator.cs b/STROOP/TTC/TtcSaveStateByteIterator.cs index 0acd0daaf..1c2f59b95 100644 --- a/STROOP/TTC/TtcSaveStateByteIterator.cs +++ b/STROOP/TTC/TtcSaveStateByteIterator.cs @@ -1,4 +1,5 @@ using STROOP.Structs; +using STROOP.Variables.Utilities; using System.Collections.Generic; using System.Linq; diff --git a/STROOP/TTC/TtcSimulation.cs b/STROOP/TTC/TtcSimulation.cs index d25bf7f70..172ac6f66 100644 --- a/STROOP/TTC/TtcSimulation.cs +++ b/STROOP/TTC/TtcSimulation.cs @@ -212,7 +212,7 @@ public string GetObjectsString(int endingFrame) int objectIndex = objectIndexNullable.Value; TtcPendulum pendulum = _rngObjects[objectIndex] as TtcPendulum; - int pendulumAmplitudeStart = (int)WatchVariableSpecialUtilities.GetPendulumAmplitude( + int pendulumAmplitudeStart = (int)VariableSpecialUtilities.GetPendulumAmplitude( pendulum._accelerationDirection, pendulum._accelerationMagnitude, pendulum._angularVelocity, pendulum._angle); int? pendulumSwingIndexStartNullable = TableConfig.PendulumSwings.GetPendulumSwingIndex(pendulumAmplitudeStart); if (!pendulumSwingIndexStartNullable.HasValue) return (false, null, 0); @@ -231,7 +231,7 @@ public string GetObjectsString(int endingFrame) rngObject.Update(); } - int pendulumAmplitude = (int)WatchVariableSpecialUtilities.GetPendulumAmplitude( + int pendulumAmplitude = (int)VariableSpecialUtilities.GetPendulumAmplitude( pendulum._accelerationDirection, pendulum._accelerationMagnitude, pendulum._angularVelocity, pendulum._angle); int? pendulumSwingIndexNullable = TableConfig.PendulumSwings.GetPendulumSwingIndex(pendulumAmplitude); if (!pendulumSwingIndexNullable.HasValue) return (false, null, 0); diff --git a/STROOP/TTC/TtcUtilities.cs b/STROOP/TTC/TtcUtilities.cs index 97350a340..487222af4 100644 --- a/STROOP/TTC/TtcUtilities.cs +++ b/STROOP/TTC/TtcUtilities.cs @@ -2,6 +2,7 @@ using STROOP.Structs; using STROOP.Structs.Configurations; using STROOP.Utilities; +using STROOP.Variables.Utilities; using System; using System.Collections.Generic; diff --git a/STROOP/Tabs/ActionsTab.Designer.cs b/STROOP/Tabs/ActionsTab.Designer.cs index 3724a131f..f609bb533 100644 --- a/STROOP/Tabs/ActionsTab.Designer.cs +++ b/STROOP/Tabs/ActionsTab.Designer.cs @@ -31,7 +31,7 @@ private void InitializeComponent() this.components = new System.ComponentModel.Container(); this.textBoxAnimationDescription = new STROOP.BetterTextbox(); this.textBoxActionDescription = new STROOP.BetterTextbox(); - this.watchVariablePanelActions = new STROOP.Controls.VariablePanel.WatchVariablePanel(); + this._variablePanelActions = new STROOP.Controls.VariablePanel.VariablePanel(); this.SuspendLayout(); // // textBoxAnimationDescription @@ -61,19 +61,19 @@ private void InitializeComponent() // // watchVariablePanelActions // - this.watchVariablePanelActions.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + this._variablePanelActions.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.watchVariablePanelActions.DataPath = "Config/ActionsData.xml"; - this.watchVariablePanelActions.Location = new System.Drawing.Point(3, 70); - this.watchVariablePanelActions.Name = "watchVariablePanelActions"; - this.watchVariablePanelActions.Size = new System.Drawing.Size(909, 390); - this.watchVariablePanelActions.TabIndex = 37; + this._variablePanelActions.DataPath = "Config/ActionsData.xml"; + this._variablePanelActions.Location = new System.Drawing.Point(3, 70); + this._variablePanelActions.Name = "_variablePanelActions"; + this._variablePanelActions.Size = new System.Drawing.Size(909, 390); + this._variablePanelActions.TabIndex = 37; // // ActionsTab // this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit; - this.Controls.Add(this.watchVariablePanelActions); + this.Controls.Add(this._variablePanelActions); this.Controls.Add(this.textBoxAnimationDescription); this.Controls.Add(this.textBoxActionDescription); this.Name = "ActionsTab"; @@ -87,6 +87,6 @@ private void InitializeComponent() private BetterTextbox textBoxAnimationDescription; private BetterTextbox textBoxActionDescription; - private STROOP.Controls.VariablePanel.WatchVariablePanel watchVariablePanelActions; + private STROOP.Controls.VariablePanel.VariablePanel _variablePanelActions; } } diff --git a/STROOP/Tabs/ActionsTab.cs b/STROOP/Tabs/ActionsTab.cs index 74c48512f..a9a5112c3 100644 --- a/STROOP/Tabs/ActionsTab.cs +++ b/STROOP/Tabs/ActionsTab.cs @@ -4,6 +4,7 @@ using STROOP.Utilities; using STROOP.Structs.Configurations; using STROOP.Forms; +using STROOP.Variables.SM64MemoryLayout; namespace STROOP.Tabs { diff --git a/STROOP/Tabs/AreaTab.Designer.cs b/STROOP/Tabs/AreaTab.Designer.cs index 4d9b715d1..fa1cc8c2b 100644 --- a/STROOP/Tabs/AreaTab.Designer.cs +++ b/STROOP/Tabs/AreaTab.Designer.cs @@ -40,7 +40,7 @@ private void InitializeComponent() this.radioButtonArea1 = new System.Windows.Forms.RadioButton(); this.radioButtonArea2 = new System.Windows.Forms.RadioButton(); this.checkBoxSelectCurrentArea = new System.Windows.Forms.CheckBox(); - this.watchVariablePanelArea = new STROOP.Controls.VariablePanel.WatchVariablePanel(); + this._variablePanelArea = new STROOP.Controls.VariablePanel.VariablePanel(); ((System.ComponentModel.ISupportInitialize)(this.splitContainerArea)).BeginInit(); this.splitContainerArea.Panel1.SuspendLayout(); this.splitContainerArea.Panel2.SuspendLayout(); @@ -75,7 +75,7 @@ private void InitializeComponent() // // splitContainerArea.Panel2 // - this.splitContainerArea.Panel2.Controls.Add(this.watchVariablePanelArea); + this.splitContainerArea.Panel2.Controls.Add(this._variablePanelArea); this.splitContainerArea.Panel2.Padding = new System.Windows.Forms.Padding(2); this.splitContainerArea.Panel2MinSize = 0; this.splitContainerArea.Size = new System.Drawing.Size(915, 463); @@ -188,13 +188,13 @@ private void InitializeComponent() // // watchVariablePanelArea // - this.watchVariablePanelArea.DataPath = "Config/AreaData.xml"; - this.watchVariablePanelArea.Dock = System.Windows.Forms.DockStyle.Fill; - this.watchVariablePanelArea.Location = new System.Drawing.Point(2, 2); - this.watchVariablePanelArea.Margin = new System.Windows.Forms.Padding(0); - this.watchVariablePanelArea.Name = "watchVariablePanelArea"; - this.watchVariablePanelArea.Size = new System.Drawing.Size(755, 457); - this.watchVariablePanelArea.TabIndex = 7; + this._variablePanelArea.DataPath = "Config/AreaData.xml"; + this._variablePanelArea.Dock = System.Windows.Forms.DockStyle.Fill; + this._variablePanelArea.Location = new System.Drawing.Point(2, 2); + this._variablePanelArea.Margin = new System.Windows.Forms.Padding(0); + this._variablePanelArea.Name = "_variablePanelArea"; + this._variablePanelArea.Size = new System.Drawing.Size(755, 457); + this._variablePanelArea.TabIndex = 7; // // AreaTab // @@ -225,6 +225,6 @@ private void InitializeComponent() private System.Windows.Forms.RadioButton radioButtonArea1; private System.Windows.Forms.RadioButton radioButtonArea2; private System.Windows.Forms.CheckBox checkBoxSelectCurrentArea; - private STROOP.Controls.VariablePanel.WatchVariablePanel watchVariablePanelArea; + private STROOP.Controls.VariablePanel.VariablePanel _variablePanelArea; } } diff --git a/STROOP/Tabs/AreaTab.cs b/STROOP/Tabs/AreaTab.cs index 1245ebd65..2eba48d77 100644 --- a/STROOP/Tabs/AreaTab.cs +++ b/STROOP/Tabs/AreaTab.cs @@ -1,14 +1,34 @@ -using System.Collections.Generic; +using STROOP.Core; +using System.Collections.Generic; using System.Windows.Forms; using STROOP.Structs; using STROOP.Structs.Configurations; +using STROOP.Variables; +using STROOP.Variables.SM64MemoryLayout; +using STROOP.Variables.Utilities; namespace STROOP.Tabs { public partial class AreaTab : STROOPTab { - public uint SelectedAreaAddress { get; private set; } + [InitializeBaseAddress] + static void InitializeBaseAddress() + { + VariableUtilities.baseAddressGetters[BaseAddressType.Area] = () => [SelectedAreaAddress]; + } + + public static uint SelectedAreaAddress + { + get + { + var tab = AccessScope.content.GetTab(); + return tab.checkBoxSelectCurrentArea.Checked + ? Config.Stream.GetUInt32(MarioConfig.StructAddress + MarioConfig.AreaPointerOffset) + : AreaUtilities.GetAreaAddress(tab.SelectedAreaIndex); + } + } + int SelectedAreaIndex; List _selectedAreaRadioButtons; public AreaTab() @@ -21,7 +41,7 @@ public AreaTab() public override void InitializeTab() { base.InitializeTab(); - SelectedAreaAddress = AreaUtilities.GetAreaAddress(0); + SelectedAreaIndex = 0; _selectedAreaRadioButtons = new List(); for (int i = 0; i < 8; i++) @@ -35,18 +55,13 @@ public override void InitializeTab() _selectedAreaRadioButtons[i].Click += (sender, e) => { checkBoxSelectCurrentArea.Checked = false; - SelectedAreaAddress = AreaUtilities.GetAreaAddress(index); + SelectedAreaIndex = index; }; } } public override void Update(bool updateView) { - if (checkBoxSelectCurrentArea.Checked) - { - SelectedAreaAddress = Config.Stream.GetUInt32(MarioConfig.StructAddress + MarioConfig.AreaPointerOffset); - } - if (!updateView) return; base.Update(updateView); diff --git a/STROOP/Tabs/BruteforceTab/BF_Utilities/BF_VariableUtilties.cs b/STROOP/Tabs/BruteforceTab/BF_Utilities/BF_VariableUtilties.cs index bbe8e9d4d..3407edef9 100644 --- a/STROOP/Tabs/BruteforceTab/BF_Utilities/BF_VariableUtilties.cs +++ b/STROOP/Tabs/BruteforceTab/BF_Utilities/BF_VariableUtilties.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Reflection; using STROOP.Controls.VariablePanel; -using STROOP.Core.Variables; +using STROOP.Variables; namespace STROOP.Tabs.BruteforceTab.BF_Utilities { @@ -25,19 +25,19 @@ public WatchVariableQuarterstepWrapper(NamedVariableCollection.IView var, } } - public static readonly Dictionary fallbackWrapperTypes = new Dictionary() + public static readonly Dictionary fallbackWrapperTypes = new Dictionary() { - ["u32"] = typeof(WatchVariableNumberWrapper), - ["s32"] = typeof(WatchVariableNumberWrapper), - ["u16"] = typeof(WatchVariableNumberWrapper), - ["s16"] = typeof(WatchVariableNumberWrapper), - ["u8"] = typeof(WatchVariableNumberWrapper), - ["s8"] = typeof(WatchVariableNumberWrapper), - ["f32"] = typeof(WatchVariableNumberWrapper), - ["f64"] = typeof(WatchVariableNumberWrapper), - ["string"] = typeof(WatchVariableStringWrapper), - ["boolean"] = typeof(WatchVariableBooleanWrapper), - ["quarterstep"] = typeof(WatchVariableQuarterstepWrapper), + ["u32"] = WatchVariableSubclass.Number, + ["s32"] = WatchVariableSubclass.Number, + ["u16"] = WatchVariableSubclass.Number, + ["s16"] = WatchVariableSubclass.Number, + ["u8"] = WatchVariableSubclass.Number, + ["s8"] = WatchVariableSubclass.Number, + ["f32"] = WatchVariableSubclass.Number, + ["f64"] = WatchVariableSubclass.Number, + ["string"] = WatchVariableSubclass.String, + ["boolean"] = WatchVariableSubclass.Boolean, + // ["quarterstep"] = /* what* /, }; public static readonly Dictionary backingTypes = new Dictionary() diff --git a/STROOP/Tabs/BruteforceTab/BruteforceTab.cs b/STROOP/Tabs/BruteforceTab/BruteforceTab.cs index f9b5165ad..58d044a6f 100644 --- a/STROOP/Tabs/BruteforceTab/BruteforceTab.cs +++ b/STROOP/Tabs/BruteforceTab/BruteforceTab.cs @@ -8,9 +8,12 @@ using System.Xml.Linq; using Microsoft.WindowsAPICodePack.Dialogs; using STROOP.Controls.VariablePanel; +using STROOP.Core; using STROOP.Core.Variables; using STROOP.Tabs.BruteforceTab.BF_Utilities; using STROOP.Utilities; +using STROOP.Variables.Utilities; +using System.Globalization; using AutomaticParameterGetters = System.Collections.Generic.Dictionary>; namespace STROOP.Tabs.BruteforceTab @@ -62,6 +65,42 @@ static BruteforceTab() moduleTypes = lst; } + static System.Text.RegularExpressions.Regex needsJsonStringEscapeRegex = new System.Text.RegularExpressions.Regex("^[-]?(([0-9]+)|(([0-9]+)\\.([0-9]+)))$"); + + public static string MakeJsonValue(string input) + { + input = input.Trim(' ', '"'); + if (!needsJsonStringEscapeRegex.IsMatch(input)) + return $"\"{input}\""; + return input; + } + + public static object GetJsonValue(Type variableCrlType, string valueString) + { + var str = valueString.Trim('"'); + double numberValue = 0; + if (TypeUtilities.IsNumber(variableCrlType)) + { + bool set = true; + if (str.StartsWith("0x")) + { + if (set = long.TryParse(str.Substring(2, str.Length - 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var hexValue)) + numberValue = hexValue; + } + else + set = double.TryParse(str, out numberValue); + + if (set) + return numberValue; + } + else if (typeof(WatchVariableBooleanWrapper) == typeof(bool)) + return valueString.ToLower() != "false" && (!int.TryParse(valueString, out var boolNumber) || boolNumber != 0); + else + return valueString; + + return 0; + } + public string modulePath { get; private set; } public Surface surface { get; private set; } public event Action Updating; @@ -276,7 +315,7 @@ private void InitStateGetters() stateGetters[v.Key] = () => { var str = lst.FirstOrDefault().ToString(); - return StringUtilities.MakeJsonValue(str); + return MakeJsonValue(str); }; } } @@ -392,7 +431,7 @@ private void FindManualParameters(string moduleName) manualParameterVariables.Add(newWatchVar); newWatchVar.ValueSet += UpdateState; ctrl = watchVariablePanelParams.AddVariable(newWatchVar); - Func fn = () => StringUtilities.MakeJsonValue(newWatchVar.value?.ToString() ?? "0"); + Func fn = () => MakeJsonValue(newWatchVar.value?.ToString() ?? "0"); if (v.Value.modifier == "control") { controlStateGetters[v.Key] = fn; @@ -481,7 +520,7 @@ void WriteFrame(StringBuilder builder) string readMethod = null; string format = null; - switch (memoryView.memoryDescriptor.MemoryType) + switch (memoryView.memoryDescriptor.ClrType) { case Type t when t == typeof(sbyte): readMethod = "bytesigned"; @@ -565,7 +604,7 @@ private void ApplyKnownState() var strBuilder = new StringBuilder(); foreach (var v in variables) if (stateGetters.TryGetValue(v.Key, out var getter)) - strBuilder.AppendLine($"\t\"{v.Key}\": {StringUtilities.MakeJsonValue(getter())},"); + strBuilder.AppendLine($"\t\"{v.Key}\": {MakeJsonValue(getter())},"); var knownState = strBuilder.ToString(); jsonTexts["knownState"] = () => knownState; } @@ -581,7 +620,7 @@ private void ReadJson(string fileName) foreach (var targetVariable in manualParameterVariables) // If any of the controllable variables match, set them if (targetVariable.GetJsonName() == kvp.Key) { - targetVariable.value = StringUtilities.GetJsonValue(targetVariable.GetWrapperType(), kvp.Value.valueObject.ToString()) as IConvertible ?? 0; + targetVariable.value = GetJsonValue(targetVariable.ClrType, kvp.Value.valueObject.ToString()) as IConvertible ?? 0; goto skipNew; } diff --git a/STROOP/Tabs/BruteforceTab/BruteforceVariableView.cs b/STROOP/Tabs/BruteforceTab/BruteforceVariableView.cs index d3c9d5f57..2e321c2c0 100644 --- a/STROOP/Tabs/BruteforceTab/BruteforceVariableView.cs +++ b/STROOP/Tabs/BruteforceTab/BruteforceVariableView.cs @@ -1,6 +1,8 @@ -using System; +using STROOP.Core.Utilities; +using System; using STROOP.Core.Variables; using STROOP.Utilities; +using STROOP.Variables; namespace STROOP.Tabs.BruteforceTab { @@ -38,8 +40,8 @@ object IBruteforceVariableView.value { } - public BruteforceVariableView(Type wrapperType, string name, T defaultValue = default(T)) - : base(wrapperType) + public BruteforceVariableView(WatchVariableSubclass subclass, string name, T defaultValue = default(T)) + : base(subclass) { Name = name; _value = defaultValue; diff --git a/STROOP/Tabs/BruteforceTab/Surfaces/GeneralPurpose/GeneralPurpose.cs b/STROOP/Tabs/BruteforceTab/Surfaces/GeneralPurpose/GeneralPurpose.cs index 82d984882..a31433bbe 100644 --- a/STROOP/Tabs/BruteforceTab/Surfaces/GeneralPurpose/GeneralPurpose.cs +++ b/STROOP/Tabs/BruteforceTab/Surfaces/GeneralPurpose/GeneralPurpose.cs @@ -4,6 +4,7 @@ using System.Windows.Forms; using STROOP.Utilities; using STROOP.Tabs.BruteforceTab.BF_Utilities; +using STROOP.Variables.Utilities; namespace STROOP.Tabs.BruteforceTab.Surfaces.GeneralPurpose { @@ -23,7 +24,7 @@ public class Identifier public double weight = 1.0; public Dictionary parameterDefinitions = new Dictionary( - new Utilities.EqualityComparer((a, b) => a.name == b.name, a => a.name.GetHashCode()) + new Core.Utilities.EqualityComparer((a, b) => a.name == b.name, a => a.name.GetHashCode()) ); public Dictionary parameterValues = new Dictionary(); @@ -240,7 +241,7 @@ public override void InitJson() precursor.parameterValues[n.Key] = BF_VariableUtilties.CreateNamedVariable( bruteforcerType, n.Key, - StringUtilities.GetJsonValue(precursor.GetParameterWrapperType(n.Key), stringNode.value) + BruteforceTab.GetJsonValue(precursor.GetParameterWrapperType(n.Key), stringNode.value) ); else precursor.parameterValues[n.Key] = BF_VariableUtilties.CreateNamedVariable( diff --git a/STROOP/Tabs/BruteforceTab/Surfaces/GeneralPurpose/MethodControllers/CheckAction.cs b/STROOP/Tabs/BruteforceTab/Surfaces/GeneralPurpose/MethodControllers/CheckAction.cs index 6b955fe9b..854264dd7 100644 --- a/STROOP/Tabs/BruteforceTab/Surfaces/GeneralPurpose/MethodControllers/CheckAction.cs +++ b/STROOP/Tabs/BruteforceTab/Surfaces/GeneralPurpose/MethodControllers/CheckAction.cs @@ -3,6 +3,7 @@ using STROOP.Core.Variables; using STROOP.Structs.Configurations; using STROOP.Utilities; +using STROOP.Variables.SM64MemoryLayout; namespace STROOP.Tabs.BruteforceTab.Surfaces.GeneralPurpose.MethodControllers { @@ -29,13 +30,13 @@ void IMethodController.SetTargetFunc(ScoringFunc target) // Init to current action if not loaded from file? if (currentActionVariable.view.GetNumberValues().FirstOrDefault() == 0) - currentActionVariable.SetValue(Config.Stream.GetInt32(Structs.MarioConfig.StructAddress + Structs.MarioConfig.ActionOffset)); + currentActionVariable.SetValue(Config.Stream.GetInt32(MarioConfig.StructAddress + MarioConfig.ActionOffset)); var ctrl = (WatchVariableSelectionWrapper)panel.AddVariable(view).WatchVarWrapper; ctrl.DisplaySingleOption = true; ctrl.options.Add(("Set action now", () => { - var action = Config.Stream.GetInt32(Structs.MarioConfig.StructAddress + Structs.MarioConfig.ActionOffset); + var action = Config.Stream.GetInt32(MarioConfig.StructAddress + MarioConfig.ActionOffset); currentActionVariable.SetValue(action); return null; } diff --git a/STROOP/Tabs/BruteforceTab/Surfaces/GeneralPurpose/MethodControllers/TrackerMethodControllerBase.cs b/STROOP/Tabs/BruteforceTab/Surfaces/GeneralPurpose/MethodControllers/TrackerMethodControllerBase.cs index eb49158bb..9f7bf187b 100644 --- a/STROOP/Tabs/BruteforceTab/Surfaces/GeneralPurpose/MethodControllers/TrackerMethodControllerBase.cs +++ b/STROOP/Tabs/BruteforceTab/Surfaces/GeneralPurpose/MethodControllers/TrackerMethodControllerBase.cs @@ -1,5 +1,6 @@ using System.Windows.Forms; using STROOP.Controls.VariablePanel; +using STROOP.Core; using STROOP.Core.Variables; using STROOP.Utilities; diff --git a/STROOP/Tabs/BruteforceTab/Surfaces/GeneralPurpose/MethodControllers/XZRadialLimit.cs b/STROOP/Tabs/BruteforceTab/Surfaces/GeneralPurpose/MethodControllers/XZRadialLimit.cs index 8b1a90386..41e7a2d0d 100644 --- a/STROOP/Tabs/BruteforceTab/Surfaces/GeneralPurpose/MethodControllers/XZRadialLimit.cs +++ b/STROOP/Tabs/BruteforceTab/Surfaces/GeneralPurpose/MethodControllers/XZRadialLimit.cs @@ -5,6 +5,7 @@ using System.Linq; using OpenTK; using OpenTK.Mathematics; +using STROOP.Core; using STROOP.Tabs.MapTab; using STROOP.Structs.Configurations; using STROOP.Utilities; diff --git a/STROOP/Tabs/BruteforceTab/Surfaces/GeneralPurpose/ScoringFunc.cs b/STROOP/Tabs/BruteforceTab/Surfaces/GeneralPurpose/ScoringFunc.cs index c5f8e3303..8017f5fe8 100644 --- a/STROOP/Tabs/BruteforceTab/Surfaces/GeneralPurpose/ScoringFunc.cs +++ b/STROOP/Tabs/BruteforceTab/Surfaces/GeneralPurpose/ScoringFunc.cs @@ -6,9 +6,12 @@ using System.Text; using System.Windows.Forms; using STROOP.Controls.VariablePanel; +using STROOP.Core; +using STROOP.Core.Utilities; using STROOP.Core.Variables; using STROOP.Tabs.BruteforceTab.BF_Utilities; using STROOP.Utilities; +using STROOP.Variables.Utilities; namespace STROOP.Tabs.BruteforceTab.Surfaces.GeneralPurpose { @@ -101,7 +104,7 @@ public void Init(GeneralPurpose.ScoringFuncPrecursor precursor, BruteforceTab br bruteforceTab.Updating += UpdateTooltip; Disposed += (_, __) => bruteforceTab.Updating -= UpdateTooltip; - variablePanelBaseValues.AddVariable(new NamedVariableCollection.CustomView(typeof(WatchVariableNumberWrapper)) + variablePanelBaseValues.AddVariable(new NamedVariableCollection.CustomView(WatchVariableSubclass.Number) { Name = "weight", _getterFunction = () => precursor.weight.Yield(), @@ -204,7 +207,7 @@ public string GetJson() if (!first) strBuilder.AppendLine(","); first = false; - strBuilder.Append($"{tabs2}\"{parameterValue.Key}\": {StringUtilities.MakeJsonValue(parameterValue.Value.value.ToString())}"); + strBuilder.Append($"{tabs2}\"{parameterValue.Key}\": {BruteforceTab.MakeJsonValue(parameterValue.Value.value.ToString())}"); } strBuilder.AppendLine($"\n{tabs1}}}"); diff --git a/STROOP/Tabs/BruteforceTab/ValueGetters.cs b/STROOP/Tabs/BruteforceTab/ValueGetters.cs index fce85e485..b60370c9b 100644 --- a/STROOP/Tabs/BruteforceTab/ValueGetters.cs +++ b/STROOP/Tabs/BruteforceTab/ValueGetters.cs @@ -1,10 +1,13 @@ -using System.Collections.Generic; +using STROOP.Core; +using STROOP.Core.Utilities; +using System.Collections.Generic; using STROOP.Utilities; using System; using System.Linq; using STROOP.Structs.Configurations; using STROOP.Structs; using STROOP.Tabs.BruteforceTab.BF_Utilities; +using STROOP.Variables.SM64MemoryLayout; using GetterFuncsDic = System.Collections.Generic.Dictionary>; namespace STROOP.Tabs.BruteforceTab diff --git a/STROOP/Tabs/CamHackTab.Designer.cs b/STROOP/Tabs/CamHackTab.Designer.cs index e7a39db01..ef1ce3a57 100644 --- a/STROOP/Tabs/CamHackTab.Designer.cs +++ b/STROOP/Tabs/CamHackTab.Designer.cs @@ -104,7 +104,7 @@ private void InitializeComponent() this.radioButtonCamHackMode2 = new System.Windows.Forms.RadioButton(); this.radioButtonCamHackMode1AbsoluteAngle = new System.Windows.Forms.RadioButton(); this.radioButtonCamHackMode1RelativeAngle = new System.Windows.Forms.RadioButton(); - this.watchVariablePanelCamHack = new STROOP.Controls.VariablePanel.WatchVariablePanel(); + this._variablePanelCamHack = new STROOP.Controls.VariablePanel.VariablePanel(); ((System.ComponentModel.ISupportInitialize)(this.splitContainerCamHack)).BeginInit(); this.splitContainerCamHack.Panel1.SuspendLayout(); this.splitContainerCamHack.Panel2.SuspendLayout(); @@ -145,7 +145,7 @@ private void InitializeComponent() // // splitContainerCamHack.Panel2 // - this.splitContainerCamHack.Panel2.Controls.Add(this.watchVariablePanelCamHack); + this.splitContainerCamHack.Panel2.Controls.Add(this._variablePanelCamHack); this.splitContainerCamHack.Panel2.Padding = new System.Windows.Forms.Padding(2); this.splitContainerCamHack.Panel2MinSize = 0; this.splitContainerCamHack.Size = new System.Drawing.Size(915, 463); @@ -959,13 +959,13 @@ private void InitializeComponent() // // watchVariablePanelCamHack // - this.watchVariablePanelCamHack.DataPath = "Config/CamHackData.xml"; - this.watchVariablePanelCamHack.Dock = System.Windows.Forms.DockStyle.Fill; - this.watchVariablePanelCamHack.Location = new System.Drawing.Point(2, 2); - this.watchVariablePanelCamHack.Margin = new System.Windows.Forms.Padding(0); - this.watchVariablePanelCamHack.Name = "watchVariablePanelCamHack"; - this.watchVariablePanelCamHack.Size = new System.Drawing.Size(469, 457); - this.watchVariablePanelCamHack.TabIndex = 2; + this._variablePanelCamHack.DataPath = "Config/CamHackData.xml"; + this._variablePanelCamHack.Dock = System.Windows.Forms.DockStyle.Fill; + this._variablePanelCamHack.Location = new System.Drawing.Point(2, 2); + this._variablePanelCamHack.Margin = new System.Windows.Forms.Padding(0); + this._variablePanelCamHack.Name = "_variablePanelCamHack"; + this._variablePanelCamHack.Size = new System.Drawing.Size(469, 457); + this._variablePanelCamHack.TabIndex = 2; // // CamHackTab // @@ -1070,6 +1070,6 @@ private void InitializeComponent() private System.Windows.Forms.RadioButton radioButtonCamHackMode2; private System.Windows.Forms.RadioButton radioButtonCamHackMode1AbsoluteAngle; private System.Windows.Forms.RadioButton radioButtonCamHackMode1RelativeAngle; - private STROOP.Controls.VariablePanel.WatchVariablePanel watchVariablePanelCamHack; + private STROOP.Controls.VariablePanel.VariablePanel _variablePanelCamHack; } } diff --git a/STROOP/Tabs/CamHackTab.cs b/STROOP/Tabs/CamHackTab.cs index 2928d490c..1ee4259fd 100644 --- a/STROOP/Tabs/CamHackTab.cs +++ b/STROOP/Tabs/CamHackTab.cs @@ -4,11 +4,14 @@ using System.Windows.Forms; using System.Xml.Linq; using STROOP.Controls.VariablePanel; -using STROOP.Core.Variables; using STROOP.Models; using STROOP.Structs; using STROOP.Structs.Configurations; using STROOP.Utilities; +using STROOP.Variables; +using STROOP.Variables.SM64MemoryLayout; +using STROOP.Variables.Utilities; +using STROOP.Variables.VariablePanel; namespace STROOP.Tabs { @@ -17,13 +20,13 @@ public partial class CamHackTab : STROOPTab [InitializeBaseAddress] static void InitBaseAddresses() { - WatchVariableUtilities.baseAddressGetters["CamHack"] = () => new List { CamHackConfig.StructAddress }; + VariableUtilities.baseAddressGetters["CamHack"] = () => new List { CamHackConfig.StructAddress }; } public CamHackMode CurrentCamHackMode { get; private set; } private int _numPans = 0; - private List> _panVars = new List>(); + private List> _panVars = new List>(); public CamHackTab() { @@ -229,7 +232,7 @@ public void NotifyNumPanChange(int numPans) for (int i = _numPans; i < numPans; i++) { SpecialConfig.PanModels.Add(new PanModel()); - _panVars.Add(watchVariablePanelCamHack.AddVariables(CreatePanVars(i))); + _panVars.Add(_variablePanelCamHack.AddVariables(CreatePanVars(i))); } } @@ -240,14 +243,14 @@ public void NotifyNumPanChange(int numPans) SpecialConfig.PanModels.RemoveAt(i); var panVars = _panVars[i]; _panVars.Remove(panVars); - watchVariablePanelCamHack.RemoveVariables(panVars); + _variablePanelCamHack.RemoveVariables(panVars); } } _numPans = numPans; } - private NamedVariableCollection.IView CreatePanVar( + private VariablePrecursor CreatePanVar( string name, string specialType, string color, @@ -264,13 +267,13 @@ private NamedVariableCollection.IView CreatePanVar( if (coord != null) xElement.Add(new XAttribute("coord", coord)); if (display != null) xElement.Add(new XAttribute("display", display)); if (yaw != null) xElement.Add(new XAttribute("yaw", yaw)); - return NamedVariableCollection.ParseXml(xElement); + return VariableCellFactory.ParseXml(xElement, VariableSpecialDictionary.Instance); } - private List CreatePanVars(int index) + private List CreatePanVars(int index) { - WatchVariableSpecialUtilities.AddPanEntriesToDictionary(index); - return new List + VariableSpecialUtilities.AddPanEntriesToDictionary(index); + return new List { CreatePanVar("Global Timer", String.Format("Pan{0}GlobalTimer", index), "Orange"), CreatePanVar(String.Format("Pan{0} Start Time", index), String.Format("Pan{0}StartTime", index), "Orange"), diff --git a/STROOP/Tabs/CameraTab.Designer.cs b/STROOP/Tabs/CameraTab.Designer.cs index 44168191d..105995236 100644 --- a/STROOP/Tabs/CameraTab.Designer.cs +++ b/STROOP/Tabs/CameraTab.Designer.cs @@ -88,7 +88,7 @@ private void InitializeComponent() this.buttonCameraPosXnZp = new System.Windows.Forms.Button(); this.buttonCameraPosXn = new System.Windows.Forms.Button(); this.buttonCameraPosXnZn = new System.Windows.Forms.Button(); - this.watchVariablePanelCamera = new STROOP.Controls.VariablePanel.WatchVariablePanel(); + this._variablePanelCamera = new STROOP.Controls.VariablePanel.VariablePanel(); ((System.ComponentModel.ISupportInitialize)(this.splitContainerCamera)).BeginInit(); this.splitContainerCamera.Panel1.SuspendLayout(); this.splitContainerCamera.Panel2.SuspendLayout(); @@ -125,7 +125,7 @@ private void InitializeComponent() // // splitContainerCamera.Panel2 // - this.splitContainerCamera.Panel2.Controls.Add(this.watchVariablePanelCamera); + this.splitContainerCamera.Panel2.Controls.Add(this._variablePanelCamera); this.splitContainerCamera.Panel2.Padding = new System.Windows.Forms.Padding(2); this.splitContainerCamera.Panel2MinSize = 0; this.splitContainerCamera.Size = new System.Drawing.Size(915, 463); @@ -769,13 +769,13 @@ private void InitializeComponent() // // watchVariablePanelCamera // - this.watchVariablePanelCamera.DataPath = "Config/CameraData.xml"; - this.watchVariablePanelCamera.Dock = System.Windows.Forms.DockStyle.Fill; - this.watchVariablePanelCamera.Location = new System.Drawing.Point(2, 2); - this.watchVariablePanelCamera.Margin = new System.Windows.Forms.Padding(0); - this.watchVariablePanelCamera.Name = "watchVariablePanelCamera"; - this.watchVariablePanelCamera.Size = new System.Drawing.Size(701, 457); - this.watchVariablePanelCamera.TabIndex = 3; + this._variablePanelCamera.DataPath = "Config/CameraData.xml"; + this._variablePanelCamera.Dock = System.Windows.Forms.DockStyle.Fill; + this._variablePanelCamera.Location = new System.Drawing.Point(2, 2); + this._variablePanelCamera.Margin = new System.Windows.Forms.Padding(0); + this._variablePanelCamera.Name = "_variablePanelCamera"; + this._variablePanelCamera.Size = new System.Drawing.Size(701, 457); + this._variablePanelCamera.TabIndex = 3; // // CameraTab // @@ -863,6 +863,6 @@ private void InitializeComponent() private System.Windows.Forms.Button buttonCameraPosXnZp; private System.Windows.Forms.Button buttonCameraPosXn; private System.Windows.Forms.Button buttonCameraPosXnZn; - private STROOP.Controls.VariablePanel.WatchVariablePanel watchVariablePanelCamera; + private STROOP.Controls.VariablePanel.VariablePanel _variablePanelCamera; } } diff --git a/STROOP/Tabs/CameraTab.cs b/STROOP/Tabs/CameraTab.cs index bbffad471..7220f7ec1 100644 --- a/STROOP/Tabs/CameraTab.cs +++ b/STROOP/Tabs/CameraTab.cs @@ -1,13 +1,36 @@ -using System.Collections.Generic; +using STROOP.Core; +using System.Collections.Generic; using System.Linq; using STROOP.Structs; using STROOP.Utilities; using STROOP.Structs.Configurations; +using STROOP.Variables; +using STROOP.Variables.SM64MemoryLayout; +using STROOP.Variables.Utilities; namespace STROOP.Tabs { public partial class CameraTab : STROOPTab { + [InitializeBaseAddress] + static void InitializeBaseAddresses() + { + VariableUtilities.baseAddressGetters[BaseAddressType.Camera] = () => new List { CameraConfig.StructAddress }; + VariableUtilities.baseAddressGetters[BaseAddressType.CameraStruct] = () => new List { CameraConfig.CamStructAddress }; + VariableUtilities.baseAddressGetters[BaseAddressType.LakituStruct] = () => new List { CameraConfig.LakituStructAddress }; + VariableUtilities.baseAddressGetters[BaseAddressType.CameraModeInfo] = () => new List { CameraConfig.ModeInfoAddress }; + VariableUtilities.baseAddressGetters[BaseAddressType.CameraModeTransition] = () => new List { CameraConfig.ModeTransitionAddress }; + VariableUtilities.baseAddressGetters[BaseAddressType.CameraSettings] = () => + { + uint a1 = 0x8033B910; + uint a2 = ProcessStream.Instance.GetUInt32(a1); + uint a3 = ProcessStream.Instance.GetUInt32(a2 + 0x10); + uint a4 = ProcessStream.Instance.GetUInt32(a3 + 0x08); + uint a5 = ProcessStream.Instance.GetUInt32(a4 + 0x10); + return new List { a5 }; + }; + } + public CameraTab() { InitializeComponent(); diff --git a/STROOP/Tabs/CellsTab.Designer.cs b/STROOP/Tabs/CellsTab.Designer.cs index 348fcf846..d28e35c84 100644 --- a/STROOP/Tabs/CellsTab.Designer.cs +++ b/STROOP/Tabs/CellsTab.Designer.cs @@ -33,7 +33,7 @@ private void InitializeComponent() this.splitContainerCellsControls = new STROOP.BetterSplitContainer(); this.buttonCellsBuildTree = new System.Windows.Forms.Button(); this.treeViewCells = new System.Windows.Forms.TreeView(); - this.watchVariablePanelCells = new STROOP.Controls.VariablePanel.WatchVariablePanel(); + this._variablePanelCells = new STROOP.Controls.VariablePanel.VariablePanel(); ((System.ComponentModel.ISupportInitialize)(this.splitContainerCells)).BeginInit(); this.splitContainerCells.Panel1.SuspendLayout(); this.splitContainerCells.Panel2.SuspendLayout(); @@ -63,7 +63,7 @@ private void InitializeComponent() // // splitContainerCells.Panel2 // - this.splitContainerCells.Panel2.Controls.Add(this.watchVariablePanelCells); + this.splitContainerCells.Panel2.Controls.Add(this._variablePanelCells); this.splitContainerCells.Panel2.Padding = new System.Windows.Forms.Padding(2); this.splitContainerCells.Panel2MinSize = 0; this.splitContainerCells.Size = new System.Drawing.Size(915, 463); @@ -119,13 +119,13 @@ private void InitializeComponent() // // watchVariablePanelCells // - this.watchVariablePanelCells.DataPath = "Config/CellsData.xml"; - this.watchVariablePanelCells.Dock = System.Windows.Forms.DockStyle.Fill; - this.watchVariablePanelCells.Location = new System.Drawing.Point(2, 2); - this.watchVariablePanelCells.Margin = new System.Windows.Forms.Padding(0); - this.watchVariablePanelCells.Name = "watchVariablePanelCells"; - this.watchVariablePanelCells.Size = new System.Drawing.Size(605, 457); - this.watchVariablePanelCells.TabIndex = 3; + this._variablePanelCells.DataPath = "Config/CellsData.xml"; + this._variablePanelCells.Dock = System.Windows.Forms.DockStyle.Fill; + this._variablePanelCells.Location = new System.Drawing.Point(2, 2); + this._variablePanelCells.Margin = new System.Windows.Forms.Padding(0); + this._variablePanelCells.Name = "_variablePanelCells"; + this._variablePanelCells.Size = new System.Drawing.Size(605, 457); + this._variablePanelCells.TabIndex = 3; // // CellsTab // @@ -152,6 +152,6 @@ private void InitializeComponent() private BetterSplitContainer splitContainerCellsControls; private System.Windows.Forms.Button buttonCellsBuildTree; private System.Windows.Forms.TreeView treeViewCells; - private STROOP.Controls.VariablePanel.WatchVariablePanel watchVariablePanelCells; + private STROOP.Controls.VariablePanel.VariablePanel _variablePanelCells; } } diff --git a/STROOP/Tabs/CellsTab.cs b/STROOP/Tabs/CellsTab.cs index 476dbb319..419fd5ae4 100644 --- a/STROOP/Tabs/CellsTab.cs +++ b/STROOP/Tabs/CellsTab.cs @@ -1,8 +1,12 @@ -using STROOP.Structs.Configurations; +using STROOP.Core; +using STROOP.Core.Utilities; +using STROOP.Structs.Configurations; using STROOP.Utilities; using System.Collections.Generic; using System.Windows.Forms; using STROOP.Structs; +using STROOP.Variables; +using STROOP.Variables.Utilities; namespace STROOP.Tabs { @@ -11,14 +15,14 @@ public partial class CellsTab : STROOPTab static IEnumerable GetTriangleAddresses() { var addr = AccessScope.content.GetTab().TriangleAddress; - return addr != 0 ? new List { addr } : WatchVariableUtilities.BaseAddressListEmpty; + return addr != 0 ? new List { addr } : VariableUtilities.BaseAddressListEmpty; } [InitializeBaseAddress] static void InitBaseAddresses() { - WatchVariableUtilities.baseAddressGetters["CellsTriangle"] = GetTriangleAddresses; - WatchVariableUtilities.baseAddressGetters["CellsTriangleExertionForceTable"] = () => + VariableUtilities.baseAddressGetters["CellsTriangle"] = GetTriangleAddresses; + VariableUtilities.baseAddressGetters["CellsTriangleExertionForceTable"] = () => GetTriangleAddresses().ConvertAll(triangleAddress => { uint exertionForceIndex = Config.Stream.GetByte(triangleAddress + TriangleOffsetsConfig.ExertionForceIndex); diff --git a/STROOP/Tabs/CoinTab.cs b/STROOP/Tabs/CoinTab.cs index 78fd8483e..3539ec3d8 100644 --- a/STROOP/Tabs/CoinTab.cs +++ b/STROOP/Tabs/CoinTab.cs @@ -1,5 +1,6 @@ using STROOP.Structs; using STROOP.Utilities; +using STROOP.Variables.Utilities; using System; using System.Collections.Generic; using System.Drawing; diff --git a/STROOP/Tabs/CustomTab.Designer.cs b/STROOP/Tabs/CustomTab.Designer.cs index 8260dc87f..bafcaaa6e 100644 --- a/STROOP/Tabs/CustomTab.Designer.cs +++ b/STROOP/Tabs/CustomTab.Designer.cs @@ -42,7 +42,7 @@ private void InitializeComponent() this.buttonCopyVars = new System.Windows.Forms.Button(); this.buttonSaveVars = new System.Windows.Forms.Button(); this.buttonOpenVars = new System.Windows.Forms.Button(); - this.watchVariablePanelCustom = new STROOP.Controls.VariablePanel.WatchVariablePanel(); + this.VariablePanelCustom = new STROOP.Controls.VariablePanel.VariablePanel(); ((System.ComponentModel.ISupportInitialize)(this.splitContainerCustom)).BeginInit(); this.splitContainerCustom.Panel1.SuspendLayout(); this.splitContainerCustom.Panel2.SuspendLayout(); @@ -78,7 +78,7 @@ private void InitializeComponent() // // splitContainerCustom.Panel2 // - this.splitContainerCustom.Panel2.Controls.Add(this.watchVariablePanelCustom); + this.splitContainerCustom.Panel2.Controls.Add(this.VariablePanelCustom); this.splitContainerCustom.Panel2.Padding = new System.Windows.Forms.Padding(2); this.splitContainerCustom.Panel2MinSize = 0; this.splitContainerCustom.Size = new System.Drawing.Size(915, 463); @@ -220,14 +220,14 @@ private void InitializeComponent() // // watchVariablePanelCustom // - this.watchVariablePanelCustom.AutoScroll = true; - this.watchVariablePanelCustom.DataPath = "Config/CustomData.xml"; - this.watchVariablePanelCustom.Dock = System.Windows.Forms.DockStyle.Fill; - this.watchVariablePanelCustom.Location = new System.Drawing.Point(2, 2); - this.watchVariablePanelCustom.Margin = new System.Windows.Forms.Padding(0); - this.watchVariablePanelCustom.Name = "watchVariablePanelCustom"; - this.watchVariablePanelCustom.Size = new System.Drawing.Size(690, 457); - this.watchVariablePanelCustom.TabIndex = 3; + this.VariablePanelCustom.AutoScroll = true; + this.VariablePanelCustom.DataPath = "Config/CustomData.xml"; + this.VariablePanelCustom.Dock = System.Windows.Forms.DockStyle.Fill; + this.VariablePanelCustom.Location = new System.Drawing.Point(2, 2); + this.VariablePanelCustom.Margin = new System.Windows.Forms.Padding(0); + this.VariablePanelCustom.Name = "VariablePanelCustom"; + this.VariablePanelCustom.Size = new System.Drawing.Size(690, 457); + this.VariablePanelCustom.TabIndex = 3; // // CustomTab // @@ -260,6 +260,6 @@ private void InitializeComponent() private System.Windows.Forms.Button buttonCopyVars; private System.Windows.Forms.Button buttonSaveVars; private System.Windows.Forms.Button buttonOpenVars; - internal STROOP.Controls.VariablePanel.WatchVariablePanel watchVariablePanelCustom; + internal STROOP.Controls.VariablePanel.VariablePanel VariablePanelCustom; } } diff --git a/STROOP/Tabs/CustomTab.cs b/STROOP/Tabs/CustomTab.cs index c84bc3f3d..78094a8f9 100644 --- a/STROOP/Tabs/CustomTab.cs +++ b/STROOP/Tabs/CustomTab.cs @@ -6,6 +6,7 @@ using STROOP.Utilities; using STROOP.Structs.Configurations; using STROOP.Forms; +using STROOP.Variables; namespace STROOP.Tabs { @@ -17,7 +18,7 @@ public partial class CustomTab : STROOPTab private int _numGaps = 0; private int _recordFreq = 1; - private CopyTypeEnum _copyType = CopyTypeEnum.CopyWithTabs; + private CopyUtilities.CopyType _copyType = CopyUtilities.CopyType.WithTabs; public CustomTab() { @@ -30,11 +31,11 @@ public override void InitializeTab() { base.InitializeTab(); - buttonOpenVars.Click += (sender, e) => watchVariablePanelCustom.OpenVariables(); + buttonOpenVars.Click += (sender, e) => VariablePanelCustom.OpenVariables(); - buttonSaveVars.Click += (sender, e) => watchVariablePanelCustom.SaveVariables(); + buttonSaveVars.Click += (sender, e) => VariablePanelCustom.SaveVariables(); - buttonCopyVars.Click += (sender, e) => CopyUtilities.Copy(watchVariablePanelCustom.GetCurrentVariableControls(), _copyType); + buttonCopyVars.Click += (sender, e) => CopyUtilities.Copy(VariablePanelCustom.GetCurrentlyVisibleCells(), _copyType); buttonCopyVars.ContextMenuStrip = new ContextMenuStrip(); ToolStripMenuItem itemSetDefaultCopyType = new ToolStripMenuItem("Set Default Copy Type"); buttonCopyVars.ContextMenuStrip.Items.Add(itemSetDefaultCopyType); @@ -42,19 +43,19 @@ public override void InitializeTab() ControlUtilities.AddCheckableDropDownItems( itemSetDefaultCopyType, CopyUtilities.GetCopyNames(), - EnumUtilities.GetEnumValues(typeof(CopyTypeEnum)), + EnumUtilities.GetEnumValues(typeof(CopyUtilities.CopyType)), copyType => _copyType = copyType, _copyType); - CopyUtilities.AddContextMenuStripFunctions(buttonCopyVars, watchVariablePanelCustom.GetCurrentVariableControls); + CopyUtilities.AddContextMenuStripFunctions(buttonCopyVars, VariablePanelCustom.GetCurrentlyVisibleCells); - buttonClearVars.Click += (sender, e) => watchVariablePanelCustom.ClearVariables(); + buttonClearVars.Click += (sender, e) => VariablePanelCustom.ClearVariables(); ControlUtilities.AddContextMenuStripFunctions( buttonClearVars, new List() { "Clear All Vars", "Clear Default Vars" }, new List() { - () => watchVariablePanelCustom.ClearVariables(), - () => watchVariablePanelCustom.RemoveVariableGroup(VariableGroup.NoGroup), + () => VariablePanelCustom.ClearVariables(), + () => VariablePanelCustom.RemoveVariableGroup(VariableGroup.NoGroup), }); checkBoxCustomRecordValues.Click += (sender, e) => ToggleRecording(); @@ -73,7 +74,7 @@ private void ShowRecordedValues() { InfoForm infoForm = new InfoForm(); - List variableNames = watchVariablePanelCustom.GetCurrentVariableNames(); + List variableNames = VariablePanelCustom.GetCurrentVariableNames(); List variableValueRowStrings = _recordedValues.ToList() .ConvertAll(pair => (pair.Key + 1) + "\t" + String.Join("\t", pair.Value)); string variableValueText = @@ -124,7 +125,7 @@ public override void Update(bool updateView) if (!alreadyContainsKey || recordEvenIfAlreadyHave) { - List currentValues = watchVariablePanelCustom.GetCurrentVariableValues(); + List currentValues = VariablePanelCustom.GetCurrentVariableValues(); _recordedValues[currentTimer] = currentValues; } } diff --git a/STROOP/Tabs/DebugTab.Designer.cs b/STROOP/Tabs/DebugTab.Designer.cs index 864d84d0e..f3c8b5b5f 100644 --- a/STROOP/Tabs/DebugTab.Designer.cs +++ b/STROOP/Tabs/DebugTab.Designer.cs @@ -49,7 +49,7 @@ private void InitializeComponent() this.radioButtonAdvancedModeCheckInfo = new System.Windows.Forms.RadioButton(); this.radioButtonAdvancedModeStageInfo = new System.Windows.Forms.RadioButton(); this.radioButtonAdvancedModeMapInfo = new System.Windows.Forms.RadioButton(); - this.watchVariablePanelDebug = new STROOP.Controls.VariablePanel.WatchVariablePanel(); + this._variablePanelDebug = new STROOP.Controls.VariablePanel.VariablePanel(); ((System.ComponentModel.ISupportInitialize)(this.splitContainerDebug)).BeginInit(); this.splitContainerDebug.Panel1.SuspendLayout(); this.splitContainerDebug.Panel2.SuspendLayout(); @@ -83,7 +83,7 @@ private void InitializeComponent() // // splitContainerDebug.Panel2 // - this.splitContainerDebug.Panel2.Controls.Add(this.watchVariablePanelDebug); + this.splitContainerDebug.Panel2.Controls.Add(this._variablePanelDebug); this.splitContainerDebug.Panel2.Padding = new System.Windows.Forms.Padding(2); this.splitContainerDebug.Panel2MinSize = 0; this.splitContainerDebug.Size = new System.Drawing.Size(915, 463); @@ -302,13 +302,13 @@ private void InitializeComponent() // // watchVariablePanelDebug // - this.watchVariablePanelDebug.DataPath = "Config/DebugData.xml"; - this.watchVariablePanelDebug.Dock = System.Windows.Forms.DockStyle.Fill; - this.watchVariablePanelDebug.Location = new System.Drawing.Point(2, 2); - this.watchVariablePanelDebug.Margin = new System.Windows.Forms.Padding(0); - this.watchVariablePanelDebug.Name = "watchVariablePanelDebug"; - this.watchVariablePanelDebug.Size = new System.Drawing.Size(520, 457); - this.watchVariablePanelDebug.TabIndex = 26; + this._variablePanelDebug.DataPath = "Config/DebugData.xml"; + this._variablePanelDebug.Dock = System.Windows.Forms.DockStyle.Fill; + this._variablePanelDebug.Location = new System.Drawing.Point(2, 2); + this._variablePanelDebug.Margin = new System.Windows.Forms.Padding(0); + this._variablePanelDebug.Name = "_variablePanelDebug"; + this._variablePanelDebug.Size = new System.Drawing.Size(520, 457); + this._variablePanelDebug.TabIndex = 26; // // DebugTab // @@ -355,6 +355,6 @@ private void InitializeComponent() private System.Windows.Forms.RadioButton radioButtonAdvancedModeCheckInfo; private System.Windows.Forms.RadioButton radioButtonAdvancedModeStageInfo; private System.Windows.Forms.RadioButton radioButtonAdvancedModeMapInfo; - private STROOP.Controls.VariablePanel.WatchVariablePanel watchVariablePanelDebug; + private STROOP.Controls.VariablePanel.VariablePanel _variablePanelDebug; } } diff --git a/STROOP/Tabs/DisassemblyTab.cs b/STROOP/Tabs/DisassemblyTab.cs index 6c323ca39..4ded0e2c5 100644 --- a/STROOP/Tabs/DisassemblyTab.cs +++ b/STROOP/Tabs/DisassemblyTab.cs @@ -1,10 +1,12 @@ -using System; +using STROOP.Core; +using System; using System.Linq; using System.Windows.Forms; using STROOP.Utilities; using System.Drawing; using STROOP.Structs; using STROOP.Structs.Configurations; +using STROOP.Variables.Utilities; namespace STROOP.Tabs { diff --git a/STROOP/Tabs/FileTab.Designer.cs b/STROOP/Tabs/FileTab.Designer.cs index f2a125e27..77b6c7f98 100644 --- a/STROOP/Tabs/FileTab.Designer.cs +++ b/STROOP/Tabs/FileTab.Designer.cs @@ -262,7 +262,7 @@ private void InitializeComponent() this.radioButtonFileC = new System.Windows.Forms.RadioButton(); this.radioButtonFileBSaved = new System.Windows.Forms.RadioButton(); this.buttonFileSave = new System.Windows.Forms.Button(); - this.watchVariablePanelFile = new STROOP.Controls.VariablePanel.WatchVariablePanel(); + this._variablePanelFile = new STROOP.Controls.VariablePanel.VariablePanel(); ((System.ComponentModel.ISupportInitialize)(this.splitContainerFile)).BeginInit(); this.splitContainerFile.Panel1.SuspendLayout(); this.splitContainerFile.Panel2.SuspendLayout(); @@ -472,7 +472,7 @@ private void InitializeComponent() // // splitContainerFile.Panel2 // - this.splitContainerFile.Panel2.Controls.Add(this.watchVariablePanelFile); + this.splitContainerFile.Panel2.Controls.Add(this._variablePanelFile); this.splitContainerFile.Panel2.Padding = new System.Windows.Forms.Padding(2); this.splitContainerFile.Panel2MinSize = 0; this.splitContainerFile.Size = new System.Drawing.Size(915, 463); @@ -3743,14 +3743,14 @@ private void InitializeComponent() // // watchVariablePanelFile // - this.watchVariablePanelFile.AutoScroll = true; - this.watchVariablePanelFile.DataPath = "Config/FileData.xml"; - this.watchVariablePanelFile.Dock = System.Windows.Forms.DockStyle.Fill; - this.watchVariablePanelFile.Location = new System.Drawing.Point(2, 2); - this.watchVariablePanelFile.Margin = new System.Windows.Forms.Padding(0); - this.watchVariablePanelFile.Name = "watchVariablePanelFile"; - this.watchVariablePanelFile.Size = new System.Drawing.Size(250, 457); - this.watchVariablePanelFile.TabIndex = 2; + this._variablePanelFile.AutoScroll = true; + this._variablePanelFile.DataPath = "Config/FileData.xml"; + this._variablePanelFile.Dock = System.Windows.Forms.DockStyle.Fill; + this._variablePanelFile.Location = new System.Drawing.Point(2, 2); + this._variablePanelFile.Margin = new System.Windows.Forms.Padding(0); + this._variablePanelFile.Name = "_variablePanelFile"; + this._variablePanelFile.Size = new System.Drawing.Size(250, 457); + this._variablePanelFile.TabIndex = 2; // // FileTab // @@ -4163,6 +4163,6 @@ private void InitializeComponent() private System.Windows.Forms.RadioButton radioButtonFileC; private System.Windows.Forms.RadioButton radioButtonFileBSaved; private System.Windows.Forms.Button buttonFileSave; - private STROOP.Controls.VariablePanel.WatchVariablePanel watchVariablePanelFile; + private STROOP.Controls.VariablePanel.VariablePanel _variablePanelFile; } } diff --git a/STROOP/Tabs/FileTab.cs b/STROOP/Tabs/FileTab.cs index 64a2f8d95..1c3bfa982 100644 --- a/STROOP/Tabs/FileTab.cs +++ b/STROOP/Tabs/FileTab.cs @@ -1,8 +1,12 @@ -using System; +using STROOP.Core; +using System; using System.Collections.Generic; using STROOP.Structs; using STROOP.Utilities; using STROOP.Structs.Configurations; +using STROOP.Variables; +using STROOP.Variables.SM64MemoryLayout; +using STROOP.Variables.Utilities; using System.Drawing; namespace STROOP.Tabs @@ -38,7 +42,13 @@ private enum FileCategory Misc }; - uint CurrentFileAddress => FileConfig.CurrentFileAddress; + public static uint CurrentFileAddress => AccessScope.content.GetTab().GetFileAddress(); + + [InitializeBaseAddress] + static void InitializeBaseAddress() + { + VariableUtilities.baseAddressGetters[BaseAddressType.File] = () => new List { CurrentFileAddress }; + } FileImageGui gui; @@ -81,7 +91,7 @@ private enum FileCategory public FileTab() { InitializeComponent(); - watchVariablePanelFile.SetGroups(ALL_VAR_GROUPS, VISIBLE_VAR_GROUPS); + _variablePanelFile.SetGroups(ALL_VAR_GROUPS, VISIBLE_VAR_GROUPS); } public override string GetDisplayName() => "File"; @@ -532,7 +542,7 @@ private void FileEraseButton_Click(object sender, EventArgs e) private void FileCopyButton_Click(object sender, EventArgs e) { - uint addressToCopy = checkBoxInGameCopyPaste.Checked ? GetNonSavedFileAddress() : getFileAddress(); + uint addressToCopy = checkBoxInGameCopyPaste.Checked ? GetNonSavedFileAddress() : GetFileAddress(); _copiedFile = GetBufferedBytes(addressToCopy); } @@ -669,7 +679,7 @@ private uint GetNonSavedFileAddress(FileMode? nullableMode = null) } } - public uint getFileAddress(FileMode? nullableMode = null) + public uint GetFileAddress(FileMode? nullableMode = null) { FileMode mode = nullableMode ?? CurrentFileMode; switch (mode) diff --git a/STROOP/Tabs/GfxTab/GfxNode.cs b/STROOP/Tabs/GfxTab/GfxNode.cs index d47020f56..35d808869 100644 --- a/STROOP/Tabs/GfxTab/GfxNode.cs +++ b/STROOP/Tabs/GfxTab/GfxNode.cs @@ -4,7 +4,9 @@ using STROOP.Structs.Configurations; using STROOP.Structs; using STROOP.Utilities; -using STROOP.Core.Variables; +using STROOP.Variables; +using STROOP.Variables.SM64MemoryLayout; +using STROOP.Variables.Utilities; namespace STROOP.Tabs.GfxTab { @@ -15,7 +17,7 @@ public class GfxNode public virtual string Name { get { return "GFX node"; } - } //This name is overridden by all the sub classes corresponding + } //This name is overridden by all the sub classes corresponding public uint Address; public List Children; @@ -81,7 +83,7 @@ public static GfxNode ReadGfxNode(uint address) for (int i = 0; i < _maxSiblings; i++) { res.Children.Add(ReadGfxNode(currentAddress)); - currentAddress = Config.Stream.GetUInt32(currentAddress + 0x08); //offset 0x08 = next pointer + currentAddress = Config.Stream.GetUInt32(currentAddress + 0x08); //offset 0x08 = next pointer if (currentAddress == childAddress) break; } } @@ -89,45 +91,45 @@ public static GfxNode ReadGfxNode(uint address) return res; } - public static List GetCommonVariables() + public static List GetCommonVariables() { - List precursors = new List(); + List precursors = new List(); precursors.Add(gfxProperty("Type", 0x00)); - precursors.Add(gfxProperty("Active", 0x02, WatchVariableSubclass.Boolean, 0x01)); - precursors.Add(gfxProperty("Bit 1", 0x02, WatchVariableSubclass.Boolean, 0x02)); - precursors.Add(gfxProperty("Billboard object", 0x02, WatchVariableSubclass.Boolean, 0x04)); - precursors.Add(gfxProperty("Bit 3", 0x02, WatchVariableSubclass.Boolean, 0x08)); - precursors.Add(gfxProperty("Invisible object", 0x02, WatchVariableSubclass.Boolean, 0x10)); - precursors.Add(gfxProperty("Is animated", 0x02, WatchVariableSubclass.Boolean, 0x20)); + precursors.Add(gfxProperty("Active", 0x02, VariableSubclass.Boolean, 0x01)); + precursors.Add(gfxProperty("Bit 1", 0x02, VariableSubclass.Boolean, 0x02)); + precursors.Add(gfxProperty("Billboard object", 0x02, VariableSubclass.Boolean, 0x04)); + precursors.Add(gfxProperty("Bit 3", 0x02, VariableSubclass.Boolean, 0x08)); + precursors.Add(gfxProperty("Invisible object", 0x02, VariableSubclass.Boolean, 0x10)); + precursors.Add(gfxProperty("Is animated", 0x02, VariableSubclass.Boolean, 0x20)); precursors.Add(gfxProperty("List index", 0x02)); //note: not actually a byte, but the result of (short>>8) - precursors.Add(gfxProperty("Previous", 0x04, WatchVariableSubclass.Address)); - precursors.Add(gfxProperty("Next", 0x08, WatchVariableSubclass.Address)); - precursors.Add(gfxProperty("Parent", 0x0C, WatchVariableSubclass.Address)); - precursors.Add(gfxProperty("Child", 0x10, WatchVariableSubclass.Address)); + precursors.Add(gfxProperty("Previous", 0x04, VariableSubclass.Address)); + precursors.Add(gfxProperty("Next", 0x08, VariableSubclass.Address)); + precursors.Add(gfxProperty("Parent", 0x0C, VariableSubclass.Address)); + precursors.Add(gfxProperty("Child", 0x10, VariableSubclass.Address)); return precursors; } // Wrapper to make defining variables easier - protected static NamedVariableCollection.IView gfxProperty( + protected static VariablePrecursor gfxProperty( string name, uint offset, - WatchVariableSubclass subclass = WatchVariableSubclass.Number, + string? subclass = null, uint? mask = null) where T : struct, IConvertible { + subclass ??= VariableSubclass.Number; mask = mask ?? 0xFFFFFFFF; Color color = (offset <= 0x13) ? ColorUtilities.GetColorFromString("Yellow") : ColorUtilities.GetColorFromString("LightBlue"); var descriptor = new MemoryDescriptor(typeof(T), BaseAddressType.GfxNode, offset, mask); - var view = descriptor.CreateView(subclass.ToString()); - view.Name = name; - return (NamedVariableCollection.MemoryDescriptorView)view; + var view = descriptor.CreateVariable(subclass.ToString()); + return (name, (MemoryVariable)view); } - // If there are type specific variables, this should be overridden - public virtual IEnumerable GetTypeSpecificVariables() => Array.Empty(); + // If there are type specific variables, this should be overridden + public virtual IEnumerable GetTypeSpecificVariables() => Array.Empty(); } internal class GfxChildSelector : GfxNode @@ -164,10 +166,10 @@ public override string Name } } - public override IEnumerable GetTypeSpecificVariables() + public override IEnumerable GetTypeSpecificVariables() { - List precursors = new List(); - precursors.Add(gfxProperty("Selection function", 0x14, WatchVariableSubclass.Address)); + List precursors = new List(); + precursors.Add(gfxProperty("Selection function", 0x14, VariableSubclass.Address)); precursors.Add(gfxProperty("Selected child", 0x1E)); return precursors; } @@ -180,10 +182,10 @@ public override string Name get { return "Background image"; } } - public override IEnumerable GetTypeSpecificVariables() + public override IEnumerable GetTypeSpecificVariables() { - var precursors = new List(); - precursors.Add(gfxProperty("Draw function", 0x14, WatchVariableSubclass.Address)); + var precursors = new List(); + precursors.Add(gfxProperty("Draw function", 0x14, VariableSubclass.Address)); return precursors; } } @@ -199,12 +201,12 @@ public override string Name //int marioOffset 0x18 memory offset from marioData to check //void* heldObj 0x1c another struct //short[3] position 0x20,2,4 - public override IEnumerable GetTypeSpecificVariables() + public override IEnumerable GetTypeSpecificVariables() { - List precursors = new List(); - precursors.Add(gfxProperty("Function pointer", 0x14, WatchVariableSubclass.Address)); + List precursors = new List(); + precursors.Add(gfxProperty("Function pointer", 0x14, VariableSubclass.Address)); precursors.Add(gfxProperty("Mario offset", 0x18)); - precursors.Add(gfxProperty("Held object", 0x1C, WatchVariableSubclass.Object)); + precursors.Add(gfxProperty("Held object", 0x1C, VariableSubclass.Object)); precursors.Add(gfxProperty("Position x", 0x20)); precursors.Add(gfxProperty("Position y", 0x22)); precursors.Add(gfxProperty("Position z", 0x24)); @@ -254,10 +256,10 @@ public override string Name } } - public override IEnumerable GetTypeSpecificVariables() + public override IEnumerable GetTypeSpecificVariables() { - var precursors = new List(); - precursors.Add(gfxProperty("Function pointer", 0x14, WatchVariableSubclass.Address)); + var precursors = new List(); + precursors.Add(gfxProperty("Function pointer", 0x14, VariableSubclass.Address)); precursors.Add(gfxProperty("Parameter 1", 0x18)); precursors.Add(gfxProperty("Parameter 2", 0x1A)); return precursors; @@ -271,10 +273,10 @@ public override string Name get { return "Camera"; } } - public override IEnumerable GetTypeSpecificVariables() + public override IEnumerable GetTypeSpecificVariables() { - List precursors = new List(); - precursors.Add(gfxProperty("Update function", 0x14, WatchVariableSubclass.Address)); + List precursors = new List(); + precursors.Add(gfxProperty("Update function", 0x14, VariableSubclass.Address)); precursors.Add(gfxProperty("X from", 0x1C)); precursors.Add(gfxProperty("Y from", 0x20)); precursors.Add(gfxProperty("Z from", 0x24)); @@ -292,10 +294,10 @@ public override string Name get { return "Projection 3D"; } } - public override IEnumerable GetTypeSpecificVariables() + public override IEnumerable GetTypeSpecificVariables() { - List precursors = new List(); - precursors.Add(gfxProperty("Update function", 0x14, WatchVariableSubclass.Address)); + List precursors = new List(); + precursors.Add(gfxProperty("Update function", 0x14, VariableSubclass.Address)); precursors.Add(gfxProperty("Fov", 0x1C)); precursors.Add(gfxProperty("Z clip near", 0x20)); precursors.Add(gfxProperty("Z clip far", 0x22)); @@ -310,10 +312,10 @@ public override string Name get { return "Object parent"; } } - public override IEnumerable GetTypeSpecificVariables() + public override IEnumerable GetTypeSpecificVariables() { - List precursors = new List(); - precursors.Add(gfxProperty("Temp child", 0x14, WatchVariableSubclass.Address)); + List precursors = new List(); + precursors.Add(gfxProperty("Temp child", 0x14, VariableSubclass.Address)); return precursors; } } @@ -325,9 +327,9 @@ public override string Name get { return "Shadow"; } } - public override IEnumerable GetTypeSpecificVariables() + public override IEnumerable GetTypeSpecificVariables() { - List precursors = new List(); + List precursors = new List(); precursors.Add(gfxProperty("Radius", 0x14)); precursors.Add(gfxProperty("Opacity", 0x16)); precursors.Add(gfxProperty("Type", 0x17)); @@ -342,9 +344,9 @@ public override string Name get { return "Scaling node"; } } - public override IEnumerable GetTypeSpecificVariables() + public override IEnumerable GetTypeSpecificVariables() { - List precursors = new List(); + List precursors = new List(); precursors.Add(gfxProperty("Scale", 0x18)); return precursors; } @@ -366,10 +368,10 @@ public override string Name get { return "Animated node"; } } - public override IEnumerable GetTypeSpecificVariables() + public override IEnumerable GetTypeSpecificVariables() { - List precursors = new List(); - precursors.Add(gfxProperty("Display list", 0x14, WatchVariableSubclass.Address)); + List precursors = new List(); + precursors.Add(gfxProperty("Display list", 0x14, VariableSubclass.Address)); precursors.Add(gfxProperty("X offset", 0x18)); precursors.Add(gfxProperty("Y offset", 0x1A)); precursors.Add(gfxProperty("Z offset", 0x1C)); @@ -384,10 +386,10 @@ public override string Name get { return "Game object"; } } - public override IEnumerable GetTypeSpecificVariables() + public override IEnumerable GetTypeSpecificVariables() { - List precursors = new List(); - precursors.Add(gfxProperty("Shared child", 0x14, WatchVariableSubclass.Address)); + List precursors = new List(); + precursors.Add(gfxProperty("Shared child", 0x14, VariableSubclass.Address)); return precursors; } } @@ -399,10 +401,10 @@ public override string Name get { return "Rotation"; } } - public override IEnumerable GetTypeSpecificVariables() + public override IEnumerable GetTypeSpecificVariables() { - List precursors = new List(); - precursors.Add(gfxProperty("Segmented address", 0x14, WatchVariableSubclass.Address)); + List precursors = new List(); + precursors.Add(gfxProperty("Segmented address", 0x14, VariableSubclass.Address)); precursors.Add(gfxProperty("Angle x", 0x18)); //Todo: make these angle types precursors.Add(gfxProperty("Angle y", 0x1A)); precursors.Add(gfxProperty("Angle z", 0x1C)); @@ -418,10 +420,10 @@ public override string Name get { return "Menu model"; } } - public override IEnumerable GetTypeSpecificVariables() + public override IEnumerable GetTypeSpecificVariables() { - List precursors = new List(); - precursors.Add(gfxProperty("Segmented address", 0x14, WatchVariableSubclass.Address)); + List precursors = new List(); + precursors.Add(gfxProperty("Segmented address", 0x14, VariableSubclass.Address)); precursors.Add(gfxProperty("X offset", 0x18)); precursors.Add(gfxProperty("Y offset", 0x1A)); precursors.Add(gfxProperty("Z offset", 0x1C)); @@ -436,9 +438,9 @@ public override string Name get { return "Debug transformation"; } } - public override IEnumerable GetTypeSpecificVariables() + public override IEnumerable GetTypeSpecificVariables() { - var precursors = new List(); + var precursors = new List(); precursors.Add(gfxProperty("X translation", 0x18)); precursors.Add(gfxProperty("Y translation", 0x1A)); precursors.Add(gfxProperty("Z translation", 0x1C)); @@ -456,12 +458,12 @@ public override string Name get { return "Level of detail"; } } - public override IEnumerable GetTypeSpecificVariables() + public override IEnumerable GetTypeSpecificVariables() { - var precursors = new List(); + var precursors = new List(); precursors.Add(gfxProperty("Min cam distance", 0x14)); precursors.Add(gfxProperty("Max cam distance", 0x16)); - precursors.Add(gfxProperty("Pointer 1", 0x18, WatchVariableSubclass.Address)); + precursors.Add(gfxProperty("Pointer 1", 0x18, VariableSubclass.Address)); return precursors; } @@ -474,25 +476,25 @@ public override string Name get { return "Master list"; } } - public override IEnumerable GetTypeSpecificVariables() - { - var precursors = new List(); - precursors.Add(gfxProperty("Pointer 0", 0x14, WatchVariableSubclass.Address)); - precursors.Add(gfxProperty("Pointer 1", 0x18, WatchVariableSubclass.Address)); - precursors.Add(gfxProperty("Pointer 2", 0x1C, WatchVariableSubclass.Address)); - precursors.Add(gfxProperty("Pointer 3", 0x20, WatchVariableSubclass.Address)); - precursors.Add(gfxProperty("Pointer 4", 0x24, WatchVariableSubclass.Address)); - precursors.Add(gfxProperty("Pointer 5", 0x28, WatchVariableSubclass.Address)); - precursors.Add(gfxProperty("Pointer 6", 0x2C, WatchVariableSubclass.Address)); - precursors.Add(gfxProperty("Pointer 7", 0x30, WatchVariableSubclass.Address)); - precursors.Add(gfxProperty("Pointer 8", 0x34, WatchVariableSubclass.Address)); - precursors.Add(gfxProperty("Pointer 9", 0x3C, WatchVariableSubclass.Address)); - precursors.Add(gfxProperty("Pointer 10", 0x40, WatchVariableSubclass.Address)); - precursors.Add(gfxProperty("Pointer 11", 0x44, WatchVariableSubclass.Address)); - precursors.Add(gfxProperty("Pointer 12", 0x48, WatchVariableSubclass.Address)); - precursors.Add(gfxProperty("Pointer 13", 0x4C, WatchVariableSubclass.Address)); - precursors.Add(gfxProperty("Pointer 14", 0x50, WatchVariableSubclass.Address)); - precursors.Add(gfxProperty("Pointer 15", 0x54, WatchVariableSubclass.Address)); + public override IEnumerable GetTypeSpecificVariables() + { + var precursors = new List(); + precursors.Add(gfxProperty("Pointer 0", 0x14, VariableSubclass.Address)); + precursors.Add(gfxProperty("Pointer 1", 0x18, VariableSubclass.Address)); + precursors.Add(gfxProperty("Pointer 2", 0x1C, VariableSubclass.Address)); + precursors.Add(gfxProperty("Pointer 3", 0x20, VariableSubclass.Address)); + precursors.Add(gfxProperty("Pointer 4", 0x24, VariableSubclass.Address)); + precursors.Add(gfxProperty("Pointer 5", 0x28, VariableSubclass.Address)); + precursors.Add(gfxProperty("Pointer 6", 0x2C, VariableSubclass.Address)); + precursors.Add(gfxProperty("Pointer 7", 0x30, VariableSubclass.Address)); + precursors.Add(gfxProperty("Pointer 8", 0x34, VariableSubclass.Address)); + precursors.Add(gfxProperty("Pointer 9", 0x3C, VariableSubclass.Address)); + precursors.Add(gfxProperty("Pointer 10", 0x40, VariableSubclass.Address)); + precursors.Add(gfxProperty("Pointer 11", 0x44, VariableSubclass.Address)); + precursors.Add(gfxProperty("Pointer 12", 0x48, VariableSubclass.Address)); + precursors.Add(gfxProperty("Pointer 13", 0x4C, VariableSubclass.Address)); + precursors.Add(gfxProperty("Pointer 14", 0x50, VariableSubclass.Address)); + precursors.Add(gfxProperty("Pointer 15", 0x54, VariableSubclass.Address)); return precursors; } } @@ -513,9 +515,9 @@ public override string Name get { return "Screenspace"; } } - public override IEnumerable GetTypeSpecificVariables() + public override IEnumerable GetTypeSpecificVariables() { - var precursors = new List(); + var precursors = new List(); precursors.Add(gfxProperty("??? 0x14", 0x14)); precursors.Add(gfxProperty("??? 0x18", 0x18)); return precursors; @@ -529,9 +531,9 @@ public override string Name get { return "Root"; } } - public override IEnumerable GetTypeSpecificVariables() + public override IEnumerable GetTypeSpecificVariables() { - List precursors = new List(); + List precursors = new List(); precursors.Add(gfxProperty("Some short", 0x14)); precursors.Add(gfxProperty("Screen xoffset", 0x16)); precursors.Add(gfxProperty("Screen yoffset", 0x18)); @@ -548,10 +550,10 @@ public override string Name get { return "Display List"; } } - public override IEnumerable GetTypeSpecificVariables() + public override IEnumerable GetTypeSpecificVariables() { - List precursors = new List(); - precursors.Add(gfxProperty("Segmented address", 0x14, WatchVariableSubclass.Address)); + List precursors = new List(); + precursors.Add(gfxProperty("Segmented address", 0x14, VariableSubclass.Address)); return precursors; } } diff --git a/STROOP/Tabs/GfxTab/GfxTab.Designer.cs b/STROOP/Tabs/GfxTab/GfxTab.Designer.cs index fab117c1f..9780e638c 100644 --- a/STROOP/Tabs/GfxTab/GfxTab.Designer.cs +++ b/STROOP/Tabs/GfxTab/GfxTab.Designer.cs @@ -37,7 +37,7 @@ private void InitializeComponent() this.buttonGfxDumpDisplayList = new System.Windows.Forms.Button(); this.buttonGfxRefreshObject = new System.Windows.Forms.Button(); this.buttonGfxRefresh = new System.Windows.Forms.Button(); - this.watchVariablePanelGfx = new STROOP.Controls.VariablePanel.WatchVariablePanel(); + this._variablePanelGfx = new STROOP.Controls.VariablePanel.VariablePanel(); this.richTextBoxGfx = new System.Windows.Forms.RichTextBox(); ((System.ComponentModel.ISupportInitialize)(this.splitContainerGfxLeft)).BeginInit(); this.splitContainerGfxLeft.Panel1.SuspendLayout(); @@ -116,7 +116,7 @@ private void InitializeComponent() // // splitContainerGfxMiddle.Panel2 // - this.splitContainerGfxMiddle.Panel2.Controls.Add(this.watchVariablePanelGfx); + this.splitContainerGfxMiddle.Panel2.Controls.Add(this._variablePanelGfx); this.splitContainerGfxMiddle.Size = new System.Drawing.Size(325, 463); this.splitContainerGfxMiddle.SplitterDistance = 60; this.splitContainerGfxMiddle.TabIndex = 1; @@ -159,12 +159,12 @@ private void InitializeComponent() // // watchVariablePanelGfx // - this.watchVariablePanelGfx.DataPath = null; - this.watchVariablePanelGfx.Dock = System.Windows.Forms.DockStyle.Fill; - this.watchVariablePanelGfx.Location = new System.Drawing.Point(0, 0); - this.watchVariablePanelGfx.Name = "watchVariablePanelGfx"; - this.watchVariablePanelGfx.Size = new System.Drawing.Size(325, 399); - this.watchVariablePanelGfx.TabIndex = 0; + this._variablePanelGfx.DataPath = null; + this._variablePanelGfx.Dock = System.Windows.Forms.DockStyle.Fill; + this._variablePanelGfx.Location = new System.Drawing.Point(0, 0); + this._variablePanelGfx.Name = "_variablePanelGfx"; + this._variablePanelGfx.Size = new System.Drawing.Size(325, 399); + this._variablePanelGfx.TabIndex = 0; // // richTextBoxGfx // @@ -209,7 +209,7 @@ private void InitializeComponent() private System.Windows.Forms.Button buttonGfxDumpDisplayList; private System.Windows.Forms.Button buttonGfxRefreshObject; private System.Windows.Forms.Button buttonGfxRefresh; - private STROOP.Controls.VariablePanel.WatchVariablePanel watchVariablePanelGfx; + private STROOP.Controls.VariablePanel.VariablePanel _variablePanelGfx; private System.Windows.Forms.RichTextBox richTextBoxGfx; } } diff --git a/STROOP/Tabs/GfxTab/GfxTab.cs b/STROOP/Tabs/GfxTab/GfxTab.cs index f81dbd440..c441c3e44 100644 --- a/STROOP/Tabs/GfxTab/GfxTab.cs +++ b/STROOP/Tabs/GfxTab/GfxTab.cs @@ -3,10 +3,15 @@ using System.Drawing; using System.Linq; using System.Windows.Forms; -using STROOP.Controls.VariablePanel; +using STROOP.Core; +using STROOP.Core.Utilities; using STROOP.Structs; using STROOP.Structs.Configurations; using STROOP.Utilities; +using STROOP.Variables; +using STROOP.Variables.SM64MemoryLayout; +using STROOP.Variables.Utilities; +using STROOP.Variables.VariablePanel; namespace STROOP.Tabs.GfxTab { @@ -23,12 +28,12 @@ public partial class GfxTab : STROOPTab [InitializeBaseAddress] static void InitBaseAddresses() { - WatchVariableUtilities.baseAddressGetters[BaseAddressType.GfxNode] = + VariableUtilities.baseAddressGetters[BaseAddressType.GfxNode] = () => AccessScope.content?.SelectedNode?.Address.Yield() ?? Array.Empty(); } public GfxNode SelectedNode; - IEnumerable SpecificVariables; + IEnumerable SpecificVariables; public GfxTab() { @@ -43,7 +48,7 @@ public GfxTab() buttonGfxDumpDisplayList.Click += DumpButton_Click; buttonGfxHitboxHack.Click += (sender, e) => InjectHitboxViewCode(); - SpecificVariables = new List(); + SpecificVariables = new List(); } public override void InitializeTab() @@ -51,7 +56,7 @@ public override void InitializeTab() base.InitializeTab(); SuspendLayout(); foreach (var precursor in GfxNode.GetCommonVariables()) - watchVariablePanelGfx.AddVariable(precursor); + _variablePanelGfx.AddVariable(precursor); ResumeLayout(); } @@ -60,18 +65,18 @@ public override void InitializeTab() // Inject code that shows hitboxes in-game // Note: a bit ugly at the moment. Hack folder is hardcoded instead of taken from Config file, // and it's put here in the GFX tab by a lack of a better place. The hacks in the hack tab are - // constantly reapplied when memory is changed, which doesn't work with this hack which initializes + // constantly reapplied when memory is changed, which doesn't work with this hack which initializes // variables that are later changed. public void InjectHitboxViewCode() { RomHack hck = null; try { - if (RomVersionConfig.Version == Structs.RomVersion.US) + if (RomVersionConfig.Version == RomVersion.US) { hck = new RomHack("Resources\\Hacks\\HitboxViewU.hck", "HitboxView"); } - else if (RomVersionConfig.Version == Structs.RomVersion.JP) + else if (RomVersionConfig.Version == RomVersion.JP) { hck = new RomHack("Resources\\Hacks\\HitboxViewJ.hck", "HitboxView"); } @@ -114,11 +119,11 @@ private void DumpButton_Click(object sender, EventArgs e) // The variables in the first 0x14 bytes in a GFX node are common, but after that there are type-specific variables void UpdateSpecificVariables(GfxNode node) { - watchVariablePanelGfx.RemoveVariables(SpecificVariables); + _variablePanelGfx.RemoveVariables(SpecificVariables); if (node != null) - SpecificVariables = watchVariablePanelGfx.AddVariables(node.GetTypeSpecificVariables()); + SpecificVariables = _variablePanelGfx.AddVariables(node.GetTypeSpecificVariables()); else - SpecificVariables = new WatchVariableControl[0]; + SpecificVariables = Array.Empty(); } // Build a GFX tree for every object that is selected in the object slot view diff --git a/STROOP/Tabs/GhostTab/ColoredHats.cs b/STROOP/Tabs/GhostTab/ColoredHats.cs index cd0c1f506..ea56fd809 100644 --- a/STROOP/Tabs/GhostTab/ColoredHats.cs +++ b/STROOP/Tabs/GhostTab/ColoredHats.cs @@ -3,9 +3,11 @@ using System.Windows.Forms; using OpenTK; using OpenTK.Mathematics; +using STROOP.Core; using STROOP.Structs; using STROOP.Structs.Configurations; using STROOP.Utilities; +using STROOP.Variables.SM64MemoryLayout; namespace STROOP.Tabs.GhostTab { @@ -135,7 +137,7 @@ private void listBoxGhosts_SelectedIndexChanged(object sender, EventArgs e) buttonGhostColor.Enabled = false; else { - buttonGhostColor.BackColor = ColorUtilities.Vec4ToColor(ghost.hatColor); + buttonGhostColor.BackColor = OpenTKUtilities.Vec4ToColor(ghost.hatColor); buttonGhostColor.Enabled = true; } @@ -148,7 +150,7 @@ private void buttonMarioColor_Click(object sender, EventArgs e) dlg.Color = System.Drawing.Color.Red; if (dlg.ShowDialog() == DialogResult.OK) { - marioHatColor = ColorUtilities.ColorToVec4(dlg.Color); + marioHatColor = OpenTKUtilities.ColorToVec4(dlg.Color); buttonMarioColor.BackColor = dlg.Color; } } @@ -161,7 +163,7 @@ private void buttonGhostColor_Click(object sender, EventArgs e) if (dlg.ShowDialog() == DialogResult.OK) { foreach (var g in GetSelectedGhosts()) - g.hatColor = ColorUtilities.ColorToVec4(dlg.Color); + g.hatColor = OpenTKUtilities.ColorToVec4(dlg.Color); buttonGhostColor.BackColor = dlg.Color; } } diff --git a/STROOP/Tabs/GhostTab/GhostTab.Designer.cs b/STROOP/Tabs/GhostTab/GhostTab.Designer.cs index c05924b28..84281af1e 100644 --- a/STROOP/Tabs/GhostTab/GhostTab.Designer.cs +++ b/STROOP/Tabs/GhostTab/GhostTab.Designer.cs @@ -51,7 +51,7 @@ private void InitializeComponent() this.labelHackActiveState = new System.Windows.Forms.Label(); this.buttonDisableGhostHack = new System.Windows.Forms.Button(); this.buttonEnableGhostHack = new System.Windows.Forms.Button(); - this.watchVariablePanelGhost = new STROOP.Controls.VariablePanel.WatchVariablePanel(); + this._variablePanelGhost = new STROOP.Controls.VariablePanel.VariablePanel(); this.groupBoxVariables = new System.Windows.Forms.GroupBox(); this.groupBoxHelp = new System.Windows.Forms.GroupBox(); this.buttonTutorialFileWatch = new System.Windows.Forms.Button(); @@ -346,23 +346,23 @@ private void InitializeComponent() // // watchVariablePanelGhost // - this.watchVariablePanelGhost.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + this._variablePanelGhost.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.watchVariablePanelGhost.AutoScroll = true; - this.watchVariablePanelGhost.DataPath = "Config/GhostData.xml"; - this.watchVariablePanelGhost.elementNameWidth = null; - this.watchVariablePanelGhost.elementValueWidth = null; - this.watchVariablePanelGhost.Location = new System.Drawing.Point(6, 19); - this.watchVariablePanelGhost.Name = "watchVariablePanelGhost"; - this.watchVariablePanelGhost.Size = new System.Drawing.Size(209, 432); - this.watchVariablePanelGhost.TabIndex = 4; + this._variablePanelGhost.AutoScroll = true; + this._variablePanelGhost.DataPath = "Config/GhostData.xml"; + this._variablePanelGhost.elementNameWidth = null; + this._variablePanelGhost.elementValueWidth = null; + this._variablePanelGhost.Location = new System.Drawing.Point(6, 19); + this._variablePanelGhost.Name = "_variablePanelGhost"; + this._variablePanelGhost.Size = new System.Drawing.Size(209, 432); + this._variablePanelGhost.TabIndex = 4; // // groupBoxVariables // this.groupBoxVariables.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Right))); - this.groupBoxVariables.Controls.Add(this.watchVariablePanelGhost); + this.groupBoxVariables.Controls.Add(this._variablePanelGhost); this.groupBoxVariables.Location = new System.Drawing.Point(691, 3); this.groupBoxVariables.Name = "groupBoxVariables"; this.groupBoxVariables.Size = new System.Drawing.Size(221, 457); @@ -547,7 +547,7 @@ private void InitializeComponent() public System.Windows.Forms.Label labelHackActiveState; private System.Windows.Forms.TextBox textBoxGhostName; public System.Windows.Forms.Label labelName; - private STROOP.Controls.VariablePanel.WatchVariablePanel watchVariablePanelGhost; + private STROOP.Controls.VariablePanel.VariablePanel _variablePanelGhost; private System.Windows.Forms.Button buttonWatchGhostFile; private System.Windows.Forms.Button buttonTutorialRecord; private System.Windows.Forms.GroupBox groupBoxVariables; diff --git a/STROOP/Tabs/GhostTab/GhostTab.cs b/STROOP/Tabs/GhostTab/GhostTab.cs index 34a1385fa..a571e2f25 100644 --- a/STROOP/Tabs/GhostTab/GhostTab.cs +++ b/STROOP/Tabs/GhostTab/GhostTab.cs @@ -8,6 +8,11 @@ using STROOP.Utilities; using System.Linq; using OpenTK.Mathematics; +using STROOP.Core; +using STROOP.Core.Utilities; +using STROOP.Variables; +using STROOP.Variables.SM64MemoryLayout; +using STROOP.Variables.Utilities; namespace STROOP.Tabs.GhostTab { @@ -24,7 +29,7 @@ static IEnumerable GetActiveGhostIndices() [InitializeSpecial] static void AddSpecialVariables() { - var target = WatchVariableSpecialUtilities.dictionary; + var target = VariableSpecialDictionary.Instance; Func, Func>> displayGhostVarFloat = (selectMember) => () => GetActiveGhostIndices().Select((uint index) => selectMember((instance.listBoxGhosts.Items[(int)index] as Ghost)?.currentFrame ?? default(GhostFrame))); diff --git a/STROOP/Tabs/HackTab.cs b/STROOP/Tabs/HackTab.cs index 82a6709fc..4ea1581b3 100644 --- a/STROOP/Tabs/HackTab.cs +++ b/STROOP/Tabs/HackTab.cs @@ -1,9 +1,11 @@ -using System; +using STROOP.Core; +using System; using System.Collections.Generic; using STROOP.Structs; using System.Windows.Forms; using STROOP.Utilities; using STROOP.Structs.Configurations; +using STROOP.Variables.Utilities; namespace STROOP.Tabs { diff --git a/STROOP/Tabs/HudTab.Designer.cs b/STROOP/Tabs/HudTab.Designer.cs index 47d6323a4..989eaed74 100644 --- a/STROOP/Tabs/HudTab.Designer.cs +++ b/STROOP/Tabs/HudTab.Designer.cs @@ -41,7 +41,7 @@ private void InitializeComponent() this.button100Lives = new STROOP.BinaryButton(); this.buttonTurnOnOffHud = new STROOP.BinaryButton(); this.buttonFullHp = new System.Windows.Forms.Button(); - this.watchVariablePanelHud = new STROOP.Controls.VariablePanel.WatchVariablePanel(); + this._variablePanelHud = new STROOP.Controls.VariablePanel.VariablePanel(); ((System.ComponentModel.ISupportInitialize)(this.splitContainerHud)).BeginInit(); this.splitContainerHud.Panel1.SuspendLayout(); this.splitContainerHud.Panel2.SuspendLayout(); @@ -78,7 +78,7 @@ private void InitializeComponent() // // splitContainerHud.Panel2 // - this.splitContainerHud.Panel2.Controls.Add(this.watchVariablePanelHud); + this.splitContainerHud.Panel2.Controls.Add(this._variablePanelHud); this.splitContainerHud.Panel2.Padding = new System.Windows.Forms.Padding(2); this.splitContainerHud.Panel2MinSize = 0; this.splitContainerHud.Size = new System.Drawing.Size(915, 463); @@ -194,13 +194,13 @@ private void InitializeComponent() // // watchVariablePanelHud // - this.watchVariablePanelHud.DataPath = "Config/HudData.xml"; - this.watchVariablePanelHud.Dock = System.Windows.Forms.DockStyle.Fill; - this.watchVariablePanelHud.Location = new System.Drawing.Point(2, 2); - this.watchVariablePanelHud.Margin = new System.Windows.Forms.Padding(0); - this.watchVariablePanelHud.Name = "watchVariablePanelHud"; - this.watchVariablePanelHud.Size = new System.Drawing.Size(791, 457); - this.watchVariablePanelHud.TabIndex = 3; + this._variablePanelHud.DataPath = "Config/HudData.xml"; + this._variablePanelHud.Dock = System.Windows.Forms.DockStyle.Fill; + this._variablePanelHud.Location = new System.Drawing.Point(2, 2); + this._variablePanelHud.Margin = new System.Windows.Forms.Padding(0); + this._variablePanelHud.Name = "_variablePanelHud"; + this._variablePanelHud.Size = new System.Drawing.Size(791, 457); + this._variablePanelHud.TabIndex = 3; // // HudTab // @@ -234,6 +234,6 @@ private void InitializeComponent() private BinaryButton button100Lives; private BinaryButton buttonTurnOnOffHud; private System.Windows.Forms.Button buttonFullHp; - private STROOP.Controls.VariablePanel.WatchVariablePanel watchVariablePanelHud; + private STROOP.Controls.VariablePanel.VariablePanel _variablePanelHud; } } diff --git a/STROOP/Tabs/HudTab.cs b/STROOP/Tabs/HudTab.cs index d36ae1f6b..00a35f26a 100644 --- a/STROOP/Tabs/HudTab.cs +++ b/STROOP/Tabs/HudTab.cs @@ -3,6 +3,7 @@ using STROOP.Structs; using STROOP.Utilities; using STROOP.Structs.Configurations; +using STROOP.Variables.SM64MemoryLayout; namespace STROOP.Tabs { diff --git a/STROOP/Tabs/InputTab.Designer.cs b/STROOP/Tabs/InputTab.Designer.cs index 8b615ecf4..f5d88d413 100644 --- a/STROOP/Tabs/InputTab.Designer.cs +++ b/STROOP/Tabs/InputTab.Designer.cs @@ -31,7 +31,7 @@ private void InitializeComponent() this.components = new System.ComponentModel.Container(); this.splitContainerInput = new STROOP.BetterSplitContainer(); this.inputDisplayPanel = new STROOP.InputDisplayPanel(); - this.watchVariablePanelInput = new STROOP.Controls.VariablePanel.WatchVariablePanel(); + this._variablePanelInput = new STROOP.Controls.VariablePanel.VariablePanel(); ((System.ComponentModel.ISupportInitialize)(this.splitContainerInput)).BeginInit(); this.splitContainerInput.Panel1.SuspendLayout(); this.splitContainerInput.Panel2.SuspendLayout(); @@ -57,7 +57,7 @@ private void InitializeComponent() // // splitContainerInput.Panel2 // - this.splitContainerInput.Panel2.Controls.Add(this.watchVariablePanelInput); + this.splitContainerInput.Panel2.Controls.Add(this._variablePanelInput); this.splitContainerInput.Panel2.Padding = new System.Windows.Forms.Padding(2); this.splitContainerInput.Panel2MinSize = 0; this.splitContainerInput.Size = new System.Drawing.Size(915, 463); @@ -77,13 +77,13 @@ private void InitializeComponent() // // watchVariablePanelInput // - this.watchVariablePanelInput.DataPath = "Config/InputData.xml"; - this.watchVariablePanelInput.Dock = System.Windows.Forms.DockStyle.Fill; - this.watchVariablePanelInput.Location = new System.Drawing.Point(2, 2); - this.watchVariablePanelInput.Margin = new System.Windows.Forms.Padding(0); - this.watchVariablePanelInput.Name = "watchVariablePanelInput"; - this.watchVariablePanelInput.Size = new System.Drawing.Size(480, 457); - this.watchVariablePanelInput.TabIndex = 2; + this._variablePanelInput.DataPath = "Config/InputData.xml"; + this._variablePanelInput.Dock = System.Windows.Forms.DockStyle.Fill; + this._variablePanelInput.Location = new System.Drawing.Point(2, 2); + this._variablePanelInput.Margin = new System.Windows.Forms.Padding(0); + this._variablePanelInput.Name = "_variablePanelInput"; + this._variablePanelInput.Size = new System.Drawing.Size(480, 457); + this._variablePanelInput.TabIndex = 2; // // InputTab // @@ -105,6 +105,6 @@ private void InitializeComponent() private BetterSplitContainer splitContainerInput; private InputDisplayPanel inputDisplayPanel; - private STROOP.Controls.VariablePanel.WatchVariablePanel watchVariablePanelInput; + private STROOP.Controls.VariablePanel.VariablePanel _variablePanelInput; } } diff --git a/STROOP/Tabs/InputTab.cs b/STROOP/Tabs/InputTab.cs index b4e603323..390444587 100644 --- a/STROOP/Tabs/InputTab.cs +++ b/STROOP/Tabs/InputTab.cs @@ -2,6 +2,8 @@ using STROOP.Structs; using STROOP.Utilities; using STROOP.Structs.Configurations; +using STROOP.Variables; +using STROOP.Variables.Utilities; namespace STROOP.Tabs { @@ -10,9 +12,9 @@ public partial class InputTab : STROOPTab [InitializeBaseAddress] static void InitBaseAddresses() { - WatchVariableUtilities.baseAddressGetters["InputCurrent"] = () => new List { InputConfig.CurrentInputAddress }; - WatchVariableUtilities.baseAddressGetters["InputJustPressed"] = () => new List { InputConfig.JustPressedInputAddress }; - WatchVariableUtilities.baseAddressGetters["InputBuffered"] = () => new List { InputConfig.BufferedInputAddress }; + VariableUtilities.baseAddressGetters["InputCurrent"] = () => new List { InputConfig.CurrentInputAddress }; + VariableUtilities.baseAddressGetters["InputJustPressed"] = () => new List { InputConfig.JustPressedInputAddress }; + VariableUtilities.baseAddressGetters["InputBuffered"] = () => new List { InputConfig.BufferedInputAddress }; } List _guiList; diff --git a/STROOP/Tabs/M64Tab.cs b/STROOP/Tabs/M64Tab.cs index e2290bc11..79b73d6d6 100644 --- a/STROOP/Tabs/M64Tab.cs +++ b/STROOP/Tabs/M64Tab.cs @@ -1,6 +1,8 @@ -using STROOP.M64; +using STROOP.Core; +using STROOP.M64; using STROOP.Structs; using STROOP.Utilities; +using STROOP.Variables.Utilities; using System; using System.Collections.Generic; using System.Drawing; diff --git a/STROOP/Tabs/MainSaveTab.Designer.cs b/STROOP/Tabs/MainSaveTab.Designer.cs index 182ec4598..97256d57d 100644 --- a/STROOP/Tabs/MainSaveTab.Designer.cs +++ b/STROOP/Tabs/MainSaveTab.Designer.cs @@ -122,7 +122,7 @@ private void InitializeComponent() this.radioButtonMainSaveStructMainSaveSaved = new System.Windows.Forms.RadioButton(); this.radioButtonMainSaveStructMainSave = new System.Windows.Forms.RadioButton(); this.buttonMainSaveSave = new System.Windows.Forms.Button(); - this.watchVariablePanelMainSave = new STROOP.Controls.VariablePanel.WatchVariablePanel(); + this._variablePanelMainSave = new STROOP.Controls.VariablePanel.VariablePanel(); ((System.ComponentModel.ISupportInitialize)(this.splitContainerMainSave)).BeginInit(); this.splitContainerMainSave.Panel1.SuspendLayout(); this.splitContainerMainSave.Panel2.SuspendLayout(); @@ -156,7 +156,7 @@ private void InitializeComponent() // // splitContainerMainSave.Panel2 // - this.splitContainerMainSave.Panel2.Controls.Add(this.watchVariablePanelMainSave); + this.splitContainerMainSave.Panel2.Controls.Add(this._variablePanelMainSave); this.splitContainerMainSave.Panel2.Padding = new System.Windows.Forms.Padding(2); this.splitContainerMainSave.Panel2MinSize = 0; this.splitContainerMainSave.Size = new System.Drawing.Size(915, 463); @@ -1509,15 +1509,15 @@ private void InitializeComponent() // // watchVariablePanelMainSave // - this.watchVariablePanelMainSave.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + this._variablePanelMainSave.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.watchVariablePanelMainSave.DataPath = "Config/MainSaveData.xml"; - this.watchVariablePanelMainSave.Location = new System.Drawing.Point(2, 2); - this.watchVariablePanelMainSave.Margin = new System.Windows.Forms.Padding(0); - this.watchVariablePanelMainSave.Name = "watchVariablePanelMainSave"; - this.watchVariablePanelMainSave.Size = new System.Drawing.Size(479, 457); - this.watchVariablePanelMainSave.TabIndex = 2; + this._variablePanelMainSave.DataPath = "Config/MainSaveData.xml"; + this._variablePanelMainSave.Location = new System.Drawing.Point(2, 2); + this._variablePanelMainSave.Margin = new System.Windows.Forms.Padding(0); + this._variablePanelMainSave.Name = "_variablePanelMainSave"; + this._variablePanelMainSave.Size = new System.Drawing.Size(479, 457); + this._variablePanelMainSave.TabIndex = 2; // // MainSaveTab // @@ -1637,6 +1637,6 @@ private void InitializeComponent() private System.Windows.Forms.RadioButton radioButtonMainSaveStructMainSaveSaved; private System.Windows.Forms.RadioButton radioButtonMainSaveStructMainSave; private System.Windows.Forms.Button buttonMainSaveSave; - private STROOP.Controls.VariablePanel.WatchVariablePanel watchVariablePanelMainSave; + private STROOP.Controls.VariablePanel.VariablePanel _variablePanelMainSave; } } diff --git a/STROOP/Tabs/MainSaveTab.cs b/STROOP/Tabs/MainSaveTab.cs index 6dd8186f3..973c57dc3 100644 --- a/STROOP/Tabs/MainSaveTab.cs +++ b/STROOP/Tabs/MainSaveTab.cs @@ -1,6 +1,10 @@ -using System; +using STROOP.Core; +using System; using System.Collections.Generic; using STROOP.Structs.Configurations; +using STROOP.Variables; +using STROOP.Variables.SM64MemoryLayout; +using STROOP.Variables.Utilities; namespace STROOP.Tabs { @@ -12,13 +16,16 @@ public enum MainSaveMode MainSaveSaved }; - public MainSaveMode CurrentMainSaveMode { get; private set; } + public static uint CurrentMainSaveAddress => AccessScope.content.GetTab().GetMainSaveAddress(); - public uint CurrentMainSaveAddress + [InitializeBaseAddress] + static void InitializeBaseAddress() { - get => GetMainSaveAddress(); + VariableUtilities.baseAddressGetters[BaseAddressType.MainSave] = () => [CurrentMainSaveAddress]; } + public MainSaveMode CurrentMainSaveMode { get; private set; } + private List _mainSaveTextboxes; public MainSaveTab() diff --git a/STROOP/Tabs/MapTab/DataUtil/HoverDatas.cs b/STROOP/Tabs/MapTab/DataUtil/HoverDatas.cs index b84a9a68a..e88f5c3ef 100644 --- a/STROOP/Tabs/MapTab/DataUtil/HoverDatas.cs +++ b/STROOP/Tabs/MapTab/DataUtil/HoverDatas.cs @@ -4,6 +4,7 @@ using System.Windows.Forms; using System.Collections.Generic; using OpenTK.Mathematics; +using STROOP.Core; namespace STROOP.Tabs.MapTab.MapObjects { diff --git a/STROOP/Tabs/MapTab/MapAssociations.cs b/STROOP/Tabs/MapTab/MapAssociations.cs index a3325f7a0..7799fee4c 100644 --- a/STROOP/Tabs/MapTab/MapAssociations.cs +++ b/STROOP/Tabs/MapTab/MapAssociations.cs @@ -4,6 +4,7 @@ using System.Drawing; using STROOP.Structs.Configurations; using STROOP.Structs; +using STROOP.Variables.SM64MemoryLayout; namespace STROOP.Tabs.MapTab { diff --git a/STROOP/Tabs/MapTab/MapGraphics.LegacyControlScheme.cs b/STROOP/Tabs/MapTab/MapGraphics.LegacyControlScheme.cs index 866610900..24b390123 100644 --- a/STROOP/Tabs/MapTab/MapGraphics.LegacyControlScheme.cs +++ b/STROOP/Tabs/MapTab/MapGraphics.LegacyControlScheme.cs @@ -7,6 +7,8 @@ using STROOP.Structs; using STROOP.Structs.Configurations; using STROOP.Utilities; +using STROOP.Variables.SM64MemoryLayout; +using STROOP.Variables.Utilities; namespace STROOP.Tabs.MapTab { diff --git a/STROOP/Tabs/MapTab/MapGraphics.cs b/STROOP/Tabs/MapTab/MapGraphics.cs index 03dcfa6b4..898933596 100644 --- a/STROOP/Tabs/MapTab/MapGraphics.cs +++ b/STROOP/Tabs/MapTab/MapGraphics.cs @@ -7,6 +7,7 @@ using OpenTK.GLControl; using OpenTK.Mathematics; using STROOP.Controls; +using STROOP.Core; using STROOP.Extensions; using STROOP.Structs; using STROOP.Structs.Configurations; diff --git a/STROOP/Tabs/MapTab/MapObjects/MapAngleRangeObject.cs b/STROOP/Tabs/MapTab/MapObjects/MapAngleRangeObject.cs index 2a0ef228d..d53f6b1f6 100644 --- a/STROOP/Tabs/MapTab/MapObjects/MapAngleRangeObject.cs +++ b/STROOP/Tabs/MapTab/MapObjects/MapAngleRangeObject.cs @@ -6,6 +6,7 @@ using STROOP.Structs.Configurations; using System.Windows.Forms; using OpenTK.Mathematics; +using STROOP.Variables.Utilities; namespace STROOP.Tabs.MapTab.MapObjects { diff --git a/STROOP/Tabs/MapTab/MapObjects/MapArrowObject.cs b/STROOP/Tabs/MapTab/MapObjects/MapArrowObject.cs index 6f5f21abb..4bb83fe36 100644 --- a/STROOP/Tabs/MapTab/MapObjects/MapArrowObject.cs +++ b/STROOP/Tabs/MapTab/MapObjects/MapArrowObject.cs @@ -7,6 +7,8 @@ using STROOP.Structs; using System.Windows.Forms; using OpenTK.Mathematics; +using STROOP.Variables.SM64MemoryLayout; +using STROOP.Variables.Utilities; namespace STROOP.Tabs.MapTab.MapObjects { @@ -141,7 +143,7 @@ public class ArrowSource public static GetYaw MarioFacingYaw = posAngle => Config.Stream.GetUInt16(MarioConfig.StructAddress + MarioConfig.FacingYawOffset); public static GetYaw MarioIndendedYaw = posAngle => Config.Stream.GetUInt16(MarioConfig.StructAddress + MarioConfig.IntendedYawOffset); public static GetYaw MarioMovingYaw = posAngle => Config.Stream.GetUInt16(MarioConfig.StructAddress + MarioConfig.MovingYawOffset); - public static GetYaw MarioSlidingYaw = posAngle => WatchVariableSpecialUtilities.GetMarioSlidingAngle(); + public static GetYaw MarioSlidingYaw = posAngle => VariableSpecialUtilities.GetMarioSlidingAngle(); public static GetYaw MarioTwirlingYaw = posAngle => Config.Stream.GetUInt16(MarioConfig.StructAddress + MarioConfig.TwirlYawOffset); @@ -150,7 +152,7 @@ public class ArrowSource public static GetRecommendedSize MarioHSpeed = posAngle => Config.Stream.GetSingle(MarioConfig.StructAddress + MarioConfig.HSpeedOffset); - public static GetRecommendedSize MarioSlidingSpeed = posAngle => WatchVariableSpecialUtilities.GetMarioSlidingSpeed(); + public static GetRecommendedSize MarioSlidingSpeed = posAngle => VariableSpecialUtilities.GetMarioSlidingSpeed(); public static GetRecommendedSize Constant(double length) => _ => length; diff --git a/STROOP/Tabs/MapTab/MapObjects/MapBruteforceTriangles.cs b/STROOP/Tabs/MapTab/MapObjects/MapBruteforceTriangles.cs index 6acc786d7..88ca57dad 100644 --- a/STROOP/Tabs/MapTab/MapObjects/MapBruteforceTriangles.cs +++ b/STROOP/Tabs/MapTab/MapObjects/MapBruteforceTriangles.cs @@ -107,7 +107,7 @@ protected override void Draw3D(MapGraphics graphics) tri.p2 + offset, tri.p3 + offset, false, - ColorUtilities.ColorToVec4(Color, 128), + OpenTKUtilities.ColorToVec4(Color, 128), new Vector4(OutlineColor.R / 255f, OutlineColor.G / 255f, OutlineColor.B / 255f, OutlineColor.A / 255f), new Vector3(OutlineWidth), true); diff --git a/STROOP/Tabs/MapTab/MapObjects/MapCellGridlinesObject.cs b/STROOP/Tabs/MapTab/MapObjects/MapCellGridlinesObject.cs index 7ebee8d8c..fee56e692 100644 --- a/STROOP/Tabs/MapTab/MapObjects/MapCellGridlinesObject.cs +++ b/STROOP/Tabs/MapTab/MapObjects/MapCellGridlinesObject.cs @@ -5,6 +5,7 @@ using OpenTK.Mathematics; using STROOP.Structs.Configurations; using STROOP.Structs; +using STROOP.Variables.SM64MemoryLayout; namespace STROOP.Tabs.MapTab.MapObjects { diff --git a/STROOP/Tabs/MapTab/MapObjects/MapCircleObject.cs b/STROOP/Tabs/MapTab/MapObjects/MapCircleObject.cs index 464e7981f..e65a41164 100644 --- a/STROOP/Tabs/MapTab/MapObjects/MapCircleObject.cs +++ b/STROOP/Tabs/MapTab/MapObjects/MapCircleObject.cs @@ -20,8 +20,8 @@ protected override void DrawTopDown(MapGraphics graphics) graphics.drawLayers[(int)MapGraphics.DrawLayers.FillBuffers].Add(() => { List<(float centerX, float centerZ, float radius)> dimensionList = Get2DDimensions(); - var color = ColorUtilities.ColorToVec4(Color, OpacityByte); - var outlineColor = ColorUtilities.ColorToVec4(OutlineColor); + var color = OpenTKUtilities.ColorToVec4(Color, OpacityByte); + var outlineColor = OpenTKUtilities.ColorToVec4(OutlineColor); foreach (var dim in dimensionList) { var transform = graphics.BillboardMatrix * Matrix4.CreateScale(dim.radius) * Matrix4.CreateTranslation(dim.centerX, 0, dim.centerZ); diff --git a/STROOP/Tabs/MapTab/MapObjects/MapCurrentCellObject.cs b/STROOP/Tabs/MapTab/MapObjects/MapCurrentCellObject.cs index 478ff2652..291d3b756 100644 --- a/STROOP/Tabs/MapTab/MapObjects/MapCurrentCellObject.cs +++ b/STROOP/Tabs/MapTab/MapObjects/MapCurrentCellObject.cs @@ -4,6 +4,7 @@ using STROOP.Structs; using STROOP.Structs.Configurations; using STROOP.Utilities; +using STROOP.Variables.SM64MemoryLayout; namespace STROOP.Tabs.MapTab.MapObjects { @@ -20,7 +21,7 @@ public MapCurrentCellObject() protected override List<(float xMin, float xMax, float zMin, float zMax, float y)> GetQuadList() { - (int cellX, int cellZ) = WatchVariableSpecialUtilities.GetMarioCell(); + (int cellX, int cellZ) = VariableSpecialUtilities.GetMarioCell(); int xMin = (cellX - 8) * 1024; int xMax = xMin + 1024; int zMin = (cellZ - 8) * 1024; diff --git a/STROOP/Tabs/MapTab/MapObjects/MapCustomCeilingObject.cs b/STROOP/Tabs/MapTab/MapObjects/MapCustomCeilingObject.cs index 98990d714..b2a16cc47 100644 --- a/STROOP/Tabs/MapTab/MapObjects/MapCustomCeilingObject.cs +++ b/STROOP/Tabs/MapTab/MapObjects/MapCustomCeilingObject.cs @@ -4,6 +4,7 @@ using STROOP.Structs.Configurations; using STROOP.Structs; using STROOP.Models; +using STROOP.Variables.SM64MemoryLayout; namespace STROOP.Tabs.MapTab.MapObjects { diff --git a/STROOP/Tabs/MapTab/MapObjects/MapCustomCylinderPointsObject.cs b/STROOP/Tabs/MapTab/MapObjects/MapCustomCylinderPointsObject.cs index 2d671107c..070506645 100644 --- a/STROOP/Tabs/MapTab/MapObjects/MapCustomCylinderPointsObject.cs +++ b/STROOP/Tabs/MapTab/MapObjects/MapCustomCylinderPointsObject.cs @@ -3,6 +3,7 @@ using System.Drawing; using STROOP.Utilities; using STROOP.Structs.Configurations; +using STROOP.Variables.Utilities; using System.Windows.Forms; namespace STROOP.Tabs.MapTab.MapObjects diff --git a/STROOP/Tabs/MapTab/MapObjects/MapCustomFloorObject.cs b/STROOP/Tabs/MapTab/MapObjects/MapCustomFloorObject.cs index fecb433db..3bfc51eb4 100644 --- a/STROOP/Tabs/MapTab/MapObjects/MapCustomFloorObject.cs +++ b/STROOP/Tabs/MapTab/MapObjects/MapCustomFloorObject.cs @@ -4,6 +4,7 @@ using STROOP.Structs.Configurations; using STROOP.Structs; using STROOP.Models; +using STROOP.Variables.SM64MemoryLayout; namespace STROOP.Tabs.MapTab.MapObjects { diff --git a/STROOP/Tabs/MapTab/MapObjects/MapCustomIconPoints.cs b/STROOP/Tabs/MapTab/MapObjects/MapCustomIconPoints.cs index eea83c5f7..84e725012 100644 --- a/STROOP/Tabs/MapTab/MapObjects/MapCustomIconPoints.cs +++ b/STROOP/Tabs/MapTab/MapObjects/MapCustomIconPoints.cs @@ -6,6 +6,8 @@ using System.Windows.Forms; using OpenTK; using OpenTK.Mathematics; +using STROOP.Core; +using STROOP.Variables.Utilities; namespace STROOP.Tabs.MapTab.MapObjects { diff --git a/STROOP/Tabs/MapTab/MapObjects/MapCustomWallObject.cs b/STROOP/Tabs/MapTab/MapObjects/MapCustomWallObject.cs index 419d93fb8..3d6794bdd 100644 --- a/STROOP/Tabs/MapTab/MapObjects/MapCustomWallObject.cs +++ b/STROOP/Tabs/MapTab/MapObjects/MapCustomWallObject.cs @@ -4,6 +4,7 @@ using STROOP.Structs.Configurations; using STROOP.Structs; using STROOP.Models; +using STROOP.Variables.SM64MemoryLayout; namespace STROOP.Tabs.MapTab.MapObjects { diff --git a/STROOP/Tabs/MapTab/MapObjects/MapCylinderObject.cs b/STROOP/Tabs/MapTab/MapObjects/MapCylinderObject.cs index 599611c92..f677287a8 100644 --- a/STROOP/Tabs/MapTab/MapObjects/MapCylinderObject.cs +++ b/STROOP/Tabs/MapTab/MapObjects/MapCylinderObject.cs @@ -35,7 +35,7 @@ protected override void DrawOrthogonal(MapGraphics graphics) var transform = Matrix4.CreateScale((float)scale * dim.radius, (dim.maxY - dim.minY) * 0.5f, 1) * graphics.BillboardMatrix * Matrix4.CreateTranslation(dim.centerX, (dim.minY + dim.maxY) * 0.5f, dim.centerZ); - graphics.circleRenderer.AddInstance(true, transform, OutlineWidth, color, Utilities.ColorUtilities.ColorToVec4(OutlineColor), Renderers.ShapeRenderer.Shapes.Quad); + graphics.circleRenderer.AddInstance(true, transform, OutlineWidth, color, Utilities.OpenTKUtilities.ColorToVec4(OutlineColor), Renderers.ShapeRenderer.Shapes.Quad); } } }); diff --git a/STROOP/Tabs/MapTab/MapObjects/MapGhostObject.cs b/STROOP/Tabs/MapTab/MapObjects/MapGhostObject.cs index 8dc8049ba..cfba3ed99 100644 --- a/STROOP/Tabs/MapTab/MapObjects/MapGhostObject.cs +++ b/STROOP/Tabs/MapTab/MapObjects/MapGhostObject.cs @@ -5,6 +5,7 @@ using System.Windows.Forms; using OpenTK; using OpenTK.Mathematics; +using STROOP.Core; namespace STROOP.Tabs.MapTab.MapObjects { diff --git a/STROOP/Tabs/MapTab/MapObjects/MapGridlinesObject.cs b/STROOP/Tabs/MapTab/MapObjects/MapGridlinesObject.cs index 0264aaa0d..857f615c5 100644 --- a/STROOP/Tabs/MapTab/MapObjects/MapGridlinesObject.cs +++ b/STROOP/Tabs/MapTab/MapObjects/MapGridlinesObject.cs @@ -6,6 +6,7 @@ using STROOP.Utilities; using System.Windows.Forms; using OpenTK.Mathematics; +using STROOP.Variables.Utilities; namespace STROOP.Tabs.MapTab.MapObjects { diff --git a/STROOP/Tabs/MapTab/MapObjects/MapHorizontalTriangleObject.cs b/STROOP/Tabs/MapTab/MapObjects/MapHorizontalTriangleObject.cs index 5d33a6941..b2fdab302 100644 --- a/STROOP/Tabs/MapTab/MapObjects/MapHorizontalTriangleObject.cs +++ b/STROOP/Tabs/MapTab/MapObjects/MapHorizontalTriangleObject.cs @@ -9,6 +9,8 @@ using STROOP.Models; using System.Windows.Forms; using OpenTK.Mathematics; +using STROOP.Variables.SM64MemoryLayout; +using STROOP.Variables.Utilities; namespace STROOP.Tabs.MapTab.MapObjects { diff --git a/STROOP/Tabs/MapTab/MapObjects/MapIwerlipsesObject.cs b/STROOP/Tabs/MapTab/MapObjects/MapIwerlipsesObject.cs index 3d04bdff1..cf00ffc25 100644 --- a/STROOP/Tabs/MapTab/MapObjects/MapIwerlipsesObject.cs +++ b/STROOP/Tabs/MapTab/MapObjects/MapIwerlipsesObject.cs @@ -60,8 +60,8 @@ protected override void DrawTopDown(MapGraphics graphics) { graphics.drawLayers[(int)MapGraphics.DrawLayers.FillBuffers].Add(() => { - var color = ColorUtilities.ColorToVec4(Color, OpacityByte); - var outlineColor = ColorUtilities.ColorToVec4(OutlineColor); + var color = OpenTKUtilities.ColorToVec4(Color, OpacityByte); + var outlineColor = OpenTKUtilities.ColorToVec4(OutlineColor); foreach (var transform in _ellipseTransforms) graphics.circleRenderer.AddInstance( graphics.view.mode != MapView.ViewMode.TopDown, diff --git a/STROOP/Tabs/MapTab/MapObjects/MapLevelCeilingObject.cs b/STROOP/Tabs/MapTab/MapObjects/MapLevelCeilingObject.cs index 3630ca615..ebae40177 100644 --- a/STROOP/Tabs/MapTab/MapObjects/MapLevelCeilingObject.cs +++ b/STROOP/Tabs/MapTab/MapObjects/MapLevelCeilingObject.cs @@ -7,6 +7,7 @@ using STROOP.Models; using System.Windows.Forms; using STROOP.Forms; +using STROOP.Variables.SM64MemoryLayout; namespace STROOP.Tabs.MapTab.MapObjects { diff --git a/STROOP/Tabs/MapTab/MapObjects/MapLevelFloorObject.cs b/STROOP/Tabs/MapTab/MapObjects/MapLevelFloorObject.cs index 60859bf26..adaea2502 100644 --- a/STROOP/Tabs/MapTab/MapObjects/MapLevelFloorObject.cs +++ b/STROOP/Tabs/MapTab/MapObjects/MapLevelFloorObject.cs @@ -7,6 +7,7 @@ using STROOP.Models; using System.Windows.Forms; using STROOP.Forms; +using STROOP.Variables.SM64MemoryLayout; namespace STROOP.Tabs.MapTab.MapObjects { diff --git a/STROOP/Tabs/MapTab/MapObjects/MapLevelWallObject.cs b/STROOP/Tabs/MapTab/MapObjects/MapLevelWallObject.cs index 4f8660a82..cff847ad2 100644 --- a/STROOP/Tabs/MapTab/MapObjects/MapLevelWallObject.cs +++ b/STROOP/Tabs/MapTab/MapObjects/MapLevelWallObject.cs @@ -7,6 +7,7 @@ using STROOP.Models; using System.Windows.Forms; using STROOP.Forms; +using STROOP.Variables.SM64MemoryLayout; namespace STROOP.Tabs.MapTab.MapObjects { diff --git a/STROOP/Tabs/MapTab/MapObjects/MapLineObject.cs b/STROOP/Tabs/MapTab/MapObjects/MapLineObject.cs index d22f4c97a..51950325a 100644 --- a/STROOP/Tabs/MapTab/MapObjects/MapLineObject.cs +++ b/STROOP/Tabs/MapTab/MapObjects/MapLineObject.cs @@ -13,7 +13,7 @@ public MapLineObject() : base() { } - protected virtual Vector4 GetColor(MapGraphics graphics) => ColorUtilities.ColorToVec4(OutlineColor, OpacityByte); + protected virtual Vector4 GetColor(MapGraphics graphics) => OpenTKUtilities.ColorToVec4(OutlineColor, OpacityByte); protected override void DrawTopDown(MapGraphics graphics) { diff --git a/STROOP/Tabs/MapTab/MapObjects/MapLineSegmentObject.cs b/STROOP/Tabs/MapTab/MapObjects/MapLineSegmentObject.cs index 322e6de17..e47a266b3 100644 --- a/STROOP/Tabs/MapTab/MapObjects/MapLineSegmentObject.cs +++ b/STROOP/Tabs/MapTab/MapObjects/MapLineSegmentObject.cs @@ -6,6 +6,7 @@ using STROOP.Structs.Configurations; using System.Windows.Forms; using OpenTK.Mathematics; +using STROOP.Variables.Utilities; namespace STROOP.Tabs.MapTab.MapObjects { diff --git a/STROOP/Tabs/MapTab/MapObjects/MapMarioCeilingObject.cs b/STROOP/Tabs/MapTab/MapObjects/MapMarioCeilingObject.cs index 6fbda2988..522eff9ab 100644 --- a/STROOP/Tabs/MapTab/MapObjects/MapMarioCeilingObject.cs +++ b/STROOP/Tabs/MapTab/MapObjects/MapMarioCeilingObject.cs @@ -4,6 +4,7 @@ using STROOP.Structs.Configurations; using STROOP.Structs; using STROOP.Models; +using STROOP.Variables.SM64MemoryLayout; namespace STROOP.Tabs.MapTab.MapObjects { diff --git a/STROOP/Tabs/MapTab/MapObjects/MapMarioFloorObject.cs b/STROOP/Tabs/MapTab/MapObjects/MapMarioFloorObject.cs index fd4b68c8b..ef1bf25f4 100644 --- a/STROOP/Tabs/MapTab/MapObjects/MapMarioFloorObject.cs +++ b/STROOP/Tabs/MapTab/MapObjects/MapMarioFloorObject.cs @@ -4,6 +4,7 @@ using STROOP.Structs.Configurations; using STROOP.Structs; using STROOP.Models; +using STROOP.Variables.SM64MemoryLayout; namespace STROOP.Tabs.MapTab.MapObjects { diff --git a/STROOP/Tabs/MapTab/MapObjects/MapMarioWallObject.cs b/STROOP/Tabs/MapTab/MapObjects/MapMarioWallObject.cs index d33abd9b2..84a2e1881 100644 --- a/STROOP/Tabs/MapTab/MapObjects/MapMarioWallObject.cs +++ b/STROOP/Tabs/MapTab/MapObjects/MapMarioWallObject.cs @@ -4,6 +4,7 @@ using STROOP.Structs.Configurations; using STROOP.Structs; using STROOP.Models; +using STROOP.Variables.SM64MemoryLayout; namespace STROOP.Tabs.MapTab.MapObjects { diff --git a/STROOP/Tabs/MapTab/MapObjects/MapNearbyUnits.cs b/STROOP/Tabs/MapTab/MapObjects/MapNearbyUnits.cs index 4fa75846c..f9d1cc8a3 100644 --- a/STROOP/Tabs/MapTab/MapObjects/MapNearbyUnits.cs +++ b/STROOP/Tabs/MapTab/MapObjects/MapNearbyUnits.cs @@ -6,6 +6,7 @@ using OpenTK; using System.Collections.Generic; using OpenTK.Mathematics; +using STROOP.Core.Utilities; namespace STROOP.Tabs.MapTab.MapObjects { @@ -202,8 +203,8 @@ protected override void DrawTopDown(MapGraphics graphics) { graphics.drawLayers[(int)MapGraphics.DrawLayers.FillBuffers].Add(() => { - var color = ColorUtilities.ColorToVec4(Color, OpacityByte); - var outlineColor = ColorUtilities.ColorToVec4(OutlineColor); + var color = OpenTKUtilities.ColorToVec4(Color, OpacityByte); + var outlineColor = OpenTKUtilities.ColorToVec4(OutlineColor); foreach (var obj in positionAngleProvider()) { var dat = GetRenderValues(graphics, obj); @@ -218,8 +219,8 @@ protected override void Draw3D(MapGraphics graphics) { graphics.drawLayers[(int)MapGraphics.DrawLayers.FillBuffers].Add(() => { - var color = ColorUtilities.ColorToVec4(Color, OpacityByte); - var outlineColor = ColorUtilities.ColorToVec4(OutlineColor); + var color = OpenTKUtilities.ColorToVec4(Color, OpacityByte); + var outlineColor = OpenTKUtilities.ColorToVec4(OutlineColor); foreach (var obj in positionAngleProvider()) { var dat = GetRenderValues(graphics, obj); diff --git a/STROOP/Tabs/MapTab/MapObjects/MapNextPositionsObject.cs b/STROOP/Tabs/MapTab/MapObjects/MapNextPositionsObject.cs index b11b82a8d..182098627 100644 --- a/STROOP/Tabs/MapTab/MapObjects/MapNextPositionsObject.cs +++ b/STROOP/Tabs/MapTab/MapObjects/MapNextPositionsObject.cs @@ -8,6 +8,8 @@ using System.Windows.Forms; using OpenTK; using OpenTK.Mathematics; +using STROOP.Variables.SM64MemoryLayout; +using STROOP.Variables.Utilities; namespace STROOP.Tabs.MapTab.MapObjects { diff --git a/STROOP/Tabs/MapTab/MapObjects/MapObject.cs b/STROOP/Tabs/MapTab/MapObjects/MapObject.cs index a0d649125..a3b23efd5 100644 --- a/STROOP/Tabs/MapTab/MapObjects/MapObject.cs +++ b/STROOP/Tabs/MapTab/MapObjects/MapObject.cs @@ -8,6 +8,8 @@ using OpenTK.Graphics; using System.Globalization; using OpenTK.Mathematics; +using STROOP.Core; +using STROOP.Variables.Utilities; namespace STROOP.Tabs.MapTab.MapObjects { diff --git a/STROOP/Tabs/MapTab/MapObjects/MapObjectCylinderObject.cs b/STROOP/Tabs/MapTab/MapObjects/MapObjectCylinderObject.cs index 27d741d99..1e9ffecc6 100644 --- a/STROOP/Tabs/MapTab/MapObjects/MapObjectCylinderObject.cs +++ b/STROOP/Tabs/MapTab/MapObjects/MapObjectCylinderObject.cs @@ -4,6 +4,7 @@ using STROOP.Utilities; using STROOP.Structs.Configurations; using STROOP.Structs; +using STROOP.Variables.SM64MemoryLayout; namespace STROOP.Tabs.MapTab.MapObjects { diff --git a/STROOP/Tabs/MapTab/MapObjects/MapObjectObject.cs b/STROOP/Tabs/MapTab/MapObjects/MapObjectObject.cs index f4fea3795..94d1dc38e 100644 --- a/STROOP/Tabs/MapTab/MapObjects/MapObjectObject.cs +++ b/STROOP/Tabs/MapTab/MapObjects/MapObjectObject.cs @@ -1,4 +1,5 @@ -using System; +using STROOP.Core.Utilities; +using System; using System.Drawing; using STROOP.Utilities; using STROOP.Structs.Configurations; diff --git a/STROOP/Tabs/MapTab/MapObjects/MapPathObject.cs b/STROOP/Tabs/MapTab/MapObjects/MapPathObject.cs index fbe6eccc7..b04e124c2 100644 --- a/STROOP/Tabs/MapTab/MapObjects/MapPathObject.cs +++ b/STROOP/Tabs/MapTab/MapObjects/MapPathObject.cs @@ -8,6 +8,7 @@ using OpenTK; using System.Windows.Forms; using OpenTK.Mathematics; +using STROOP.Variables.Utilities; namespace STROOP.Tabs.MapTab.MapObjects { @@ -80,7 +81,7 @@ protected override void DrawTopDown(MapGraphics graphics) int counter = 0; foreach (var vertex in vertices) { - Vector4 color = ColorUtilities.ColorToVec4(useBlending ? ColorUtilities.InterpolateColor(OutlineColor, Color, (double)counter / (vertices.Count - 1)) : Color, OpacityByte); + Vector4 color = OpenTKUtilities.ColorToVec4(useBlending ? ColorUtilities.InterpolateColor(OutlineColor, Color, (double)counter / (vertices.Count - 1)) : Color, OpacityByte); if (counter > 0) graphics.lineRenderer.Add(vertex, lastVertex, color, OutlineWidth); counter++; diff --git a/STROOP/Tabs/MapTab/MapObjects/MapPreviousPositionsObject.cs b/STROOP/Tabs/MapTab/MapObjects/MapPreviousPositionsObject.cs index 4a24c5085..e4c61f4d2 100644 --- a/STROOP/Tabs/MapTab/MapObjects/MapPreviousPositionsObject.cs +++ b/STROOP/Tabs/MapTab/MapObjects/MapPreviousPositionsObject.cs @@ -6,6 +6,9 @@ using STROOP.Structs; using System.Windows.Forms; using OpenTK.Mathematics; +using STROOP.Core; +using STROOP.Variables.SM64MemoryLayout; +using STROOP.Variables.Utilities; namespace STROOP.Tabs.MapTab.MapObjects { @@ -79,7 +82,7 @@ protected override void DrawTopDown(MapGraphics graphics) if (OutlineWidth != 0) { - var color = ColorUtilities.ColorToVec4(OutlineColor, OpacityByte); + var color = OpenTKUtilities.ColorToVec4(OutlineColor, OpacityByte); for (int i = 0; i < data.Count - 1; i++) graphics.lineRenderer.Add( new Vector3(data[i].x, data[i].y, data[i].z), diff --git a/STROOP/Tabs/MapTab/MapObjects/MapPuGridlinesObject.cs b/STROOP/Tabs/MapTab/MapObjects/MapPuGridlinesObject.cs index 9ec394234..df28b3d27 100644 --- a/STROOP/Tabs/MapTab/MapObjects/MapPuGridlinesObject.cs +++ b/STROOP/Tabs/MapTab/MapObjects/MapPuGridlinesObject.cs @@ -7,6 +7,7 @@ using STROOP.Structs; using System.Windows.Forms; using OpenTK.Mathematics; +using STROOP.Variables.SM64MemoryLayout; namespace STROOP.Tabs.MapTab.MapObjects { diff --git a/STROOP/Tabs/MapTab/MapObjects/MapQuadObject.cs b/STROOP/Tabs/MapTab/MapObjects/MapQuadObject.cs index d8b668d2f..85dd661a3 100644 --- a/STROOP/Tabs/MapTab/MapObjects/MapQuadObject.cs +++ b/STROOP/Tabs/MapTab/MapObjects/MapQuadObject.cs @@ -15,8 +15,8 @@ protected override void DrawTopDown(MapGraphics graphics) { graphics.drawLayers[(int)MapGraphics.DrawLayers.FillBuffers].Add(() => { - var color = Utilities.ColorUtilities.ColorToVec4(Color, OpacityByte); - var outlineColor = Utilities.ColorUtilities.ColorToVec4(OutlineColor); + var color = Utilities.OpenTKUtilities.ColorToVec4(Color, OpacityByte); + var outlineColor = Utilities.OpenTKUtilities.ColorToVec4(OutlineColor); foreach (var quad in GetQuadList()) { diff --git a/STROOP/Tabs/MapTab/MapObjects/MapSectorObject.cs b/STROOP/Tabs/MapTab/MapObjects/MapSectorObject.cs index 4fa467faf..fdbe86ef8 100644 --- a/STROOP/Tabs/MapTab/MapObjects/MapSectorObject.cs +++ b/STROOP/Tabs/MapTab/MapObjects/MapSectorObject.cs @@ -6,6 +6,7 @@ using OpenTK; using System.Windows.Forms; using OpenTK.Mathematics; +using STROOP.Variables.Utilities; namespace STROOP.Tabs.MapTab.MapObjects { @@ -38,13 +39,13 @@ protected override void DrawTopDown(MapGraphics graphics) graphics.lineRenderer.Add( new Vector3(centerX, 0, centerZ), new Vector3(centerX + (float)Math.Sin(pfft) * radius, 0, centerZ + (float)Math.Cos(pfft) * radius), - ColorUtilities.ColorToVec4(OutlineColor), + OpenTKUtilities.ColorToVec4(OutlineColor), OutlineWidth); graphics.lineRenderer.Add( new Vector3(centerX, 0, centerZ), new Vector3(centerX + (float)Math.Sin(pfft2) * radius, 0, centerZ + (float)Math.Cos(pfft2) * radius), - ColorUtilities.ColorToVec4(OutlineColor), + OpenTKUtilities.ColorToVec4(OutlineColor), OutlineWidth); } }); diff --git a/STROOP/Tabs/MapTab/MapObjects/MapSphereObject.cs b/STROOP/Tabs/MapTab/MapObjects/MapSphereObject.cs index 65d4981ed..272bc461e 100644 --- a/STROOP/Tabs/MapTab/MapObjects/MapSphereObject.cs +++ b/STROOP/Tabs/MapTab/MapObjects/MapSphereObject.cs @@ -4,6 +4,7 @@ using STROOP.Structs; using OpenTK; using OpenTK.Mathematics; +using STROOP.Variables.SM64MemoryLayout; namespace STROOP.Tabs.MapTab.MapObjects { diff --git a/STROOP/Tabs/MapTab/MapObjects/MapTapeMeasureObject.cs b/STROOP/Tabs/MapTab/MapObjects/MapTapeMeasureObject.cs index 44165b3bf..1c54a087a 100644 --- a/STROOP/Tabs/MapTab/MapObjects/MapTapeMeasureObject.cs +++ b/STROOP/Tabs/MapTab/MapObjects/MapTapeMeasureObject.cs @@ -191,7 +191,7 @@ protected override void Draw3D(MapGraphics graphics) } var lineColor = colors[colorIndex - 1]; - graphics.lineRenderer.Add(p1, p2, ColorUtilities.ColorToVec4(lineColor), OutlineWidth); + graphics.lineRenderer.Add(p1, p2, OpenTKUtilities.ColorToVec4(lineColor), OutlineWidth); graphics.textRenderer.AddText($"{nameString}: {(p1 - p2).Length}", (p1 + p2) * 0.5f, lineColor, StringAlignment.Far); } }); diff --git a/STROOP/Tabs/MapTab/MapObjects/MapTriangleObject.cs b/STROOP/Tabs/MapTab/MapObjects/MapTriangleObject.cs index 74848e9f9..6796bcc48 100644 --- a/STROOP/Tabs/MapTab/MapObjects/MapTriangleObject.cs +++ b/STROOP/Tabs/MapTab/MapObjects/MapTriangleObject.cs @@ -7,6 +7,8 @@ using STROOP.Models; using System.Windows.Forms; using OpenTK.Mathematics; +using STROOP.Variables.SM64MemoryLayout; +using STROOP.Variables.Utilities; namespace STROOP.Tabs.MapTab.MapObjects { @@ -73,7 +75,7 @@ public void AddContextMenuItems(MapTab tab, ContextMenuStrip menu) { var dlg = new ColorDialog(); if (dlg.ShowDialog() == DialogResult.OK) - parent.individualTriangleColors[triangle.Address] = ColorUtilities.ColorToVec4(dlg.Color); + parent.individualTriangleColors[triangle.Address] = OpenTKUtilities.ColorToVec4(dlg.Color); }; myItem.DropDownItems.Add(itemAssignColor); @@ -257,7 +259,7 @@ protected override void Draw3D(MapGraphics graphics) Vector4 baseColor; if (!individualTriangleColors.TryGetValue(tri.Address, out baseColor)) if (useRandomColors) - baseColor = ColorUtilities.GetRandomColor((int)tri.Address); + baseColor = OpenTKUtilities.GetRandomColor((int)tri.Address); else baseColor = regularBaseColor; baseColor.W = OpacityByte / 255f; diff --git a/STROOP/Tabs/MapTab/MapObjects/MapWallObject.cs b/STROOP/Tabs/MapTab/MapObjects/MapWallObject.cs index 624b474ef..a7415ec4d 100644 --- a/STROOP/Tabs/MapTab/MapObjects/MapWallObject.cs +++ b/STROOP/Tabs/MapTab/MapObjects/MapWallObject.cs @@ -8,6 +8,8 @@ using System.Windows.Forms; using OpenTK.Mathematics; using STROOP.Models; +using STROOP.Variables.SM64MemoryLayout; +using STROOP.Variables.Utilities; namespace STROOP.Tabs.MapTab.MapObjects { @@ -124,11 +126,11 @@ protected override void Draw3D(MapGraphics graphics) Vector4 baseColor; if (!individualTriangleColors.TryGetValue(tri.Address, out baseColor)) if (useRandomColors) - baseColor = ColorUtilities.GetRandomColor((int)tri.Address); + baseColor = OpenTKUtilities.GetRandomColor((int)tri.Address); else baseColor = regularBaseColor; - double uphillAngle = WatchVariableSpecialUtilities.GetTriangleUphillAngle(tri); + double uphillAngle = VariableSpecialUtilities.GetTriangleUphillAngle(tri); double pushAngle = MoreMath.ReverseAngle(uphillAngle); float d = Size / (tri.XProjection ? tri.NormX : tri.NormZ); @@ -168,8 +170,8 @@ protected override void DrawTopDown(MapGraphics graphics) graphics.drawLayers[(int)MapGraphics.DrawLayers.FillBuffers].Add(() => { - Vector4 color = ColorUtilities.ColorToVec4(Color, OpacityByte), - outlineColor = ColorUtilities.ColorToVec4(OutlineColor); + Vector4 color = OpenTKUtilities.ColorToVec4(Color, OpacityByte), + outlineColor = OpenTKUtilities.ColorToVec4(OutlineColor); foreach ((float x1, float z1, float x2, float z2, bool xProjection, double pushAngle) in topDownWallData) { float angle = (float)MoreMath.AngleTo_Radians(x1, z1, x2, z2); diff --git a/STROOP/Tabs/MapTab/MapPopout.cs b/STROOP/Tabs/MapTab/MapPopout.cs index de39a0191..b9e3d94c6 100644 --- a/STROOP/Tabs/MapTab/MapPopout.cs +++ b/STROOP/Tabs/MapTab/MapPopout.cs @@ -2,6 +2,7 @@ using System; using System.Windows.Forms; using OpenTK.GLControl; +using STROOP.Core; using STROOP.Utilities; namespace STROOP.Tabs.MapTab diff --git a/STROOP/Tabs/MapTab/MapTab.cs b/STROOP/Tabs/MapTab/MapTab.cs index ba0c0493c..10dd5b85a 100644 --- a/STROOP/Tabs/MapTab/MapTab.cs +++ b/STROOP/Tabs/MapTab/MapTab.cs @@ -13,6 +13,10 @@ using System.Xml.Linq; using OpenTK.GLControl; using OpenTK.Mathematics; +using STROOP.Core; +using STROOP.Core.Utilities; +using STROOP.Variables.SM64MemoryLayout; +using STROOP.Variables.Utilities; namespace STROOP.Tabs.MapTab { @@ -26,6 +30,8 @@ public partial class MapTab : STROOPTab, IDisposable static XElement configNode; static string lastTrackerFileName = null; + static Type[] stroopTypes; + [InitializeConfigParser] static void InitConfigParser() { @@ -44,6 +50,18 @@ static void SaveConfig() configNode.Document.Save(Program.CONFIG_FILE_NAME); } + static MapTab() + { + stroopTypes = typeof(MapTab).Assembly.GetTypes(); + } + + static IEnumerable EnumerateTypes(Func filter) + { + foreach (var t in stroopTypes) + if (filter(t)) + yield return t; + } + public GLControl glControlMap2D { get; private set; } public MapGraphics graphics { get; private set; } public List popouts = new List(); @@ -191,7 +209,7 @@ public BackgroundImage GetBackgroundImage(object backgroundChoice = null) void InitAddTrackerButton() { var adders = new Dictionary)>>(); - foreach (var type in GeneralUtilities.EnumerateTypes(_ => _.IsSubclassOf(typeof(MapObject)))) + foreach (var type in EnumerateTypes(_ => _.IsSubclassOf(typeof(MapObject)))) { var attrArray = type.GetCustomAttributes(); foreach (var attr in attrArray) @@ -654,7 +672,7 @@ public void UpdateHover() using (new AccessScope(this)) { if (Form.ActiveForm != null && glControlMap2D.ClientRectangle.Contains(glControlMap2D.PointToClient(Cursor.Position))) - graphics.UpdateFlyingControls(Config.Stream.lastFrameTime); + graphics.UpdateFlyingControls(Config.CoreLoop.lastFrameTime); if (!graphics.IsMouseDown(0)) { var newCursor = graphics.mapCursorPosition; diff --git a/STROOP/Tabs/MapTab/MapTracker.cs b/STROOP/Tabs/MapTab/MapTracker.cs index 69a5bc11a..cf8ebcf34 100644 --- a/STROOP/Tabs/MapTab/MapTracker.cs +++ b/STROOP/Tabs/MapTab/MapTracker.cs @@ -1,10 +1,12 @@ -using System; +using STROOP.Core; +using System; using System.Collections.Generic; using System.Drawing; using System.Windows.Forms; using STROOP.Structs; using STROOP.Utilities; using STROOP.Tabs.MapTab.MapObjects; +using STROOP.Variables.Utilities; namespace STROOP.Tabs.MapTab { diff --git a/STROOP/Tabs/MapTab/MapUtilities.cs b/STROOP/Tabs/MapTab/MapUtilities.cs index 604a6f065..04f90fc78 100644 --- a/STROOP/Tabs/MapTab/MapUtilities.cs +++ b/STROOP/Tabs/MapTab/MapUtilities.cs @@ -2,9 +2,11 @@ using System.Collections.Generic; using System.Linq; using OpenTK.Graphics.OpenGL; +using STROOP.Core; using STROOP.Utilities; using STROOP.Structs; using STROOP.Models; +using STROOP.Variables.Utilities; using System.Windows.Forms; namespace STROOP.Tabs.MapTab @@ -38,7 +40,7 @@ public static List GetTriangles(List triAddresses) public static (float x1, float z1, float x2, float z2, bool xProjection, double pushAngle)? Get2DWallDataFromTri( TriangleDataModel tri, float? heightNullable = null) { - double uphillAngle = WatchVariableSpecialUtilities.GetTriangleUphillAngle(tri); + double uphillAngle = VariableSpecialUtilities.GetTriangleUphillAngle(tri); double pushAngle = MoreMath.ReverseAngle(uphillAngle); if (!heightNullable.HasValue) diff --git a/STROOP/Tabs/MapTab/Renderers/CircleRenderer.cs b/STROOP/Tabs/MapTab/Renderers/CircleRenderer.cs index d0aacc033..4054fa76b 100644 --- a/STROOP/Tabs/MapTab/Renderers/CircleRenderer.cs +++ b/STROOP/Tabs/MapTab/Renderers/CircleRenderer.cs @@ -1,6 +1,7 @@ using OpenTK; using OpenTK.Graphics.OpenGL; using OpenTK.Mathematics; +using STROOP.Core; using STROOP.Utilities; namespace STROOP.Tabs.MapTab.Renderers diff --git a/STROOP/Tabs/MapTab/Renderers/GeometryRenderer.cs b/STROOP/Tabs/MapTab/Renderers/GeometryRenderer.cs index 4d8ce7a01..415bf7477 100644 --- a/STROOP/Tabs/MapTab/Renderers/GeometryRenderer.cs +++ b/STROOP/Tabs/MapTab/Renderers/GeometryRenderer.cs @@ -2,6 +2,7 @@ using OpenTK; using OpenTK.Graphics.OpenGL; using OpenTK.Mathematics; +using STROOP.Core; using STROOP.Utilities; namespace STROOP.Tabs.MapTab.Renderers diff --git a/STROOP/Tabs/MapTab/Renderers/InstanceRenderer.cs b/STROOP/Tabs/MapTab/Renderers/InstanceRenderer.cs index beb0e2449..cea003722 100644 --- a/STROOP/Tabs/MapTab/Renderers/InstanceRenderer.cs +++ b/STROOP/Tabs/MapTab/Renderers/InstanceRenderer.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Runtime.InteropServices; using OpenTK.Mathematics; +using STROOP.Core; using STROOP.Utilities; namespace STROOP.Tabs.MapTab.Renderers diff --git a/STROOP/Tabs/MapTab/Renderers/LineRenderer.cs b/STROOP/Tabs/MapTab/Renderers/LineRenderer.cs index 5589a944d..8bd1348dc 100644 --- a/STROOP/Tabs/MapTab/Renderers/LineRenderer.cs +++ b/STROOP/Tabs/MapTab/Renderers/LineRenderer.cs @@ -1,6 +1,7 @@ using OpenTK; using OpenTK.Graphics.OpenGL; using OpenTK.Mathematics; +using STROOP.Core; using STROOP.Utilities; namespace STROOP.Tabs.MapTab.Renderers diff --git a/STROOP/Tabs/MapTab/Renderers/RendererCollection.cs b/STROOP/Tabs/MapTab/Renderers/RendererCollection.cs index 9eed2d397..101c4e954 100644 --- a/STROOP/Tabs/MapTab/Renderers/RendererCollection.cs +++ b/STROOP/Tabs/MapTab/Renderers/RendererCollection.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using OpenTK.Graphics.OpenGL; +using STROOP.Core; using System.Drawing; using STROOP.Utilities; diff --git a/STROOP/Tabs/MapTab/Renderers/SpriteRenderer.cs b/STROOP/Tabs/MapTab/Renderers/SpriteRenderer.cs index 3117cc22b..6aaca46fb 100644 --- a/STROOP/Tabs/MapTab/Renderers/SpriteRenderer.cs +++ b/STROOP/Tabs/MapTab/Renderers/SpriteRenderer.cs @@ -1,6 +1,7 @@ using OpenTK.Graphics.OpenGL; using OpenTK; using OpenTK.Mathematics; +using STROOP.Core; using STROOP.Utilities; namespace STROOP.Tabs.MapTab.Renderers diff --git a/STROOP/Tabs/MapTab/Renderers/TextRenderer.cs b/STROOP/Tabs/MapTab/Renderers/TextRenderer.cs index 853e8cd7e..b278fd38e 100644 --- a/STROOP/Tabs/MapTab/Renderers/TextRenderer.cs +++ b/STROOP/Tabs/MapTab/Renderers/TextRenderer.cs @@ -8,6 +8,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using OpenTK.Mathematics; +using STROOP.Core; using Imaging = System.Drawing.Imaging; namespace STROOP.Tabs.MapTab.Renderers diff --git a/STROOP/Tabs/MapTab/Renderers/TransparencyRenderer.cs b/STROOP/Tabs/MapTab/Renderers/TransparencyRenderer.cs index 7ebe40802..fc17cb56c 100644 --- a/STROOP/Tabs/MapTab/Renderers/TransparencyRenderer.cs +++ b/STROOP/Tabs/MapTab/Renderers/TransparencyRenderer.cs @@ -3,6 +3,7 @@ using OpenTK; using System.Collections.Generic; using OpenTK.Mathematics; +using STROOP.Core; using STROOP.Utilities; namespace STROOP.Tabs.MapTab.Renderers diff --git a/STROOP/Tabs/MapTab/Renderers/TriangleRenderer.cs b/STROOP/Tabs/MapTab/Renderers/TriangleRenderer.cs index 8de97ad29..91f9ce636 100644 --- a/STROOP/Tabs/MapTab/Renderers/TriangleRenderer.cs +++ b/STROOP/Tabs/MapTab/Renderers/TriangleRenderer.cs @@ -4,6 +4,7 @@ using System.Runtime.InteropServices; using System.Collections.Generic; using OpenTK.Mathematics; +using STROOP.Core; using STROOP.Utilities; namespace STROOP.Tabs.MapTab.Renderers diff --git a/STROOP/Tabs/MarioTab.Designer.cs b/STROOP/Tabs/MarioTab.Designer.cs index 791f0706e..9c8ebf0ab 100644 --- a/STROOP/Tabs/MarioTab.Designer.cs +++ b/STROOP/Tabs/MarioTab.Designer.cs @@ -87,7 +87,7 @@ private void InitializeComponent() this.buttonMarioHOLPGoto = new System.Windows.Forms.Button(); this.buttonMarioToggleHandsfree = new System.Windows.Forms.Button(); this.buttonMarioHOLPRetrieve = new System.Windows.Forms.Button(); - this.watchVariablePanelMario = new STROOP.Controls.VariablePanel.WatchVariablePanel(); + this._variablePanelMario = new STROOP.Controls.VariablePanel.VariablePanel(); ((System.ComponentModel.ISupportInitialize)(this.splitContainerMario)).BeginInit(); this.splitContainerMario.Panel1.SuspendLayout(); this.splitContainerMario.Panel2.SuspendLayout(); @@ -127,7 +127,7 @@ private void InitializeComponent() // // splitContainerMario.Panel2 // - this.splitContainerMario.Panel2.Controls.Add(this.watchVariablePanelMario); + this.splitContainerMario.Panel2.Controls.Add(this._variablePanelMario); this.splitContainerMario.Panel2.Padding = new System.Windows.Forms.Padding(2); this.splitContainerMario.Panel2MinSize = 0; this.splitContainerMario.Size = new System.Drawing.Size(915, 463); @@ -766,15 +766,15 @@ private void InitializeComponent() // // watchVariablePanelMario // - this.watchVariablePanelMario.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + this._variablePanelMario.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.watchVariablePanelMario.DataPath = "Config/MarioData.xml"; - this.watchVariablePanelMario.Location = new System.Drawing.Point(2, 2); - this.watchVariablePanelMario.Margin = new System.Windows.Forms.Padding(0); - this.watchVariablePanelMario.Name = "watchVariablePanelMario"; - this.watchVariablePanelMario.Size = new System.Drawing.Size(703, 457); - this.watchVariablePanelMario.TabIndex = 1; + this._variablePanelMario.DataPath = "Config/MarioData.xml"; + this._variablePanelMario.Location = new System.Drawing.Point(2, 2); + this._variablePanelMario.Margin = new System.Windows.Forms.Padding(0); + this._variablePanelMario.Name = "_variablePanelMario"; + this._variablePanelMario.Size = new System.Drawing.Size(703, 457); + this._variablePanelMario.TabIndex = 1; // // MarioTab // @@ -861,6 +861,6 @@ private void InitializeComponent() private System.Windows.Forms.Button buttonMarioHOLPGoto; private System.Windows.Forms.Button buttonMarioToggleHandsfree; private System.Windows.Forms.Button buttonMarioHOLPRetrieve; - private STROOP.Controls.VariablePanel.WatchVariablePanel watchVariablePanelMario; + private STROOP.Controls.VariablePanel.VariablePanel _variablePanelMario; } } diff --git a/STROOP/Tabs/MarioTab.cs b/STROOP/Tabs/MarioTab.cs index 552aa4c4f..8ee068ac7 100644 --- a/STROOP/Tabs/MarioTab.cs +++ b/STROOP/Tabs/MarioTab.cs @@ -1,9 +1,13 @@ -using System; +using STROOP.Core; +using System; using System.Collections.Generic; using STROOP.Structs; using System.Windows.Forms; using STROOP.Utilities; using STROOP.Structs.Configurations; +using STROOP.Variables; +using STROOP.Variables.SM64MemoryLayout; +using STROOP.Variables.Utilities; namespace STROOP.Tabs { @@ -12,20 +16,26 @@ public partial class MarioTab : STROOPTab [InitializeBaseAddress] static void InitBaseAddresses() { - WatchVariableUtilities.baseAddressGetters["Floor"] = () => + VariableUtilities.baseAddressGetters[BaseAddressType.Mario] = () => new List { MarioConfig.StructAddress }; + VariableUtilities.baseAddressGetters[BaseAddressType.MarioObj] = () => new List + { + ProcessStream.Instance.GetUInt32(MarioObjectConfig.PointerAddress) + }; + + VariableUtilities.baseAddressGetters["Floor"] = () => { uint floorAddress = Config.Stream.GetUInt32(MarioConfig.StructAddress + MarioConfig.FloorTriangleOffset); - return floorAddress != 0 ? new List() { floorAddress } : WatchVariableUtilities.BaseAddressListEmpty; + return floorAddress != 0 ? new List() { floorAddress } : VariableUtilities.BaseAddressListEmpty; }; - WatchVariableUtilities.baseAddressGetters["Wall"] = () => + VariableUtilities.baseAddressGetters["Wall"] = () => { uint wallAddress = Config.Stream.GetUInt32(MarioConfig.StructAddress + MarioConfig.WallTriangleOffset); - return wallAddress != 0 ? new List() { wallAddress } : WatchVariableUtilities.BaseAddressListEmpty; + return wallAddress != 0 ? new List() { wallAddress } : VariableUtilities.BaseAddressListEmpty; }; - WatchVariableUtilities.baseAddressGetters["Ceiling"] = () => + VariableUtilities.baseAddressGetters["Ceiling"] = () => { uint ceilingAddress = Config.Stream.GetUInt32(MarioConfig.StructAddress + MarioConfig.CeilingTriangleOffset); - return ceilingAddress != 0 ? new List() { ceilingAddress } : WatchVariableUtilities.BaseAddressListEmpty; + return ceilingAddress != 0 ? new List() { ceilingAddress } : VariableUtilities.BaseAddressListEmpty; }; } @@ -53,7 +63,7 @@ static void InitBaseAddresses() public MarioTab() { InitializeComponent(); - watchVariablePanelMario.SetGroups(ALL_VAR_GROUPS, VISIBLE_VAR_GROUPS); + _variablePanelMario.SetGroups(ALL_VAR_GROUPS, VISIBLE_VAR_GROUPS); } public override string GetDisplayName() => "Mario"; @@ -66,7 +76,7 @@ public override void InitializeTab() panelMarioBorder.BackColor = Config.ObjectAssociations.MarioColor; pictureBoxMario.BackColor = Config.ObjectAssociations.MarioColor.Lighten(0.5); - watchVariablePanelMario.SetGroups(ALL_VAR_GROUPS, VISIBLE_VAR_GROUPS); + _variablePanelMario.SetGroups(ALL_VAR_GROUPS, VISIBLE_VAR_GROUPS); buttonMarioToggleHandsfree.Click += (sender, e) => ButtonUtilities.ToggleHandsfree(); diff --git a/STROOP/Tabs/MemoryTab.Designer.cs b/STROOP/Tabs/MemoryTab.Designer.cs index 148d17f8f..4cfe952d6 100644 --- a/STROOP/Tabs/MemoryTab.Designer.cs +++ b/STROOP/Tabs/MemoryTab.Designer.cs @@ -53,7 +53,7 @@ private void InitializeComponent() this.splitContainerMemoryControlsDisplays = new STROOP.BetterSplitContainer(); this.richTextBoxMemoryAddresses = new STROOP.Controls.RichTextBoxEx(); this.richTextBoxMemoryValues = new STROOP.Controls.RichTextBoxEx(); - this.watchVariablePanelMemory = new STROOP.Controls.VariablePanel.WatchVariablePanel(); + this._variablePanelMemory = new STROOP.Controls.VariablePanel.VariablePanel(); ((System.ComponentModel.ISupportInitialize)(this.splitContainerMemory)).BeginInit(); this.splitContainerMemory.Panel1.SuspendLayout(); this.splitContainerMemory.Panel2.SuspendLayout(); @@ -87,7 +87,7 @@ private void InitializeComponent() // // splitContainerMemory.Panel2 // - this.splitContainerMemory.Panel2.Controls.Add(this.watchVariablePanelMemory); + this.splitContainerMemory.Panel2.Controls.Add(this._variablePanelMemory); this.splitContainerMemory.Panel2.Padding = new System.Windows.Forms.Padding(2); this.splitContainerMemory.Panel2MinSize = 0; this.splitContainerMemory.Size = new System.Drawing.Size(915, 463); @@ -384,15 +384,15 @@ private void InitializeComponent() // // watchVariablePanelMemory // - this.watchVariablePanelMemory.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + this._variablePanelMemory.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.watchVariablePanelMemory.DataPath = "Config/ObjectData.xml"; - this.watchVariablePanelMemory.Location = new System.Drawing.Point(2, 2); - this.watchVariablePanelMemory.Margin = new System.Windows.Forms.Padding(0); - this.watchVariablePanelMemory.Name = "watchVariablePanelMemory"; - this.watchVariablePanelMemory.Size = new System.Drawing.Size(168, 457); - this.watchVariablePanelMemory.TabIndex = 7; + this._variablePanelMemory.DataPath = "Config/ObjectData.xml"; + this._variablePanelMemory.Location = new System.Drawing.Point(2, 2); + this._variablePanelMemory.Margin = new System.Windows.Forms.Padding(0); + this._variablePanelMemory.Name = "_variablePanelMemory"; + this._variablePanelMemory.Size = new System.Drawing.Size(168, 457); + this._variablePanelMemory.TabIndex = 7; // // MemoryTab // @@ -442,6 +442,6 @@ private void InitializeComponent() private BetterSplitContainer splitContainerMemoryControlsDisplays; private Controls.RichTextBoxEx richTextBoxMemoryAddresses; private Controls.RichTextBoxEx richTextBoxMemoryValues; - private STROOP.Controls.VariablePanel.WatchVariablePanel watchVariablePanelMemory; + private STROOP.Controls.VariablePanel.VariablePanel _variablePanelMemory; } } diff --git a/STROOP/Tabs/MemoryTab.cs b/STROOP/Tabs/MemoryTab.cs index bf6953033..de5c20930 100644 --- a/STROOP/Tabs/MemoryTab.cs +++ b/STROOP/Tabs/MemoryTab.cs @@ -1,4 +1,6 @@ -using STROOP.Models; +using STROOP.Core; +using STROOP.Core.Utilities; +using STROOP.Models; using STROOP.Structs; using STROOP.Structs.Configurations; using STROOP.Utilities; @@ -8,8 +10,10 @@ using System.Linq; using System.Text; using System.Windows.Forms; -using System.Windows.Input; -using STROOP.Core.Variables; +using STROOP.Variables; +using STROOP.Variables.SM64MemoryLayout; +using STROOP.Variables.Utilities; +using STROOP.Variables.VariablePanel; namespace STROOP.Tabs { @@ -18,7 +22,7 @@ public partial class MemoryTab : STROOPTab private readonly List _currentValueTexts; private readonly List _objectPrecursors; private readonly List _objectSpecificPrecursors; - private List _memTabPrecursors => watchVariablePanelMemory.GetCurrentVariablePrecursors().ToList(); + private List _memTabPrecursors => _variablePanelMemory.GetCurrentVariableMemoryDescriptors().ToList(); private uint? _address; @@ -56,8 +60,8 @@ private BehaviorCriteria? Behavior _objectSpecificPrecursors.Clear(); if (_behavior.HasValue) _objectSpecificPrecursors.AddRange( - Config.ObjectAssociations.GetWatchVarControls(_behavior.Value) - .ConvertAndRemoveNull(x => (x as NamedVariableCollection.IMemoryDescriptorView)?.memoryDescriptor) + Config.ObjectAssociations.GetVariablePrecursors(_behavior.Value) + .ConvertAndRemoveNull(x => (x as IMemoryVariable)?.memoryDescriptor) ); } } @@ -77,8 +81,8 @@ public MemoryTab() _objectSnapshot = null; _currentValueTexts = new List(); - _objectPrecursors = XmlConfigParser.OpenWatchVariableControlPrecursors(watchVariablePanelMemory.DataPath) - .ConvertAndRemoveNull(x => (x as NamedVariableCollection.MemoryDescriptorView)?.memoryDescriptor); + _objectPrecursors = XmlConfigParser.OpenVariableControlPrecursors(_variablePanelMemory.DataPath) + .ConvertAndRemoveNull(x => (x as IMemoryVariable)?.memoryDescriptor); _objectSpecificPrecursors = new List(); } @@ -249,8 +253,10 @@ private void MemoryValueClick() { precursorLists.ForEach(precursors => { - foreach (var ctrl in watchVariablePanelMemory.AddVariables(valueText.GetOverlapped(precursors).Select(x => x.CreateView()))) - ctrl.GroupList.Add("Custom"); + var overlapped = valueText.GetOverlapped(precursors) + .Select(x => ($"{x.ClrType.Name}@0x{x.Offset : X8}", (IVariable)x.CreateVariable())); + foreach (var cell in _variablePanelMemory.AddVariables(overlapped)) + cell.control.GroupList.Add("Custom"); }); } }); @@ -260,7 +266,7 @@ private void MemoryValueClick() _currentValueTexts.ForEach(valueText => { if (index >= valueText.StringIndex && index <= valueText.StringIndex + valueText.StringSize) - watchVariablePanelMemory.AddVariable(valueText.CreatePrecursor(useObjAddress, useHex, useObj, useRelativeName)); + _variablePanelMemory.AddVariable(valueText.CreatePrecursor(useObjAddress, useHex, useObj, useRelativeName)); }); } @@ -326,19 +332,15 @@ public List GetOverlapped(List precursors) })); } - public NamedVariableCollection.IView CreatePrecursor(bool useObjAddress, bool useHex, bool useObj, bool useRelativeName) + public VariablePrecursor CreatePrecursor(bool useObjAddress, bool useHex, bool useObj, bool useRelativeName) { - WatchVariableSubclass subclass = useObj - ? WatchVariableSubclass.Object - : WatchVariableSubclass.Number; - if (GlobalKeyboard.IsDown(Keys.A)) subclass = WatchVariableSubclass.Angle; - if (GlobalKeyboard.IsDown(Keys.B)) subclass = WatchVariableSubclass.Boolean; - if (GlobalKeyboard.IsDown(Keys.Q)) subclass = WatchVariableSubclass.Object; - if (GlobalKeyboard.IsDown(Keys.T)) subclass = WatchVariableSubclass.Triangle; - - bool isObjectOrTriangle = - subclass == WatchVariableSubclass.Object || - subclass == WatchVariableSubclass.Triangle; + string subclass = useObj ? VariableSubclass.Object : VariableSubclass.Number; + if (GlobalKeyboard.IsDown(Keys.A)) subclass = VariableSubclass.Angle; + if (GlobalKeyboard.IsDown(Keys.B)) subclass = VariableSubclass.Boolean; + if (GlobalKeyboard.IsDown(Keys.Q)) subclass = VariableSubclass.Object; + if (GlobalKeyboard.IsDown(Keys.T)) subclass = VariableSubclass.Triangle; + + bool isObjectOrTriangle = subclass == VariableSubclass.Object || subclass == VariableSubclass.Triangle; Type effectiveType = isObjectOrTriangle ? typeof(uint) @@ -347,11 +349,11 @@ public NamedVariableCollection.IView CreatePrecursor(bool useObjAddress, bool us string baseAddressType = useObjAddress ? BaseAddressType.Object : BaseAddressType.Relative; uint offset = useObjAddress ? (uint)ByteIndex : MemoryAddress; uint nameOffset = useRelativeName ? (uint)ByteIndex : MemoryAddress; - bool isAbsolute = baseAddressType == BaseAddressType.Absolute; - var view = new MemoryDescriptor(effectiveType, baseAddressType, offset).CreateView(); - view.SetValueByKey(NamedVariableCollection.ViewProperties.useHex, true); - return view; + var view = new MemoryDescriptor(effectiveType, baseAddressType, offset).CreateVariable(); + view.SetValueByKey(CommonVariableProperties.useHex, true.ToString()); + var name = TypeUtilities.TypeToString.GetValueOrDefault(effectiveType, effectiveType.Name) + " " + HexUtilities.FormatValue(nameOffset); + return (name, view); } } diff --git a/STROOP/Tabs/MiscTab.Designer.cs b/STROOP/Tabs/MiscTab.Designer.cs index 9a51b3b5b..d584e1895 100644 --- a/STROOP/Tabs/MiscTab.Designer.cs +++ b/STROOP/Tabs/MiscTab.Designer.cs @@ -37,7 +37,7 @@ private void InitializeComponent() this.checkBoxTurnOffMusic = new System.Windows.Forms.CheckBox(); this.panelMiscBorder = new System.Windows.Forms.Panel(); this.pictureBoxMisc = new STROOP.Controls.IntPictureBox(); - this.watchVariablePanelMisc = new STROOP.Controls.VariablePanel.WatchVariablePanel(); + this._variablePanelMisc = new STROOP.Controls.VariablePanel.VariablePanel(); this.txtRNGIncrement = new STROOP.BetterTextbox(); this.labelRNGIncrement = new System.Windows.Forms.Label(); ((System.ComponentModel.ISupportInitialize)(this.splitContainerMisc)).BeginInit(); @@ -71,7 +71,7 @@ private void InitializeComponent() // // splitContainerMisc.Panel2 // - this.splitContainerMisc.Panel2.Controls.Add(this.watchVariablePanelMisc); + this.splitContainerMisc.Panel2.Controls.Add(this._variablePanelMisc); this.splitContainerMisc.Panel2.Padding = new System.Windows.Forms.Padding(2); this.splitContainerMisc.Panel2MinSize = 0; this.splitContainerMisc.Size = new System.Drawing.Size(915, 463); @@ -157,13 +157,13 @@ private void InitializeComponent() // // watchVariablePanelMisc // - this.watchVariablePanelMisc.DataPath = "Config/MiscData.xml"; - this.watchVariablePanelMisc.Dock = System.Windows.Forms.DockStyle.Fill; - this.watchVariablePanelMisc.Location = new System.Drawing.Point(2, 2); - this.watchVariablePanelMisc.Margin = new System.Windows.Forms.Padding(0); - this.watchVariablePanelMisc.Name = "watchVariablePanelMisc"; - this.watchVariablePanelMisc.Size = new System.Drawing.Size(778, 457); - this.watchVariablePanelMisc.TabIndex = 5; + this._variablePanelMisc.DataPath = "Config/MiscData.xml"; + this._variablePanelMisc.Dock = System.Windows.Forms.DockStyle.Fill; + this._variablePanelMisc.Location = new System.Drawing.Point(2, 2); + this._variablePanelMisc.Margin = new System.Windows.Forms.Padding(0); + this._variablePanelMisc.Name = "_variablePanelMisc"; + this._variablePanelMisc.Size = new System.Drawing.Size(778, 457); + this._variablePanelMisc.TabIndex = 5; // // txtRNGIncrement // @@ -213,7 +213,7 @@ private void InitializeComponent() private System.Windows.Forms.CheckBox checkBoxTurnOffMusic; private System.Windows.Forms.Panel panelMiscBorder; private Controls.IntPictureBox pictureBoxMisc; - private STROOP.Controls.VariablePanel.WatchVariablePanel watchVariablePanelMisc; + private STROOP.Controls.VariablePanel.VariablePanel _variablePanelMisc; private System.Windows.Forms.Label labelRNGIncrement; private BetterTextbox txtRNGIncrement; } diff --git a/STROOP/Tabs/MiscTab.cs b/STROOP/Tabs/MiscTab.cs index 0fca5a702..d8c48f561 100644 --- a/STROOP/Tabs/MiscTab.cs +++ b/STROOP/Tabs/MiscTab.cs @@ -3,6 +3,9 @@ using System.Windows.Forms; using STROOP.Utilities; using STROOP.Structs.Configurations; +using STROOP.Variables; +using STROOP.Variables.SM64MemoryLayout; +using STROOP.Variables.Utilities; using System.Linq; namespace STROOP.Tabs @@ -12,15 +15,15 @@ public partial class MiscTab : STROOPTab [InitializeBaseAddress] static void InitBaseAddresses() { - WatchVariableUtilities.baseAddressGetters["LastCoin"] = () => + VariableUtilities.baseAddressGetters["LastCoin"] = () => { List coinAddresses = Config.ObjectSlotsManager.GetLoadedObjectsWithPredicate( o => o.BehaviorAssociation?.Name == "Yellow Coin" || o.BehaviorAssociation?.Name == "Blue Coin") .ConvertAll(objectDataModel => objectDataModel.Address); - return coinAddresses.Count > 0 ? new List() { coinAddresses.Last() } : WatchVariableUtilities.BaseAddressListEmpty; + return coinAddresses.Count > 0 ? new List() { coinAddresses.Last() } : VariableUtilities.BaseAddressListEmpty; }; - WatchVariableUtilities.baseAddressGetters["WarpDestination"] = () => new List() { MiscConfig.WarpDestinationAddress }; + VariableUtilities.baseAddressGetters["WarpDestination"] = () => new List() { MiscConfig.WarpDestinationAddress }; } private static readonly List ALL_VAR_GROUPS = @@ -44,7 +47,7 @@ static void InitBaseAddresses() public MiscTab() { InitializeComponent(); - watchVariablePanelMisc.SetGroups(ALL_VAR_GROUPS, VISIBLE_VAR_GROUPS); + _variablePanelMisc.SetGroups(ALL_VAR_GROUPS, VISIBLE_VAR_GROUPS); if (Program.IsVisualStudioHostProcess()) return; } @@ -58,7 +61,7 @@ public override void InitializeTab() panelMiscBorder.BackColor = Config.ObjectAssociations.MiscColor; pictureBoxMisc.BackColor = Config.ObjectAssociations.MiscColor.Lighten(0.5); - watchVariablePanelMisc.SetGroups(ALL_VAR_GROUPS, VISIBLE_VAR_GROUPS); + _variablePanelMisc.SetGroups(ALL_VAR_GROUPS, VISIBLE_VAR_GROUPS); buttonRNGIndexTester.Click += (sender, e) => diff --git a/STROOP/Tabs/ModelTab.cs b/STROOP/Tabs/ModelTab.cs index 2a4e4a7ce..5aa0f28c3 100644 --- a/STROOP/Tabs/ModelTab.cs +++ b/STROOP/Tabs/ModelTab.cs @@ -8,6 +8,7 @@ using STROOP.Controls; using STROOP.Structs.Configurations; using STROOP.Models; +using STROOP.Variables.Utilities; namespace STROOP.Tabs { diff --git a/STROOP/Tabs/MusicTab.Designer.cs b/STROOP/Tabs/MusicTab.Designer.cs index 06dfbea95..84790d9d7 100644 --- a/STROOP/Tabs/MusicTab.Designer.cs +++ b/STROOP/Tabs/MusicTab.Designer.cs @@ -31,7 +31,7 @@ private void InitializeComponent() this.components = new System.ComponentModel.Container(); this.splitContainerMusic = new STROOP.BetterSplitContainer(); this.listBoxMusic = new System.Windows.Forms.ListBox(); - this.watchVariablePanelMusic = new STROOP.Controls.VariablePanel.WatchVariablePanel(); + this._variablePanelMusic = new STROOP.Controls.VariablePanel.VariablePanel(); ((System.ComponentModel.ISupportInitialize)(this.splitContainerMusic)).BeginInit(); this.splitContainerMusic.Panel1.SuspendLayout(); this.splitContainerMusic.Panel2.SuspendLayout(); @@ -57,7 +57,7 @@ private void InitializeComponent() // // splitContainerMusic.Panel2 // - this.splitContainerMusic.Panel2.Controls.Add(this.watchVariablePanelMusic); + this.splitContainerMusic.Panel2.Controls.Add(this._variablePanelMusic); this.splitContainerMusic.Panel2.Padding = new System.Windows.Forms.Padding(2); this.splitContainerMusic.Panel2MinSize = 0; this.splitContainerMusic.Size = new System.Drawing.Size(915, 463); @@ -76,12 +76,12 @@ private void InitializeComponent() // // watchVariablePanelMusic // - this.watchVariablePanelMusic.DataPath = "Config/MusicData2.xml"; - this.watchVariablePanelMusic.Location = new System.Drawing.Point(2, 2); - this.watchVariablePanelMusic.Margin = new System.Windows.Forms.Padding(0); - this.watchVariablePanelMusic.Name = "watchVariablePanelMusic"; - this.watchVariablePanelMusic.Size = new System.Drawing.Size(755, 457); - this.watchVariablePanelMusic.TabIndex = 7; + this._variablePanelMusic.DataPath = "Config/MusicData2.xml"; + this._variablePanelMusic.Location = new System.Drawing.Point(2, 2); + this._variablePanelMusic.Margin = new System.Windows.Forms.Padding(0); + this._variablePanelMusic.Name = "_variablePanelMusic"; + this._variablePanelMusic.Size = new System.Drawing.Size(755, 457); + this._variablePanelMusic.TabIndex = 7; // // MusicTab // @@ -102,6 +102,6 @@ private void InitializeComponent() private BetterSplitContainer splitContainerMusic; private System.Windows.Forms.ListBox listBoxMusic; - private STROOP.Controls.VariablePanel.WatchVariablePanel watchVariablePanelMusic; + private STROOP.Controls.VariablePanel.VariablePanel _variablePanelMusic; } } diff --git a/STROOP/Tabs/MusicTab.cs b/STROOP/Tabs/MusicTab.cs index e56956f84..d989b8c47 100644 --- a/STROOP/Tabs/MusicTab.cs +++ b/STROOP/Tabs/MusicTab.cs @@ -1,7 +1,10 @@ -using STROOP.Structs.Configurations; +using STROOP.Core; +using STROOP.Structs.Configurations; using STROOP.Utilities; using System.Collections.Generic; using STROOP.Structs; +using STROOP.Variables; +using STROOP.Variables.Utilities; namespace STROOP.Tabs { @@ -10,10 +13,10 @@ public partial class MusicTab : STROOPTab [InitializeBaseAddress] static void InitBaseAddresses() { - WatchVariableUtilities.baseAddressGetters["Music"] = () => + VariableUtilities.baseAddressGetters["Music"] = () => { uint? musicAddress = AccessScope.content.GetTab().GetMusicAddress(); - return musicAddress != null ? new List() { musicAddress.Value } : WatchVariableUtilities.BaseAddressListEmpty; + return musicAddress != null ? new List() { musicAddress.Value } : VariableUtilities.BaseAddressListEmpty; }; } diff --git a/STROOP/Tabs/ObjectTab.Designer.cs b/STROOP/Tabs/ObjectTab.Designer.cs index 97f15bdf7..6c5ec068b 100644 --- a/STROOP/Tabs/ObjectTab.Designer.cs +++ b/STROOP/Tabs/ObjectTab.Designer.cs @@ -105,7 +105,7 @@ private void InitializeComponent() this.labelObjSlotPos = new System.Windows.Forms.Label(); this.labelObjAdd = new System.Windows.Forms.Label(); this.labelObjSlotInd = new System.Windows.Forms.Label(); - this.watchVariablePanelObject = new STROOP.Controls.VariablePanel.WatchVariablePanel(); + this._variablePanelObject = new STROOP.Controls.VariablePanel.VariablePanel(); ((System.ComponentModel.ISupportInitialize)(this.splitContainerObject)).BeginInit(); this.splitContainerObject.Panel1.SuspendLayout(); this.splitContainerObject.Panel2.SuspendLayout(); @@ -148,7 +148,7 @@ private void InitializeComponent() // // splitContainerObject.Panel2 // - this.splitContainerObject.Panel2.Controls.Add(this.watchVariablePanelObject); + this.splitContainerObject.Panel2.Controls.Add(this._variablePanelObject); this.splitContainerObject.Panel2.Padding = new System.Windows.Forms.Padding(2); this.splitContainerObject.Panel2MinSize = 0; this.splitContainerObject.Size = new System.Drawing.Size(915, 463); @@ -990,13 +990,13 @@ private void InitializeComponent() // // watchVariablePanelObject // - this.watchVariablePanelObject.DataPath = "Config/ObjectData.xml"; - this.watchVariablePanelObject.Dock = System.Windows.Forms.DockStyle.Fill; - this.watchVariablePanelObject.Location = new System.Drawing.Point(2, 2); - this.watchVariablePanelObject.Margin = new System.Windows.Forms.Padding(0); - this.watchVariablePanelObject.Name = "watchVariablePanelObject"; - this.watchVariablePanelObject.Size = new System.Drawing.Size(691, 457); - this.watchVariablePanelObject.TabIndex = 3; + this._variablePanelObject.DataPath = "Config/ObjectData.xml"; + this._variablePanelObject.Dock = System.Windows.Forms.DockStyle.Fill; + this._variablePanelObject.Location = new System.Drawing.Point(2, 2); + this._variablePanelObject.Margin = new System.Windows.Forms.Padding(0); + this._variablePanelObject.Name = "_variablePanelObject"; + this._variablePanelObject.Size = new System.Drawing.Size(691, 457); + this._variablePanelObject.TabIndex = 3; // // ObjectTab // @@ -1103,6 +1103,6 @@ private void InitializeComponent() private System.Windows.Forms.Label labelObjSlotPos; private System.Windows.Forms.Label labelObjAdd; private System.Windows.Forms.Label labelObjSlotInd; - private STROOP.Controls.VariablePanel.WatchVariablePanel watchVariablePanelObject; + private STROOP.Controls.VariablePanel.VariablePanel _variablePanelObject; } } diff --git a/STROOP/Tabs/ObjectTab.cs b/STROOP/Tabs/ObjectTab.cs index add11aeca..20f5f34a2 100644 --- a/STROOP/Tabs/ObjectTab.cs +++ b/STROOP/Tabs/ObjectTab.cs @@ -9,7 +9,9 @@ using STROOP.Structs.Configurations; using STROOP.Forms; using STROOP.Models; -using STROOP.Core.Variables; +using STROOP.Variables; +using STROOP.Variables.Utilities; +using STROOP.Variables.VariablePanel; namespace STROOP.Tabs { @@ -137,7 +139,7 @@ private HashSet _addresses public ObjectTab() { InitializeComponent(); - watchVariablePanelObject.SetGroups(ALL_VAR_GROUPS, VISIBLE_VAR_GROUPS); + _variablePanelObject.SetGroups(ALL_VAR_GROUPS, VISIBLE_VAR_GROUPS); } public override string GetDisplayName() => "Object"; @@ -145,7 +147,7 @@ public ObjectTab() public override void InitializeTab() { base.InitializeTab(); - this.watchVariablePanelObject.SetGroups(ALL_VAR_GROUPS, VISIBLE_VAR_GROUPS); + this._variablePanelObject.SetGroups(ALL_VAR_GROUPS, VISIBLE_VAR_GROUPS); _objectSlots = Config.StroopMainForm.ObjectSlotsManager; labelObjAddValue.Click += ObjAddressLabel_Click; @@ -411,11 +413,11 @@ public override void InitializeTab() // Having an empty action assigned to this adds the context menu entry to the ObjectSlot controls public override Action> objectSlotsClicked => objectSlots => { }; - public void SetBehaviorWatchVariables(IEnumerable watchVars, Color color) + public void SetBehaviorVariables(IEnumerable precursors, Color color) { - watchVariablePanelObject.RemoveVariableGroup(VariableGroup.ObjectSpecific); - foreach (var ctrl in watchVariablePanelObject.AddVariables(watchVars)) - ctrl.BaseColor = color; + _variablePanelObject.RemoveVariableGroup(VariableGroup.ObjectSpecific); + foreach (var ctrl in _variablePanelObject.AddVariables(precursors)) + ctrl.control.BaseColor = color; } private void ObjAddressLabel_Click(object sender, EventArgs e) @@ -465,7 +467,7 @@ void UpdateUI() SlotPos = ""; labelObjAddValue.Text = ""; _lastGeneralizedBehavior = null; - SetBehaviorWatchVariables(Array.Empty(), Color.White); + SetBehaviorVariables([], Color.White); } else if (_objects.Count() == 1) { @@ -474,8 +476,8 @@ void UpdateUI() if (!BehaviorCriteria.HasSameAssociation(_lastGeneralizedBehavior, newBehavior)) { Behavior = $"0x{obj.SegmentedBehavior & 0x00FFFFFF:X4}"; - SetBehaviorWatchVariables( - Config.ObjectAssociations.GetWatchVarControls(newBehavior), + SetBehaviorVariables( + Config.ObjectAssociations.GetVariablePrecursors(newBehavior), ObjectSlotsConfig.GetProcessingGroupColor(obj.BehaviorProcessGroup) .Lighten(0.8)); _lastGeneralizedBehavior = newBehavior; @@ -509,14 +511,14 @@ void UpdateUI() if (multiBehavior.HasValue) { Behavior = $"0x{multiBehavior.Value.BehaviorAddress:X4}"; - SetBehaviorWatchVariables( - Config.ObjectAssociations.GetWatchVarControls(multiBehavior.Value), + SetBehaviorVariables( + Config.ObjectAssociations.GetVariablePrecursors(multiBehavior.Value), ObjectSlotsConfig.GetProcessingGroupColor(processGroup).Lighten(0.8)); } else { Behavior = ""; - SetBehaviorWatchVariables(Array.Empty(), Color.White); + SetBehaviorVariables([], Color.White); } _lastGeneralizedBehavior = multiBehavior; diff --git a/STROOP/Tabs/OptionsTab.Designer.cs b/STROOP/Tabs/OptionsTab.Designer.cs index 327e7bbf0..550086418 100644 --- a/STROOP/Tabs/OptionsTab.Designer.cs +++ b/STROOP/Tabs/OptionsTab.Designer.cs @@ -35,7 +35,7 @@ private void InitializeComponent() this.checkBoxUseRomHack = new System.Windows.Forms.CheckBox(); this.buttonOptionsResetSavedSettings = new System.Windows.Forms.Button(); this.label3 = new System.Windows.Forms.Label(); - this.watchVariablePanelOptions = new STROOP.Controls.VariablePanel.WatchVariablePanel(); + this._variablePanelOptions = new STROOP.Controls.VariablePanel.VariablePanel(); ((System.ComponentModel.ISupportInitialize)(this.splitContainerOptions)).BeginInit(); this.splitContainerOptions.Panel1.SuspendLayout(); this.splitContainerOptions.Panel2.SuspendLayout(); @@ -65,7 +65,7 @@ private void InitializeComponent() // // splitContainerOptions.Panel2 // - this.splitContainerOptions.Panel2.Controls.Add(this.watchVariablePanelOptions); + this.splitContainerOptions.Panel2.Controls.Add(this._variablePanelOptions); this.splitContainerOptions.Panel2.Padding = new System.Windows.Forms.Padding(2); this.splitContainerOptions.Panel2MinSize = 0; this.splitContainerOptions.Size = new System.Drawing.Size(915, 463); @@ -126,13 +126,13 @@ private void InitializeComponent() // // watchVariablePanelOptions // - this.watchVariablePanelOptions.DataPath = "Config/OptionsData.xml"; - this.watchVariablePanelOptions.Dock = System.Windows.Forms.DockStyle.Fill; - this.watchVariablePanelOptions.Location = new System.Drawing.Point(2, 2); - this.watchVariablePanelOptions.Margin = new System.Windows.Forms.Padding(0); - this.watchVariablePanelOptions.Name = "watchVariablePanelOptions"; - this.watchVariablePanelOptions.Size = new System.Drawing.Size(440, 457); - this.watchVariablePanelOptions.TabIndex = 5; + this._variablePanelOptions.DataPath = "Config/OptionsData.xml"; + this._variablePanelOptions.Dock = System.Windows.Forms.DockStyle.Fill; + this._variablePanelOptions.Location = new System.Drawing.Point(2, 2); + this._variablePanelOptions.Margin = new System.Windows.Forms.Padding(0); + this._variablePanelOptions.Name = "_variablePanelOptions"; + this._variablePanelOptions.Size = new System.Drawing.Size(440, 457); + this._variablePanelOptions.TabIndex = 5; // // OptionsTab // @@ -158,6 +158,6 @@ private void InitializeComponent() internal System.Windows.Forms.CheckBox checkBoxUseRomHack; private System.Windows.Forms.Button buttonOptionsResetSavedSettings; private System.Windows.Forms.Label label3; - private STROOP.Controls.VariablePanel.WatchVariablePanel watchVariablePanelOptions; + private STROOP.Controls.VariablePanel.VariablePanel _variablePanelOptions; } } diff --git a/STROOP/Tabs/PaintingTab.Designer.cs b/STROOP/Tabs/PaintingTab.Designer.cs index 30f2184f6..f3ea3e956 100644 --- a/STROOP/Tabs/PaintingTab.Designer.cs +++ b/STROOP/Tabs/PaintingTab.Designer.cs @@ -31,7 +31,7 @@ private void InitializeComponent() this.components = new System.ComponentModel.Container(); this.splitContainerPainting = new STROOP.BetterSplitContainer(); this.listBoxPainting = new System.Windows.Forms.ListBox(); - this.watchVariablePanelPainting = new STROOP.Controls.VariablePanel.WatchVariablePanel(); + this._variablePanelPainting = new STROOP.Controls.VariablePanel.VariablePanel(); ((System.ComponentModel.ISupportInitialize)(this.splitContainerPainting)).BeginInit(); this.splitContainerPainting.Panel1.SuspendLayout(); this.splitContainerPainting.Panel2.SuspendLayout(); @@ -57,7 +57,7 @@ private void InitializeComponent() // // splitContainerPainting.Panel2 // - this.splitContainerPainting.Panel2.Controls.Add(this.watchVariablePanelPainting); + this.splitContainerPainting.Panel2.Controls.Add(this._variablePanelPainting); this.splitContainerPainting.Panel2.Padding = new System.Windows.Forms.Padding(2); this.splitContainerPainting.Panel2MinSize = 0; this.splitContainerPainting.Size = new System.Drawing.Size(915, 463); @@ -77,13 +77,13 @@ private void InitializeComponent() // // watchVariablePanelPainting // - this.watchVariablePanelPainting.DataPath = "Config/PaintingData.xml"; - this.watchVariablePanelPainting.Dock = System.Windows.Forms.DockStyle.Fill; - this.watchVariablePanelPainting.Location = new System.Drawing.Point(2, 2); - this.watchVariablePanelPainting.Margin = new System.Windows.Forms.Padding(0); - this.watchVariablePanelPainting.Name = "watchVariablePanelPainting"; - this.watchVariablePanelPainting.Size = new System.Drawing.Size(755, 457); - this.watchVariablePanelPainting.TabIndex = 7; + this._variablePanelPainting.DataPath = "Config/PaintingData.xml"; + this._variablePanelPainting.Dock = System.Windows.Forms.DockStyle.Fill; + this._variablePanelPainting.Location = new System.Drawing.Point(2, 2); + this._variablePanelPainting.Margin = new System.Windows.Forms.Padding(0); + this._variablePanelPainting.Name = "_variablePanelPainting"; + this._variablePanelPainting.Size = new System.Drawing.Size(755, 457); + this._variablePanelPainting.TabIndex = 7; // // PaintingTab // @@ -104,6 +104,6 @@ private void InitializeComponent() private BetterSplitContainer splitContainerPainting; private System.Windows.Forms.ListBox listBoxPainting; - private STROOP.Controls.VariablePanel.WatchVariablePanel watchVariablePanelPainting; + private STROOP.Controls.VariablePanel.VariablePanel _variablePanelPainting; } } diff --git a/STROOP/Tabs/PaintingTab.cs b/STROOP/Tabs/PaintingTab.cs index 26ed1e606..25e9cce69 100644 --- a/STROOP/Tabs/PaintingTab.cs +++ b/STROOP/Tabs/PaintingTab.cs @@ -1,6 +1,9 @@ -using System.Collections.Generic; +using STROOP.Core; +using System.Collections.Generic; using STROOP.Structs; using STROOP.Utilities; +using STROOP.Variables; +using STROOP.Variables.Utilities; namespace STROOP.Tabs { @@ -9,10 +12,10 @@ public partial class PaintingTab : STROOPTab [InitializeBaseAddress] static void InitBaseAddresses() { - WatchVariableUtilities.baseAddressGetters["Painting"] = () => + VariableUtilities.baseAddressGetters["Painting"] = () => { uint? paintingAddress = AccessScope.content.GetTab().GetPaintingAddress(); - return paintingAddress != null ? new List() { paintingAddress.Value } : WatchVariableUtilities.BaseAddressListEmpty; + return paintingAddress != null ? new List() { paintingAddress.Value } : VariableUtilities.BaseAddressListEmpty; }; } diff --git a/STROOP/Tabs/PuTab.Designer.cs b/STROOP/Tabs/PuTab.Designer.cs index 139869049..ce4913d21 100644 --- a/STROOP/Tabs/PuTab.Designer.cs +++ b/STROOP/Tabs/PuTab.Designer.cs @@ -62,7 +62,7 @@ private void InitializeComponent() this.buttonPuConZpPu = new System.Windows.Forms.Button(); this.buttonPuConZpQpu = new System.Windows.Forms.Button(); this.buttonPuConHome = new System.Windows.Forms.Button(); - this.watchVariablePanelPu = new STROOP.Controls.VariablePanel.WatchVariablePanel(); + this._variablePanelPu = new STROOP.Controls.VariablePanel.VariablePanel(); ((System.ComponentModel.ISupportInitialize)(this.splitContainerPu)).BeginInit(); this.splitContainerPu.Panel1.SuspendLayout(); this.splitContainerPu.Panel2.SuspendLayout(); @@ -91,7 +91,7 @@ private void InitializeComponent() // // splitContainerPu.Panel2 // - this.splitContainerPu.Panel2.Controls.Add(this.watchVariablePanelPu); + this.splitContainerPu.Panel2.Controls.Add(this._variablePanelPu); this.splitContainerPu.Panel2.Padding = new System.Windows.Forms.Padding(2); this.splitContainerPu.Panel2MinSize = 0; this.splitContainerPu.Size = new System.Drawing.Size(915, 463); @@ -472,13 +472,13 @@ private void InitializeComponent() // // watchVariablePanelPu // - this.watchVariablePanelPu.DataPath = "Config/PuData.xml"; - this.watchVariablePanelPu.Dock = System.Windows.Forms.DockStyle.Fill; - this.watchVariablePanelPu.Location = new System.Drawing.Point(2, 2); - this.watchVariablePanelPu.Margin = new System.Windows.Forms.Padding(0); - this.watchVariablePanelPu.Name = "watchVariablePanelPu"; - this.watchVariablePanelPu.Size = new System.Drawing.Size(615, 457); - this.watchVariablePanelPu.TabIndex = 5; + this._variablePanelPu.DataPath = "Config/PuData.xml"; + this._variablePanelPu.Dock = System.Windows.Forms.DockStyle.Fill; + this._variablePanelPu.Location = new System.Drawing.Point(2, 2); + this._variablePanelPu.Margin = new System.Windows.Forms.Padding(0); + this._variablePanelPu.Name = "_variablePanelPu"; + this._variablePanelPu.Size = new System.Drawing.Size(615, 457); + this._variablePanelPu.TabIndex = 5; // // PuTab // @@ -534,6 +534,6 @@ private void InitializeComponent() private System.Windows.Forms.Button buttonPuConZpPu; private System.Windows.Forms.Button buttonPuConZpQpu; private System.Windows.Forms.Button buttonPuConHome; - private STROOP.Controls.VariablePanel.WatchVariablePanel watchVariablePanelPu; + private STROOP.Controls.VariablePanel.VariablePanel _variablePanelPu; } } diff --git a/STROOP/Tabs/PuTab.cs b/STROOP/Tabs/PuTab.cs index c08588ad5..8b671f1fe 100644 --- a/STROOP/Tabs/PuTab.cs +++ b/STROOP/Tabs/PuTab.cs @@ -1,5 +1,7 @@ using STROOP.Structs; using STROOP.Utilities; +using STROOP.Variables; +using STROOP.Variables.Utilities; using System.Collections.Generic; namespace STROOP.Tabs @@ -27,7 +29,7 @@ public partial class PuTab : STROOPTab public PuTab() { InitializeComponent(); - watchVariablePanelPu.SetGroups(ALL_VAR_GROUPS, VISIBLE_VAR_GROUPS); + _variablePanelPu.SetGroups(ALL_VAR_GROUPS, VISIBLE_VAR_GROUPS); } public override string GetDisplayName() => "PU"; diff --git a/STROOP/Tabs/QuarterFramesTab.Designer.cs b/STROOP/Tabs/QuarterFramesTab.Designer.cs index 0a5258c2a..d71a24dab 100644 --- a/STROOP/Tabs/QuarterFramesTab.Designer.cs +++ b/STROOP/Tabs/QuarterFramesTab.Designer.cs @@ -29,26 +29,26 @@ protected override void Dispose(bool disposing) private void InitializeComponent() { this.components = new System.ComponentModel.Container(); - this.watchVariablePanelQuarterFrame = new STROOP.Controls.VariablePanel.WatchVariablePanel(); + this._variablePanelQuarterFrame = new STROOP.Controls.VariablePanel.VariablePanel(); this.SuspendLayout(); // // watchVariablePanelQuarterFrame // - this.watchVariablePanelQuarterFrame.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + this._variablePanelQuarterFrame.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.watchVariablePanelQuarterFrame.DataPath = "Config/QuarterFrameData.xml"; - this.watchVariablePanelQuarterFrame.Location = new System.Drawing.Point(0, 0); - this.watchVariablePanelQuarterFrame.Margin = new System.Windows.Forms.Padding(0); - this.watchVariablePanelQuarterFrame.Name = "watchVariablePanelQuarterFrame"; - this.watchVariablePanelQuarterFrame.Size = new System.Drawing.Size(915, 463); - this.watchVariablePanelQuarterFrame.TabIndex = 3; + this._variablePanelQuarterFrame.DataPath = "Config/QuarterFrameData.xml"; + this._variablePanelQuarterFrame.Location = new System.Drawing.Point(0, 0); + this._variablePanelQuarterFrame.Margin = new System.Windows.Forms.Padding(0); + this._variablePanelQuarterFrame.Name = "_variablePanelQuarterFrame"; + this._variablePanelQuarterFrame.Size = new System.Drawing.Size(915, 463); + this._variablePanelQuarterFrame.TabIndex = 3; // // QuarterFramesTab // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.Controls.Add(this.watchVariablePanelQuarterFrame); + this.Controls.Add(this._variablePanelQuarterFrame); this.Name = "QuarterFramesTab"; this.Size = new System.Drawing.Size(915, 463); this.ResumeLayout(false); @@ -57,6 +57,6 @@ private void InitializeComponent() #endregion - private STROOP.Controls.VariablePanel.WatchVariablePanel watchVariablePanelQuarterFrame; + private STROOP.Controls.VariablePanel.VariablePanel _variablePanelQuarterFrame; } } diff --git a/STROOP/Tabs/QuarterFramesTab.cs b/STROOP/Tabs/QuarterFramesTab.cs index 14617dda9..461000b2b 100644 --- a/STROOP/Tabs/QuarterFramesTab.cs +++ b/STROOP/Tabs/QuarterFramesTab.cs @@ -1,6 +1,8 @@ using System.Collections.Generic; using STROOP.Structs; using STROOP.Utilities; +using STROOP.Variables; +using STROOP.Variables.Utilities; namespace STROOP.Tabs { @@ -9,7 +11,7 @@ public partial class QuarterFramesTab : STROOPTab [InitializeBaseAddress] static void InitBaseAddresses() { - WatchVariableUtilities.baseAddressGetters["HackedArea"] = () => new List { MiscConfig.HackedAreaAddress }; + VariableUtilities.baseAddressGetters["HackedArea"] = () => new List { MiscConfig.HackedAreaAddress }; } private static readonly List ALL_VAR_GROUPS = @@ -30,7 +32,7 @@ static void InitBaseAddresses() public QuarterFramesTab() { InitializeComponent(); - watchVariablePanelQuarterFrame.SetGroups(ALL_VAR_GROUPS, VISIBLE_VAR_GROUPS); + _variablePanelQuarterFrame.SetGroups(ALL_VAR_GROUPS, VISIBLE_VAR_GROUPS); } public override string GetDisplayName() => "QFrames"; diff --git a/STROOP/Tabs/STROOPTab.cs b/STROOP/Tabs/STROOPTab.cs index db4ca1123..91dcf0f10 100644 --- a/STROOP/Tabs/STROOPTab.cs +++ b/STROOP/Tabs/STROOPTab.cs @@ -64,9 +64,9 @@ public virtual string GetDisplayName() return baseName; } - public static void PerformRecursiveAction(Control c, Action action) + public static void PerformRecursiveAction(Control c, Action action) { - if (c is WatchVariablePanel panel) + if (c is VariablePanel panel) action(panel); foreach (Control child in c.Controls) PerformRecursiveAction(child, action); diff --git a/STROOP/Tabs/SearchTab.Designer.cs b/STROOP/Tabs/SearchTab.Designer.cs index 42236a307..b644ae13f 100644 --- a/STROOP/Tabs/SearchTab.Designer.cs +++ b/STROOP/Tabs/SearchTab.Designer.cs @@ -49,7 +49,7 @@ private void InitializeComponent() this.dataGridViewSearch = new System.Windows.Forms.DataGridView(); this.Address = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.Value = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.watchVariablePanelSearch = new STROOP.Controls.VariablePanel.WatchVariablePanel(); + this._variablePanelSearch = new STROOP.Controls.VariablePanel.VariablePanel(); ((System.ComponentModel.ISupportInitialize)(this.splitContainerSearch)).BeginInit(); this.splitContainerSearch.Panel1.SuspendLayout(); this.splitContainerSearch.Panel2.SuspendLayout(); @@ -80,7 +80,7 @@ private void InitializeComponent() // // splitContainerSearch.Panel2 // - this.splitContainerSearch.Panel2.Controls.Add(this.watchVariablePanelSearch); + this.splitContainerSearch.Panel2.Controls.Add(this._variablePanelSearch); this.splitContainerSearch.Panel2.Padding = new System.Windows.Forms.Padding(2); this.splitContainerSearch.Panel2MinSize = 0; this.splitContainerSearch.Size = new System.Drawing.Size(915, 463); @@ -292,13 +292,13 @@ private void InitializeComponent() // // watchVariablePanelSearch // - this.watchVariablePanelSearch.DataPath = null; - this.watchVariablePanelSearch.Dock = System.Windows.Forms.DockStyle.Fill; - this.watchVariablePanelSearch.Location = new System.Drawing.Point(2, 2); - this.watchVariablePanelSearch.Margin = new System.Windows.Forms.Padding(0); - this.watchVariablePanelSearch.Name = "watchVariablePanelSearch"; - this.watchVariablePanelSearch.Size = new System.Drawing.Size(451, 457); - this.watchVariablePanelSearch.TabIndex = 7; + this._variablePanelSearch.DataPath = null; + this._variablePanelSearch.Dock = System.Windows.Forms.DockStyle.Fill; + this._variablePanelSearch.Location = new System.Drawing.Point(2, 2); + this._variablePanelSearch.Margin = new System.Windows.Forms.Padding(0); + this._variablePanelSearch.Name = "_variablePanelSearch"; + this._variablePanelSearch.Size = new System.Drawing.Size(451, 457); + this._variablePanelSearch.TabIndex = 7; // // SearchTab // @@ -340,6 +340,6 @@ private void InitializeComponent() private System.Windows.Forms.DataGridView dataGridViewSearch; private System.Windows.Forms.DataGridViewTextBoxColumn Address; private System.Windows.Forms.DataGridViewTextBoxColumn Value; - private STROOP.Controls.VariablePanel.WatchVariablePanel watchVariablePanelSearch; + private STROOP.Controls.VariablePanel.VariablePanel _variablePanelSearch; } } diff --git a/STROOP/Tabs/SearchTab.cs b/STROOP/Tabs/SearchTab.cs index 119278cd4..bb32c517a 100644 --- a/STROOP/Tabs/SearchTab.cs +++ b/STROOP/Tabs/SearchTab.cs @@ -1,7 +1,9 @@ -using STROOP.Core.Variables; -using STROOP.Structs; -using STROOP.Structs.Configurations; +using STROOP.Structs.Configurations; using STROOP.Utilities; +using STROOP.Variables; +using STROOP.Variables.SM64MemoryLayout; +using STROOP.Variables.Utilities; +using STROOP.Variables.VariablePanel; using System; using System.Collections.Generic; using System.Linq; @@ -74,11 +76,12 @@ private void AddTableRowsAsVars(List rows) foreach (DataGridViewRow row in rows) { uint? addressNullable = ParsingUtilities.ParseHexNullable(row.Cells[0].Value); - if (!addressNullable.HasValue) continue; - uint address = addressNullable.Value; + if (!addressNullable.HasValue) + continue; + uint address = addressNullable.Value; MemoryDescriptor watchVar = new MemoryDescriptor(_memoryType, BaseAddressType.Relative, address); - watchVariablePanelSearch.AddVariable(watchVar.CreateView()); + _variablePanelSearch.AddVariable(($"{_memoryType.Name}@0x{address : X8}", watchVar.CreateVariable())); } } diff --git a/STROOP/Tabs/SnowTab.Designer.cs b/STROOP/Tabs/SnowTab.Designer.cs index 086f10511..86a15a348 100644 --- a/STROOP/Tabs/SnowTab.Designer.cs +++ b/STROOP/Tabs/SnowTab.Designer.cs @@ -46,7 +46,7 @@ private void InitializeComponent() this.buttonSnowPositionXnZp = new System.Windows.Forms.Button(); this.buttonSnowPositionXn = new System.Windows.Forms.Button(); this.buttonSnowPositionXnZn = new System.Windows.Forms.Button(); - this.watchVariablePanelSnow = new STROOP.Controls.VariablePanel.WatchVariablePanel(); + this._variablePanelSnow = new STROOP.Controls.VariablePanel.VariablePanel(); ((System.ComponentModel.ISupportInitialize)(this.splitContainerSnow)).BeginInit(); this.splitContainerSnow.Panel1.SuspendLayout(); this.splitContainerSnow.Panel2.SuspendLayout(); @@ -75,7 +75,7 @@ private void InitializeComponent() // // splitContainerSnow.Panel2 // - this.splitContainerSnow.Panel2.Controls.Add(this.watchVariablePanelSnow); + this.splitContainerSnow.Panel2.Controls.Add(this._variablePanelSnow); this.splitContainerSnow.Panel2.Padding = new System.Windows.Forms.Padding(2); this.splitContainerSnow.Panel2MinSize = 0; this.splitContainerSnow.Size = new System.Drawing.Size(915, 463); @@ -258,13 +258,13 @@ private void InitializeComponent() // // watchVariablePanelSnow // - this.watchVariablePanelSnow.DataPath = "Config/SnowData.xml"; - this.watchVariablePanelSnow.Dock = System.Windows.Forms.DockStyle.Fill; - this.watchVariablePanelSnow.Location = new System.Drawing.Point(2, 2); - this.watchVariablePanelSnow.Margin = new System.Windows.Forms.Padding(0); - this.watchVariablePanelSnow.Name = "watchVariablePanelSnow"; - this.watchVariablePanelSnow.Size = new System.Drawing.Size(698, 457); - this.watchVariablePanelSnow.TabIndex = 3; + this._variablePanelSnow.DataPath = "Config/SnowData.xml"; + this._variablePanelSnow.Dock = System.Windows.Forms.DockStyle.Fill; + this._variablePanelSnow.Location = new System.Drawing.Point(2, 2); + this._variablePanelSnow.Margin = new System.Windows.Forms.Padding(0); + this._variablePanelSnow.Name = "_variablePanelSnow"; + this._variablePanelSnow.Size = new System.Drawing.Size(698, 457); + this._variablePanelSnow.TabIndex = 3; // // SnowTab // @@ -303,6 +303,6 @@ private void InitializeComponent() private System.Windows.Forms.Button buttonSnowPositionXnZp; private System.Windows.Forms.Button buttonSnowPositionXn; private System.Windows.Forms.Button buttonSnowPositionXnZn; - private STROOP.Controls.VariablePanel.WatchVariablePanel watchVariablePanelSnow; + private STROOP.Controls.VariablePanel.VariablePanel _variablePanelSnow; } } diff --git a/STROOP/Tabs/SnowTab.cs b/STROOP/Tabs/SnowTab.cs index 33ba2ab05..b087be47f 100644 --- a/STROOP/Tabs/SnowTab.cs +++ b/STROOP/Tabs/SnowTab.cs @@ -1,10 +1,12 @@ using System; using System.Collections.Generic; -using STROOP.Controls.VariablePanel; -using STROOP.Core.Variables; +using STROOP.Core.Utilities; using STROOP.Structs; using STROOP.Structs.Configurations; using STROOP.Utilities; +using STROOP.Variables; +using STROOP.Variables.Utilities; +using STROOP.Variables.VariablePanel; namespace STROOP.Tabs { @@ -31,12 +33,12 @@ public partial class SnowTab : STROOPTab }; private short _numSnowParticles; - private List> _snowParticleControls; + private List> _snowParticleCells; public SnowTab() { InitializeComponent(); - watchVariablePanelSnow.SetGroups(ALL_VAR_GROUPS, VISIBLE_VAR_GROUPS); + _variablePanelSnow.SetGroups(ALL_VAR_GROUPS, VISIBLE_VAR_GROUPS); } public override string GetDisplayName() => "Snow"; @@ -46,7 +48,7 @@ public override void InitializeTab() base.InitializeTab(); _numSnowParticles = 0; - _snowParticleControls = new List>(); + _snowParticleCells = new List>(); buttonSnowRetrieve.Click += (sender, e) => { @@ -77,7 +79,7 @@ public override void InitializeTab() }); } - private List GetSnowParticleControls(int index) + private List GetSnowParticleControls(int index) { uint structOffset = (uint)index * SnowConfig.ParticleStructSize; List offsets = new List() @@ -93,19 +95,15 @@ public override void InitializeTab() String.Format("Particle {0} Z", index), }; - var controls = new List(); + var precursors = new List(); for (int i = 0; i < 3; i++) - { - var view = new NamedVariableCollection.CustomView(typeof(WatchVariableNumberWrapper)) + precursors.Add((names[i], new CustomVariable(VariableSubclass.Number) { - Name = names[i], - _getterFunction = () => Config.Stream.GetInt32(Config.Stream.GetUInt32(SnowConfig.SnowArrayPointerAddress) + offsets[i]).Yield(), - _setterFunction = (val) => Config.Stream.SetValue(val, Config.Stream.GetUInt32(SnowConfig.SnowArrayPointerAddress) + offsets[i]).Yield() - }; - controls.Add(view); - } + getter = () => Config.Stream.GetInt32(Config.Stream.GetUInt32(SnowConfig.SnowArrayPointerAddress) + offsets[i]).Yield(), + setter = (val) => Config.Stream.SetValue(val, Config.Stream.GetUInt32(SnowConfig.SnowArrayPointerAddress) + offsets[i]).Yield() + })); - return controls; + return precursors; } public override void Update(bool updateView) @@ -116,16 +114,16 @@ public override void Update(bool updateView) if (numSnowParticles > _numSnowParticles) // need to add controls { for (int i = _numSnowParticles; i < numSnowParticles; i++) - _snowParticleControls.Add(watchVariablePanelSnow.AddVariables(GetSnowParticleControls(i))); + _snowParticleCells.Add(_variablePanelSnow.AddVariables(GetSnowParticleControls(i))); _numSnowParticles = numSnowParticles; } else if (numSnowParticles < _numSnowParticles) // need to remove controls { for (int i = _numSnowParticles - 1; i >= numSnowParticles; i--) { - var snowParticleControls = _snowParticleControls[i]; - _snowParticleControls.Remove(snowParticleControls); - watchVariablePanelSnow.RemoveVariables(snowParticleControls); + var snowParticleControls = _snowParticleCells[i]; + _snowParticleCells.Remove(snowParticleControls); + _variablePanelSnow.RemoveVariables(snowParticleControls); } _numSnowParticles = numSnowParticles; diff --git a/STROOP/Tabs/SoundTab.cs b/STROOP/Tabs/SoundTab.cs index 79e30acc9..205363117 100644 --- a/STROOP/Tabs/SoundTab.cs +++ b/STROOP/Tabs/SoundTab.cs @@ -2,6 +2,8 @@ using STROOP.Structs; using STROOP.Utilities; using STROOP.Structs.Configurations; +using STROOP.Variables.SM64MemoryLayout; +using STROOP.Variables.Utilities; namespace STROOP.Tabs { diff --git a/STROOP/Tabs/TrianglesTab.Designer.cs b/STROOP/Tabs/TrianglesTab.Designer.cs index 5affcbbbc..600d546ba 100644 --- a/STROOP/Tabs/TrianglesTab.Designer.cs +++ b/STROOP/Tabs/TrianglesTab.Designer.cs @@ -85,7 +85,7 @@ private void InitializeComponent() this.buttonGotoV3 = new System.Windows.Forms.Button(); this.buttonGotoV1 = new System.Windows.Forms.Button(); this.buttonGotoV2 = new System.Windows.Forms.Button(); - this.watchVariablePanelTriangles = new STROOP.Controls.VariablePanel.WatchVariablePanel(); + this._variablePanelTriangles = new STROOP.Controls.VariablePanel.VariablePanel(); ((System.ComponentModel.ISupportInitialize)(this.splitContainerTriangles)).BeginInit(); this.splitContainerTriangles.Panel1.SuspendLayout(); this.splitContainerTriangles.Panel2.SuspendLayout(); @@ -143,7 +143,7 @@ private void InitializeComponent() // // splitContainerTriangles.Panel2 // - this.splitContainerTriangles.Panel2.Controls.Add(this.watchVariablePanelTriangles); + this.splitContainerTriangles.Panel2.Controls.Add(this._variablePanelTriangles); this.splitContainerTriangles.Panel2.Padding = new System.Windows.Forms.Padding(2); this.splitContainerTriangles.Panel2MinSize = 0; this.splitContainerTriangles.Size = new System.Drawing.Size(915, 463); @@ -707,13 +707,13 @@ private void InitializeComponent() // // watchVariablePanelTriangles // - this.watchVariablePanelTriangles.DataPath = "Config/TrianglesData.xml"; - this.watchVariablePanelTriangles.Dock = System.Windows.Forms.DockStyle.Fill; - this.watchVariablePanelTriangles.Location = new System.Drawing.Point(2, 2); - this.watchVariablePanelTriangles.Margin = new System.Windows.Forms.Padding(0); - this.watchVariablePanelTriangles.Name = "watchVariablePanelTriangles"; - this.watchVariablePanelTriangles.Size = new System.Drawing.Size(700, 457); - this.watchVariablePanelTriangles.TabIndex = 7; + this._variablePanelTriangles.DataPath = "Config/TrianglesData.xml"; + this._variablePanelTriangles.Dock = System.Windows.Forms.DockStyle.Fill; + this._variablePanelTriangles.Location = new System.Drawing.Point(2, 2); + this._variablePanelTriangles.Margin = new System.Windows.Forms.Padding(0); + this._variablePanelTriangles.Name = "_variablePanelTriangles"; + this._variablePanelTriangles.Size = new System.Drawing.Size(700, 457); + this._variablePanelTriangles.TabIndex = 7; // // TrianglesTab // @@ -795,6 +795,6 @@ private void InitializeComponent() private System.Windows.Forms.Button buttonGotoV3; private System.Windows.Forms.Button buttonGotoV1; private System.Windows.Forms.Button buttonGotoV2; - private STROOP.Controls.VariablePanel.WatchVariablePanel watchVariablePanelTriangles; + private STROOP.Controls.VariablePanel.VariablePanel _variablePanelTriangles; } } diff --git a/STROOP/Tabs/TrianglesTab.cs b/STROOP/Tabs/TrianglesTab.cs index 7b3ab1b4d..c843184f7 100644 --- a/STROOP/Tabs/TrianglesTab.cs +++ b/STROOP/Tabs/TrianglesTab.cs @@ -3,12 +3,16 @@ using System.Linq; using System.Windows.Forms; using STROOP.Controls.VariablePanel; -using STROOP.Core.Variables; +using STROOP.Core; +using STROOP.Core.Utilities; using STROOP.Forms; using STROOP.Models; using STROOP.Structs; using STROOP.Structs.Configurations; using STROOP.Utilities; +using STROOP.Variables; +using STROOP.Variables.SM64MemoryLayout; +using STROOP.Variables.Utilities; namespace STROOP.Tabs { @@ -18,15 +22,15 @@ static IEnumerable GetTriangleAddresses() { var trianglesTab = AccessScope.content.GetTab(); List triangleAddresses = trianglesTab.TriangleAddresses; - if (triangleAddresses.Count == 1 && triangleAddresses[0] == 0) return WatchVariableUtilities.BaseAddressListEmpty; + if (triangleAddresses.Count == 1 && triangleAddresses[0] == 0) return VariableUtilities.BaseAddressListEmpty; return trianglesTab.TriangleAddresses; } [InitializeBaseAddress] static void InitBaseAddresses() { - WatchVariableUtilities.baseAddressGetters[BaseAddressType.Triangle] = GetTriangleAddresses; - WatchVariableUtilities.baseAddressGetters["TriangleExertionForceTable"] = () => + VariableUtilities.baseAddressGetters[BaseAddressType.Triangle] = GetTriangleAddresses; + VariableUtilities.baseAddressGetters["TriangleExertionForceTable"] = () => GetTriangleAddresses().ConvertAll(triangleAddress => { uint exertionForceIndex = Config.Stream.GetByte(triangleAddress + TriangleOffsetsConfig.ExertionForceIndex); @@ -34,19 +38,17 @@ static void InitBaseAddresses() }); } - static IEnumerable OperateOnTriangles(Func operate) => WatchVariableUtilities.GetBaseAddresses(BaseAddressType.Triangle).Select(triAddress => operate(triAddress)); + static IEnumerable OperateOnTriangles(Func operate) => VariableUtilities.GetBaseAddresses(BaseAddressType.Triangle).Select(triAddress => operate(triAddress)); - static (string, WatchVariablePanel.SpecialFuncWatchVariables) GenerateTriangleRelations = - ("Triangle projections", - (PositionAngle.HybridPositionAngle pa) => + static (string, VariablePanel.SpecialFuncVariables) GenerateTriangleRelations = + ("Triangle projections", pa => { - var vars = new List(); - vars.Add(new NamedVariableCollection.CustomView(typeof(WatchVariableNumberWrapper)) + var vars = new List(); + vars.Add(($"{pa.name} Normal Dist Away", new CustomVariable(VariableSubclass.Number) { Color = "LightBlue", - Name = $"{pa.name} Normal Dist Away", - _getterFunction = () => - WatchVariableUtilities.GetBaseAddresses(BaseAddressType.Triangle).Select(triAddress => + getter = () => + VariableUtilities.GetBaseAddresses(BaseAddressType.Triangle).Select(triAddress => { TriangleDataModel triStruct = TriangleDataModel.Create(AccessScope.content.selection.First()); double normalDistAway = @@ -56,8 +58,8 @@ static void InitBaseAddresses() triStruct.NormOffset; return normalDistAway; }), - _setterFunction = (double distAway) => - WatchVariableUtilities.GetBaseAddresses(BaseAddressType.Triangle).Select(triAddress => + setter = distAway => + VariableUtilities.GetBaseAddresses(BaseAddressType.Triangle).Select(triAddress => { TriangleDataModel triStruct = TriangleDataModel.Create(triAddress); @@ -77,54 +79,51 @@ static void InitBaseAddresses() return pa.SetValues(x: newSelfX, y: newSelfY, z: newSelfZ); }) - }); + })); - vars.Add(new NamedVariableCollection.CustomView(typeof(WatchVariableNumberWrapper)) + vars.Add(($"{pa.name} Vertical Dist Away", new CustomVariable(VariableSubclass.Number) { Color = "LightBlue", - Name = $"{pa.name} Vertical Dist Away", - _getterFunction = () => - WatchVariableUtilities.GetBaseAddresses(BaseAddressType.Triangle).Select(triAddress => + getter = () => + VariableUtilities.GetBaseAddresses(BaseAddressType.Triangle).Select(triAddress => { TriangleDataModel triStruct = TriangleDataModel.Create(triAddress); double verticalDistAway = pa.Y + (pa.X * triStruct.NormX + pa.Z * triStruct.NormZ + triStruct.NormOffset) / triStruct.NormY; return verticalDistAway; }), - _setterFunction = (double distAbove) => - WatchVariableUtilities.GetBaseAddresses(BaseAddressType.Triangle).Select(triAddress => + setter = (double distAbove) => + VariableUtilities.GetBaseAddresses(BaseAddressType.Triangle).Select(triAddress => { TriangleDataModel triStruct = TriangleDataModel.Create(triAddress); double newSelfY = distAbove - (pa.X * triStruct.NormX + pa.Z * triStruct.NormZ + triStruct.NormOffset) / triStruct.NormY; pa.SetY(newSelfY); return true; }) - }); + })); - vars.Add(new NamedVariableCollection.CustomView(typeof(WatchVariableNumberWrapper)) + vars.Add(($"{pa.name} Height On Triangle", new CustomVariable(VariableSubclass.Number) { Color = "LightBlue", - Name = $"{pa.name} Height On Triangle", - _getterFunction = () => - WatchVariableUtilities.GetBaseAddresses(BaseAddressType.Triangle).Select(triAddress => + getter = () => + VariableUtilities.GetBaseAddresses(BaseAddressType.Triangle).Select(triAddress => { TriangleDataModel triStruct = TriangleDataModel.Create(triAddress); double heightOnTriangle = triStruct.GetHeightOnTriangle(pa.X, pa.Z); return heightOnTriangle; }), - _setterFunction = WatchVariableSpecialUtilities.Defaults.DEFAULT_SETTER - }); + setter = SpecialVariableDefaults.DEFAULT_SETTER + })); - vars.Add(new NamedVariableCollection.CustomView(typeof(WatchVariableNumberWrapper)) + vars.Add(($"{pa.name} Distance To Line 12", new CustomVariable(VariableSubclass.Number) { Color = "LightBlue", - Name = $"{pa.name} Distance To Line 12", - _getterFunction = () => - WatchVariableUtilities.GetBaseAddresses(BaseAddressType.Triangle).Select(triAddress => + getter = () => + VariableUtilities.GetBaseAddresses(BaseAddressType.Triangle).Select(triAddress => { TriangleDataModel triStruct = TriangleDataModel.Create(triAddress); - double signedDistToLine12 = MoreMath.GetSignedDistanceFromPointToLine( + double signedDistToLine12 = STROOPMath.GetSignedDistanceFromPointToLine( pa.X, pa.Z, triStruct.X1, triStruct.Z1, triStruct.X2, triStruct.Z2, @@ -132,11 +131,11 @@ static void InitBaseAddresses() TriangleDataModel.Create(triAddress).Classification); return signedDistToLine12; }), - _setterFunction = (double dist) => - WatchVariableUtilities.GetBaseAddresses(BaseAddressType.Triangle).Select(triAddress => + setter = (double dist) => + VariableUtilities.GetBaseAddresses(BaseAddressType.Triangle).Select(triAddress => { TriangleDataModel triStruct = TriangleDataModel.Create(triAddress); - double signedDistToLine12 = MoreMath.GetSignedDistanceFromPointToLine( + double signedDistToLine12 = STROOPMath.GetSignedDistanceFromPointToLine( pa.X, pa.Z, triStruct.X1, triStruct.Z1, triStruct.X2, triStruct.Z2, @@ -153,17 +152,16 @@ static void InitBaseAddresses() double newSelfZ = pa.Z + zDiff; return pa.SetValues(x: newSelfX, z: newSelfZ); }) - }); + })); - vars.Add(new NamedVariableCollection.CustomView(typeof(WatchVariableNumberWrapper)) + vars.Add(($"{pa.name} Distance To Line 23", new CustomVariable(VariableSubclass.Number) { Color = "LightBlue", - Name = $"{pa.name} Distance To Line 23", - _getterFunction = () => - WatchVariableUtilities.GetBaseAddresses(BaseAddressType.Triangle).Select(triAddress => + getter = () => + VariableUtilities.GetBaseAddresses(BaseAddressType.Triangle).Select(triAddress => { TriangleDataModel triStruct = TriangleDataModel.Create(triAddress); - double signedDistToLine23 = MoreMath.GetSignedDistanceFromPointToLine( + double signedDistToLine23 = STROOPMath.GetSignedDistanceFromPointToLine( pa.X, pa.Z, triStruct.X1, triStruct.Z1, triStruct.X2, triStruct.Z2, @@ -171,11 +169,11 @@ static void InitBaseAddresses() TriangleDataModel.Create(triAddress).Classification); return signedDistToLine23; }), - _setterFunction = (double dist) => - WatchVariableUtilities.GetBaseAddresses(BaseAddressType.Triangle).Select(triAddress => + setter = (double dist) => + VariableUtilities.GetBaseAddresses(BaseAddressType.Triangle).Select(triAddress => { TriangleDataModel triStruct = TriangleDataModel.Create(triAddress); - double signedDistToLine23 = MoreMath.GetSignedDistanceFromPointToLine( + double signedDistToLine23 = STROOPMath.GetSignedDistanceFromPointToLine( pa.X, pa.Z, triStruct.X1, triStruct.Z1, triStruct.X2, triStruct.Z2, @@ -192,17 +190,16 @@ static void InitBaseAddresses() double newSelfZ = pa.Z + zDiff; return pa.SetValues(x: newSelfX, z: newSelfZ); }) - }); + })); - vars.Add(new NamedVariableCollection.CustomView(typeof(WatchVariableNumberWrapper)) + vars.Add(($"{pa.name} Distance To Line 31", new CustomVariable(VariableSubclass.Number) { Color = "LightBlue", - Name = $"{pa.name} Distance To Line 31", - _getterFunction = () => - WatchVariableUtilities.GetBaseAddresses(BaseAddressType.Triangle).Select(triAddress => + getter = () => + VariableUtilities.GetBaseAddresses(BaseAddressType.Triangle).Select(triAddress => { TriangleDataModel triStruct = TriangleDataModel.Create(triAddress); - double signedDistToLine31 = MoreMath.GetSignedDistanceFromPointToLine( + double signedDistToLine31 = STROOPMath.GetSignedDistanceFromPointToLine( pa.X, pa.Z, triStruct.X1, triStruct.Z1, triStruct.X2, triStruct.Z2, @@ -210,11 +207,11 @@ static void InitBaseAddresses() TriangleDataModel.Create(triAddress).Classification); return signedDistToLine31; }), - _setterFunction = (double dist) => - WatchVariableUtilities.GetBaseAddresses(BaseAddressType.Triangle).Select(triAddress => + setter = (double dist) => + VariableUtilities.GetBaseAddresses(BaseAddressType.Triangle).Select(triAddress => { TriangleDataModel triStruct = TriangleDataModel.Create(triAddress); - double signedDistToLine31 = MoreMath.GetSignedDistanceFromPointToLine( + double signedDistToLine31 = STROOPMath.GetSignedDistanceFromPointToLine( pa.X, pa.Z, triStruct.X1, triStruct.Z1, triStruct.X2, triStruct.Z2, @@ -231,7 +228,7 @@ static void InitBaseAddresses() double newSelfZ = pa.Z + zDiff; return pa.SetValues(x: newSelfX, z: newSelfZ); }) - }); + })); foreach ((string name, Func func) vertex_it in new (string, Func)[] { @@ -241,45 +238,41 @@ static void InitBaseAddresses() }) { var vertex = vertex_it; - foreach (var distFunc in WatchVariableSpecialUtilities.distFuncs) + foreach (var distFunc in VariableSpecialUtilities.distFuncs) { var getter = distFunc.getter; var setter = distFunc.setter; - vars.Add(new NamedVariableCollection.CustomView(typeof(WatchVariableNumberWrapper)) + vars.Add(($"{distFunc.type}Dist {pa.name} To {vertex.name}", new CustomVariable(VariableSubclass.Number) { Color = "LightBlue", - Name = $"{distFunc.type}Dist {pa.name} To {vertex.name}", - _getterFunction = () => OperateOnTriangles(triAddress => getter(new[] { pa, vertex.func(triAddress) })), - _setterFunction = (double dist) => OperateOnTriangles(triAddress => setter(new[] { pa, vertex.func(triAddress) }, dist)) - }); + getter = () => OperateOnTriangles(triAddress => getter(new[] { pa, vertex.func(triAddress) })), + setter = (double dist) => OperateOnTriangles(triAddress => setter(new[] { pa, vertex.func(triAddress) }, dist)) + })); } - vars.Add(new NamedVariableCollection.CustomView(typeof(WatchVariableAngleWrapper)) + vars.Add(($"Angle {pa.name} To {vertex.name}", new CustomVariable(VariableSubclass.Angle) { Color = "LightBlue", Display = "short", - Name = $"Angle {pa.name} To {vertex.name}", - _getterFunction = () => OperateOnTriangles(triAddress => PositionAngle.GetAngleTo(pa, vertex.func(triAddress))), - _setterFunction = (double angle) => OperateOnTriangles(triAddress => PositionAngle.SetAngleTo(pa, vertex.func(triAddress), angle)) - }); + getter = () => OperateOnTriangles(triAddress => PositionAngle.GetAngleTo(pa, vertex.func(triAddress))), + setter = (double angle) => OperateOnTriangles(triAddress => PositionAngle.SetAngleTo(pa, vertex.func(triAddress), angle)) + })); - vars.Add(new NamedVariableCollection.CustomView(typeof(WatchVariableAngleWrapper)) + vars.Add(($"DAngle {pa.name} To {vertex.name}", new CustomVariable(VariableSubclass.Angle) { Color = "LightBlue", Display = "short", - Name = $"DAngle {pa.name} To {vertex.name}", - _getterFunction = () => OperateOnTriangles(triAddress => PositionAngle.GetDAngleTo(pa, vertex.func(triAddress))), - _setterFunction = (double angleDiff) => OperateOnTriangles(triAddress => PositionAngle.SetDAngleTo(pa, vertex.func(triAddress), angleDiff)) - }); + getter = () => OperateOnTriangles(triAddress => PositionAngle.GetDAngleTo(pa, vertex.func(triAddress))), + setter = (double angleDiff) => OperateOnTriangles(triAddress => PositionAngle.SetDAngleTo(pa, vertex.func(triAddress), angleDiff)) + })); - vars.Add(new NamedVariableCollection.CustomView(typeof(WatchVariableAngleWrapper)) + vars.Add(($"AngleDiff {pa.name} To {vertex.name}", new CustomVariable(VariableSubclass.Angle) { Color = "LightBlue", Display = "short", - Name = $"AngleDiff {pa.name} To {vertex.name}", - _getterFunction = () => OperateOnTriangles(triAddress => PositionAngle.GetAngleDifference(pa, vertex.func(triAddress))), - _setterFunction = (double angleDiff) => OperateOnTriangles(triAddress => PositionAngle.SetAngleDifference(pa, vertex.func(triAddress), angleDiff)) - }); + getter = () => OperateOnTriangles(triAddress => PositionAngle.GetAngleDifference(pa, vertex.func(triAddress))), + setter = (double angleDiff) => OperateOnTriangles(triAddress => PositionAngle.SetAngleDifference(pa, vertex.func(triAddress), angleDiff)) + })); } return vars; @@ -307,8 +300,8 @@ public enum TriangleMode public TrianglesTab() { InitializeComponent(); - watchVariablePanelTriangles.SetGroups(ALL_VAR_GROUPS, VISIBLE_VAR_GROUPS); - watchVariablePanelTriangles.getSpecialFuncWatchVariables = () => new[] { GenerateTriangleRelations }; + _variablePanelTriangles.SetGroups(ALL_VAR_GROUPS, VISIBLE_VAR_GROUPS); + _variablePanelTriangles.getSpecialFuncVariables = () => new[] { GenerateTriangleRelations }; } public override string GetDisplayName() => "Triangles"; diff --git a/STROOP/Tabs/VarHackTab.cs b/STROOP/Tabs/VarHackTab.cs index c4ccf06ac..87331347c 100644 --- a/STROOP/Tabs/VarHackTab.cs +++ b/STROOP/Tabs/VarHackTab.cs @@ -3,6 +3,7 @@ using System.Windows.Forms; using STROOP.Utilities; using STROOP.Structs.Configurations; +using STROOP.Variables.Utilities; namespace STROOP.Tabs { diff --git a/STROOP/Tabs/WarpTab.Designer.cs b/STROOP/Tabs/WarpTab.Designer.cs index 0c2239362..47acbfbea 100644 --- a/STROOP/Tabs/WarpTab.Designer.cs +++ b/STROOP/Tabs/WarpTab.Designer.cs @@ -33,7 +33,7 @@ private void InitializeComponent() this.splitContainerWarpLeft = new STROOP.BetterSplitContainer(); this.buttonWarpInstructions = new System.Windows.Forms.Button(); this.buttonWarpHookUpTeleporters = new System.Windows.Forms.Button(); - this.watchVariablePanelWarp = new STROOP.Controls.VariablePanel.WatchVariablePanel(); + this._variablePanelWarp = new STROOP.Controls.VariablePanel.VariablePanel(); ((System.ComponentModel.ISupportInitialize)(this.splitContainerWarp)).BeginInit(); this.splitContainerWarp.Panel1.SuspendLayout(); this.splitContainerWarp.Panel2.SuspendLayout(); @@ -61,7 +61,7 @@ private void InitializeComponent() // // splitContainerWarp.Panel2 // - this.splitContainerWarp.Panel2.Controls.Add(this.watchVariablePanelWarp); + this.splitContainerWarp.Panel2.Controls.Add(this._variablePanelWarp); this.splitContainerWarp.Panel2.Padding = new System.Windows.Forms.Padding(2); this.splitContainerWarp.Panel2MinSize = 0; this.splitContainerWarp.Size = new System.Drawing.Size(915, 463); @@ -120,11 +120,11 @@ private void InitializeComponent() // // watchVariablePanelWarp // - this.watchVariablePanelWarp.DataPath = "Config/WarpData.xml"; - this.watchVariablePanelWarp.Location = new System.Drawing.Point(1, 2); - this.watchVariablePanelWarp.Name = "watchVariablePanelWarp"; - this.watchVariablePanelWarp.Size = new System.Drawing.Size(800, 454); - this.watchVariablePanelWarp.TabIndex = 0; + this._variablePanelWarp.DataPath = "Config/WarpData.xml"; + this._variablePanelWarp.Location = new System.Drawing.Point(1, 2); + this._variablePanelWarp.Name = "_variablePanelWarp"; + this._variablePanelWarp.Size = new System.Drawing.Size(800, 454); + this._variablePanelWarp.TabIndex = 0; // // WarpTab // @@ -151,6 +151,6 @@ private void InitializeComponent() private BetterSplitContainer splitContainerWarpLeft; private System.Windows.Forms.Button buttonWarpInstructions; private System.Windows.Forms.Button buttonWarpHookUpTeleporters; - private STROOP.Controls.VariablePanel.WatchVariablePanel watchVariablePanelWarp; + private STROOP.Controls.VariablePanel.VariablePanel _variablePanelWarp; } } diff --git a/STROOP/Tabs/WarpTab.cs b/STROOP/Tabs/WarpTab.cs index 8f63f3fce..5c07b5f18 100644 --- a/STROOP/Tabs/WarpTab.cs +++ b/STROOP/Tabs/WarpTab.cs @@ -1,11 +1,13 @@ using System.Collections.Generic; using System.Linq; using STROOP.Controls.VariablePanel; -using STROOP.Core.Variables; +using STROOP.Core.Utilities; using STROOP.Forms; using STROOP.Structs; using STROOP.Structs.Configurations; using STROOP.Utilities; +using STROOP.Variables; +using STROOP.Variables.VariablePanel; namespace STROOP.Tabs { @@ -32,7 +34,7 @@ public partial class WarpTab : STROOPTab public WarpTab() { InitializeComponent(); - watchVariablePanelWarp.SetGroups(ALL_VAR_GROUPS, VISIBLE_VAR_GROUPS); + _variablePanelWarp.SetGroups(ALL_VAR_GROUPS, VISIBLE_VAR_GROUPS); } public override string GetDisplayName() => "Warp"; @@ -56,66 +58,60 @@ public override void Update(bool updateView) { if (!updateView) return; - List warpNodeAddresses = WatchVariableSpecialUtilities.GetWarpNodeAddresses(); + List warpNodeAddresses = VariableSpecialUtilities.GetWarpNodeAddresses(); if (!Enumerable.SequenceEqual(warpNodeAddresses, _warpNodeAddresses)) { - watchVariablePanelWarp.RemoveVariableGroup(VariableGroup.WarpNode); - watchVariablePanelWarp.AddVariables(GetWarpNodeVariables(warpNodeAddresses)); + _variablePanelWarp.RemoveVariableGroup(VariableGroup.WarpNode); + _variablePanelWarp.AddVariables(GetWarpNodeVariables(warpNodeAddresses)); _warpNodeAddresses = warpNodeAddresses; } base.Update(updateView); } - private List GetWarpNodeVariables(List addresses) + private List GetWarpNodeVariables(List addresses) { - var controls = new List(); + var precursors = new List(); int i = 0; foreach (var address in addresses) - controls.AddRange(GetWarpNodeVariables(address, i++)); - return controls; + precursors.AddRange(GetWarpNodeVariables(address, i++)); + return precursors; } - private IEnumerable GetWarpNodeVariables(uint address, int index) + private IEnumerable GetWarpNodeVariables(uint address, int index) { - return new NamedVariableCollection.CustomView[] + return new VariablePrecursor[] { - new NamedVariableCollection.CustomView(typeof(WatchVariableNumberWrapper)) + ($"Warp {index} ID", new CustomVariable(VariableSubclass.Number) { - Name = $"Warp {index} ID", - _getterFunction = () => Config.Stream.GetByte(address).Yield(), - _setterFunction = (val) => Config.Stream.SetValue(val, address).Yield() - }, - new NamedVariableCollection.CustomView(typeof(WatchVariableNumberWrapper)) + getter = () => Config.Stream.GetByte(address).Yield(), + setter = (val) => Config.Stream.SetValue(val, address).Yield() + }), + ($"Warp {index} Dest Level", new CustomVariable(VariableSubclass.Number) { - Name = $"Warp {index} Dest Level", - _getterFunction = () => Config.Stream.GetByte(address + 0x1).Yield(), - _setterFunction = val => Config.Stream.SetValue(val, address + 0x1).Yield() - }, - new NamedVariableCollection.CustomView(typeof(WatchVariableNumberWrapper)) + getter = () => Config.Stream.GetByte(address + 0x1).Yield(), + setter = val => Config.Stream.SetValue(val, address + 0x1).Yield() + }), + ($"Warp {index} Dest Area", new CustomVariable(VariableSubclass.Number) { - Name = $"Warp {index} Dest Area", - _getterFunction = () => Config.Stream.GetByte(address + 0x2).Yield(), - _setterFunction = val => Config.Stream.SetValue(val, address + 0x2).Yield() - }, - new NamedVariableCollection.CustomView(typeof(WatchVariableNumberWrapper)) + getter = () => Config.Stream.GetByte(address + 0x2).Yield(), + setter = val => Config.Stream.SetValue(val, address + 0x2).Yield() + }), + ($"Warp {index} Dest Node", new CustomVariable(VariableSubclass.Number) { - Name = $"Warp {index} Dest Node", - _getterFunction = () => Config.Stream.GetByte(address + 0x3).Yield(), - _setterFunction = val => Config.Stream.SetValue(val, address + 0x3).Yield() - }, - new NamedVariableCollection.CustomView(typeof(WatchVariableNumberWrapper)) + getter = () => Config.Stream.GetByte(address + 0x3).Yield(), + setter = val => Config.Stream.SetValue(val, address + 0x3).Yield() + }), + ($"Warp {index} Object", new CustomVariable(VariableSubclass.Number) { - Name = $"Warp {index} Object", - _getterFunction = () => Config.Stream.GetUInt32(address + 0x4).Yield(), - _setterFunction = val => Config.Stream.SetValue(val, address + 0x4).Yield() - }, - new NamedVariableCollection.CustomView(typeof(WatchVariableNumberWrapper)) + getter = () => Config.Stream.GetUInt32(address + 0x4).Yield(), + setter = val => Config.Stream.SetValue(val, address + 0x4).Yield() + }), + ($"Warp {index} Next", new CustomVariable(VariableSubclass.Number) { - Name = $"Warp {index} Next", - _getterFunction = () => Config.Stream.GetUInt32(address + 0x8).Yield(), - _setterFunction = val => Config.Stream.SetValue(val, address + 0x8).Yield() - }, + getter = () => Config.Stream.GetUInt32(address + 0x8).Yield(), + setter = val => Config.Stream.SetValue(val, address + 0x8).Yield() + }), }; } @@ -124,7 +120,7 @@ public void HookUpTeleporters() uint mainSegmentEnd = 0x80367460; //uint engineSegmentStart = 0x80378800; - uint lastWarpNodeAddress = WatchVariableSpecialUtilities.GetWarpNodeAddresses().LastOrDefault(); + uint lastWarpNodeAddress = VariableSpecialUtilities.GetWarpNodeAddresses().LastOrDefault(); if (lastWarpNodeAddress == 0) return; List objAddresses = Config.ObjectSlotsManager.SelectedObjects.ConvertAll(obj => obj.Address); diff --git a/STROOP/Tabs/WaterTab.Designer.cs b/STROOP/Tabs/WaterTab.Designer.cs index 2ebe9a19d..0114f72aa 100644 --- a/STROOP/Tabs/WaterTab.Designer.cs +++ b/STROOP/Tabs/WaterTab.Designer.cs @@ -2,12 +2,12 @@ { partial class WaterTab { - /// + /// /// Erforderliche Designervariable. /// private System.ComponentModel.IContainer components = null; - /// + /// /// Verwendete Ressourcen bereinigen. /// /// True, wenn verwaltete Ressourcen gelöscht werden sollen; andernfalls False. @@ -22,32 +22,32 @@ protected override void Dispose(bool disposing) #region Vom Komponenten-Designer generierter Code - /// - /// Erforderliche Methode für die Designerunterstützung. + /// + /// Erforderliche Methode für die Designerunterstützung. /// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden. /// private void InitializeComponent() { this.components = new System.ComponentModel.Container(); - this.watchVariablePanelWater = new STROOP.Controls.VariablePanel.WatchVariablePanel(); + this._variablePanelWater = new STROOP.Controls.VariablePanel.VariablePanel(); this.SuspendLayout(); - // + // // watchVariablePanelWater - // - this.watchVariablePanelWater.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + // + this._variablePanelWater.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.watchVariablePanelWater.DataPath = "Config/WaterData.xml"; - this.watchVariablePanelWater.Location = new System.Drawing.Point(0, 0); - this.watchVariablePanelWater.Name = "watchVariablePanelWater"; - this.watchVariablePanelWater.Size = new System.Drawing.Size(915, 463); - this.watchVariablePanelWater.TabIndex = 0; - // + this._variablePanelWater.DataPath = "Config/WaterData.xml"; + this._variablePanelWater.Location = new System.Drawing.Point(0, 0); + this._variablePanelWater.Name = "_variablePanelWater"; + this._variablePanelWater.Size = new System.Drawing.Size(915, 463); + this._variablePanelWater.TabIndex = 0; + // // WaterTab - // + // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.Controls.Add(this.watchVariablePanelWater); + this.Controls.Add(this._variablePanelWater); this.Name = "WaterTab"; this.Size = new System.Drawing.Size(915, 463); this.ResumeLayout(false); @@ -56,6 +56,6 @@ private void InitializeComponent() #endregion - private STROOP.Controls.VariablePanel.WatchVariablePanel watchVariablePanelWater; + private STROOP.Controls.VariablePanel.VariablePanel _variablePanelWater; } } diff --git a/STROOP/Tabs/WaterTab.cs b/STROOP/Tabs/WaterTab.cs index 2f3b0f8d9..b49c8b24d 100644 --- a/STROOP/Tabs/WaterTab.cs +++ b/STROOP/Tabs/WaterTab.cs @@ -2,6 +2,8 @@ using STROOP.Structs; using STROOP.Structs.Configurations; using STROOP.Utilities; +using STROOP.Variables; +using STROOP.Variables.Utilities; namespace STROOP.Tabs { @@ -10,10 +12,10 @@ public partial class WaterTab : STROOPTab [InitializeBaseAddress] static void InitBaseAddresses() { - WatchVariableUtilities.baseAddressGetters["Water"] = () => + VariableUtilities.baseAddressGetters["Water"] = () => { uint waterAddress = Config.Stream.GetUInt32(MiscConfig.WaterPointerAddress); - return waterAddress != 0 ? new List() { waterAddress } : WatchVariableUtilities.BaseAddressListEmpty; + return waterAddress != 0 ? new List() { waterAddress } : VariableUtilities.BaseAddressListEmpty; }; } diff --git a/STROOP/Utilities/BehaviorDecoder.cs b/STROOP/Utilities/BehaviorDecoder.cs index 2a744d826..aa8a2c271 100644 --- a/STROOP/Utilities/BehaviorDecoder.cs +++ b/STROOP/Utilities/BehaviorDecoder.cs @@ -1,4 +1,5 @@ -using STROOP.Structs; +using STROOP.Core; +using STROOP.Structs; using STROOP.Structs.Configurations; using System; using System.Collections.Generic; diff --git a/STROOP/Utilities/ButtonUtilities.cs b/STROOP/Utilities/ButtonUtilities.cs index 11ce934ec..98d05fb63 100644 --- a/STROOP/Utilities/ButtonUtilities.cs +++ b/STROOP/Utilities/ButtonUtilities.cs @@ -4,6 +4,7 @@ using STROOP.Structs; using STROOP.Structs.Configurations; using STROOP.Models; +using STROOP.Variables.SM64MemoryLayout; using System.Diagnostics; namespace STROOP.Utilities @@ -926,7 +927,7 @@ public static bool Lives100() public static bool GotoTriangleVertexClosest(uint triangleAddress, bool useMisalignmentOffset = false) { if (triangleAddress == 0) return false; - int closestVertex = WatchVariableSpecialUtilities.GetClosestTriangleVertexIndex(triangleAddress); + int closestVertex = VariableSpecialUtilities.GetClosestTriangleVertexIndex(triangleAddress); return GotoTriangleVertex(triangleAddress, closestVertex, useMisalignmentOffset); } diff --git a/STROOP/Utilities/ColorUtilities.cs b/STROOP/Utilities/ColorUtilities.cs index dd3143911..c58af222b 100644 --- a/STROOP/Utilities/ColorUtilities.cs +++ b/STROOP/Utilities/ColorUtilities.cs @@ -1,179 +1,18 @@ -using System; -using System.Collections.Generic; +using OpenTK.Mathematics; +using System; using System.Drawing; -using System.Linq; using System.Windows.Forms; -using OpenTK.Mathematics; -namespace STROOP.Utilities +namespace STROOP.Utilities; + +public class ColorDialogUtilities { - public static class ColorUtilities + public static Color? GetColorFromDialog(Color? defaultColor = null) { - public static readonly Dictionary ColorToParamsDictionary = - new Dictionary() - { - ["Red"] = "#FFD7D7", - ["Orange"] = "#FFE2B7", - ["Yellow"] = "#FFFFD0", - ["Green"] = "#CFFFCC", - ["LightBlue"] = "#CCFFFA", - ["Blue"] = "#CADDFF", - ["Purple"] = "#E5CCFF", - ["Pink"] = "#FFCCFF", - ["Grey"] = "#D0D0D0", - }; - - public static readonly List ColorList = - ColorToParamsDictionary.Values.ToList() - .ConvertAll(html => ColorTranslator.FromHtml(html)); - - private static readonly Dictionary ParamsToColorDictionary = - DictionaryUtilities.ReverseDictionary(ColorToParamsDictionary); - - public static Color GetColorFromString(string colorString) - { - if (colorString.Substring(0, 1) != "#") - colorString = ColorToParamsDictionary[colorString]; - return ColorTranslator.FromHtml(colorString); - } - - public static string ConvertColorToString(Color color) - { - string colorParams = ConvertColorToParams(color); - if (ParamsToColorDictionary.ContainsKey(colorParams)) - return ParamsToColorDictionary[colorParams]; - return colorParams; - } - - public static string ConvertColorToParams(Color color) - { - string r = String.Format("{0:X2}", color.R); - string g = String.Format("{0:X2}", color.G); - string b = String.Format("{0:X2}", color.B); - return "#" + r + g + b; - } - - public static Color LastCustomColor = SystemColors.Control; - - public static Color GetColorForVariable() - { - int? inputtedNumber = GlobalKeyboard.GetCurrentlyInputtedNumber(); - - if (inputtedNumber.HasValue && - inputtedNumber.Value > 0 && - inputtedNumber.Value <= ColorList.Count) - { - return ColorList[inputtedNumber.Value - 1]; - } - - return SystemColors.Control; - } - - public static Color? GetColorForHighlight() - { - int? inputtedNumber = GlobalKeyboard.GetCurrentlyInputtedNumber(); - switch (inputtedNumber) - { - case 1: - return Color.Red; - case 2: - return Color.Orange; - case 3: - return Color.Yellow; - case 4: - return Color.Green; - case 5: - return Color.Blue; - case 6: - return Color.Purple; - case 7: - return Color.Pink; - case 8: - return Color.Brown; - case 9: - return Color.Black; - case 0: - return Color.White; - default: - return null; - } - } - - public static Color? ConvertDecimalToColor(string text) - { - List numbersNullable = ParsingUtilities.ParseIntList(text); - if (numbersNullable.Count != 3) return null; - if (numbersNullable.Any(number => !number.HasValue)) return null; - if (numbersNullable.Any(number => number.Value < 0 || number.Value > 255)) return null; - List numbers = numbersNullable.ConvertAll(number => number.Value); - return Color.FromArgb(numbers[0], numbers[1], numbers[2]); - } - - public static string ConvertColorToDecimal(Color color) - { - return color.R + "," + color.G + "," + color.B; - } - - public static Color InterpolateColor(Color c1, Color c2, double amount) - { - amount = MoreMath.Clamp(amount, 0, 1); - byte r = (byte)((c1.R * (1 - amount)) + c2.R * amount); - byte g = (byte)((c1.G * (1 - amount)) + c2.G * amount); - byte b = (byte)((c1.B * (1 - amount)) + c2.B * amount); - return Color.FromArgb(r, g, b); - } - - public static Color? GetColorFromDialog(Color? defaultColor = null) - { - ColorDialog colorDialog = new ColorDialog(); - colorDialog.FullOpen = true; - if (defaultColor.HasValue) colorDialog.Color = defaultColor.Value; - if (colorDialog.ShowDialog() == DialogResult.OK) return colorDialog.Color; - return null; - } - - public static Color AddAlpha(Color color, byte alpha) - { - return Color.FromArgb(alpha, color.R, color.G, color.B); - } - - public static Vector4 ColorToVec4(Color color, int alpha = -1) => - new Vector4(color.R / 255f, color.G / 255f, color.B / 255f, (alpha == -1 ? color.A : alpha) / 255f); - - public static Color Vec4ToColor(Vector4 color) => - Color.FromArgb((byte)(Math.Max(0, Math.Min(255, color.W * 255))), - (byte)(Math.Max(0, Math.Min(255, color.X * 255))), - (byte)(Math.Max(0, Math.Min(255, color.Y * 255))), - (byte)(Math.Max(0, Math.Min(255, color.Z * 255)))); - - public static Vector4 ColorFromHSV(float hue, float saturation, float value, float alpha = 1) - { - int hi = Convert.ToInt32(Math.Floor(hue / 60)) % 6; - float f = hue / 60 - (float)Math.Floor(hue / 60); - - float v = value; - float p = value * (1 - saturation); - float q = value * (1 - f * saturation); - float t = value * (1 - (1 - f) * saturation); - - if (hi == 0) - return new Vector4(v, t, p, alpha); - else if (hi == 1) - return new Vector4(q, v, p, alpha); - else if (hi == 2) - return new Vector4(p, v, t, alpha); - else if (hi == 3) - return new Vector4(p, q, v, alpha); - else if (hi == 4) - return new Vector4(t, p, v, alpha); - else - return new Vector4(v, p, q, alpha); - } - - public static Vector4 GetRandomColor(int seed) - { - Random rnd = new Random(seed); - return ColorFromHSV((float)rnd.NextDouble() * 360, 0.5f, 0.8f); - } + ColorDialog colorDialog = new ColorDialog(); + colorDialog.FullOpen = true; + if (defaultColor.HasValue) colorDialog.Color = defaultColor.Value; + if (colorDialog.ShowDialog() == DialogResult.OK) return colorDialog.Color; + return null; } } diff --git a/STROOP/Utilities/ControlUtilities.cs b/STROOP/Utilities/ControlUtilities.cs index 0383ab537..24da348a7 100644 --- a/STROOP/Utilities/ControlUtilities.cs +++ b/STROOP/Utilities/ControlUtilities.cs @@ -7,6 +7,7 @@ using System.Reflection; using STROOP.Structs.Configurations; using STROOP.Forms; +using STROOP.Variables.Utilities; namespace STROOP.Utilities { diff --git a/STROOP/Utilities/CopyUtilities.cs b/STROOP/Utilities/CopyUtilities.cs index f9164ccab..d5ff31158 100644 --- a/STROOP/Utilities/CopyUtilities.cs +++ b/STROOP/Utilities/CopyUtilities.cs @@ -3,20 +3,30 @@ using System.Windows.Forms; using OpenTK.Mathematics; using STROOP.Controls.VariablePanel; -using STROOP.Structs; +using STROOP.Variables.VariablePanel; namespace STROOP.Utilities { public static class CopyUtilities { - public static void Copy(List vars, CopyTypeEnum copyType) + public enum CopyType { - int index = EnumUtilities.GetEnumValues(typeof(CopyTypeEnum)).IndexOf(copyType); + WithCommas, + WithSpaces, + WithTabs, + WithLineBreaks, + WithCommasAndSpaces, + WithNames, + } + + public static void Copy(List> vars, CopyType copyType) + { + int index = EnumUtilities.GetEnumValues(typeof(CopyType)).IndexOf(copyType); GetCopyActions(() => vars)[index](); } public static void AddContextMenuStripFunctions( - Control control, Func> getVars) + Control control, Func>> getVars) { ControlUtilities.AddContextMenuStripFunctions( control, @@ -25,7 +35,7 @@ public static void AddContextMenuStripFunctions( } public static void AddDropDownItems( - ToolStripMenuItem control, Func> getVars) + ToolStripMenuItem control, Func>> getVars) { ControlUtilities.AddDropDownItems( control, @@ -43,12 +53,10 @@ public static List GetCopyNames() "Copy with Line Breaks", "Copy with Commas and Spaces", "Copy with Names", - "Copy as Table", - "Copy for Code", }; } - private static List GetCopyActions(Func> getVars) + private static List GetCopyActions(Func>> getVars) { return new List() { @@ -58,84 +66,27 @@ private static List GetCopyActions(Func> getV () => CopyWithSeparator(getVars(), "\r\n"), () => CopyWithSeparator(getVars(), ", "), () => CopyWithNames(getVars()), - () => CopyAsTable(getVars()), - () => CopyForCode(getVars()), }; } private static void CopyWithSeparator( - List controls, string separator) + List> controls, string separator) { if (controls.Count == 0) return; - Clipboard.SetText(string.Join(separator, controls.ConvertAll(control => control.WatchVarWrapper.GetValueText()))); + Clipboard.SetText(string.Join(separator, controls.ConvertAll(cell => cell.GetValueText()))); } - private static void CopyWithNames(List controls) + private static void CopyWithNames(List> controls) { if (controls.Count == 0) return; - List lines = controls.ConvertAll(watchVar => watchVar.VarName + "\t" + watchVar.WatchVarWrapper.GetValueText()); + List lines = controls.ConvertAll(cell => cell.control.VarName + "\t" + cell.GetValueText()); Clipboard.SetText(string.Join("\r\n", lines)); } - private static void CopyAsTable(List controls) - { - // TODO: reconsider CopyAsTable - //if (controls.Count == 0) return; - //List hexAddresses = controls.Select(x => x.view as NamedVariableCollection.MemoryDescriptorView).Where(x => x != null).ConvertAll(address => HexUtilities.FormatValue(address)); - //string header = "Vars\t" + string.Join("\t", hexAddresses); - - //List names = controls.ConvertAll(control => control.VarName); - //List> valuesTable = controls.ConvertAll(control => control.view.GetValues()); - //List valuesStrings = new List(); - //for (int i = 0; i < names.Count; i++) - //{ - // string line = names[i] + "\t" + string.Join("\t", valuesTable[i]); - // valuesStrings.Add(line); - //} - - //string output = header + "\r\n" + string.Join("\r\n", valuesStrings); - //Clipboard.SetText(output); - } - - private static void CopyForCode(List controls) - { - if (controls.Count == 0) return; - Func varNameFunc; - if (GlobalKeyboard.IsCtrlDown()) - { - string template = DialogUtilities.GetStringFromDialog("$"); - if (template == null) return; - varNameFunc = varName => template.Replace("$", varName); - } - else - { - varNameFunc = varName => varName; - } - - List lines = new List(); - foreach (WatchVariableControl watchVar in controls) - { - Type type = watchVar.GetMemoryType(); - string line = string.Format( - "{0} {1} = {2}{3};", - type != null ? TypeUtilities.TypeToString[type] : "double", - varNameFunc(watchVar.VarName.Replace(" ", "")), - // TODO: indicate that the watchVarWrapper should produce code conforming output (whatever that means) - watchVar.WatchVarWrapper.GetValueText(), - type == typeof(float) ? "f" : ""); - lines.Add(line); - } - - if (lines.Count > 0) - { - Clipboard.SetText(string.Join("\r\n", lines)); - } - } - public static void CopyPosition(Vector3 v) { DataObject vec3Data = new DataObject("Position", v); - vec3Data.SetText($"{v.X}; {v.Y}; {v.Z}"); + vec3Data.SetText($"{v.X}, {v.Y}, {v.Z}"); Clipboard.SetDataObject(vec3Data); } @@ -144,7 +95,7 @@ public static bool TryPastePosition(out Vector3 v) v = default(Vector3); bool hasData = false; var clipboardObj = Clipboard.GetDataObject(); - if (!(hasData |= ParsingUtilities.TryParseVector3(clipboardObj.GetData(DataFormats.Text) as string, out v))) + if (!(hasData |= OpenTKUtilities.TryParseVector3(clipboardObj.GetData(DataFormats.Text) as string, out v))) { if (Clipboard.GetData("Position") is Vector3 dataVector) { diff --git a/STROOP/Utilities/DemoCounterUtilities.cs b/STROOP/Utilities/DemoCounterUtilities.cs index fd2cb9056..7097d7d40 100644 --- a/STROOP/Utilities/DemoCounterUtilities.cs +++ b/STROOP/Utilities/DemoCounterUtilities.cs @@ -1,4 +1,6 @@ -using STROOP.Structs.Configurations; +using STROOP.Core; +using STROOP.Structs.Configurations; +using STROOP.Variables.SM64MemoryLayout; using System; using System.Collections.Generic; diff --git a/STROOP/Utilities/DialogUtilities.cs b/STROOP/Utilities/DialogUtilities.cs index bc18033cb..b66715ee4 100644 --- a/STROOP/Utilities/DialogUtilities.cs +++ b/STROOP/Utilities/DialogUtilities.cs @@ -1,4 +1,5 @@ -using STROOP.Forms; +using STROOP.Core; +using STROOP.Forms; using System; using System.Collections.Generic; using System.Drawing; @@ -7,6 +8,7 @@ using System.Windows.Forms; using System.Xml.Linq; using STROOP.Structs; +using STROOP.Variables.Utilities; namespace STROOP.Utilities { @@ -205,7 +207,7 @@ public static double GetDoubleFromDialog( string buttonText = "OK") { string text = GetStringFromDialog(textBoxText, labelText, buttonText); - float? relativeHeightNullable = Utilities.ParsingUtilities.ParseFloatNullable(text); + float? relativeHeightNullable = ParsingUtilities.ParseFloatNullable(text); if (relativeHeightNullable.HasValue) return relativeHeightNullable.Value; return defaultValue; @@ -223,21 +225,6 @@ public static (string text, bool rightButtonClicked)? GetStringAndSideFromDialog return null; } - public static List ReadFileLines(string filePath) - { - List lines = new List(); - string line; - - StreamReader file = new StreamReader(filePath); - while ((line = file.ReadLine()) != null) - { - lines.Add(line); - } - - file.Close(); - return lines; - } - public static Image GetImage() { string directory = Directory.GetCurrentDirectory() + "\\Resources\\Maps\\Object Images"; diff --git a/STROOP/Utilities/DictionaryUtilities.cs b/STROOP/Utilities/DictionaryUtilities.cs index 5c7c19eca..c2f2a0d9f 100644 --- a/STROOP/Utilities/DictionaryUtilities.cs +++ b/STROOP/Utilities/DictionaryUtilities.cs @@ -5,13 +5,6 @@ namespace STROOP.Utilities { public static class DictionaryUtilities { - public static Dictionary ReverseDictionary(Dictionary dictionary) - { - Dictionary reverseDictionary = new Dictionary(); - dictionary.ToList().ForEach(keyValuePair => { reverseDictionary.Add(keyValuePair.Value, keyValuePair.Key); }); - return reverseDictionary; - } - public static string GetString(Dictionary dictionary) { List entries = new List(); diff --git a/STROOP/Utilities/EndiannessUtilities.cs b/STROOP/Utilities/EndiannessUtilities.cs deleted file mode 100644 index cc62c5e52..000000000 --- a/STROOP/Utilities/EndiannessUtilities.cs +++ /dev/null @@ -1,122 +0,0 @@ -using STROOP.Structs; -using System; -using System.Linq; - -namespace STROOP.Utilities -{ - public static class EndiannessUtilities - { - 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) - { - return (address.ToUInt64() & 0x03) != 0; - } - - public static bool AddressIsMisaligned(uint address) - { - return (address & 0x03) != 0; - } - - static readonly byte[] _bytesToAlignment = new byte[] { 0x00, 0x03, 0x02, 0x01 }; - - public static int NumberOfBytesToAlignment(UIntPtr address) - { - return _bytesToAlignment[address.ToUInt64() & 0x03]; - } - - public static int NumberOfBytesToAlignment(uint address) - { - return _bytesToAlignment[address & 0x03]; - } - - public static uint AlignedAddressFloor(uint address) - { - return (address & ~0x03U); - } - - public static UIntPtr AlignedAddressFloor(UIntPtr address) - { - return (UIntPtr)(address.ToUInt64() & ~0x03U); - } - - public static uint AlignedAddressCeil(uint address) - { - return ((address & ~0x03U) + 4); - } - - public static UIntPtr AlignedAddressCeil(UIntPtr address) - { - return (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; - } - } -} diff --git a/STROOP/Utilities/FlyingUtilities.cs b/STROOP/Utilities/FlyingUtilities.cs index ce94c2e48..f64ff6c2b 100644 --- a/STROOP/Utilities/FlyingUtilities.cs +++ b/STROOP/Utilities/FlyingUtilities.cs @@ -1,5 +1,6 @@ using STROOP.Structs; using STROOP.Structs.Configurations; +using STROOP.Variables.SM64MemoryLayout; using System; namespace STROOP.Utilities diff --git a/STROOP/Utilities/GeneralUtilities.cs b/STROOP/Utilities/GeneralUtilities.cs deleted file mode 100644 index 84e54a8df..000000000 --- a/STROOP/Utilities/GeneralUtilities.cs +++ /dev/null @@ -1,131 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Reflection; - -namespace STROOP.Utilities -{ - public class Wrapper - { - public T value; - - public Wrapper() - { - } - - public Wrapper(T value) - { - this.value = value; - } - } - - public class EqualityComparer : IEqualityComparer - { - Func equalsFunc; - Func getHashCodeFunc; - - public EqualityComparer(Func equalsFunc, Func getHashCodeFunc = null) - { - this.equalsFunc = equalsFunc; - this.getHashCodeFunc = getHashCodeFunc ?? (_ => _.GetHashCode()); - } - - bool IEqualityComparer.Equals(T x, T y) => equalsFunc(x, y); - - int IEqualityComparer.GetHashCode(T obj) => getHashCodeFunc(obj); - } - - public class OrderComparer : IComparer - { - Func func; - - public OrderComparer(Func func) - { - this.func = func; - } - - int IComparer.Compare(T x, T y) => func(x, y); - } - - public static class GeneralUtilities - { - static Type[] stroopTypes; - - static GeneralUtilities() - { - stroopTypes = typeof(GeneralUtilities).Assembly.GetTypes(); - } - - public static IEnumerable EnumerateTypes(Func filter) - { - foreach (var t in stroopTypes) - if (filter(t)) - yield return t; - } - - public static IEnumerable Yield(this T value) - { - yield return value; - } - - public static EqualityComparer GetEqualityComparer(Func equalsFunc, Func getHashCodeFunc = null) - => new EqualityComparer(equalsFunc, getHashCodeFunc); - - public static void ExecuteInitializers(params object[] args) where T : InitializerAttribute - { - foreach (var type in typeof(T).Assembly.GetTypes()) - foreach (var m in type.GetMethods(BindingFlags.Static | BindingFlags.NonPublic)) - if (m.GetParameters().Length == 0 && m.GetCustomAttribute() != null) - m.Invoke(null, args); - } - - public static List ConvertAndRemoveNull(this IEnumerable lstIn, Func converter) where TOut : class - { - var lstOut = new List(); - foreach (var obj in lstIn) - { - var convertedObj = converter(obj); - if (convertedObj != null) - lstOut.Add(convertedObj); - } - - return lstOut; - } - - public static List ConvertAndRemoveNull(this System.Collections.IEnumerable lstIn, Func converter) where TOut : class - { - var lstOut = new List(); - foreach (var obj in lstIn) - { - var convertedObj = converter(obj); - if (convertedObj != null) - lstOut.Add(convertedObj); - } - - return lstOut; - } - - public static IEnumerable ConvertAll(this IEnumerable lstIn, Func converter) - { - foreach (var obj in lstIn) - yield return converter(obj); - } - - - public static T GetMeaningfulValue(Func> values, T fail, T @default) - { - T result = @default; - foreach (var value in values()) - GetMeaningfulValue(ref result, value, fail); - return result; - } - - public static void GetMeaningfulValue(ref T result, T input, T fail) - { - if (!(result?.Equals(fail) ?? fail == null)) - if (result == null) - result = input; - else if (!(input?.Equals(result) ?? result == null)) - result = fail; - } - } -} diff --git a/STROOP/Utilities/GlobalKeyboard.cs b/STROOP/Utilities/GlobalKeyboard.cs index d3c835c5b..3da4954ca 100644 --- a/STROOP/Utilities/GlobalKeyboard.cs +++ b/STROOP/Utilities/GlobalKeyboard.cs @@ -1,51 +1,31 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Windows.Forms; +using System.Windows.Forms; +using Windows.Win32; namespace STROOP.Utilities; public static class GlobalKeyboard { - static HashSet pressedKeys = new(); - static HashSet
registeredForms = new(); + private static bool IsDownInternal(Keys key) + => (PInvoke.GetAsyncKeyState((int)key) & 0x8000) != 0; - public static void AddForm(Form form) - { - registeredForms.Add(form); - form.KeyPreview = true; - form.KeyDown += OnKeyDown; - form.KeyUp += OnKeyUp; - - EventHandler unbind = null; - unbind = (sender, e) => - { - registeredForms.Remove(form); - ((Form)sender).Disposed -= unbind; - form.KeyDown -= OnKeyDown; - form.KeyUp -= OnKeyUp; - }; - form.Disposed += unbind; - } + public static bool IsDown(Keys key) => IsDownInternal(key); - public static bool IsDown(Keys key) => pressedKeys.Contains(key) && registeredForms.Any(f => Form.ActiveForm == f); - - public static bool IsCtrlDown() => pressedKeys.Contains(Keys.ControlKey); - public static bool IsShiftDown() => pressedKeys.Contains(Keys.ShiftKey); - public static bool IsAltDown() => pressedKeys.Contains(Keys.Menu) || pressedKeys.Contains(Keys.Alt); // Don't ask me why... + public static bool IsCtrlDown() => IsDown(Keys.ControlKey); + public static bool IsShiftDown() => IsDown(Keys.ShiftKey); + public static bool IsAltDown() => IsDown(Keys.Menu) || IsDown(Keys.Alt); // Don't ask me why... public static int? GetCurrentlyInputtedNumber() { - if (pressedKeys.Contains(Keys.D1)) return 1; - if (pressedKeys.Contains(Keys.D2)) return 2; - if (pressedKeys.Contains(Keys.D3)) return 3; - if (pressedKeys.Contains(Keys.D4)) return 4; - if (pressedKeys.Contains(Keys.D5)) return 5; - if (pressedKeys.Contains(Keys.D6)) return 6; - if (pressedKeys.Contains(Keys.D7)) return 7; - if (pressedKeys.Contains(Keys.D8)) return 8; - if (pressedKeys.Contains(Keys.D9)) return 9; - if (pressedKeys.Contains(Keys.D0)) return 0; + if (IsDown(Keys.D1)) return 1; + if (IsDown(Keys.D2)) return 2; + if (IsDown(Keys.D3)) return 3; + if (IsDown(Keys.D4)) return 4; + if (IsDown(Keys.D5)) return 5; + if (IsDown(Keys.D6)) return 6; + if (IsDown(Keys.D7)) return 7; + if (IsDown(Keys.D8)) return 8; + if (IsDown(Keys.D9)) return 9; + if (IsDown(Keys.D0)) return 0; return null; } @@ -60,10 +40,4 @@ public static bool IsDeletishKeyDown() IsDown(Keys.Back) || IsDown(Keys.Escape); } - - private static void OnKeyDown(object sender, KeyEventArgs e) - => pressedKeys.Add(e.KeyCode); - - private static void OnKeyUp(object sender, KeyEventArgs e) - => pressedKeys.Remove(e.KeyCode); } diff --git a/STROOP/Utilities/HelpfulHintUtilities.cs b/STROOP/Utilities/HelpfulHintUtilities.cs index 70842857e..863027bba 100644 --- a/STROOP/Utilities/HelpfulHintUtilities.cs +++ b/STROOP/Utilities/HelpfulHintUtilities.cs @@ -29,16 +29,10 @@ public static class HelpfulHintUtilities // Left clicking while holding a key "Click on a variable while holding Z to zero that variable.", "Click on a variable while holding Escape to delete that variable.", - "Click on a variable while holding -/+ to decrement/increment that variable.", "Click on a variable while holding Alt to enable custom functionality for that variable, i.e. fixing its address, renaming, deleting.", "Click on a variable while holding Backtick to add that variable to the Var Hack tab, so that it can be displayed on screen.", "Click on a variable while holding H to highlight that variable.", - "Click on a variable while holding L to lock that variable.", - "Click on a variable while holding S to add that variable to the Custom tab.", - "Click on a variable while holding M to add that variable to the Memory tab.", "Click on a variable while holding P to add that variable to any tab of your choice.", - "Click on a variable while holding D to toggle display as hex.", - "Click on a variable while holding R to rename that variable.", "Click on a variable while holding C to open a controller for that variable.", "Click on a variable while holding Q to give that variable a custom background color.", "Click on a variable while holding O to give that variable the last custom color as its background color.", @@ -48,8 +42,6 @@ public static class HelpfulHintUtilities "Click on a variable while holding a number to highlight that variable with different colors.", "Click on a variable while holding Shift and a number to give that variable different background colors.", - "Click on an object slot while holding Alt to mark that slot. Then it will have a black border to help distinguish it.", - "Click on an object slot while holding Ctrl to toggle whether that slot is selected. You can use this to select multiple slots at once.", "Click on an object slot while holding Shift to select all slots from the one currently selected to the one you clicked on.", "When entering values for certain variables, hold Ctrl to toggle the behavior. For example, setting \"HDist Obj to Mario\" usually moves Mario, but holding Ctrl will move the object instead.", diff --git a/STROOP/Utilities/HexUtilities.cs b/STROOP/Utilities/HexUtilities.cs deleted file mode 100644 index 15e29827a..000000000 --- a/STROOP/Utilities/HexUtilities.cs +++ /dev/null @@ -1,61 +0,0 @@ -using STROOP.Structs; -using System; -using System.Collections.Generic; - -namespace STROOP.Utilities -{ - public static class HexUtilities - { - public static string FormatValue(object number, int? numDigits = null, bool usePrefix = true) - { - object numberFormatted = number; - - // Make sure it's a number - if (!TypeUtilities.IsNumber(numberFormatted)) - { - numberFormatted = ParsingUtilities.ParseDoubleNullable(numberFormatted); - if (numberFormatted == null) return number.ToString(); - } - - // Convert floats/doubles into ints/uints - if (numberFormatted is float || numberFormatted is double) - { - if (numberFormatted is float floatValue) numberFormatted = Math.Round(floatValue); - if (numberFormatted is double doubleValue) numberFormatted = Math.Round(doubleValue); - - int? intValueNullable = ParsingUtilities.ParseIntNullable(numberFormatted); - if (intValueNullable.HasValue) numberFormatted = intValueNullable.Value; - uint? uintValueNullable = ParsingUtilities.ParseUIntNullable(numberFormatted); - if (uintValueNullable.HasValue) numberFormatted = uintValueNullable.Value; - } - - if (!TypeUtilities.IsIntegerNumber(numberFormatted)) return number.ToString(); - - string numDigitsString = numDigits.HasValue ? numDigits.Value.ToString() : ""; - string hexString = String.Format("{0:X" + numDigitsString + "}", numberFormatted); - string prefix = usePrefix ? "0x" : ""; - if (numDigits.HasValue) - { - hexString = StringUtilities.ExactLength(hexString, numDigits.Value, true, '0'); - } - - return prefix + hexString; - } - - public static string FormatMemory(object number, int? numDigits = null, bool usePrefix = true) - { - if (number is bool boolValue) - number = boolValue ? 1 : 0; - if (!TypeUtilities.IsNumber(number)) throw new ArgumentOutOfRangeException(); - - byte[] bytes = TypeUtilities.GetBytes(number); - List byteList = new List(bytes); - byteList.Reverse(); - List stringList = byteList.ConvertAll(b => String.Format("{0:X2}", b)); - string byteString = String.Join("", stringList); - if (numDigits.HasValue) byteString = StringUtilities.ExactLength(byteString, numDigits.Value, true, '0'); - string prefix = usePrefix ? "0x" : ""; - return prefix + byteString; - } - } -} diff --git a/STROOP/Utilities/InGameFunctionCall.cs b/STROOP/Utilities/InGameFunctionCall.cs index e75c63cd8..53321a601 100644 --- a/STROOP/Utilities/InGameFunctionCall.cs +++ b/STROOP/Utilities/InGameFunctionCall.cs @@ -1,4 +1,5 @@ using STROOP.Structs.Configurations; +using STROOP.Variables.SM64MemoryLayout; namespace STROOP.Structs { diff --git a/STROOP/Utilities/InGameTrigUtilities.cs b/STROOP/Utilities/InGameTrigUtilities.cs index 24f403873..28f31c391 100644 --- a/STROOP/Utilities/InGameTrigUtilities.cs +++ b/STROOP/Utilities/InGameTrigUtilities.cs @@ -1,4 +1,5 @@ using STROOP.Structs.Configurations; +using STROOP.Variables.SM64MemoryLayout; using System; using System.Collections.Generic; using System.Linq; diff --git a/STROOP/Utilities/Kernal32NativeMethods.cs b/STROOP/Utilities/Kernal32NativeMethods.cs deleted file mode 100644 index e35dee2c3..000000000 --- a/STROOP/Utilities/Kernal32NativeMethods.cs +++ /dev/null @@ -1,208 +0,0 @@ -using System; -using System.Diagnostics; -using System.Runtime.InteropServices; - -namespace STROOP.Utilities -{ - public static class Kernal32NativeMethods - { - [Flags] - public enum ThreadAccess : int - { - TERMINATE = (0x0001), - SUSPEND_RESUME = (0x0002), - GET_CONTEXT = (0x0008), - SET_CONTEXT = (0x0010), - SET_INFORMATION = (0x0020), - QUERY_INFORMATION = (0x0040), - SET_THREAD_TOKEN = (0x0080), - IMPERSONATE = (0x0100), - DIRECT_IMPERSONATION = (0x0200) - } - - [Flags] - public enum ProcessAccess : int - { - VM_OPERATION = 0x0008, - VM_READ = 0x0010, - VM_WRITE = 0x0020, - PROCESS_QUERY_LIMITED_INFORMATION = 0x1000, - SUSPEND_RESUME = 0x0800, - } - - [Flags] - public enum MemoryType : uint - { - MEM_IMAGE = 0x1000000, - MEM_MAPPED = 0x40000, - MEM_PRIVATE = 0x20000 - } - - [StructLayout(LayoutKind.Sequential)] - public struct MemoryBasicInformation - { - public UIntPtr BaseAddress; - public IntPtr AllocationBase; - public uint AllocationProtect; - public IntPtr RegionSize; - public uint State; - public uint Protect; - public MemoryType Type; - } - - [StructLayout(LayoutKind.Sequential)] - public struct PsapiWorkingSetExInformation - { - public IntPtr VirtualAddress; - public ulong VirtualAttributes; - } - - /// - /// C# representation of SYMBOL_INFO in dbghelp.h. - /// https://learn.microsoft.com/de-de/windows/win32/api/dbghelp/ns-dbghelp-symbol_info - /// - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] - public struct Win32SymbolInfo - { - const int MaxSymbolLen = 2000; - - public static Win32SymbolInfo Create() - => new Win32SymbolInfo - { - MaxNameLen = MaxSymbolLen, - SizeOfStruct = 88 - }; - - public int SizeOfStruct; - public int TypeIndex; - readonly ulong Reserved1, Reserved2; - public int Index; - public int Size; - public ulong ModuleBase; - public uint Flags; - public long Value; - public ulong Address; - public uint Register; - public uint Scope; - public uint Tag; - public uint NameLen; - public int MaxNameLen; - - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MaxSymbolLen)] - public string Name; - } - - #region DLL Import - - [DllImport("kernel32.dll")] - static extern IntPtr OpenThread(ThreadAccess dwDesiredAccess, bool bInheritHandle, uint dwThreadId); - - [DllImport("kernel32.dll")] - static extern uint SuspendThread(IntPtr hThread); - - [DllImport("kernel32.dll")] - static extern int ResumeThread(IntPtr hThread); - - [DllImport("kernel32.dll")] - static extern bool CloseHandle(IntPtr hObject); - - [DllImport("kernel32.dll")] - static extern IntPtr OpenProcess(ProcessAccess dwDesiredAccess, bool bInheritHandle, int dwProcessId); - - [DllImport("kernel32.dll")] - static extern bool ReadProcessMemory(IntPtr hProcess, - UIntPtr lpBaseAddress, byte[] lpBuffer, IntPtr dwSize, ref int lpNumberOfBytesRead); - - [DllImport("kernel32.dll", SetLastError = true)] - static extern bool WriteProcessMemory(IntPtr hProcess, UIntPtr lpBaseAddress, - byte[] lpBuffer, IntPtr dwSize, ref int lpNumberOfBytesWritten); - - [DllImport("kernel32.dll")] - static extern IntPtr VirtualQueryEx(IntPtr hProcess, IntPtr lpAddress, out MemoryBasicInformation lpBuffer, IntPtr dwLength); - - [DllImport("psapi", SetLastError = true)] - static extern bool QueryWorkingSetEx(IntPtr hProcess, out PsapiWorkingSetExInformation pv, uint cb); - - [DllImport("dbghelp", SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "SymInitializeW", ExactSpelling = true)] - public static extern bool SymInitialize(IntPtr hProcess, string searchPath, bool invadeProcess); - - [DllImport("dbghelp", SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "SymCleanup", ExactSpelling = true)] - public static extern bool SymCleanup(IntPtr hProcess); - - [DllImport("dbghelp", SetLastError = true)] - public static extern bool SymFromName(IntPtr hProcess, string name, ref Win32SymbolInfo win32Symbol); - - [DllImport("kernel32.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool IsWow64Process([In] IntPtr process, [Out] out bool wow64Process); - - #endregion - - public static IntPtr ProcessGetHandleFromId(ProcessAccess dwDesiredAccess, bool bInheritHandle, int dwProcessId) - { - return OpenProcess(dwDesiredAccess, bInheritHandle, dwProcessId); - } - - public static bool CloseProcess(IntPtr processHandle) - { - return CloseHandle(processHandle); - } - - public static bool ProcessReadMemory(IntPtr hProcess, - UIntPtr lpBaseAddress, byte[] lpBuffer, IntPtr dwSize, ref int lpNumberOfBytesRead) - { - return ReadProcessMemory(hProcess, lpBaseAddress, lpBuffer, dwSize, ref lpNumberOfBytesRead); - } - - public static bool ProcessWriteMemory(IntPtr hProcess, UIntPtr lpBaseAddress, - byte[] lpBuffer, IntPtr dwSize, ref int lpNumberOfBytesWritten) - { - return WriteProcessMemory(hProcess, lpBaseAddress, lpBuffer, dwSize, ref lpNumberOfBytesWritten); - } - - public static void ResumeProcess(Process process) - { - // Resume all threads - foreach (ProcessThread pT in process.Threads) - { - IntPtr pOpenThread = OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint)pT.Id); - - if (pOpenThread == IntPtr.Zero) - continue; - - int suspendCount = 0; - do - { - suspendCount = ResumeThread(pOpenThread); - } while (suspendCount > 0); - - CloseHandle(pOpenThread); - } - } - - public static void SuspendProcess(Process process) - { - // Pause all threads - foreach (ProcessThread pT in process.Threads) - { - IntPtr pOpenThread = Kernal32NativeMethods.OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint)pT.Id); - - if (pOpenThread == IntPtr.Zero) - continue; - - SuspendThread(pOpenThread); - CloseHandle(pOpenThread); - } - } - - public static IntPtr VQueryEx(IntPtr hProcess, IntPtr lpAddress, out MemoryBasicInformation lpBuffer, IntPtr dwLength) - { - return VirtualQueryEx(hProcess, lpAddress, out lpBuffer, dwLength); - } - - public static bool QWorkingSetEx(IntPtr hProcess, out PsapiWorkingSetExInformation pv, uint cb) - { - return QueryWorkingSetEx(hProcess, out pv, cb); - } - } -} diff --git a/STROOP/Utilities/MathOperationUtilities.cs b/STROOP/Utilities/MathOperationUtilities.cs index 299a6de8e..1a7080976 100644 --- a/STROOP/Utilities/MathOperationUtilities.cs +++ b/STROOP/Utilities/MathOperationUtilities.cs @@ -5,69 +5,69 @@ namespace STROOP.Utilities { public static class MathOperationUtilities { - public static string GetSymbol(BinaryMathOperation operation, bool useX = true, bool useSlash = true) + public static string GetSymbol(BinaryOperationName operationName, bool useX = true, bool useSlash = true) { - switch (operation) + switch (operationName) { - case BinaryMathOperation.Add: + case BinaryOperationName.Add: return "+"; - case BinaryMathOperation.Subtract: + case BinaryOperationName.Subtract: return "-"; - case BinaryMathOperation.Multiply: + case BinaryOperationName.Multiply: return useX ? "×" : "*"; - case BinaryMathOperation.Divide: + case BinaryOperationName.Divide: return useSlash ? "/" : "÷"; - case BinaryMathOperation.Modulo: + case BinaryOperationName.Modulo: return "%"; - case BinaryMathOperation.NonNegativeModulo: + case BinaryOperationName.NonNegativeModulo: return "%%"; - case BinaryMathOperation.Exponent: + case BinaryOperationName.Exponent: return "^"; default: throw new ArgumentOutOfRangeException(); } } - public static string GetNoun(BinaryMathOperation operation) + public static string GetNoun(BinaryOperationName operationName) { - switch (operation) + switch (operationName) { - case BinaryMathOperation.Add: + case BinaryOperationName.Add: return "Addition"; - case BinaryMathOperation.Subtract: + case BinaryOperationName.Subtract: return "Subtraction"; - case BinaryMathOperation.Multiply: + case BinaryOperationName.Multiply: return "Multiplication"; - case BinaryMathOperation.Divide: + case BinaryOperationName.Divide: return "Division"; - case BinaryMathOperation.Modulo: + case BinaryOperationName.Modulo: return "Modulo"; - case BinaryMathOperation.NonNegativeModulo: + case BinaryOperationName.NonNegativeModulo: return "Non-Negative Modulo"; - case BinaryMathOperation.Exponent: + case BinaryOperationName.Exponent: return "Exponent"; default: throw new ArgumentOutOfRangeException(); } } - public static string GetResultName(BinaryMathOperation operation) + public static string GetResultName(BinaryOperationName operationName) { - switch (operation) + switch (operationName) { - case BinaryMathOperation.Add: + case BinaryOperationName.Add: return "Sum"; - case BinaryMathOperation.Subtract: + case BinaryOperationName.Subtract: return "Difference"; - case BinaryMathOperation.Multiply: + case BinaryOperationName.Multiply: return "Product"; - case BinaryMathOperation.Divide: + case BinaryOperationName.Divide: return "Quotient"; - case BinaryMathOperation.Modulo: + case BinaryOperationName.Modulo: return "Modulo"; - case BinaryMathOperation.NonNegativeModulo: + case BinaryOperationName.NonNegativeModulo: return "Non-Negative Modulo"; - case BinaryMathOperation.Exponent: + case BinaryOperationName.Exponent: return "Exponent"; default: throw new ArgumentOutOfRangeException(); diff --git a/STROOP/Utilities/MoreMath.cs b/STROOP/Utilities/MoreMath.cs index 8042eee37..8d919f0b1 100644 --- a/STROOP/Utilities/MoreMath.cs +++ b/STROOP/Utilities/MoreMath.cs @@ -4,789 +4,149 @@ using System.Collections.Generic; using System.Linq; using System.Text; -using OpenTK; using OpenTK.Mathematics; +using STROOP.Variables.SM64MemoryLayout; +using STROOP.Variables.Utilities; -namespace STROOP.Utilities +namespace STROOP.Utilities; + +public static class STROOPMath { - public static class MoreMath + public static Vector2 Min(Vector2 min, Vector2 @new) => new Vector2(Math.Min(min.X, @new.X), Math.Min(min.Y, @new.Y)); + public static Vector2 Max(Vector2 max, Vector2 @new) => new Vector2(Math.Max(max.X, @new.X), Math.Max(max.Y, @new.Y)); + public static Vector3 Min(Vector3 min, Vector3 @new) => new Vector3(Math.Min(min.X, @new.X), Math.Min(min.Y, @new.Y), Math.Min(min.Z, @new.Z)); + public static Vector3 Max(Vector3 max, Vector3 @new) => new Vector3(Math.Max(max.X, @new.X), Math.Max(max.Y, @new.Y), Math.Max(max.Z, @new.Z)); + + public static double GetSignedDistanceFromPointToLine( + double pX, double pZ, double v1X, double v1Z, double v2X, double v2Z, double v3X, double v3Z, int p1Index, int p2Index, + TriangleClassification classification, bool? misalignmentOffsetNullable = null) { - public static float EaseIn(float f) => 1 - 1 / (float)Math.Exp(f); + pX = PuUtilities.GetRelativeCoordinate(pX); + pZ = PuUtilities.GetRelativeCoordinate(pZ); - public static int Sign(double value) - { - if (value == 0 || double.IsNaN(value)) return 0; - return value > 0 ? 1 : -1; - } + double[] vX = new double[] { v1X, v2X, v3X }; + double[] vZ = new double[] { v1Z, v2Z, v3Z }; - public static Vector2 Min(Vector2 min, Vector2 @new) => new Vector2(Math.Min(min.X, @new.X), Math.Min(min.Y, @new.Y)); - public static Vector2 Max(Vector2 max, Vector2 @new) => new Vector2(Math.Max(max.X, @new.X), Math.Max(max.Y, @new.Y)); - public static Vector3 Min(Vector3 min, Vector3 @new) => new Vector3(Math.Min(min.X, @new.X), Math.Min(min.Y, @new.Y), Math.Min(min.Z, @new.Z)); - public static Vector3 Max(Vector3 max, Vector3 @new) => new Vector3(Math.Max(max.X, @new.X), Math.Max(max.Y, @new.Y), Math.Max(max.Z, @new.Z)); + double p1X = vX[p1Index - 1]; + double p1Z = vZ[p1Index - 1]; + double p2X = vX[p2Index - 1]; + double p2Z = vZ[p2Index - 1]; - public static int Min(params int[] values) - { - if (values.Length == 0) return 0; - int min = values[0]; - for (int i = 1; i < values.Length; i++) - { - if (values[i] < min) min = values[i]; - } + double dist = MoreMath.GetDistanceFromPointToLine(pX, pZ, p1X, p1Z, p2X, p2Z); + bool leftOfLine = MoreMath.IsPointLeftOfLine(pX, pZ, p1X, p1Z, p2X, p2Z); + bool floorTri = MoreMath.IsPointLeftOfLine(v3X, v3Z, v1X, v1Z, v2X, v2Z); + bool onSideOfLineTowardsTri = floorTri == leftOfLine; + double signedDist = dist * (onSideOfLineTowardsTri ? 1 : -1); - return min; - } - - public static int Max(params int[] values) + bool misalignmentOffset = misalignmentOffsetNullable ?? SavedSettingsConfig.UseMisalignmentOffsetForDistanceToLine; + if (misalignmentOffset && classification != TriangleClassification.Wall) { - if (values.Length == 0) return 0; - int max = values[0]; - for (int i = 1; i < values.Length; i++) + if (p1X == p2X) { - if (values[i] > max) max = values[i]; - } - - return max; - } - - public static double Min(params double[] values) - { - if (values.Length == 0) return 0; - double min = values[0]; - for (int i = 1; i < values.Length; i++) - { - if (values[i] < min) min = values[i]; - } - - return min; - } - - public static double Max(params double[] values) - { - if (values.Length == 0) return 0; - double max = values[0]; - for (int i = 1; i < values.Length; i++) - { - if (values[i] > max) max = values[i]; - } - - return max; - } - - public static double Average(params double[] values) - { - if (values.Length == 0) return 0; - double sum = 0; - for (int i = 0; i < values.Length; i++) - { - sum += values[i]; - } - - return sum / values.Length; - } - - public static double GetHypotenuse(double x, double y) - { - return Math.Sqrt(x * x + y * y); - } - - public static double GetHypotenuse(double x, double y, double z) - { - return Math.Sqrt(x * x + y * y + z * z); - } - - public static double GetDistanceBetween(double x1, double y1, double z1, double x2, double y2, double z2) - { - double dx, dy, dz; - dx = x1 - x2; - dy = y1 - y2; - dz = z1 - z2; - return Math.Sqrt(dx * dx + dy * dy + dz * dz); - } - - public static double GetDistanceBetween(double x1, double z1, double x2, double z2) - { - double dx, dz; - dx = x1 - x2; - dz = z1 - z2; - return Math.Sqrt(dx * dx + dz * dz); - } - - public static (double xDist, double zDist) GetComponentsFromVector(double magnitude, double angle) - { - double radians = AngleUnitsToRadians(angle); - double xComponent = Math.Sin(radians); - double zComponent = Math.Cos(radians); - return (magnitude * xComponent, magnitude * zComponent); - } - - public static (double xDist, double zDist) AddVectorToPoint( - double magnitude, double angle, double x1, double z1) - { - (double xDist, double zDist) = GetComponentsFromVector(magnitude, angle); - return (x1 + xDist, z1 + zDist); - } - - public static (double sidewaysDist, double forwardsDist) GetComponentsFromVectorRelatively( - double magnitude, double vectorAngle, double baseAngle) - { - double rotatedAngle = NormalizeAngleDouble(vectorAngle - baseAngle); - (double xComponent, double zComponent) = GetComponentsFromVector(magnitude, rotatedAngle); - return (-1 * xComponent, zComponent); - } - - public static (double sidewaysDist, double forwardsDist) GetSidewaysAndForwardsDist( - double x1, double z1, double x2, double z2, double baseAngle) - { - double hDist = GetDistanceBetween(x1, z1, x2, z2); - double angle = AngleTo_AngleUnits(x1, z1, x2, z2); - return GetComponentsFromVectorRelatively(hDist, angle, baseAngle); - } - - public static (double xDist, double zDist) GetAbsoluteComponents( - double sidewaysDist, double forwardsDist, double relativeAngle) - { - double relX = sidewaysDist; - double relZ = -1 * forwardsDist; - double relDist = GetHypotenuse(relX, relZ); - double relAngle = AngleTo_AngleUnits(relX, relZ); - double absAngle = relativeAngle + ReverseAngle(relAngle); - return GetComponentsFromVector(relDist, absAngle); - } - - public static (double newXPos, double newZPos) GetRelativelyOffsettedPosition( - double baseX, double baseZ, double baseAngle, double pointX, double pointZ, - double? goalSidewaysDistNullable, double? goalForwardsDistNullable) - { - double hdist = GetDistanceBetween(baseX, baseZ, pointX, pointZ); - double angle = AngleTo_AngleUnits(baseX, baseZ, pointX, pointZ); - (double currentSidewaysDist, double currentForwardsDist) = - GetComponentsFromVectorRelatively(hdist, angle, baseAngle); - - double goalSidewaysDist = goalSidewaysDistNullable ?? currentSidewaysDist; - double goalForwardsDist = goalForwardsDistNullable ?? currentForwardsDist; - - (double xDist, double zDist) = GetAbsoluteComponents(goalSidewaysDist, goalForwardsDist, baseAngle); - return (baseX + xDist, baseZ + zDist); - } - - public static (double magnitude, double angle) GetVectorFromComponents(double xDist, double zDist) - { - double magnitude = Math.Sqrt(xDist * xDist + zDist * zDist); - double angle = AngleTo_AngleUnits(0, 0, xDist, zDist); - return (magnitude, angle); - } - - public static (double magnitude, double angle) GetVectorFromCoordinates( - double xFrom, double zFrom, double xTo, double zTo, bool usePositiveMagnitude) - { - double xDist = xTo - xFrom; - double zDist = zTo - zFrom; - (double magnitude, double angle) = GetVectorFromComponents(xDist, zDist); - double adjustedMagnitude = usePositiveMagnitude ? magnitude : -1 * magnitude; - double adjustedAngle = usePositiveMagnitude ? angle : ReverseAngle(angle); - return (adjustedMagnitude, adjustedAngle); - } - - public static (double x, double y, double z) ScaleVector3D( - double xComp, double yComp, double zComp, double finalDist) - { - double magnitude = GetHypotenuse(xComp, yComp, zComp); - if (magnitude == 0) return (finalDist, 0, 0); - double multiplier = finalDist / magnitude; - return (xComp * multiplier, yComp * multiplier, zComp * multiplier); - } - - public static (double x, double z) ScaleVector2D( - double xComp, double zComp, double finalDist) - { - double magnitude = GetHypotenuse(xComp, zComp); - if (magnitude == 0) return (finalDist, 0); - double multiplier = finalDist / magnitude; - return (xComp * multiplier, zComp * multiplier); - } - - public static double ScaleVector1D( - double xComp, double finalDist) - { - return xComp >= 0 ? finalDist : -1 * finalDist; - } - - public static (double x, double y, double z) ExtrapolateLine3D( - double p1X, double p1Y, double p1Z, double p2X, double p2Y, double p2Z, double finalDist) - { - double diffX = p2X - p1X; - double diffY = p2Y - p1Y; - double diffZ = p2Z - p1Z; - (double scaledX, double scaledY, double scaledZ) = ScaleVector3D(diffX, diffY, diffZ, finalDist); - return (p1X + scaledX, p1Y + scaledY, p1Z + scaledZ); - } - - public static (double x, double z) ExtrapolateLine2D( - double p1X, double p1Z, double p2X, double p2Z, double finalDist) - { - double diffX = p2X - p1X; - double diffZ = p2Z - p1Z; - (double scaledX, double scaledZ) = ScaleVector2D(diffX, diffZ, finalDist); - return (p1X + scaledX, p1Z + scaledZ); - } - - public static double GetPositionAlongLine(double p1X, double p1Y, double p2X, double p2Y, double x) - { - double slope = (p2Y - p1Y) / (p2X - p1X); - return (x - p1X) * slope + p1Y; - } - - /** p2 is pivot. */ - public static (double x, double z) RotatePointAboutPointToAngle( - double p1X, double p1Z, double p2X, double p2Z, double finalAngle) - { - double dist = GetDistanceBetween(p1X, p1Z, p2X, p2Z); - (double xDiff, double zDiff) = GetComponentsFromVector(dist, finalAngle); - return (p2X + xDiff, p2Z + zDiff); - } - - /** p2 is pivot. */ - public static (double x, double z) RotatePointAboutPointAnAngularDistance( - double p1X, double p1Z, double p2X, double p2Z, double angularDistance) - { - double dist = GetDistanceBetween(p1X, p1Z, p2X, p2Z); - double angle = AngleTo_AngleUnits(p1X, p1Z, p2X, p2Z); - (double xDiff, double zDiff) = GetComponentsFromVector(dist, angle + angularDistance); - return (p2X + xDiff, p2Z + zDiff); - } - - public static double GetDistanceFromPointToLine( - double pX, double pZ, double v1X, double v1Z, double v2X, double v2Z) - { - double numerator = Math.Abs((v2Z - v1Z) * pX - (v2X - v1X) * pZ + v2X * v1Z - v2Z * v1X); - double denominator = GetDistanceBetween(v1X, v1Z, v2X, v2Z); - return numerator / denominator; - } - - public static double GetSignedDistanceFromPointToLine( - double pX, double pZ, double v1X, double v1Z, double v2X, double v2Z, double v3X, double v3Z, int p1Index, int p2Index, - TriangleClassification classification, bool? misalignmentOffsetNullable = null) - { - pX = PuUtilities.GetRelativeCoordinate(pX); - pZ = PuUtilities.GetRelativeCoordinate(pZ); - - double[] vX = new double[] { v1X, v2X, v3X }; - double[] vZ = new double[] { v1Z, v2Z, v3Z }; - - double p1X = vX[p1Index - 1]; - double p1Z = vZ[p1Index - 1]; - double p2X = vX[p2Index - 1]; - double p2Z = vZ[p2Index - 1]; - - double dist = MoreMath.GetDistanceFromPointToLine(pX, pZ, p1X, p1Z, p2X, p2Z); - bool leftOfLine = MoreMath.IsPointLeftOfLine(pX, pZ, p1X, p1Z, p2X, p2Z); - bool floorTri = MoreMath.IsPointLeftOfLine(v3X, v3Z, v1X, v1Z, v2X, v2Z); - bool onSideOfLineTowardsTri = floorTri == leftOfLine; - double signedDist = dist * (onSideOfLineTowardsTri ? 1 : -1); - - bool misalignmentOffset = misalignmentOffsetNullable ?? SavedSettingsConfig.UseMisalignmentOffsetForDistanceToLine; - if (misalignmentOffset && classification != TriangleClassification.Wall) - { - if (p1X == p2X) + bool thirdPointOnLeft = p1Z >= p2Z == floorTri; + if ((thirdPointOnLeft && p1X >= 0) || (!thirdPointOnLeft && p1X <= 0)) { - bool thirdPointOnLeft = p1Z >= p2Z == floorTri; - if ((thirdPointOnLeft && p1X >= 0) || (!thirdPointOnLeft && p1X <= 0)) - { - signedDist += 1; - } - } - else if (p1Z == p2Z) - { - bool thirdPointOnTop = p1X <= p2X == floorTri; - if ((thirdPointOnTop && p1Z >= 0) || (!thirdPointOnTop && p1Z <= 0)) - { - signedDist += 1; - } + signedDist += 1; } } - - return signedDist; - } - - public static bool IsPointInsideTriangle( - double pX, double pZ, double v1X, double v1Z, double v2X, double v2Z, double v3X, double v3Z) - { - bool leftOf12 = IsPointLeftOfLine(pX, pZ, v1X, v1Z, v2X, v2Z); - bool leftOf23 = IsPointLeftOfLine(pX, pZ, v2X, v2Z, v3X, v3Z); - bool leftOf31 = IsPointLeftOfLine(pX, pZ, v3X, v3Z, v1X, v1Z); - - bool rightOf12 = IsPointRightOfLine(pX, pZ, v1X, v1Z, v2X, v2Z); - bool rightOf23 = IsPointRightOfLine(pX, pZ, v2X, v2Z, v3X, v3Z); - bool rightOf31 = IsPointRightOfLine(pX, pZ, v3X, v3Z, v1X, v1Z); - - return (leftOf12 && leftOf23 && leftOf31) || (rightOf12 && rightOf23 && rightOf31); - } - - public static bool IsPointLeftOfLine( - double pX, double pZ, double v1X, double v1Z, double v2X, double v2Z) - { - return (v1Z - pZ) * (v2X - v1X) >= (v1X - pX) * (v2Z - v1Z); - } - - public static bool IsPointRightOfLine( - double pX, double pZ, double v1X, double v1Z, double v2X, double v2Z) - { - return (v1Z - pZ) * (v2X - v1X) <= (v1X - pX) * (v2Z - v1Z); - } - - public static double GetPlaneDistanceBetweenPoints( - double pointX, double pointY, double pointZ, double startX, double startY, double startZ, double endX, double endY, double endZ) - { - double startToPointX = pointX - startX; - double startToPointY = pointY - startY; - double startToPointZ = pointZ - startZ; - double startToEndX = endX - startX; - double startToEndY = endY - startY; - double startToEndZ = endZ - startZ; - - double dotProduct = GetDotProduct(startToPointX, startToPointY, startToPointZ, startToEndX, startToEndY, startToEndZ); - double prevToNextDist = GetDistanceBetween(startX, startY, startZ, endX, endY, endZ); - double planeDistance = dotProduct / prevToNextDist; - - return planeDistance; - } - - public static double ReflectValueAboutValue(double value, double pivot) - { - double diff = pivot - value; - return pivot + diff; - } - - public static double NormalizeAngleDouble(double angle) - { - return NonNegativeModulus(angle, 65536); - } - - public static double NormalizeAngleDoubleSigned(double angle) - { - return MaybeNegativeModulus(angle, 65536); - } - - public static ushort NormalizeAngleUshort(double angle) - { - double nonNegative = NormalizeAngleDouble(angle); - return (ushort)(Math.Round(nonNegative) % 65536); - } - - public static short NormalizeAngleShort(double angle) - { - ushort angleUshort = NormalizeAngleUshort(angle); - short angleShort; - if (angleUshort > 32767) - { - angleShort = (short)(angleUshort - 65536); - } - else + else if (p1Z == p2Z) { - angleShort = (short)angleUshort; + bool thirdPointOnTop = p1X <= p2X == floorTri; + if ((thirdPointOnTop && p1Z >= 0) || (!thirdPointOnTop && p1Z <= 0)) + { + signedDist += 1; + } } - - return angleShort; } - public static ushort NormalizeAngleTruncated(double angle) - { - angle = NormalizeAngleDouble(angle); - ushort angleUshort = (ushort)angle; - ushort angleTruncated = (ushort)(angleUshort - (angleUshort % 16)); - return angleTruncated; - } - - public static double NormalizeAngleUsingType(double angle, Type type) - { - if (type == typeof(short)) return MaybeNegativeModulus(angle, 1.0 + short.MaxValue - short.MinValue); - if (type == typeof(ushort)) return NonNegativeModulus(angle, 1.0 + ushort.MaxValue - ushort.MinValue); - if (type == typeof(int)) return MaybeNegativeModulus(angle, 1.0 + int.MaxValue - int.MinValue); - if (type == typeof(uint)) return NonNegativeModulus(angle, 1.0 + uint.MaxValue - uint.MinValue); - throw new ArgumentOutOfRangeException("Cannot call NormalizeAngleUsingType with type " + type); - } - - public static double NormalizeAngle45Degrees(double angle) - { - int divided = NormalizeAngleUshort(angle + 4096) / 8192; - return divided * 8192; - } - - public static double AngleTo_Radians(double xFrom, double zFrom, double xTo, double zTo) - { - return Math.Atan2(xTo - xFrom, zTo - zFrom); - } - - public static double AngleTo_Radians(double xTo, double zTo) - { - return AngleTo_Radians(0, 0, xTo, zTo); - } - - public static double AngleTo_AngleUnits(double xFrom, double zFrom, double xTo, double zTo) - { - return RadiansToAngleUnits(AngleTo_Radians(xFrom, zFrom, xTo, zTo)); - } - - public static double AngleTo_AngleUnits(double xTo, double zTo) - { - return AngleTo_AngleUnits(0, 0, xTo, zTo); - } - - public static double? AngleTo_AngleUnitsNullable(double xTo, double zTo) - { - if (xTo == 0 && zTo == 0) return null; - return AngleTo_AngleUnits(0, 0, xTo, zTo); - } - - public static ushort AngleTo_AngleUnitsRounded(double xFrom, double zFrom, double xTo, double zTo) - { - return RadiansToAngleUnitsRounded(AngleTo_Radians(xFrom, zFrom, xTo, zTo)); - } - - public static ushort AngleTo_AngleUnitsRounded(double xTo, double zTo) - { - return AngleTo_AngleUnitsRounded(0, 0, xTo, zTo); - } - - public static (double radius, double theta, double phi) EulerToSpherical_Radians(double x, double y, double z) - { - double radius = Math.Sqrt(x * x + y * y + z * z); - double theta = Math.Atan2(x, z); - double phi = radius == 0 ? 0 : Math.Asin(y / radius); - return (radius, theta, phi); - } - - public static (double radius, double theta, double phi) EulerToSpherical_AngleUnits(double x, double y, double z) - { - double radius, thetaRadians, phiRadians; - (radius, thetaRadians, phiRadians) = EulerToSpherical_Radians(x, y, z); - double thetaAngleUnits = RadiansToAngleUnits(thetaRadians); - double phiAngleUnits = RadiansToAngleUnits(phiRadians); - return (radius, thetaAngleUnits, phiAngleUnits); - } - - public static (double x, double y, double z) SphericalToEuler_Radians(double radius, double theta, double phi) - { - double x = radius * Math.Sin(theta) * Math.Cos(phi); - double y = radius * Math.Sin(phi); - double z = radius * Math.Cos(theta) * Math.Cos(phi); - return (x, y, z); - } - - public static (double x, double y, double z) SphericalToEuler_AngleUnits(double radius, double thetaAngleUnits, double phiAngleUnits) - { - double thetaRadians = AngleUnitsToRadians(thetaAngleUnits); - double phiRadians = AngleUnitsToRadians(phiAngleUnits); - return SphericalToEuler_Radians(radius, thetaRadians, phiRadians); - } - - public static (double radius, double theta, double height) EulerToCylindrical_Radians(double x, double y, double z) - { - double radius = Math.Sqrt(x * x + z * z); - double theta = Math.Atan2(x, z); - double height = y; - return (radius, theta, height); - } - - public static (double x, double y, double z) CylindricalToEuler_Radians(double radius, double theta, double height) - { - double x = radius * Math.Sin(theta); - double y = height; - double z = radius * Math.Cos(theta); - return (x, y, z); - } - - public static (double radius, double thetaAngleUnits, double height) EulerToCylindrical_AngleUnits(double x, double y, double z) - { - double radius, thetaRadians, height; - (radius, thetaRadians, height) = EulerToCylindrical_Radians(x, y, z); - double thetaAngleUnits = RadiansToAngleUnits(thetaRadians); - return (radius, thetaAngleUnits, height); - } - - public static (double x, double y, double z) CylindricalToEuler_AngleUnits(double radius, double thetaAngleUnits, double height) - { - double thetaRadians = AngleUnitsToRadians(thetaAngleUnits); - return CylindricalToEuler_Radians(radius, thetaRadians, height); - } - - public static (double radius, double thetaAngleUnits, double height) EulerToCylindricalAboutPivot( - double x, double y, double z, double pivotX, double pivotY, double pivotZ) - { - return EulerToCylindrical_AngleUnits(x - pivotX, y - pivotY, z - pivotZ); - } - - public static double GetPitch(double startX, double startY, double startZ, double endX, double endY, double endZ) - { - (double radius, double theta, double phi) = EulerToSpherical_AngleUnits(endX - startX, endY - startY, endZ - startZ); - return phi; - } - - public static double RadiansToAngleUnits(double radians) - { - double angleUnits = radians / (2 * Math.PI) * 65536; - return NonNegativeModulus(angleUnits, 65536); - } - - public static ushort RadiansToAngleUnitsRounded(double radians) - { - double angleUnits = radians / (2 * Math.PI) * 65536; - double nonNegative = NonNegativeModulus(angleUnits, 65536); - return (ushort)(Math.Round(nonNegative) % 65536); - } - - public static double AngleUnitsToRadians(double angleUnits) - { - double radians = angleUnits / 65536 * (2 * Math.PI); - return NonNegativeModulus(radians, 2 * Math.PI); - } - - public static double AngleUnitsToDegrees(double angleUnits) - { - double radians = angleUnits / 65536 * 360; - return NonNegativeModulus(radians, 360); - } - - public static double RotateAngleCCW(double angleUnits, double rotationDiff) - { - return NormalizeAngleDouble(angleUnits + rotationDiff); - } - - public static double RotateAngleCW(double angleUnits, double rotationDiff) - { - return RotateAngleCCW(angleUnits, -1 * rotationDiff); - } - - public static double ReverseAngle(double angleUnits) - { - return RotateAngleCCW(angleUnits, 32768); - } - - public static (double x, double y, double z) OffsetSpherically( - double x, double y, double z, double radiusChange, double thetaChangeAngleUnits, double phiChangeAngleUnits) - { - double oldRadius, oldTheta, oldPhi; - (oldRadius, oldTheta, oldPhi) = EulerToSpherical_AngleUnits(x, y, z); - - double newRadius = Math.Max(oldRadius + radiusChange, 0); - double newTheta = NonNegativeModulus(oldTheta + thetaChangeAngleUnits, 65536); - double newPhi = Clamp(NormalizeAngleDoubleSigned(oldPhi) + phiChangeAngleUnits, -16384, 16384); - - return SphericalToEuler_AngleUnits(newRadius, newTheta, newPhi); - } - - public static (double x, double y, double z) OffsetSphericallyAboutPivot( - double x, double y, double z, double radiusChange, double thetaChangeAngleUnits, double phiChangeAngleUnits, - double pivotX, double pivotY, double pivotZ) - { - double oldRelX = x - pivotX; - double oldRelY = y - pivotY; - double oldRelZ = z - pivotZ; - - double newRelX, newRelY, newRelZ; - (newRelX, newRelY, newRelZ) = - OffsetSpherically(oldRelX, oldRelY, oldRelZ, radiusChange, thetaChangeAngleUnits, phiChangeAngleUnits); - - return (newRelX + pivotX, newRelY + pivotY, newRelZ + pivotZ); - } - - public static double OffsetAngleUnitsCapped(double angleUnits, double change) - { - angleUnits = NonNegativeModulus(angleUnits, 65536); - angleUnits = Clamp(angleUnits + change, 0, 65536); - angleUnits = NonNegativeModulus(angleUnits, 65536); - return angleUnits; - } - - /** Gets the value in [0, modulus). */ - public static int NonNegativeModulus(int value, int modulus) - { - value %= modulus; - if (value < 0) value += modulus; - return value; - } - - /** Gets the value in [0, modulus). */ - public static double NonNegativeModulus(double value, double modulus) - { - value %= modulus; - if (value < 0) value += modulus; - return value; - } - - /** Gets the value in [-modulus/2, modulus/2). */ - public static double MaybeNegativeModulus(double value, double modulus) - { - value %= modulus; - if (value < 0) value += modulus; - if (value >= modulus / 2) value -= modulus; - return value; - } - - /** Rounds and then wraps the value to be in [-range/2, range/2) if signed or [0, range) if unsigned. */ - public static double GetIntegerInRangeWrapped(double value, double range, bool signed) - { - value = Math.Round(value, MidpointRounding.AwayFromZero); - return signed ? MaybeNegativeModulus(value, range) : NonNegativeModulus(value, range); - } - - /** Rounds and then caps the value to be in [-range/2, range/2) if signed or [0, range) if unsigned. */ - public static double GetIntegerInRangeCapped(double value, double range, bool signed) - { - value = Math.Round(value, MidpointRounding.AwayFromZero); - double min = signed ? -1 * range / 2 : 0; - double exclusiveMax = signed ? range / 2 : range; - double inclusiveMax = exclusiveMax - 1; - return Clamp(value, min, inclusiveMax); - } - - public static double GetUnsignedAngleDifference(double angle1, double angle2) - { - return NonNegativeModulus(angle2 - angle1, 65536); - } - - public static double GetAngleDifference(double angle1, double angle2) - { - return MaybeNegativeModulus(angle2 - angle1, 65536); - } - - public static double GetAngleDistance(double angle1, double angle2) - { - return Math.Abs(GetAngleDifference(angle1, angle2)); - } - - public static bool IsAngleBetweenAngles(double angle, double angleMin, double angleMax) - { - double effectiveAngle = NonNegativeModulus(angle - angleMin, 65536); - double effectiveRange = NonNegativeModulus(angleMax - angleMin, 65536); - return effectiveAngle <= effectiveRange; - } - - public static double Clamp(double value, double min, double max) - { - return Math.Min(Math.Max(value, min), max); - } - - public static int Clamp(int value, int min, int max) - { - return Math.Min(Math.Max(value, min), max); - } - - public static double TruncateToMultipleOf16(double value) - { - double divided = value / 16; - double truncated = Math.Floor(divided); - double multipled = truncated * 16; - return multipled; - } + return signedDist; + } - public static string GetPercentString(double count, double total, int decimalPlaces) + public static string GetBitString(byte b) + { + StringBuilder builder = new StringBuilder(); + for (int i = 7; i >= 0; i--) { - double percent = Math.Round(100 * count / total, decimalPlaces); - string percentString = percent.ToString("N" + decimalPlaces) + "%"; - return percentString; + bool bit = (b & (1 << i)) != 0; + builder.Append(bit ? "1" : "0"); } - public static (double scaledX, double scaledZ) ScaleValues(double xValue, double zValue) - { - double magnitude = Math.Max(Math.Abs(xValue), Math.Abs(zValue)); - double totalMagnitude = Math.Sqrt(xValue * xValue + zValue * zValue); - double multiplier = totalMagnitude == 0 ? 1 : magnitude / totalMagnitude; - return (xValue * multiplier, zValue * multiplier); - } + return builder.ToString(); + } - public static ushort getUphillAngle(double normX, double normY, double normZ) - { - var uphillRadians = Math.PI + Math.Atan2(normX, normZ); - if (normY < -0.01) - uphillRadians += Math.PI; - if (normX == 0 && normZ == 0) - uphillRadians = 0; - return RadiansToAngleUnitsRounded(uphillRadians); - } + public static string GetBitString(object value) + { + List bitStrings = TypeUtilities.GetBytes(value).ToList().ConvertAll(b => GetBitString(b)); + bitStrings.Reverse(); + return String.Join("", bitStrings); + } - public static byte ApplyValueToMaskedByte(byte currentValue, byte mask, byte valueToSet) - { - byte maskedValueToSet = (byte)(valueToSet & mask); - byte unmaskedCurrentValue = (byte)(currentValue & ~mask); - byte newValue = (byte)(unmaskedCurrentValue | maskedValueToSet); - return newValue; - } + // Float stuff - public static byte ApplyValueToMaskedByte(byte currentValue, byte mask, bool useWholeMask) - { - return ApplyValueToMaskedByte(currentValue, mask, useWholeMask ? mask : (byte)0); - } + public static int GetFloatSign(float floatValue) + { + string bitString = GetBitString(floatValue); + string signChar = bitString.Substring(0, 1); + return signChar == "0" ? 1 : -1; + } - public static double RotateAngleTowards(double angle1, double angle2, double cap) + public static int GetFloatExponent(float floatValue) + { + string bitString = GetBitString(floatValue); + string exponentString = bitString.Substring(1, 8); + int byteValue = 0; + for (int i = 0; i < 8; i++) { - angle1 = NormalizeAngleDouble(angle1); - angle2 = NormalizeAngleDouble(angle2); - double angle12Diff = NormalizeAngleDouble(angle1 - angle2); - double angle21Diff = NormalizeAngleDouble(angle2 - angle1); - double rotationDiff = Math.Min(cap, Math.Min(angle12Diff, angle21Diff)); - bool angle1Less = angle21Diff <= angle12Diff; - double newAngle = angle1 + (angle1Less ? 1 : -1) * rotationDiff; - return NormalizeAngleDouble(newAngle); + string bitChar = exponentString.Substring(8 - 1 - i, 1); + bool bitBool = bitChar == "1"; + if (bitBool) byteValue = (byte)(byteValue | (1 << i)); } - public static double MoveNumberTowards(double start, double end, double cap) - { - bool startLessThanEnd = start < end; - double diff = Math.Abs(end - start); - double cappedDiff = Math.Min(diff, cap); - double moved = start + (startLessThanEnd ? 1 : -1) * cappedDiff; - return moved; - } + int exponent = byteValue - 127; + return exponent; + } - public static double GetDotProduct(double v1X, double v1Y, double v1Z, double v2X, double v2Y, double v2Z) + public static double GetFloatMantissa(float floatValue) + { + string bitString = GetBitString(floatValue); + string exponentString = bitString.Substring(9, 23); + double sum = 1; + double multiplier = 1; + for (int i = 0; i < 23; i++) { - return v1X * v2X + v1Y * v2Y + v1Z * v2Z; + multiplier *= 0.5; + string bitChar = exponentString.Substring(i, 1); + bool bitBool = bitChar == "1"; + if (bitBool) sum += multiplier; } - // Input angle stuff - - public static (float effectiveX, float effectiveY) GetEffectiveInput(int rawX, int rawY) - { - float effectiveX = rawX >= 8 ? rawX - 6 : rawX <= -8 ? rawX + 6 : 0; - float effectiveY = rawY >= 8 ? rawY - 6 : rawY <= -8 ? rawY + 6 : 0; - float hypotenuse = (float)Math.Sqrt(effectiveX * effectiveX + effectiveY * effectiveY); - if (hypotenuse > 64) - { - effectiveX *= 64 / hypotenuse; - effectiveY *= 64 / hypotenuse; - } - - return (effectiveX, effectiveY); - } + return sum; + } - public static float GetEffectiveInputMagnitudeUncapped(int rawX, int rawY) - { - int effectiveX = rawX >= 8 ? rawX - 6 : rawX <= -8 ? rawX + 6 : 0; - int effectiveY = rawY >= 8 ? rawY - 6 : rawY <= -8 ? rawY + 6 : 0; - return (float)Math.Sqrt(effectiveX * effectiveX + effectiveY * effectiveY); - } + public static ushort CalculateAngleFromInputs(int xInput, int yInput, ushort? cameraAngleNullable = null) + { + (float effectiveX, float effectiveY) = GetEffectiveInput(xInput, yInput); + ushort marioAngle = InGameTrigUtilities.InGameATan(effectiveY, -effectiveX); + ushort cameraAngleRaw = cameraAngleNullable ?? Config.Stream.GetUInt16(CameraConfig.StructAddress + CameraConfig.CentripetalAngleOffset); + ushort cameraAngle = MoreMath.NormalizeAngleUshort(MoreMath.ReverseAngle(cameraAngleRaw)); + ushort summedAngle = MoreMath.NormalizeAngleUshort(marioAngle + cameraAngle); + return summedAngle; + } - public static float GetEffectiveInputMagnitude(int rawX, int rawY) + public static (float effectiveX, float effectiveY) GetEffectiveInput(int rawX, int rawY) + { + float effectiveX = rawX >= 8 ? rawX - 6 : rawX <= -8 ? rawX + 6 : 0; + float effectiveY = rawY >= 8 ? rawY - 6 : rawY <= -8 ? rawY + 6 : 0; + float hypotenuse = (float)Math.Sqrt(effectiveX * effectiveX + effectiveY * effectiveY); + if (hypotenuse > 64) { - int effectiveX = rawX >= 8 ? rawX - 6 : rawX <= -8 ? rawX + 6 : 0; - int effectiveY = rawY >= 8 ? rawY - 6 : rawY <= -8 ? rawY + 6 : 0; - float hypotenuse = (float)Math.Sqrt(effectiveX * effectiveX + effectiveY * effectiveY); - return Math.Min(hypotenuse, 64f); + effectiveX *= 64 / hypotenuse; + effectiveY *= 64 / hypotenuse; } - public static float GetScaledInputMagnitude(int rawX, int rawY, bool squished) - { - float effectiveMagnitude = GetEffectiveInputMagnitude(rawX, rawY); - float scaled = (effectiveMagnitude / 64f) * (effectiveMagnitude / 64f) * 64f; - int divider = squished ? 8 : 2; - return scaled / divider; - } + return (effectiveX, effectiveY); + } - public static bool InputIsInDeadZone(int input) - { - return input > -8 && input < 8 && input != 0; - } public static (int xInput, int yInput) CalculateInputsForAngle(ushort goalAngle, ushort cameraAngle) { @@ -794,18 +154,18 @@ public static (int xInput, int yInput) CalculateInputsForAngle(ushort goalAngle, int bestX = 0; int bestY = 0; - ushort truncatedGoalAngle = NormalizeAngleTruncated(goalAngle); + ushort truncatedGoalAngle = MoreMath.NormalizeAngleTruncated(goalAngle); for (int x = -128; x <= 127; x++) { - if (InputIsInDeadZone(x)) continue; + if (MoreMath.InputIsInDeadZone(x)) continue; for (int y = -128; y <= 127; y++) { - if (InputIsInDeadZone(y)) continue; + if (MoreMath.InputIsInDeadZone(y)) continue; ushort inputAngle = CalculateAngleFromInputs(x, y, cameraAngle); - ushort truncatedInputAngle = NormalizeAngleTruncated(inputAngle); + ushort truncatedInputAngle = MoreMath.NormalizeAngleTruncated(inputAngle); if (truncatedInputAngle == truncatedGoalAngle) { - double magnitude = GetEffectiveInputMagnitudeUncapped(x, y); + double magnitude = MoreMath.GetEffectiveInputMagnitudeUncapped(x, y); if (magnitude > bestMagnitude) { bestMagnitude = magnitude; @@ -825,10 +185,10 @@ public static (int xInput, int yInput) CalculateInputsForAngleOptimized(ushort g int bestX = 0; int bestY = 0; - ushort truncatedGoalAngle = NormalizeAngleTruncated(goalAngle); - ushort reversedCameraAngle = NormalizeAngleUshort(ReverseAngle(cameraAngle)); - ushort goalMarioAngle = NormalizeAngleUshort(goalAngle - reversedCameraAngle); - double goalMarioAngleRadians = AngleUnitsToRadians(goalMarioAngle); + ushort truncatedGoalAngle = MoreMath.NormalizeAngleTruncated(goalAngle); + ushort reversedCameraAngle = MoreMath.NormalizeAngleUshort(MoreMath.ReverseAngle(cameraAngle)); + ushort goalMarioAngle = MoreMath.NormalizeAngleUshort(goalAngle - reversedCameraAngle); + double goalMarioAngleRadians = MoreMath.AngleUnitsToRadians(goalMarioAngle); bool useX; bool positiveA; @@ -904,10 +264,10 @@ public static (int xInput, int yInput) CalculateInputsForAngleOptimized(ushort g int y = yEffective < 0 ? yEffective - 6 : yEffective > 0 ? yEffective + 6 : 0; ushort inputAngle = CalculateAngleFromInputs(x, y, cameraAngle); - ushort truncatedInputAngle = NormalizeAngleTruncated(inputAngle); + ushort truncatedInputAngle = MoreMath.NormalizeAngleTruncated(inputAngle); if (truncatedInputAngle == truncatedGoalAngle) { - double magnitude = GetEffectiveInputMagnitudeUncapped(x, y); + double magnitude = MoreMath.GetEffectiveInputMagnitudeUncapped(x, y); if (magnitude > bestMagnitude) { bestMagnitude = magnitude; @@ -920,228 +280,4 @@ public static (int xInput, int yInput) CalculateInputsForAngleOptimized(ushort g return (bestX, bestY); } - - public static ushort CalculateAngleFromInputs(int xInput, int yInput, ushort? cameraAngleNullable = null) - { - (float effectiveX, float effectiveY) = GetEffectiveInput(xInput, yInput); - ushort marioAngle = InGameTrigUtilities.InGameATan(effectiveY, -effectiveX); - ushort cameraAngleRaw = cameraAngleNullable ?? Config.Stream.GetUInt16(CameraConfig.StructAddress + CameraConfig.CentripetalAngleOffset); - ushort cameraAngle = NormalizeAngleUshort(ReverseAngle(cameraAngleRaw)); - ushort summedAngle = NormalizeAngleUshort(marioAngle + cameraAngle); - return summedAngle; - } - - // Float stuff - - public static int GetFloatSign(float floatValue) - { - string bitString = GetBitString(floatValue); - string signChar = bitString.Substring(0, 1); - return signChar == "0" ? 1 : -1; - } - - public static int GetFloatExponent(float floatValue) - { - string bitString = GetBitString(floatValue); - string exponentString = bitString.Substring(1, 8); - int byteValue = 0; - for (int i = 0; i < 8; i++) - { - string bitChar = exponentString.Substring(8 - 1 - i, 1); - bool bitBool = bitChar == "1"; - if (bitBool) byteValue = (byte)(byteValue | (1 << i)); - } - - int exponent = byteValue - 127; - return exponent; - } - - public static double GetFloatMantissa(float floatValue) - { - string bitString = GetBitString(floatValue); - string exponentString = bitString.Substring(9, 23); - double sum = 1; - double multiplier = 1; - for (int i = 0; i < 23; i++) - { - multiplier *= 0.5; - string bitChar = exponentString.Substring(i, 1); - bool bitBool = bitChar == "1"; - if (bitBool) sum += multiplier; - } - - return sum; - } - - public static string GetBitString(object value) - { - List bitStrings = TypeUtilities.GetBytes(value).ToList().ConvertAll(b => GetBitString(b)); - bitStrings.Reverse(); - return String.Join("", bitStrings); - } - - public static string GetBitString(byte b) - { - StringBuilder builder = new StringBuilder(); - for (int i = 7; i >= 0; i--) - { - bool bit = (b & (1 << i)) != 0; - builder.Append(bit ? "1" : "0"); - } - - return builder.ToString(); - } - - /** relX = how much right, relY = how much up, relZ = how much towards the camera */ - public static (double x, double y, double z) TranslateRelatively( - double yaw, double pitch, double roll, double relX, double relY, double relZ) - { - (double fx, double fy, double fz) = SphericalToEuler_AngleUnits(relZ, yaw, pitch); - (double sx, double sy, double sz) = SphericalToEuler_AngleUnits(relX, yaw - 16384, 0); - (double vx, double vy, double vz) = SphericalToEuler_AngleUnits(relY, yaw, pitch - 16384); - return (fx + sx + vx, fy + sy + vy, fz + sz + vz); - } - - public static float GetNextFloatInterval(float value) - { - value = Math.Abs(value); - float interval = 262144; - while (true) - { - float testValue = value + (interval / 2); - if (value == testValue) return interval; - interval /= 2; - } - } - - public static float GetPreviousFloatInterval(float value) - { - value = Math.Abs(value); - float interval = 262144; - while (true) - { - float testValue = value - (interval / 2); - if (value == testValue) return interval; - interval /= 2; - } - } - - public static float GetNextFloat(float value) - { - return value + GetNextFloatInterval(value); - } - - public static float GetPreviousFloat(float value) - { - return value - GetPreviousFloatInterval(value); - } - - public static float MoveFloat(float value, int num) - { - int iters = Math.Abs(num); - for (int i = 0; i < iters; i++) - { - value = num > 0 ? GetNextFloat(value) : GetPreviousFloat(value); - } - - return value; - } - - public static float MoveFloatTowards(float value, float goal) - { - if (goal > value) return GetNextFloat(value); - if (goal < value) return GetPreviousFloat(value); - return value; - } - - public static (double x, double y, double z, double t) GetPlaneLineIntersection( - double planeX, double planeY, double planeZ, double planeYaw, double planePitch, - double x1, double y1, double z1, double x2, double y2, double z2) - { - // Ax + By + Cz = D - double yawRadians = AngleUnitsToRadians(planeYaw); - double pitchRadians = AngleUnitsToRadians(planePitch); - double A = Math.Sin(yawRadians) * Math.Cos(pitchRadians); - double B = Math.Sin(pitchRadians); - double C = Math.Cos(yawRadians) * Math.Cos(pitchRadians); - double D = A * planeX + B * planeY + C * planeZ; - - // x = x1 + xDiff * t - // y = y1 + yDiff * t - // z = z1 + zDiff * t - double xDiff = x2 - x1; - double yDiff = y2 - y1; - double zDiff = z2 - z1; - - // A * x + B * y + C * z = D - // A * (x1 + xDiff * t) + B * (y1 + yDiff * t) + C * (z1 + zDiff * t) = D - // A * x1 + A * xDiff * t + B * y1 + B * yDiff * t + C * z1 + C * zDiff * t = D - // A * xDiff * t + B * yDiff * t + C * zDiff * t = D - (A * x1) - (B * y1) - (C * z1) - // t * (A * xDiff + B * yDiff + C * zDiff) = D - (A * x1) - (B * y1) - (C * z1) - // t = (D - (A * x1) - (B * y1) - (C * z1)) / (A * xDiff + B * yDiff + C * zDiff) - double t = (D - (A * x1) - (B * y1) - (C * z1)) / (A * xDiff + B * yDiff + C * zDiff); - - return (x1 + xDiff * t, y1 + yDiff * t, z1 + zDiff * t, t); - } - - public static (double x, double y, double z, double t) GetPlaneLineIntersection( - double planeX, double planeY, double planeZ, double planeYaw, double planePitch, - double x1, double y1, double z1, double lineYaw, double linePitch) - { - // Ax + By + Cz = D - double yawRadians = AngleUnitsToRadians(planeYaw); - double pitchRadians = AngleUnitsToRadians(planePitch); - double A = Math.Sin(yawRadians) * Math.Cos(pitchRadians); - double B = Math.Sin(pitchRadians); - double C = Math.Cos(yawRadians) * Math.Cos(pitchRadians); - double D = A * planeX + B * planeY + C * planeZ; - - // x = x1 + xDiff * t - // y = y1 + yDiff * t - // z = z1 + zDiff * t - (double xDiff, double yDiff, double zDiff) = SphericalToEuler_AngleUnits(1, lineYaw, linePitch); - - // A * x + B * y + C * z = D - // A * (x1 + xDiff * t) + B * (y1 + yDiff * t) + C * (z1 + zDiff * t) = D - // A * x1 + A * xDiff * t + B * y1 + B * yDiff * t + C * z1 + C * zDiff * t = D - // A * xDiff * t + B * yDiff * t + C * zDiff * t = D - (A * x1) - (B * y1) - (C * z1) - // t * (A * xDiff + B * yDiff + C * zDiff) = D - (A * x1) - (B * y1) - (C * z1) - // t = (D - (A * x1) - (B * y1) - (C * z1)) / (A * xDiff + B * yDiff + C * zDiff) - double t = (D - (A * x1) - (B * y1) - (C * z1)) / (A * xDiff + B * yDiff + C * zDiff); - - return (x1 + xDiff * t, y1 + yDiff * t, z1 + zDiff * t, t); - } - - public static (double x, double y, double z) GetPlanePointAtPoint( - double planeX, double planeY, double planeZ, double planeYaw, double planePitch, - double px, double py, double pz) - { - (double qx, double qz) = AddVectorToPoint(1, planeYaw, planeX, planeZ); - (double rx, double ry, double rz, double t) = GetPlaneLineIntersection( - px, py, pz, planeYaw, planePitch, planeX, planeY, planeZ, qx, planeY, qz); - return (rx, ry, rz); - } - - public static double GetPlaneDistanceToPoint( - double planeX, double planeY, double planeZ, double planeYaw, double planePitch, - double px, double py, double pz) - { - return Math.Abs(GetPlaneDistanceToPointSigned( - planeX, planeY, planeZ, planeYaw, planePitch, px, py, pz)); - } - - public static double GetPlaneDistanceToPointSigned( - double planeX, double planeY, double planeZ, double planeYaw, double planePitch, - double px, double py, double pz) - { - // Ax + By + Cz = D - double yawRadians = AngleUnitsToRadians(planeYaw); - double pitchRadians = AngleUnitsToRadians(planePitch); - double A = Math.Sin(yawRadians) * Math.Cos(pitchRadians); - double B = Math.Sin(pitchRadians); - double C = Math.Cos(yawRadians) * Math.Cos(pitchRadians); - double D = A * planeX + B * planeY + C * planeZ; - return A * px + B * py + C * pz - D; - } - } } diff --git a/STROOP/Utilities/MouseUtility.cs b/STROOP/Utilities/MouseUtility.cs index 8fc05baa2..a0cb0924b 100644 --- a/STROOP/Utilities/MouseUtility.cs +++ b/STROOP/Utilities/MouseUtility.cs @@ -1,27 +1,20 @@ -using System.Runtime.InteropServices; -using System.Windows.Forms; +using System.Windows.Forms; +using Windows.Win32; +using Windows.Win32.UI.WindowsAndMessaging; namespace STROOP.Utilities { public static class MouseUtility { - const int SM_SWAPBUTTON = 23; - - [DllImport("user32.dll")] - static extern short GetAsyncKeyState(Keys vKey); - - [DllImport("user32.dll")] - static extern int GetSystemMetrics(int nIndex); - public static bool IsMouseDown(int button) { - bool buttonsSwapped = GetSystemMetrics(SM_SWAPBUTTON) != 0; + bool buttonsSwapped = PInvoke.GetSystemMetrics(SYSTEM_METRICS_INDEX.SM_SWAPBUTTON) != 0; if (buttonsSwapped) if (button == 0) button = 1; else if (button == 1) button = 0; Keys key = button == 2 ? Keys.MButton : (Keys)(button + 1); - return (GetAsyncKeyState(key) & 0x8000) != 0; + return (PInvoke.GetAsyncKeyState((int)key) & 0x8000) != 0; } } } diff --git a/STROOP/Utilities/MupenUtilities.cs b/STROOP/Utilities/MupenUtilities.cs index 14102a673..a8ca1563b 100644 --- a/STROOP/Utilities/MupenUtilities.cs +++ b/STROOP/Utilities/MupenUtilities.cs @@ -1,4 +1,5 @@ -using STROOP.Structs; +using STROOP.Core; +using STROOP.Structs; using STROOP.Structs.Configurations; using System; diff --git a/STROOP/Utilities/ObjectOrderingUtilities.cs b/STROOP/Utilities/ObjectOrderingUtilities.cs index fdbf57e0e..3f7649e5a 100644 --- a/STROOP/Utilities/ObjectOrderingUtilities.cs +++ b/STROOP/Utilities/ObjectOrderingUtilities.cs @@ -4,6 +4,7 @@ using STROOP.Structs.Configurations; using STROOP.Forms; using STROOP.Models; +using STROOP.Variables.Utilities; namespace STROOP.Utilities { diff --git a/STROOP/Utilities/ObjectUtilities.cs b/STROOP/Utilities/ObjectUtilities.cs index 544bfcb9b..0faa6d243 100644 --- a/STROOP/Utilities/ObjectUtilities.cs +++ b/STROOP/Utilities/ObjectUtilities.cs @@ -1,6 +1,7 @@ using STROOP.Models; using STROOP.Structs; using STROOP.Structs.Configurations; +using STROOP.Variables.SM64MemoryLayout; using System; using System.Collections.Generic; using System.Drawing; diff --git a/STROOP/Utilities/OpenTKUtilities.cs b/STROOP/Utilities/OpenTKUtilities.cs new file mode 100644 index 000000000..cc884581e --- /dev/null +++ b/STROOP/Utilities/OpenTKUtilities.cs @@ -0,0 +1,58 @@ +using OpenTK.Mathematics; +using System; +using System.Drawing; + +namespace STROOP.Utilities; + +public static class OpenTKUtilities +{ + public static bool TryParseVector3(string text, out Vector3 value) + { + value = default(Vector3); + if (text == null) return false; + string[] split = text.Split(';'); + return (split.Length == 3 + && float.TryParse(split[0].Trim(), out value.X) + && float.TryParse(split[1].Trim(), out value.Y) + && float.TryParse(split[2].Trim(), out value.Z)); + } + + public static Vector4 ColorToVec4(Color color, int alpha = -1) => + new Vector4(color.R / 255f, color.G / 255f, color.B / 255f, (alpha == -1 ? color.A : alpha) / 255f); + + public static Color Vec4ToColor(Vector4 color) => + Color.FromArgb((byte)(Math.Max(0, Math.Min(255, color.W * 255))), + (byte)(Math.Max(0, Math.Min(255, color.X * 255))), + (byte)(Math.Max(0, Math.Min(255, color.Y * 255))), + (byte)(Math.Max(0, Math.Min(255, color.Z * 255)))); + + public static Vector4 ColorFromHSV(float hue, float saturation, float value, float alpha = 1) + { + int hi = Convert.ToInt32(Math.Floor(hue / 60)) % 6; + float f = hue / 60 - (float)Math.Floor(hue / 60); + + float v = value; + float p = value * (1 - saturation); + float q = value * (1 - f * saturation); + float t = value * (1 - (1 - f) * saturation); + + if (hi == 0) + return new Vector4(v, t, p, alpha); + else if (hi == 1) + return new Vector4(q, v, p, alpha); + else if (hi == 2) + return new Vector4(p, v, t, alpha); + else if (hi == 3) + return new Vector4(p, q, v, alpha); + else if (hi == 4) + return new Vector4(t, p, v, alpha); + else + return new Vector4(v, p, q, alpha); + } + + public static Vector4 GetRandomColor(int seed) + { + Random rnd = new Random(seed); + return ColorFromHSV((float)rnd.NextDouble() * 360, 0.5f, 0.8f); + } +} diff --git a/STROOP/Utilities/PositionAngle/PositionAngle.Commons.cs b/STROOP/Utilities/PositionAngle/PositionAngle.Commons.cs index 9d5b7868b..238fd0d54 100644 --- a/STROOP/Utilities/PositionAngle/PositionAngle.Commons.cs +++ b/STROOP/Utilities/PositionAngle/PositionAngle.Commons.cs @@ -2,6 +2,7 @@ using STROOP.Structs.Configurations; using System; using OpenTK.Mathematics; +using STROOP.Variables.SM64MemoryLayout; namespace STROOP.Utilities { diff --git a/STROOP/Utilities/PositionAngle/PositionAngle.Derivatives.cs b/STROOP/Utilities/PositionAngle/PositionAngle.Derivatives.cs index be209508b..d6c4e7a04 100644 --- a/STROOP/Utilities/PositionAngle/PositionAngle.Derivatives.cs +++ b/STROOP/Utilities/PositionAngle/PositionAngle.Derivatives.cs @@ -3,7 +3,8 @@ using System.Linq; using OpenTK.Mathematics; using STROOP.Controls.VariablePanel; -using STROOP.Core.Variables; +using STROOP.Core.Utilities; +using STROOP.Variables; namespace STROOP.Utilities { @@ -19,92 +20,85 @@ public class HybridPositionAngle : PositionAngle new HybridPositionAngle(() => pointCustom, () => pointCustom, "Point") }; - public static readonly (string, WatchVariablePanel.SpecialFuncWatchVariables) GenerateBaseVariables = + public static readonly (string, VariablePanel.SpecialFuncVariables) GenerateBaseVariables = ("Base Info", pa => { - T MakePATypeView(T view) where T : NamedVariableCollection.IView + T MakePATypeView(T view) where T : IVariable { - view.SetValueByKey(NamedVariableCollection.ViewProperties.specialType, "PositionAngle"); + view.SetValueByKey(CommonVariableProperties.specialType, "PositionAngle"); return view; } - var vars = new NamedVariableCollection.CustomView[] + var vars = new VariablePrecursor[] { - MakePATypeView(new NamedVariableCollection.CustomView(typeof(WatchVariableStringWrapper)) + ($"{pa.name} Pos Type", MakePATypeView(new CustomVariable(VariableSubclass.String) { - Name = $"{pa.name} Pos Type", Color = "Blue", - _getterFunction = () => pa.first().ToString().Yield(), - _setterFunction = newPAString => + getter = () => pa.first().ToString().Yield(), + setter = newPAString => { - var newPA = PositionAngle.FromString((string)newPAString); + var newPA = FromString(newPAString); if (newPA == null) return false.Yield(); pa.first = () => newPA; return true.Yield(); } - }), - MakePATypeView(new NamedVariableCollection.CustomView(typeof(WatchVariableStringWrapper)) + })), + ($"{pa.name} Angle Type", MakePATypeView(new CustomVariable(VariableSubclass.String) { - Name = $"{pa.name} Angle Type", Color = "Blue", - _getterFunction = () => pa.second().ToString().Yield(), - _setterFunction = newPAString => + getter = () => pa.second().ToString().Yield(), + setter = newPAString => { - var newPA = PositionAngle.FromString((string)newPAString); + var newPA = FromString(newPAString); if (newPA == null) return false.Yield(); pa.second = () => newPA; return true.Yield(); } - }), - new NamedVariableCollection.CustomView(typeof(WatchVariableNumberWrapper)) + })), + ($"{pa.name} X", new CustomVariable(VariableSubclass.Number) { - Name = $"{pa.name} X", Color = "Blue", - _getterFunction = () => pa.first().X.Yield(), - _setterFunction = val => pa.first().SetX(val).Yield() - }, - new NamedVariableCollection.CustomView(typeof(WatchVariableNumberWrapper)) + getter = () => pa.first().X.Yield(), + setter = val => pa.first().SetX(val).Yield() + }), + ($"{pa.name} Y", new CustomVariable(VariableSubclass.Number) { - Name = $"{pa.name} Y", Color = "Blue", - _getterFunction = () => pa.first().Y.Yield(), - _setterFunction = val => pa.first().SetY(val).Yield() - }, - new NamedVariableCollection.CustomView(typeof(WatchVariableNumberWrapper)) + getter = () => pa.first().Y.Yield(), + setter = val => pa.first().SetY(val).Yield() + }), + ($"{pa.name} Z", new CustomVariable(VariableSubclass.Number) { - Name = $"{pa.name} Z", Color = "Blue", - _getterFunction = () => pa.first().Z.Yield(), - _setterFunction = val => pa.first().SetZ(val).Yield() - }, - new NamedVariableCollection.CustomView(typeof(WatchVariableAngleWrapper)) + getter = () => pa.first().Z.Yield(), + setter = val => pa.first().SetZ(val).Yield() + }), + ($"{pa.name} Angle", new CustomVariable(VariableSubclass.Angle) { - Name = $"{pa.name} Angle", Color = "Blue", Display = "short", - _getterFunction = () => pa.second().Angle.Yield(), - _setterFunction = val => pa.second().SetAngle(val).Yield() - }, + getter = () => pa.second().Angle.Yield(), + setter = val => pa.second().SetAngle(val).Yield() + }), }; pa.OnDelete += () => { foreach (var v in vars) - v.OnDelete(); + v.var.OnDelete(); }; return vars; } ); - public static (string, WatchVariablePanel.SpecialFuncWatchVariables) GenerateRelations(HybridPositionAngle relation) => - ($"Relations to {relation.name}", - (HybridPositionAngle pa) => + public static (string, VariablePanel.SpecialFuncVariables) GenerateRelations(HybridPositionAngle relation) => + ($"Relations to {relation.name}", pa => { - List vars = new List(); + List vars = new List(); var distTypes = new[] { "X", "Y", "Z", "H", "", "F", "S" }; - var distGetters = new Func[] + var distGetters = new [] { GetXDistance, GetYDistance, @@ -114,7 +108,7 @@ public static (string, WatchVariablePanel.SpecialFuncWatchVariables) GenerateRel GetFDistance, GetSDistance, }; - var distSetters = new Func[] + var distSetters = new [] { SetXDistance, SetYDistance, @@ -131,46 +125,42 @@ public static (string, WatchVariablePanel.SpecialFuncWatchVariables) GenerateRel Func getter = distGetters[k]; Func setter = distSetters[k]; - vars.Add(new NamedVariableCollection.CustomView(typeof(WatchVariableNumberWrapper)) + vars.Add(($"{distType}Dist {relation.name} To {pa.name}", new CustomVariable(VariableSubclass.Number) { Color = "LightBlue", - Name = $"{distType}Dist {relation.name} To {pa.name}", - _getterFunction = () => getter(relation, pa).Yield(), - _setterFunction = (double dist) => setter(relation, pa, dist).Yield() - }); + getter = () => getter(relation, pa).Yield(), + setter = (double dist) => setter(relation, pa, dist).Yield() + })); } - vars.Add(new NamedVariableCollection.CustomView(typeof(WatchVariableAngleWrapper)) + vars.Add(($"Angle {relation.name} To {pa.name}", new CustomVariable(VariableSubclass.Number) { Color = "LightBlue", - Name = $"Angle {relation.name} To {pa.name}", Display = "short", - _getterFunction = () => GetAngleTo(relation, pa).Yield(), - _setterFunction = (double angle) => SetAngleTo(relation, pa, angle).Yield() - }); + getter = () => GetAngleTo(relation, pa).Yield(), + setter = (double angle) => SetAngleTo(relation, pa, angle).Yield() + })); - vars.Add(new NamedVariableCollection.CustomView(typeof(WatchVariableAngleWrapper)) + vars.Add(($"DAngle {relation.name} To {pa.name}", new CustomVariable(VariableSubclass.Number) { Color = "LightBlue", - Name = $"DAngle {relation.name} To {pa.name}", Display = "short", - _getterFunction = () => GetDAngleTo(relation, pa).Yield(), - _setterFunction = (double angleDiff) => SetDAngleTo(relation, pa, Convert.ToDouble(angleDiff)).Yield() - }); + getter = () => GetDAngleTo(relation, pa).Yield(), + setter = angleDiff => SetDAngleTo(relation, pa, Convert.ToDouble(angleDiff)).Yield() + })); - vars.Add(new NamedVariableCollection.CustomView(typeof(WatchVariableAngleWrapper)) + vars.Add(($"AngleDiff {relation.name} To {pa.name}", new CustomVariable(VariableSubclass.Number) { Color = "LightBlue", - Name = $"AngleDiff {relation.name} To {pa.name}", Display = "short", - _getterFunction = () => GetAngleDifference(relation, pa).Yield(), - _setterFunction = (double angleDiff) => SetAngleDifference(relation, pa, Convert.ToDouble(angleDiff)).Yield() - }); + getter = () => GetAngleDifference(relation, pa).Yield(), + setter = (double angleDiff) => SetAngleDifference(relation, pa, Convert.ToDouble(angleDiff)).Yield() + })); Action remove = () => { foreach (var v in vars) - v.OnDelete(); + v.var.OnDelete(); }; pa.OnDelete += remove; relation.OnDelete += remove; diff --git a/STROOP/Utilities/PositionAngle/PositionAngle.cs b/STROOP/Utilities/PositionAngle/PositionAngle.cs index 0aaccbc18..6aaaaee71 100644 --- a/STROOP/Utilities/PositionAngle/PositionAngle.cs +++ b/STROOP/Utilities/PositionAngle/PositionAngle.cs @@ -29,6 +29,9 @@ public override string ToString() using System.Collections.Generic; using System.Linq; using OpenTK.Mathematics; +using STROOP.Core; +using STROOP.Variables.SM64MemoryLayout; +using STROOP.Variables.Utilities; namespace STROOP.Utilities { diff --git a/STROOP/Utilities/ProcessStreamExtensions.cs b/STROOP/Utilities/ProcessStreamExtensions.cs new file mode 100644 index 000000000..34842cda1 --- /dev/null +++ b/STROOP/Utilities/ProcessStreamExtensions.cs @@ -0,0 +1,61 @@ +using STROOP.Core; +using STROOP.Variables.Utilities; +using System; + +namespace STROOP.Utilities; + +public static class ProcessStreamExtensions +{ + public static bool SetValueRoundingWrapping(this ProcessStream processStream, Type type, object value, uint address, uint? mask = null, int? shift = null) + { + // Allow short circuiting if object is already of type + if (type == typeof(byte) && value is byte byteValue) return processStream.SetValue(byteValue, address, false, mask, shift); + if (type == typeof(sbyte) && value is sbyte sbyteValue) return processStream.SetValue(sbyteValue, address, false, mask, shift); + if (type == typeof(short) && value is short shortValue) return processStream.SetValue(shortValue, address, false, mask, shift); + if (type == typeof(ushort) && value is ushort ushortValue) return processStream.SetValue(ushortValue, address, false, mask, shift); + if (type == typeof(int) && value is int intValue) return processStream.SetValue(intValue, address, false, mask, shift); + if (type == typeof(uint) && value is uint uintValue) return processStream.SetValue(uintValue, address, false, mask, shift); + if (type == typeof(float) && value is float floatValue) return processStream.SetValue(floatValue, address, false, mask, shift); + if (type == typeof(double) && value is double doubleValue) return processStream.SetValue(doubleValue, address, false, mask, shift); + + value = ParsingUtilities.ParseDoubleNullable(value); + if (value == null) return false; + + if (type == typeof(byte)) value = ParsingUtilities.ParseByteRoundingWrapping(value); + if (type == typeof(sbyte)) value = ParsingUtilities.ParseSByteRoundingWrapping(value); + if (type == typeof(short)) value = ParsingUtilities.ParseShortRoundingWrapping(value); + if (type == typeof(ushort)) value = ParsingUtilities.ParseUShortRoundingWrapping(value); + if (type == typeof(int)) value = ParsingUtilities.ParseIntRoundingWrapping(value); + if (type == typeof(uint)) value = ParsingUtilities.ParseUIntRoundingWrapping(value); + + return processStream.SetValue(type, value.ToString(), address, false, mask, shift); + } + + public static bool SetValue(this ProcessStream processStream, Type type, object value, uint address, bool absoluteAddress = false, uint? mask = null, int? shift = null) + { + if (value is string) + { + if (type == typeof(byte)) value = ParsingUtilities.ParseByteNullable(value); + if (type == typeof(sbyte)) value = ParsingUtilities.ParseSByteNullable(value); + if (type == typeof(short)) value = ParsingUtilities.ParseShortNullable(value); + if (type == typeof(ushort)) value = ParsingUtilities.ParseUShortNullable(value); + if (type == typeof(int)) value = ParsingUtilities.ParseIntNullable(value); + if (type == typeof(uint)) value = ParsingUtilities.ParseUIntNullable(value); + if (type == typeof(float)) value = ParsingUtilities.ParseFloatNullable(value); + if (type == typeof(double)) value = ParsingUtilities.ParseDoubleNullable(value); + } + + if (value == null) return false; + + if (type == typeof(byte)) return processStream.SetValue((byte)value, address, absoluteAddress, mask, shift); + if (type == typeof(sbyte)) return processStream.SetValue((sbyte)value, address, absoluteAddress, mask, shift); + if (type == typeof(short)) return processStream.SetValue((short)value, address, absoluteAddress, mask, shift); + if (type == typeof(ushort)) return processStream.SetValue((ushort)value, address, absoluteAddress, mask, shift); + if (type == typeof(int)) return processStream.SetValue((int)value, address, absoluteAddress, mask, shift); + if (type == typeof(uint)) return processStream.SetValue((uint)value, address, absoluteAddress, mask, shift); + if (type == typeof(float)) return processStream.SetValue((float)value, address, absoluteAddress, mask, shift); + if (type == typeof(double)) return processStream.SetValue((double)value, address, absoluteAddress, mask, shift); + + throw new ArgumentOutOfRangeException("Cannot call ProcessStream.SetValue with type " + type); + } +} diff --git a/STROOP/Utilities/PuUtilities.cs b/STROOP/Utilities/PuUtilities.cs index 5e9eb4b82..350994c82 100644 --- a/STROOP/Utilities/PuUtilities.cs +++ b/STROOP/Utilities/PuUtilities.cs @@ -1,5 +1,6 @@ using STROOP.Structs; using STROOP.Structs.Configurations; +using STROOP.Variables.SM64MemoryLayout; using System; using System.Collections.Generic; diff --git a/STROOP/Utilities/Scopes.cs b/STROOP/Utilities/Scopes.cs deleted file mode 100644 index 859f5dc34..000000000 --- a/STROOP/Utilities/Scopes.cs +++ /dev/null @@ -1,70 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace STROOP.Utilities -{ -#pragma warning disable CA1063 // Implement IDisposable correctly - this is not a resource! - public abstract class Scope : IDisposable - { - protected Scope() - { - } - - protected abstract void Close(); - void IDisposable.Dispose() => Close(); - } -#pragma warning restore CA1063 - - public sealed class AccessScope : Scope - { - public static T content => scopes.Count == 0 ? default(T) : scopes.Peek().obj; - - static Stack> scopes = new Stack>(); - T obj; - - public AccessScope(T obj) - { - this.obj = obj; - scopes.Push(this); - } - - protected override void Close() - { - if (scopes.Pop() != this) - throw new Exception($"Scopes must be disposed in reverse creation order."); - } - } - - public class IgnoreScope : Scope - { - Stack scopeStack = new Stack(); - - IgnoreScope parent; - - public IgnoreScope() - { - } - - private IgnoreScope(IgnoreScope parent) - { - this.parent = parent; - } - - public IgnoreScope New() - { - var newScope = new IgnoreScope(this); - scopeStack.Push(newScope); - return newScope; - } - - protected override void Close() - { - if (parent.scopeStack.Pop() != this) - throw new InvalidOperationException("IgnoreScopes popped in invalid order"); - } - - public bool ignore => scopeStack.Count > 0; - - public static implicit operator bool(IgnoreScope ignoreScope) => ignoreScope.ignore; - } -} diff --git a/STROOP/Utilities/SegmentationUtilities.cs b/STROOP/Utilities/SegmentationUtilities.cs index 5f43d5e13..6b345c693 100644 --- a/STROOP/Utilities/SegmentationUtilities.cs +++ b/STROOP/Utilities/SegmentationUtilities.cs @@ -1,5 +1,6 @@ using STROOP.Managers; using STROOP.Structs.Configurations; +using STROOP.Variables.SM64MemoryLayout; using System; using System.Collections.Generic; using System.Drawing; diff --git a/STROOP/Utilities/Stream/BaseProcessIO.cs b/STROOP/Utilities/Stream/BaseProcessIO.cs deleted file mode 100644 index 21cbb581d..000000000 --- a/STROOP/Utilities/Stream/BaseProcessIO.cs +++ /dev/null @@ -1,124 +0,0 @@ -using STROOP.Structs; -using STROOP.Structs.Configurations; -using System; -using System.Diagnostics; -using System.Text; - -namespace STROOP.Utilities -{ - public abstract class BaseProcessIO : IEmuRamIO - { - public abstract event EventHandler OnClose; - - protected StringBuilder messageLogBuilder = new StringBuilder(); - - protected abstract bool WriteFunc(UIntPtr address, byte[] buffer); - protected abstract bool ReadFunc(UIntPtr address, byte[] buffer); - protected abstract UIntPtr BaseOffset { get; } - protected abstract EndiannessType Endianness { get; } - public abstract byte[] ReadAllMemory(); - - public abstract bool IsSuspended { get; } - - public abstract string Name { get; } - public abstract Process Process { get; } - - public abstract bool Suspend(); - public abstract bool Resume(); - - public BaseProcessIO() - { - } - - public string GetLastMessages() - { - var result = messageLogBuilder.ToString(); - messageLogBuilder.Clear(); - return result; - } - - public bool ReadRelative(uint address, byte[] buffer, EndiannessType endianness) - { - return ReadAbsolute(GetAbsoluteAddress(address, buffer.Length), buffer, endianness); - } - - static readonly byte[] _swapByteOrder = new byte[] { 0x03, 0x02, 0x01, 0x00 }; - - public bool ReadAbsolute(UIntPtr address, byte[] buffer, EndiannessType endianness) - { - if (Endianness == endianness) - { - return ReadFunc(address, buffer); - } - else - { - // Not a between alignment, or aligned write - if (buffer.Length >= 4 && (buffer.Length % 4 != 0)) - throw new Exception("Misaligned data"); - - address = EndiannessUtilities.SwapAddressEndianness(address, buffer.Length); - byte[] readBytes = new byte[buffer.Length]; - if (!ReadFunc(address, readBytes)) - return false; - - readBytes = EndiannessUtilities.SwapByteEndianness(readBytes); - Buffer.BlockCopy(readBytes, 0, buffer, 0, buffer.Length); - - return true; - } - } - - public bool WriteRelative(uint address, byte[] buffer, EndiannessType endianness) - { - return WriteAbsolute(GetAbsoluteAddress(address, buffer.Length), buffer, endianness); - } - - public bool WriteAbsolute(UIntPtr address, byte[] buffer, EndiannessType endianness) - { - // Safety bounds check - if (address.ToUInt64() < BaseOffset.ToUInt64() - || address.ToUInt64() + (uint)buffer.Length >= BaseOffset.ToUInt64() + Config.RamSize) - return false; - - if (Endianness == endianness) - { - return WriteFunc(address, buffer); - } - else - { - bool success = true; - byte[] toWrite = EndiannessUtilities.SwapByteEndianness(buffer); - - // Between alignment writes - if (buffer.Length < 4) - { - address = EndiannessUtilities.SwapAddressEndianness(address, toWrite.Length); - success &= WriteFunc(address, toWrite); - } - else if (buffer.Length % 4 == 0) // Full alignment writes - { - success &= WriteFunc(address, toWrite); - } - else - { - throw new Exception("Misaligned data"); - } - - return success; - } - } - - public UIntPtr GetAbsoluteAddress(uint n64Address, int size) - { - n64Address &= ~0x80000000U; - UIntPtr absoluteAddress = (UIntPtr)(BaseOffset.ToUInt64() + n64Address); - return EndiannessUtilities.SwapAddressEndianness(absoluteAddress, size); - } - - public uint GetRelativeAddress(UIntPtr absoluteAddress, int size) - { - uint n64address = 0x80000000 | (uint)(absoluteAddress.ToUInt64() - BaseOffset.ToUInt64()); - return EndiannessUtilities.SwapAddressEndianness(n64address, size); - } - } -} diff --git a/STROOP/Utilities/Stream/DolphinProcessIO.cs b/STROOP/Utilities/Stream/DolphinProcessIO.cs deleted file mode 100644 index 825291e12..000000000 --- a/STROOP/Utilities/Stream/DolphinProcessIO.cs +++ /dev/null @@ -1,68 +0,0 @@ -using STROOP.Exceptions; -using STROOP.Structs; -using System; -using System.Diagnostics; -using System.Runtime.InteropServices; -using static STROOP.Utilities.Kernal32NativeMethods; - -namespace STROOP.Utilities -{ - class DolphinProcessIO : WindowsProcessRamIO - { - public DolphinProcessIO(Process process, Emulator emulator) - : base(process, emulator) - { - } - - protected override void CalculateOffset() - { - MemoryBasicInformation info; - IntPtr infoSize = (IntPtr)Marshal.SizeOf(typeof(MemoryBasicInformation)); - uint setInfoSize = (uint)Marshal.SizeOf(typeof(PsapiWorkingSetExInformation)); - - _baseOffset = (UIntPtr)0; - bool mem1Found = false; - for (IntPtr p = new IntPtr(); - VQueryEx(_processHandle, p, out info, infoSize) == infoSize; - p = (IntPtr)(p.ToInt64() + info.RegionSize.ToInt64())) - { - if (mem1Found) - { - if (info.BaseAddress == _baseOffset + 0x10000000) - { - break; - } - else if (info.BaseAddress.ToUInt64() > _baseOffset.ToUInt64() + 0x10000000) - { - break; - } - - continue; - } - - if (info.RegionSize == (IntPtr)0x2000000 && info.Type == MemoryType.MEM_MAPPED) - { - // Here, it's likely the right page, but it can happen that multiple pages with these criteria - // exists and have nothing to do with the emulated memory. Only the right page has valid - // working set information so an additional check is required that it is backed by physical - // memory. - PsapiWorkingSetExInformation wsInfo; - wsInfo.VirtualAddress = (IntPtr)info.BaseAddress.ToUInt64(); - if (QWorkingSetEx(_processHandle, out wsInfo, setInfoSize)) - { - if ((wsInfo.VirtualAttributes & 0x01) != 0) - { - _baseOffset = info.BaseAddress; - mem1Found = true; - } - } - } - } - - if (_baseOffset.ToUInt64() == 0) - throw new DolphinNotRunningGameException(); - - _baseOffset = (UIntPtr)(_baseOffset.ToUInt64() + _emulator.RamStart); - } - } -} diff --git a/STROOP/Utilities/Stream/IEmuRamIO.cs b/STROOP/Utilities/Stream/IEmuRamIO.cs deleted file mode 100644 index 9d5985e46..000000000 --- a/STROOP/Utilities/Stream/IEmuRamIO.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; -using System.Diagnostics; -using STROOP.Structs; - -namespace STROOP.Utilities -{ - public interface IEmuRamIO - { - string Name { get; } - Process Process { get; } - string GetLastMessages(); - bool Suspend(); - bool Resume(); - - bool IsSuspended { get; } - - bool ReadRelative(uint address, byte[] buffer, EndiannessType endianness); - bool ReadAbsolute(UIntPtr address, byte[] buffer, EndiannessType endianness); - bool WriteRelative(uint address, byte[] buffer, EndiannessType endianness); - bool WriteAbsolute(UIntPtr address, byte[] buffer, EndiannessType endianness); - byte[] ReadAllMemory(); - - UIntPtr GetAbsoluteAddress(uint n64Address, int size); - uint GetRelativeAddress(UIntPtr absoluteAddress, int size); - - event EventHandler OnClose; - } -} diff --git a/STROOP/Utilities/Stream/IProcessMemory.cs b/STROOP/Utilities/Stream/IProcessMemory.cs deleted file mode 100644 index 682109128..000000000 --- a/STROOP/Utilities/Stream/IProcessMemory.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace STROOP.Utilities.Stream -{ - interface IProcessMemory - { - } -} diff --git a/STROOP/Utilities/Stream/ProcessStream.cs b/STROOP/Utilities/Stream/ProcessStream.cs deleted file mode 100644 index d633fd4a2..000000000 --- a/STROOP/Utilities/Stream/ProcessStream.cs +++ /dev/null @@ -1,634 +0,0 @@ -using STROOP.Exceptions; -using STROOP.Structs; -using STROOP.Structs.Configurations; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using System.Windows.Forms; - -namespace STROOP.Utilities -{ - public class ProcessStream : IDisposable - { - IEmuRamIO _io; - public IEmuRamIO IO => _io; - - List _fpsTimes = new List(); - byte[] _ram; - object _enableLocker = new object(); - object _mStreamProcess = new object(); - - public event EventHandler OnDisconnect; - public event EventHandler FpsUpdated; - public event EventHandler WarnReadonlyOff; - private Action OnUpdate; - - public bool Readonly { get; set; } = false; - public bool ShowWarning { get; set; } = false; - - public byte[] Ram => _ram; - public string ProcessName => _io?.Name ?? "(No Emulator)"; - public double FpsInPractice => _fpsTimes.Count == 0 ? 0 : 1 / _fpsTimes.Average(); - public double lastFrameTime => _fpsTimes.Count == 0 ? RefreshRateConfig.RefreshRateInterval : _fpsTimes.Last(); - - public ProcessStream(Action onUpdate) - { - this.OnUpdate = onUpdate; - _ram = new byte[Config.RamSize]; - } - - public void Run() - { - ProcessUpdate(); - } - - private void LogException(Exception e) - { - try - { - var log = String.Format("{0}\n{1}\n{2}\n", e.Message, e.TargetSite.ToString(), e.StackTrace); - File.AppendAllText("error.txt", log); - } - catch (Exception) - { - } - } - - private void ExceptionHandler(Task obj) - { - LogException(obj.Exception); - throw obj.Exception; - } - - private readonly Dictionary> _ioCreationTable = new Dictionary>() - { - { typeof(WindowsProcessRamIO), (p, e) => new WindowsProcessRamIO(p, e) }, - { typeof(DolphinProcessIO), (p, e) => new DolphinProcessIO(p, e) }, - }; - - public bool SwitchIO(IEmuRamIO newIO) - { - lock (_mStreamProcess) - { - // Dipose of old process - (_io as IDisposable)?.Dispose(); - if (_io != null) - _io.OnClose -= ProcessClosed; - - // Check for no process - if (newIO == null) - goto Error; - - try - { - // Open and set new process - _io = newIO; - _io.OnClose += ProcessClosed; - } - catch (Exception) // Failed to create process - { - goto Error; - } - - return true; - - Error: - _io = null; - return false; - } - } - - public bool OpenSTFile(string fileName) - { - StFileIO fileIO = new StFileIO(fileName); - return SwitchIO(fileIO); - } - - public bool SwitchProcess(Process newProcess, Emulator emulator) - { - IEmuRamIO newIo = null; - try - { - newIo = newProcess != null ? _ioCreationTable[emulator.IOType](newProcess, emulator) : null; - var messages = newIo?.GetLastMessages() ?? string.Empty; - if (string.Empty != messages) - MessageBox.Show(messages, "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); - } - catch (DolphinNotRunningGameException e) - { - MessageBox.Show(e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - return false; - } - - return SwitchIO(newIo); - } - - - int suspendCounter = 0; - - class SuspendScope : Scope - { - readonly ProcessStream stream; - - public SuspendScope(ProcessStream stream) - { - this.stream = stream; - if (stream.suspendCounter == 0) - stream._io?.Suspend(); - stream.suspendCounter++; - } - - protected override void Close() - { - stream.suspendCounter--; - if (stream.suspendCounter == 0) - stream._io?.Resume(); - } - } - - public Scope Suspend() => new SuspendScope(this); - - private void ProcessClosed(object sender, EventArgs e) - { - OnDisconnect?.Invoke(this, new EventArgs()); - } - - public UIntPtr GetAbsoluteAddress(uint relativeAddress, int size = 0) - { - return _io?.GetAbsoluteAddress(relativeAddress, size) ?? new UIntPtr(0); - } - - public uint GetRelativeAddress(UIntPtr relativeAddress, int size) - { - return _io?.GetRelativeAddress(relativeAddress, size) ?? 0; - } - - public object GetValue(Type type, uint address, bool absoluteAddress = false, uint? mask = null, int? shift = null) - { - if (type == typeof(byte)) return GetByte(address, absoluteAddress, mask, shift); - if (type == typeof(sbyte)) return GetSByte(address, absoluteAddress, mask, shift); - if (type == typeof(short)) return GetInt16(address, absoluteAddress, mask, shift); - if (type == typeof(ushort)) return GetUInt16(address, absoluteAddress, mask, shift); - if (type == typeof(int)) return GetInt32(address, absoluteAddress, mask, shift); - if (type == typeof(uint)) return GetUInt32(address, absoluteAddress, mask, shift); - if (type == typeof(float)) return GetSingle(address, absoluteAddress, mask, shift); - if (type == typeof(double)) return GetDouble(address, absoluteAddress, mask, shift); - - throw new ArgumentOutOfRangeException("Cannot call ProcessStream.GetValue with type " + type); - } - - public byte GetByte(uint address, bool absoluteAddress = false, uint? mask = null, int? shift = null) - { - byte value = ReadRam((UIntPtr)address, 1, EndiannessType.Little, absoluteAddress)[0]; - if (mask.HasValue) value = (byte)(value & mask.Value); - if (shift.HasValue) value = (byte)(value >> shift.Value); - return value; - } - - public sbyte GetSByte(uint address, bool absoluteAddress = false, uint? mask = null, int? shift = null) - { - sbyte value = (sbyte)ReadRam((UIntPtr)address, 1, EndiannessType.Little, absoluteAddress)[0]; - if (mask.HasValue) value = (sbyte)(value & mask.Value); - if (shift.HasValue) value = (sbyte)(value >> shift.Value); - return value; - } - - public short GetInt16(uint address, bool absoluteAddress = false, uint? mask = null, int? shift = null) - { - short value = BitConverter.ToInt16(ReadRam((UIntPtr)address, 2, EndiannessType.Little, absoluteAddress), 0); - if (mask.HasValue) value = (short)(value & mask.Value); - if (shift.HasValue) value = (short)(value >> shift.Value); - return value; - } - - public ushort GetUInt16(uint address, bool absoluteAddress = false, uint? mask = null, int? shift = null) - { - ushort value = BitConverter.ToUInt16(ReadRam((UIntPtr)address, 2, EndiannessType.Little, absoluteAddress), 0); - if (mask.HasValue) value = (ushort)(value & mask.Value); - if (shift.HasValue) value = (ushort)(value >> shift.Value); - return value; - } - - public int GetInt32(uint address, bool absoluteAddress = false, uint? mask = null, int? shift = null) - { - int value = BitConverter.ToInt32(ReadRam((UIntPtr)address, 4, EndiannessType.Little, absoluteAddress), 0); - if (mask.HasValue) value = (int)(value & mask.Value); - if (shift.HasValue) value = (int)(value >> shift.Value); - return value; - } - - public uint GetUInt32(uint address, bool absoluteAddress = false, uint? mask = null, int? shift = null) - { - uint value = BitConverter.ToUInt32(ReadRam((UIntPtr)address, 4, EndiannessType.Little, absoluteAddress), 0); - if (mask.HasValue) value = (uint)(value & mask.Value); - if (shift.HasValue) value = (uint)(value >> shift.Value); - return value; - } - - public float GetSingle(uint address, bool absoluteAddress = false, uint? mask = null, int? shift = null) - { - return BitConverter.ToSingle(ReadRam((UIntPtr)address, 4, EndiannessType.Little, absoluteAddress), 0); - } - - public double GetDouble(uint address, bool absoluteAddress = false, uint? mask = null, int? shift = null) - { - return BitConverter.ToDouble(ReadRam((UIntPtr)address, 8, EndiannessType.Little, absoluteAddress), 0); - } - - public byte[] ReadRam(uint address, int length, EndiannessType endianness, bool absoluteAddress = false) - { - return ReadRam((UIntPtr)address, length, endianness, absoluteAddress); - } - - public byte[] ReadRam(UIntPtr address, int length, EndiannessType endianness, bool absoluteAddress = false) - { - byte[] readBytes = new byte[length]; - - // Get local address - uint localAddress; - if (absoluteAddress) - localAddress = _io?.GetRelativeAddress(address, length) ?? 0; - else - localAddress = address.ToUInt32(); - localAddress &= ~0x80000000; - - if (EndiannessUtilities.DataIsMisaligned(address, length, EndiannessType.Big)) - return readBytes; - - /// Fix endianness - switch (endianness) - { - case EndiannessType.Little: - // Address is not little endian, fix: - localAddress = EndiannessUtilities.SwapAddressEndianness(localAddress, length); - - if (localAddress + length > _ram.Length) - break; - - Buffer.BlockCopy(_ram, (int)localAddress, readBytes, 0, length); - break; - - case EndiannessType.Big: - // Read padded if misaligned address - byte[] swapBytes; - uint alignedAddress = EndiannessUtilities.AlignedAddressFloor(localAddress); - - - int alignedReadByteCount = (readBytes.Length / 4) * 4 + 8; - if (alignedAddress + alignedReadByteCount > _ram.Length) - break; - swapBytes = new byte[alignedReadByteCount]; - - // Read memory - Buffer.BlockCopy(_ram, (int)alignedAddress, swapBytes, 0, swapBytes.Length); - swapBytes = EndiannessUtilities.SwapByteEndianness(swapBytes); - - // Copy memory - Buffer.BlockCopy(swapBytes, (int)(localAddress - alignedAddress), readBytes, 0, readBytes.Length); - - break; - } - - - return readBytes; - } - - public bool ReadProcessMemory(UIntPtr address, byte[] buffer, EndiannessType endianness) - { - return _io?.ReadAbsolute(address, buffer, endianness) ?? false; - } - - public byte[] ReadAllMemory() - { - return _io?.ReadAllMemory(); - } - - public bool CheckReadonlyOff() - { - if (ShowWarning) - WarnReadonlyOff?.Invoke(this, new EventArgs()); - - return Readonly; - } - - public bool SetValueRoundingWrapping( - Type type, object value, uint address, bool absoluteAddress = false, uint? mask = null, int? shift = null) - { - // Allow short circuiting if object is already of type - if (type == typeof(byte) && value is byte byteValue) return SetValue(byteValue, address, absoluteAddress, mask, shift); - if (type == typeof(sbyte) && value is sbyte sbyteValue) return SetValue(sbyteValue, address, absoluteAddress, mask, shift); - if (type == typeof(short) && value is short shortValue) return SetValue(shortValue, address, absoluteAddress, mask, shift); - if (type == typeof(ushort) && value is ushort ushortValue) return SetValue(ushortValue, address, absoluteAddress, mask, shift); - if (type == typeof(int) && value is int intValue) return SetValue(intValue, address, absoluteAddress, mask, shift); - if (type == typeof(uint) && value is uint uintValue) return SetValue(uintValue, address, absoluteAddress, mask, shift); - if (type == typeof(float) && value is float floatValue) return SetValue(floatValue, address, absoluteAddress, mask, shift); - if (type == typeof(double) && value is double doubleValue) return SetValue(doubleValue, address, absoluteAddress, mask, shift); - - value = ParsingUtilities.ParseDoubleNullable(value); - if (value == null) return false; - - if (type == typeof(byte)) value = ParsingUtilities.ParseByteRoundingWrapping(value); - if (type == typeof(sbyte)) value = ParsingUtilities.ParseSByteRoundingWrapping(value); - if (type == typeof(short)) value = ParsingUtilities.ParseShortRoundingWrapping(value); - if (type == typeof(ushort)) value = ParsingUtilities.ParseUShortRoundingWrapping(value); - if (type == typeof(int)) value = ParsingUtilities.ParseIntRoundingWrapping(value); - if (type == typeof(uint)) value = ParsingUtilities.ParseUIntRoundingWrapping(value); - - return SetValue(type, value.ToString(), address, absoluteAddress, mask, shift); - } - - public bool SetValue(Type type, object value, uint address, bool absoluteAddress = false, uint? mask = null, int? shift = null) - { - if (value is string) - { - if (type == typeof(byte)) value = ParsingUtilities.ParseByteNullable(value); - if (type == typeof(sbyte)) value = ParsingUtilities.ParseSByteNullable(value); - if (type == typeof(short)) value = ParsingUtilities.ParseShortNullable(value); - if (type == typeof(ushort)) value = ParsingUtilities.ParseUShortNullable(value); - if (type == typeof(int)) value = ParsingUtilities.ParseIntNullable(value); - if (type == typeof(uint)) value = ParsingUtilities.ParseUIntNullable(value); - if (type == typeof(float)) value = ParsingUtilities.ParseFloatNullable(value); - if (type == typeof(double)) value = ParsingUtilities.ParseDoubleNullable(value); - } - - if (value == null) return false; - - if (type == typeof(byte)) return SetValue((byte)value, address, absoluteAddress, mask, shift); - if (type == typeof(sbyte)) return SetValue((sbyte)value, address, absoluteAddress, mask, shift); - if (type == typeof(short)) return SetValue((short)value, address, absoluteAddress, mask, shift); - if (type == typeof(ushort)) return SetValue((ushort)value, address, absoluteAddress, mask, shift); - if (type == typeof(int)) return SetValue((int)value, address, absoluteAddress, mask, shift); - if (type == typeof(uint)) return SetValue((uint)value, address, absoluteAddress, mask, shift); - if (type == typeof(float)) return SetValue((float)value, address, absoluteAddress, mask, shift); - if (type == typeof(double)) return SetValue((double)value, address, absoluteAddress, mask, shift); - - throw new ArgumentOutOfRangeException("Cannot call ProcessStream.SetValue with type " + type); - } - - public bool SetValue(byte value, uint address, bool absoluteAddress = false, uint? mask = null, int? shift = null) - { - if (shift.HasValue) - { - value = (byte)(value << shift.Value); - } - - if (mask.HasValue) - { - byte oldValue = GetByte(address, absoluteAddress); - value = (byte)((oldValue & ~mask.Value) | (value & mask.Value)); - } - - bool returnValue = WriteRam(new byte[] { value }, (UIntPtr)address, EndiannessType.Little, absoluteAddress); - return returnValue; - } - - public bool SetValue(sbyte value, uint address, bool absoluteAddress = false, uint? mask = null, int? shift = null) - { - if (shift.HasValue) - { - value = (sbyte)(value << shift.Value); - } - - if (mask.HasValue) - { - sbyte oldValue = GetSByte(address, absoluteAddress); - value = (sbyte)((oldValue & ~mask.Value) | (value & mask.Value)); - } - - bool returnValue = WriteRam(new byte[] { (byte)value }, (UIntPtr)address, EndiannessType.Little, absoluteAddress); - return returnValue; - } - - public bool SetValue(Int16 value, uint address, bool absoluteAddress = false, uint? mask = null, int? shift = null) - { - if (shift.HasValue) - { - value = (short)(value << shift.Value); - } - - if (mask.HasValue) - { - short oldValue = GetInt16(address, absoluteAddress); - value = (short)((oldValue & ~mask.Value) | (value & mask.Value)); - } - - bool returnValue = WriteRam(BitConverter.GetBytes(value), (UIntPtr)address, EndiannessType.Little, absoluteAddress); - return returnValue; - } - - public bool SetValue(UInt16 value, uint address, bool absoluteAddress = false, uint? mask = null, int? shift = null) - { - if (shift.HasValue) - { - value = (ushort)(value << shift.Value); - } - - if (mask.HasValue) - { - ushort oldValue = GetUInt16(address, absoluteAddress); - value = (ushort)((oldValue & ~mask.Value) | (value & mask.Value)); - } - - bool returnValue = WriteRam(BitConverter.GetBytes(value), (UIntPtr)address, EndiannessType.Little, absoluteAddress); - return returnValue; - } - - public bool SetValue(Int32 value, uint address, bool absoluteAddress = false, uint? mask = null, int? shift = null) - { - if (shift.HasValue) - { - value = (int)(value << shift.Value); - } - - if (mask.HasValue) - { - int oldValue = GetInt32(address, absoluteAddress); - value = (int)((oldValue & ~mask.Value) | (value & mask.Value)); - } - - bool returnValue = WriteRam(BitConverter.GetBytes(value), (UIntPtr)address, EndiannessType.Little, absoluteAddress); - return returnValue; - } - - public bool SetValue(UInt32 value, uint address, bool absoluteAddress = false, uint? mask = null, int? shift = null) - { - if (shift.HasValue) - { - value = (uint)(value << shift.Value); - } - - if (mask.HasValue) - { - uint oldValue = GetUInt32(address, absoluteAddress); - value = (uint)((oldValue & ~mask.Value) | (value & mask.Value)); - } - - bool returnValue = WriteRam(BitConverter.GetBytes(value), (UIntPtr)address, EndiannessType.Little, absoluteAddress); - return returnValue; - } - - public bool SetValue(float value, uint address, bool absoluteAddress = false, uint? mask = null, int? shift = null) - { - bool returnValue = WriteRam(BitConverter.GetBytes(value), (UIntPtr)address, EndiannessType.Little, absoluteAddress); - return returnValue; - } - - public bool SetValue(double value, uint address, bool absoluteAddress = false, uint? mask = null, int? shift = null) - { - byte[] bytes = BitConverter.GetBytes(value); - byte[] bytes1 = bytes.Take(4).ToArray(); - byte[] bytes2 = bytes.Skip(4).Take(4).ToArray(); - byte[] bytesSwapped = bytes2.Concat(bytes1).ToArray(); - - bool returnValue = WriteRam(bytesSwapped, (UIntPtr)address, EndiannessType.Little, absoluteAddress); - return returnValue; - } - - public bool WriteRam(byte[] buffer, uint address, EndiannessType endianness, - int bufferStart = 0, int? length = null, bool safeWrite = true) - { - return WriteRam(buffer, (UIntPtr)address, endianness, false, bufferStart, length, safeWrite); - } - - private object ram_write_lock = new object(); - - public bool WriteRam(byte[] buffer, UIntPtr address, EndiannessType endianness, bool absoluteAddress = false, - int bufferStart = 0, int? length = null, bool safeWrite = true) - { - lock (ram_write_lock) - { - if (length == null) - length = buffer.Length - bufferStart; - - if (CheckReadonlyOff()) - return false; - - byte[] writeBytes = new byte[length.Value]; - Array.Copy(buffer, bufferStart, writeBytes, 0, length.Value); - - // Attempt to pause the game before writing - bool preSuspended = _io?.IsSuspended ?? false; - if (safeWrite) - _io?.Suspend(); - - if (EndiannessUtilities.DataIsMisaligned(address, length.Value, EndiannessType.Big)) - throw new Exception("Misaligned data"); - - // Write memory to game/process - bool result; - if (absoluteAddress) - result = _io?.WriteAbsolute(address, writeBytes, endianness) ?? false; - else - { - result = _io?.WriteRelative(address.ToUInt32(), writeBytes, endianness) ?? false; - if (result && _io.ReadRelative(address.ToUInt32(), writeBytes, endianness)) - Array.Copy(writeBytes, 0, Ram, address.ToUInt32() & 0x00FFFFFF, writeBytes.Length); - } - - // Resume stream - if (safeWrite && !preSuspended) - _io?.Resume(); - - return result; - } - } - - public bool RefreshRam() - { - lock (_ram) - { - try - { - // Read whole ram value to buffer - if (_ram.Length != Config.RamSize) - _ram = new byte[Config.RamSize]; - - return _io?.ReadRelative(0, _ram, EndiannessType.Little) ?? false; - } - catch (Exception) - { - return false; - } - } - } - - public bool GetAllRam(out byte[] allRam) - { - allRam = new byte[Config.RamSize]; - try - { - return _io?.ReadRelative(0, allRam, EndiannessType.Little) ?? false; - } - catch - { - return false; - } - } - - private void ProcessUpdate() - { - Stopwatch frameStopwatch = Stopwatch.StartNew(); - - while (!disposedValue) - { - frameStopwatch.Restart(); - Application.DoEvents(); - double timeToWait; - lock (_mStreamProcess) - { - RefreshRam(); - OnUpdate?.Invoke(); - - // Calculate delay to match correct FPS - frameStopwatch.Stop(); - double timePassed = (frameStopwatch.ElapsedTicks / (double)Stopwatch.Frequency); - timeToWait = RefreshRateConfig.RefreshRateInterval - timePassed; - timeToWait = Math.Max(timeToWait, 0); - - // Calculate Fps - while (_fpsTimes.Count() >= 10) - _fpsTimes.RemoveAt(0); - _fpsTimes.Add(timePassed + timeToWait); - FpsUpdated?.Invoke(this, new EventArgs()); - } - - if (timeToWait > 0) - Thread.Sleep(new TimeSpan((long)(timeToWait * 10000000))); - else - Thread.Yield(); - } - } - - #region IDisposable Support - - private bool disposedValue = false; // To detect redundant calls - - protected virtual void Dispose(bool disposing) - { - if (!disposedValue) - { - if (disposing) - { - if (_io != null) - { - _io.OnClose -= ProcessClosed; - (_io as IDisposable)?.Dispose(); - } - } - - disposedValue = true; - } - } - - public void Dispose() - { - Dispose(true); - } - - #endregion - } -} diff --git a/STROOP/Utilities/Stream/StFileIO.cs b/STROOP/Utilities/Stream/StFileIO.cs deleted file mode 100644 index c80ec89ce..000000000 --- a/STROOP/Utilities/Stream/StFileIO.cs +++ /dev/null @@ -1,93 +0,0 @@ -using System; -using STROOP.Structs; -using ICSharpCode.SharpZipLib.GZip; -using System.IO; -using System.Diagnostics; - -namespace STROOP.Utilities -{ - class StFileIO : BaseProcessIO - { - public override bool IsSuspended => false; - - public override event EventHandler OnClose; - - private string _path; - public string Path => _path; - - protected override UIntPtr BaseOffset => new UIntPtr(0x1B0); - protected override EndiannessType Endianness => EndiannessType.Little; - - public override string Name => System.IO.Path.GetFileName(_path); - public override Process Process => null; - - private byte[] _data; - - public StFileIO(string path) : base() - { - _path = path; - LoadMemory(); - } - - public void LoadMemory() - { - using (var fileStream = new FileStream(_path, FileMode.Open)) - { - using (var gzipStream = new GZipInputStream(fileStream)) - { - using (MemoryStream unzip = new MemoryStream()) - { - gzipStream.CopyTo(unzip); - _data = unzip.GetBuffer(); - } - } - } - } - - public void SaveMemory(string path) - { - using (var fileStream = new FileStream(path, FileMode.Create)) - { - using (var gzipStream = new GZipOutputStream(fileStream)) - { - gzipStream.Write(_data, 0, _data.Length); - } - } - } - - public override bool Resume() - { - return true; - } - - public override bool Suspend() - { - return true; - } - - protected override bool WriteFunc(UIntPtr address, byte[] buffer) - { - if ((uint)address + buffer.Length > _data.Length) - return false; - - Array.Copy(buffer, 0, _data, (uint)address, buffer.Length); - return true; - } - - protected override bool ReadFunc(UIntPtr address, byte[] buffer) - { - if ((uint)address + buffer.Length > _data.Length) - return false; - - Array.Copy(_data, (uint)address, buffer, 0, buffer.Length); - return true; - } - - public override byte[] ReadAllMemory() - { - byte[] output = new byte[_data.Length]; - Array.Copy(_data, output, _data.Length); - return output; - } - } -} diff --git a/STROOP/Utilities/Stream/WindowsProcessIO.cs b/STROOP/Utilities/Stream/WindowsProcessIO.cs deleted file mode 100644 index 2f5ff1bf2..000000000 --- a/STROOP/Utilities/Stream/WindowsProcessIO.cs +++ /dev/null @@ -1,270 +0,0 @@ -using STROOP.Structs; -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Diagnostics; -using System.Linq; -using System.Runtime.InteropServices; -using static STROOP.Utilities.Kernal32NativeMethods; - -namespace STROOP.Utilities -{ - class WindowsProcessRamIO : BaseProcessIO, IDisposable - { - protected IntPtr _processHandle; - protected Process _process; - protected bool _isSuspended = false; - protected UIntPtr _baseOffset; - protected Emulator _emulator; - - public override bool IsSuspended => _isSuspended; - - protected override EndiannessType Endianness => _emulator.Endianness; - protected override UIntPtr BaseOffset => _baseOffset; - - public override string Name => _process.ProcessName; - public override Process Process => _process; - - public override event EventHandler OnClose; - - public WindowsProcessRamIO(Process process, Emulator emulator) : base() - { - _process = process; - _emulator = emulator; - - _process.EnableRaisingEvents = true; - - ProcessAccess accessFlags = ProcessAccess.PROCESS_QUERY_LIMITED_INFORMATION | ProcessAccess.SUSPEND_RESUME - | ProcessAccess.VM_OPERATION | ProcessAccess.VM_READ | ProcessAccess.VM_WRITE; - _processHandle = ProcessGetHandleFromId(accessFlags, false, _process.Id); - try - { - CalculateOffset(); - } - catch (Exception e) - { - CloseProcess(_processHandle); - throw; - } - - _process.Exited += _process_Exited; - } - - private void _process_Exited(object sender, EventArgs e) - { - Dispose(); - OnClose.Invoke(sender, e); - } - - protected override bool ReadFunc(UIntPtr address, byte[] buffer) - { - int numOfBytes = 0; - return ProcessReadMemory(_processHandle, address, buffer, (IntPtr)buffer.Length, ref numOfBytes); - } - - protected override bool WriteFunc(UIntPtr address, byte[] buffer) - { - int numOfBytes = 0; - return ProcessWriteMemory(_processHandle, address, buffer, (IntPtr)buffer.Length, ref numOfBytes); - } - - public override byte[] ReadAllMemory() - { - List output = new List(); - byte[] buffer = new byte[1]; - int numBytes = 1; - - for (uint address = 0; true; address++) - { - bool success = ProcessReadMemory(_processHandle, (UIntPtr)address, buffer, (IntPtr)buffer.Length, ref numBytes); - if (!success) break; - output.Add(buffer[0]); - } - - return output.ToArray(); - } - - bool CompareBytes(byte[] a, byte[] b) - { - if (a.Length != b.Length) return false; - for (int i = 0; i < a.Length; i++) - if (a[i] != b[i]) - return false; - return true; - } - - // see https://msdn.microsoft.com/en-us/library/windows/desktop/ms684139%28v=vs.85%29.aspx - public static bool Is64Bit(Process process) - => Environment.Is64BitOperatingSystem - && IsWow64Process(process.Handle, out bool isWow64) - ? !isWow64 - : throw new Win32Exception(); - - protected virtual void CalculateOffset() - { - // Find CORE_RDRAM export from mupen if present - var symbol = Win32SymbolInfo.Create(); - if (SymInitialize(_process.Handle, null, true)) - { - try - { - if (SymFromName(_process.Handle, "CORE_RDRAM", ref symbol)) - { - var is64Bit = Is64Bit(_process); - var buffer = new byte[is64Bit ? 8 : 4]; - ReadAbsolute((UIntPtr)symbol.Address, buffer, EndiannessType.Little); - _baseOffset = (UIntPtr)(is64Bit ? BitConverter.ToUInt64(buffer, 0) : (ulong)BitConverter.ToUInt32(buffer, 0)); - return; - } - } - finally - { - if (!SymCleanup(_process.Handle)) - throw new Win32Exception(); - } - } - else - { - // documentation doesn't say what to do when SymInitialize returns false, so just call this and don't care for its result for good (or bad) measure :shrug: - // https://learn.microsoft.com/en-us/windows/win32/api/dbghelp/nf-dbghelp-syminitialize - SymCleanup(_process.Handle); - } - - // Find DLL offset if needed - IntPtr dllOffset = new IntPtr(); - - if (_emulator != null && _emulator.Dll != null) - { - ProcessModule dll = _process.Modules.Cast() - ?.FirstOrDefault(d => d.ModuleName == _emulator.Dll); - - if (dll == null) - throw new ArgumentNullException("Could not find "); - - dllOffset = dll.BaseAddress; - } - - _baseOffset = (UIntPtr)(_emulator.RamStart + (UInt64)dllOffset.ToInt64()); - - if (!_emulator.AllowAutoDetect) - return; - - // Address of create_thread - foreach ((string name, uint offset) x in new[] { ("US", 0x246338), ("JP", 0x246338) }) - { - var path = $"Resources/AutoDetectFile {x.name}.bin"; - if (!System.IO.File.Exists(path)) - continue; - - var autoDetectPattern = System.IO.File.ReadAllBytes(path); - var comparisonBuffer = new byte[autoDetectPattern.Length]; - - var processScanner = new SigScanSharp(Process.Handle); - var minOffset = 0; - while (processScanner.SelectModule(Process.MainModule)) - { - var foundPatternAddress = processScanner.FindPattern(autoDetectPattern, ref minOffset, out var t); - minOffset += autoDetectPattern.Length; - if (foundPatternAddress != IntPtr.Zero) - { - var newBaseOffset = UIntPtr.Subtract((UIntPtr)(long)foundPatternAddress, (int)x.offset); - _baseOffset = newBaseOffset; - if (VerifyCandidate(newBaseOffset)) - goto verified; - } - else - break; - } - } - - messageLogBuilder.AppendLine("Unable to verify or correct RAM start.\r\nVerify that the game is currently running."); - verified:; - - bool VerifyCandidate(UIntPtr candidate) - { - try - { - var mem = new byte[0x200]; - var expectedSignature = new byte?[] - { - null, 0x80, 0x1a, 0x3c, - null, null, 0x5a, 0x27, - 0x08, 0x00, 0x40, 0x03, - 0x00, 0x00, 0x00, 0x00, - }; - if (!ReadFunc(candidate, mem)) - return false; - - for (int i = 0; i < expectedSignature.Length; i++) - { - if (expectedSignature[i].HasValue && mem[i] != expectedSignature[i].Value) - return false; - else if (!expectedSignature[i].HasValue) - expectedSignature[i] = mem[i]; - } - - foreach (var location in new[] { 0x80, 0x100, 0x180 }) - for (var i = 0; i < expectedSignature.Length; i++) - if (expectedSignature[i].Value != mem[i + location]) - return false; - } - catch (Exception e) - { - return false; - } - - return true; - } - } - - public override bool Suspend() - { - SuspendProcess(_process); - _isSuspended = true; - return true; - } - - public override bool Resume() - { - // Resume all threads - ResumeProcess(_process); - _isSuspended = false; - return true; - } - - #region IDisposable Support - - private bool disposedValue = false; // To detect redundant calls - - protected virtual void Dispose(bool disposing) - { - if (!disposedValue) - { - if (disposing) - { - if (IsSuspended) - Resume(); - _process.Exited -= _process_Exited; - } - - // Close old process - CloseProcess(_processHandle); - - disposedValue = true; - } - } - - ~WindowsProcessRamIO() - { - Dispose(false); - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - #endregion - } -} diff --git a/STROOP/Utilities/StringUtilities.cs b/STROOP/Utilities/StringUtilities.cs deleted file mode 100644 index 42b16197a..000000000 --- a/STROOP/Utilities/StringUtilities.cs +++ /dev/null @@ -1,109 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Reflection; -using STROOP.Controls.VariablePanel; -using STROOP.Structs; - -namespace STROOP.Utilities -{ - /// - /// Denotes that a static string variable's value shall be initialized with its field name when is called on its declaring type. - /// - [AttributeUsage(AttributeTargets.Field)] - public class DeclaredStringAttribute : Attribute - { - } - - public static class StringUtilities - { - public static void InitializeDeclaredStrings(Type t) - { - foreach (var field in t.GetFields(BindingFlags.Public | BindingFlags.Static)) - if (field.FieldType == typeof(string)) - field.SetValue(null, field.Name); - } - - public static string Cap(string stringValue, int length) - { - if (stringValue == null) return stringValue; - if (stringValue.Length <= length) return stringValue; - return stringValue.Substring(0, length); - } - - public static string ExactLength(string stringValue, int length, bool leftAppend, char appendChar) - { - if (stringValue == null) return stringValue; - if (stringValue.Length < length) - { - return leftAppend - ? stringValue.PadLeft(length, appendChar) - : stringValue.PadRight(length, appendChar); - } - - if (stringValue.Length > length) - { - return leftAppend - ? stringValue.Substring(stringValue.Length - length) - : stringValue.Substring(0, length); - } - - return stringValue; - } - - public static string FormatIntegerWithSign(int num) - { - return (num > 0 ? "+" : "") + num; - } - - public static string Capitalize(string s) - { - if (string.IsNullOrEmpty(s)) return s; - return s.Substring(0, 1).ToUpper() + s.Substring(1); - } - - public static string Concat(IEnumerable ts, Func toString) - { - List strings = new List(); - foreach (var t in ts) - strings.Add(toString(t)); - return string.Concat(strings); - } - - static System.Text.RegularExpressions.Regex needsJsonStringEscapeRegex = new System.Text.RegularExpressions.Regex("^[-]?(([0-9]+)|(([0-9]+)\\.([0-9]+)))$"); - - public static string MakeJsonValue(string input) - { - input = input.Trim(' ', '"'); - if (!needsJsonStringEscapeRegex.IsMatch(input)) - return $"\"{input}\""; - return input; - } - - public static object GetJsonValue(Type variableWrapperType, string valueString) - { - var str = valueString.Trim('"'); - double numberValue = 0; - if (TypeUtilities.MatchesGenericType(typeof(WatchVariableNumberWrapper<>), variableWrapperType)) - { - bool set = true; - if (str.StartsWith("0x")) - { - if (set = long.TryParse(str.Substring(2, str.Length - 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var hexValue)) - numberValue = hexValue; - } - else - set = double.TryParse(str, out numberValue); - - if (set) - return numberValue; - } - else if (typeof(WatchVariableBooleanWrapper).IsAssignableFrom(variableWrapperType)) - return valueString.ToLower() != "false" && (!int.TryParse(valueString, out var boolNumber) || boolNumber != 0); - else - return valueString; - - return 0; - } - } -} diff --git a/STROOP/Utilities/TypeUtilities.cs b/STROOP/Utilities/TypeUtilities.cs deleted file mode 100644 index e40727599..000000000 --- a/STROOP/Utilities/TypeUtilities.cs +++ /dev/null @@ -1,287 +0,0 @@ -using STROOP.Structs.Configurations; -using STROOP.Utilities; -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Text; - -namespace STROOP.Structs -{ - public static class TypeUtilities - { - public readonly static Dictionary StringToType = new Dictionary() - { - { "byte", typeof(byte) }, - { "sbyte", typeof(sbyte) }, - { "short", typeof(short) }, - { "ushort", typeof(ushort) }, - { "int", typeof(int) }, - { "uint", typeof(uint) }, - { "long", typeof(long) }, - { "ulong", typeof(ulong) }, - { "float", typeof(float) }, - { "double", typeof(double) }, - }; - - public readonly static Dictionary TypeToString = new Dictionary() - { - { typeof(byte), "byte" }, - { typeof(sbyte), "sbyte" }, - { typeof(short), "short" }, - { typeof(ushort), "ushort" }, - { typeof(int), "int" }, - { typeof(uint), "uint" }, - { typeof(long), "long" }, - { typeof(ulong), "ulong" }, - { typeof(float), "float" }, - { typeof(double), "double" }, - }; - - public readonly static Dictionary TypeSize = new Dictionary() - { - { typeof(byte), 1 }, - { typeof(sbyte), 1 }, - { typeof(short), 2 }, - { typeof(ushort), 2 }, - { typeof(int), 4 }, - { typeof(uint), 4 }, - { typeof(long), 8 }, - { typeof(ulong), 8 }, - { typeof(float), 4 }, - { typeof(double), 8 }, - }; - - public readonly static Dictionary TypeSign = new Dictionary() - { - { typeof(byte), false }, - { typeof(sbyte), true }, - { typeof(short), true }, - { typeof(ushort), false }, - { typeof(int), true }, - { typeof(uint), false }, - { typeof(long), true }, - { typeof(ulong), false }, - { typeof(float), true }, - { typeof(double), true }, - }; - - public readonly static Dictionary UnsignedByteType = new Dictionary() - { - { 1, typeof(byte) }, - { 2, typeof(ushort) }, - { 4, typeof(uint) }, - { 8, typeof(ulong) }, - }; - - public readonly static List SimpleTypeList = - new List() - { - "byte", - "sbyte", - "short", - "ushort", - "int", - "uint", - "float", - }; - - public readonly static List InGameTypeList = - new List() - { - "byte", - "sbyte", - "short", - "ushort", - "int", - "uint", - "float", - "double", - }; - - public static object ConvertBytes(Type type, string hexString, bool littleEndian) - { - if (hexString == null) return null; - if (hexString.Length >= 2 && hexString.Substring(0, 2) == "0x") hexString = hexString.Substring(2); - hexString = StringUtilities.ExactLength(hexString, 2 * TypeSize[type], true, '0'); - - try - { - byte[] bytes = Enumerable.Range(0, hexString.Length) - .ToList() - .FindAll(i => i % 2 == 0) - .ConvertAll(i => Convert.ToByte(hexString.Substring(i, 2), 16)) - .ToArray(); - return ConvertBytes(type, bytes, 0, littleEndian); - } - catch (Exception) - { - return null; - } - } - - public static object ConvertBytes(Type type, byte[] allBytes, int startIndex, bool littleEndian) - { - int typeSize = TypeSize[type]; - int modValue = startIndex % 4; - int baseValue = startIndex - modValue; - int newModValue = modValue; - if (littleEndian) - { - if (typeSize == 2) newModValue = 2 - modValue; - if (typeSize == 1) newModValue = 3 - modValue; - } - - int newStartAddress = baseValue + newModValue; - - byte[] bytes = new byte[typeSize]; - for (int i = 0; i < typeSize; i++) - { - byte byteValue = allBytes[newStartAddress + i]; - int index = typeSize - 1 - i; - bytes[index] = byteValue; - } - - return ConvertBytes(type, bytes); - } - - public static object ConvertBytes(Type type, byte[] bytes) - { - if (type == typeof(byte)) return bytes[0]; - if (type == typeof(sbyte)) return (sbyte)bytes[0]; - if (type == typeof(short)) return BitConverter.ToInt16(bytes, 0); - if (type == typeof(ushort)) return BitConverter.ToUInt16(bytes, 0); - if (type == typeof(int)) return BitConverter.ToInt32(bytes, 0); - if (type == typeof(uint)) return BitConverter.ToUInt32(bytes, 0); - if (type == typeof(float)) return BitConverter.ToSingle(bytes, 0); - if (type == typeof(double)) return BitConverter.ToDouble(bytes, 0); - throw new ArgumentOutOfRangeException(); - } - - public static byte[] GetBytes(object obj, int? fixedLength = null, Encoding encoding = null) - { - byte[] bytes; - - if (obj is byte byteValue) bytes = new byte[] { byteValue }; - else if (obj is sbyte sbyteValue) bytes = new byte[] { (byte)sbyteValue }; - else if (obj is short shortValue) bytes = BitConverter.GetBytes(shortValue); - else if (obj is ushort ushortValue) bytes = BitConverter.GetBytes(ushortValue); - else if (obj is int intValue) bytes = BitConverter.GetBytes(intValue); - else if (obj is uint uintValue) bytes = BitConverter.GetBytes(uintValue); - else if (obj is float floatValue) bytes = BitConverter.GetBytes(floatValue); - else if (obj is double doubleValue) bytes = BitConverter.GetBytes(doubleValue); - else if (obj is string stringValue) - { - if (encoding == null) throw new ArgumentOutOfRangeException(); - bytes = encoding.GetBytes(stringValue); - } - else throw new ArgumentOutOfRangeException(); - - if (fixedLength.HasValue) - { - if (bytes.Length > fixedLength.Value) - { - bytes = bytes.Take(fixedLength.Value).ToArray(); - } - else if (bytes.Length < fixedLength.Value) - { - bytes = bytes.Concat(new byte[fixedLength.Value - bytes.Length]).ToArray(); - } - } - - return bytes; - } - - public static bool IsNumber(object obj) - { - return obj is byte || - obj is sbyte || - obj is short || - obj is ushort || - obj is int || - obj is uint || - obj is long || - obj is ulong || - obj is float || - obj is double; - } - - public static bool IsIntegerNumber(object obj) - { - return obj is byte || - obj is sbyte || - obj is short || - obj is ushort || - obj is int || - obj is uint || - obj is long || - obj is ulong; - } - - public static byte[] ConvertHexStringToByteArray(string stringValue, bool swapEndianness) - { - if (stringValue == null || stringValue.Length % 2 == 1) - { - throw new ArgumentOutOfRangeException("stringValue must have even length"); - } - - byte[] bytes = new byte[stringValue.Length / 2]; - for (int i = 0; i < bytes.Length; i++) - { - string byteString = stringValue.Substring(i * 2, 2); - byte byteValue = byte.Parse(byteString, NumberStyles.HexNumber); - int index = swapEndianness ? bytes.Length - 1 - i : i; - bytes[index] = byteValue; - } - - return bytes; - } - - public static bool IsSubtype(Type type1, Type type2) - { - return type1 == type2 || type1.IsSubclassOf(type2); - } - - public static bool MatchesGenericType(Type genericType, Type typeToCheck) - { - var t = typeToCheck; - while (t != null) - { - if (t.IsGenericType && t.GetGenericTypeDefinition() == genericType) - return true; - t = t.BaseType; - } - - return false; - } - - public static uint GetRelativeAddressFromAbsoluteAddress(uint addr, int byteCount) - { - UIntPtr addressPtr = new UIntPtr(addr); - uint address = EndiannessUtilities.SwapAddressEndianness( - Config.Stream.GetRelativeAddress(addressPtr, byteCount), byteCount); - return address | 0x80000000; - } - - public static uint GetAbsoluteAddressFromRelativeAddress(uint addr, int byteCount) - { - return Config.Stream.GetAbsoluteAddress(addr, byteCount).ToUInt32(); - } - - public static uint? SwapRelativeAbsolute(uint addr, int byteCount) - { - try - { - string addressString = HexUtilities.FormatValue(addr); - if (addressString.Length >= 4 && addressString.StartsWith("0x80")) - return GetAbsoluteAddressFromRelativeAddress(addr, byteCount); - else - return GetRelativeAddressFromAbsoluteAddress(addr, byteCount); - } - catch (Exception) - { - return null; - } - } - } -} diff --git a/STROOP/Utilities/VarHackSpecialUtilities.cs b/STROOP/Utilities/VarHackSpecialUtilities.cs index b76076585..2ee8abf26 100644 --- a/STROOP/Utilities/VarHackSpecialUtilities.cs +++ b/STROOP/Utilities/VarHackSpecialUtilities.cs @@ -1,5 +1,6 @@ using STROOP.Structs.Configurations; using STROOP.Utilities; +using STROOP.Variables.SM64MemoryLayout; using System; namespace STROOP.Structs @@ -33,12 +34,12 @@ public static (string, Func) CreateGetterFunction(string specialType) case "DefactoSpeed": name = "Defacto " + VarHackConfig.EscapeChar; - getterFunction = () => { return FormatInteger(WatchVariableSpecialUtilities.GetMarioDeFactoSpeed()); }; + getterFunction = () => { return FormatInteger(VariableSpecialUtilities.GetMarioDeFactoSpeed()); }; break; case "SlidingSpeed": name = "Spd " + VarHackConfig.EscapeChar; - getterFunction = () => { return FormatInteger(WatchVariableSpecialUtilities.GetMarioSlidingSpeed()); }; + getterFunction = () => { return FormatInteger(VariableSpecialUtilities.GetMarioSlidingSpeed()); }; break; case "MarioAction": @@ -53,12 +54,12 @@ public static (string, Func) CreateGetterFunction(string specialType) case "DYawIntendFacing": name = "DYaw " + VarHackConfig.EscapeChar; - getterFunction = () => { return FormatInteger(WatchVariableSpecialUtilities.GetDeltaYawIntendedFacing()); }; + getterFunction = () => { return FormatInteger(VariableSpecialUtilities.GetDeltaYawIntendedFacing()); }; break; case "DYawIntendFacingHau": name = "DYaw " + VarHackConfig.EscapeChar; - getterFunction = () => { return FormatInteger(WatchVariableSpecialUtilities.GetDeltaYawIntendedFacing() / 16); }; + getterFunction = () => { return FormatInteger(VariableSpecialUtilities.GetDeltaYawIntendedFacing() / 16); }; break; default: diff --git a/STROOP/Utilities/WatchVariableSelectionUtilities.cs b/STROOP/Utilities/VariableSelectionUtilities.cs similarity index 54% rename from STROOP/Utilities/WatchVariableSelectionUtilities.cs rename to STROOP/Utilities/VariableSelectionUtilities.cs index 33fbd2d60..1bf7e6407 100644 --- a/STROOP/Utilities/WatchVariableSelectionUtilities.cs +++ b/STROOP/Utilities/VariableSelectionUtilities.cs @@ -6,32 +6,60 @@ using OpenTK.Mathematics; using STROOP.Controls; using STROOP.Controls.VariablePanel; -using STROOP.Core.Variables; +using STROOP.Controls.VariablePanel.Cells; +using STROOP.Core.Utilities; using STROOP.Extensions; using STROOP.Forms; using STROOP.Structs.Configurations; using STROOP.Utilities; +using STROOP.Variables; +using STROOP.Variables.Utilities; +using STROOP.Variables.VariablePanel; +using System.Globalization; namespace STROOP.Structs { - public static class WatchVariableSelectionUtilities + using BinaryScalarOperation = Func; + + public static class VariableSelectionUtilities { + static IEnumerable FilterNumberVariables(IEnumerable cells) + => cells.OfType().Where(x => x is not IVariableCellData); + + static double GetNumberValue(this INumberVariableCell cell) + => (double)(Convert.ChangeType(cell.CombineValues().value, TypeCode.Double) ?? double.NaN); + + static bool SetValue(this INumberVariableCell cell, double value) + => cell.TrySetValue(value.ToString(CultureInfo.InvariantCulture)); + + static readonly List VarInfoLabels = + [ + "Name", + "Class", + "Type", + "BaseType + Offset", + "N64 Base Address", + "Emulator Base Address", + "N64 Address", + "Emulator Address", + ]; + public static List CreateSelectionToolStripItems( - List vars, - WatchVariablePanel panel) + List vars, + VariablePanel panel) { var itemList = new List(); ToolStripMenuItem itemShowAlways = new ToolStripMenuItem("Always visible"); itemShowAlways.CheckState = GeneralUtilities.GetMeaningfulValue( - () => vars.ConvertAll(v => (CheckState?)(v.alwaysVisible ? CheckState.Checked : CheckState.Unchecked)), + () => vars.ConvertAll(v => (CheckState?)(v.control.alwaysVisible ? CheckState.Checked : CheckState.Unchecked)), CheckState.Indeterminate, null) ?? CheckState.Indeterminate; itemShowAlways.MouseDown += (_, __) => { itemShowAlways.Checked = !itemShowAlways.Checked; foreach (var v in vars) - v.alwaysVisible = itemShowAlways.Checked; + v.control.alwaysVisible = itemShowAlways.Checked; itemShowAlways.PreventClosingMenuStrip(); }; itemList.Add(itemShowAlways); @@ -52,7 +80,7 @@ public static List CreateSelectionToolStripItems( { for (int i = 0; i < vars.Count; i++) { - vars[i].SetValue(stringList[i % stringList.Count]); + vars[i].control.SetValue(stringList[i % stringList.Count]); } } }; @@ -66,7 +94,7 @@ public static List CreateSelectionToolStripItems( infoForm.SetText( "Variable Info", "Variable XML", - String.Join("\r\n", vars.ConvertAll(control => control.ToXml()))); + String.Join("\r\n", vars.ConvertAll(cell => cell.control.ToXml()))); infoForm.Show(); }; itemList.Add(itemShowVariableXml); @@ -79,105 +107,97 @@ public static List CreateSelectionToolStripItems( "Variable Info", "Variable Info", String.Join("\t", - WatchVariableWrapper.GetVarInfoLabels()) + + VarInfoLabels) + "\r\n" + String.Join( "\r\n", - vars.ConvertAll(control => control.GetVarInfo()) + vars.ConvertAll(cell => cell.control.GetVarInfo()) .ConvertAll(infoList => String.Join("\t", infoList)))); infoForm.Show(); }; itemList.Add(itemShowVariableInfo); itemList.Add(new ToolStripSeparator()); - Dictionary> binaryMathOperations = new Dictionary>() + Dictionary binaryMathOperations = new Dictionary() { - [BinaryMathOperation.Add] = (a, b) => a + b, - [BinaryMathOperation.Subtract] = (a, b) => a - b, - [BinaryMathOperation.Multiply] = (a, b) => a * b, - [BinaryMathOperation.Divide] = (a, b) => a / b, - [BinaryMathOperation.Exponent] = (a, b) => Math.Pow(a, b), - [BinaryMathOperation.Modulo] = (a, b) => a % b, - [BinaryMathOperation.NonNegativeModulo] = (a, b) => MoreMath.NonNegativeModulus(a, b), + [BinaryOperationName.Add] = (a, b) => a + b, + [BinaryOperationName.Subtract] = (a, b) => a - b, + [BinaryOperationName.Multiply] = (a, b) => a * b, + [BinaryOperationName.Divide] = (a, b) => a / b, + [BinaryOperationName.Exponent] = (a, b) => Math.Pow(a, b), + [BinaryOperationName.Modulo] = (a, b) => a % b, + [BinaryOperationName.NonNegativeModulo] = (a, b) => MoreMath.NonNegativeModulus(a, b), }; - Dictionary> binaryMathOperationsInverse1 = new Dictionary>() + Dictionary binaryMathOperationsInverse1 = new Dictionary() { - [BinaryMathOperation.Add] = (sum, b) => sum - b, - [BinaryMathOperation.Subtract] = (diff, b) => b + diff, - [BinaryMathOperation.Multiply] = (product, b) => product / b, - [BinaryMathOperation.Divide] = (quotient, b) => b * quotient, + [BinaryOperationName.Add] = (sum, b) => sum - b, + [BinaryOperationName.Subtract] = (diff, b) => b + diff, + [BinaryOperationName.Multiply] = (product, b) => product / b, + [BinaryOperationName.Divide] = (quotient, b) => b * quotient, }; - Dictionary> binaryMathOperationsInverse2 = new Dictionary>() + Dictionary binaryMathOperationsInverse2 = new Dictionary() { - [BinaryMathOperation.Add] = (sum, b) => sum - b, - [BinaryMathOperation.Subtract] = (diff, b) => b - diff, - [BinaryMathOperation.Multiply] = (product, a) => product / a, - [BinaryMathOperation.Divide] = (quotient, a) => a / quotient, + [BinaryOperationName.Add] = (sum, b) => sum - b, + [BinaryOperationName.Subtract] = (diff, b) => b - diff, + [BinaryOperationName.Multiply] = (product, a) => product / a, + [BinaryOperationName.Divide] = (quotient, a) => a / quotient, }; - void createBinaryMathOperationVariable(BinaryMathOperation operation) + void createBinaryMathOperationVariable(BinaryOperationName operation) { - List controls = new List(vars); - if (controls.Count % 2 == 1) controls.RemoveAt(controls.Count - 1); + var cells = FilterNumberVariables(vars).ToArray(); if (binaryMathOperations.TryGetValue(operation, out var func)) - for (int i = 0; i < controls.Count / 2; i++) + for (int i = 0; i < cells.Length / 2; i++) { - var control1 = controls[i]; - var control2 = controls[i + controls.Count / 2]; - var wrapper1 = control1.WatchVarWrapper; - var wrapper2 = control2.WatchVarWrapper; + var cell1 = cells[i]; + var cell2 = cells[i + cells.Length / 2]; - Func inverseSetter1, inverseSetter2; - binaryMathOperationsInverse1.TryGetValue(operation, out inverseSetter1); - binaryMathOperationsInverse2.TryGetValue(operation, out inverseSetter2); + binaryMathOperationsInverse1.TryGetValue(operation, out BinaryScalarOperation inverseSetter1); + binaryMathOperationsInverse2.TryGetValue(operation, out BinaryScalarOperation inverseSetter2); - var view = new NamedVariableCollection.CustomView(typeof(WatchVariableNumberWrapper)) + var result = new CustomVariable(VariableSubclass.Number) { - Name = $"{control1.view.Name} {MathOperationUtilities.GetSymbol(operation)} {control2.view.Name}", - _getterFunction = () => func(wrapper1._view.CombineValues().value, wrapper2._view.CombineValues().value).Yield(), - _setterFunction = val => + getter = () => func(cell1.GetNumberValue(), cell2.GetNumberValue()).Yield(), + setter = val => { - if (val is double valueDouble) - if (!GlobalKeyboard.IsCtrlDown()) - { - var wrapper1Value = wrapper1._view.CombineValues().value; - return inverseSetter2 == null - ? Array.Empty() - : control1.view.TrySetValue(inverseSetter2(valueDouble, wrapper1Value)); - } - else - { - var wrapper2Value = wrapper2._view.CombineValues().value; - return inverseSetter1 == null - ? Array.Empty() - : control2.view.TrySetValue(inverseSetter1(valueDouble, wrapper2Value)); - } + if (!GlobalKeyboard.IsCtrlDown()) + { + var wrapper1Value = (double)Convert.ChangeType(cell1.CombineValues().value, TypeCode.Double)!; + return inverseSetter2 == null + ? Array.Empty() + : cell1.SetValue(inverseSetter2(val, wrapper1Value)).Yield(); + } else - return Array.Empty(); + { + var wrapper2Value = (double)Convert.ChangeType(cell2.CombineValues().value, TypeCode.Double)!; + return inverseSetter1 == null + ? Array.Empty() + : cell2.SetValue(inverseSetter1(val, wrapper2Value)).Yield(); + } } }; - panel.AddVariable(view); + panel.AddVariable(($"{cell1.control.VarName} {MathOperationUtilities.GetSymbol(operation)} {cell2.control.VarName}", result)); } } void createAggregateMathOperationVariable(AggregateMathOperation operation) { if (vars.Count == 0) return; - var getter = WatchVariableSpecialUtilities.AddAggregateMathOperationEntry(vars, operation); - var view = new NamedVariableCollection.CustomView(typeof(WatchVariableNumberWrapper)) + var getter = VariableSpecialUtilities.AddAggregateMathOperationEntry(vars, operation); + var result = new CustomVariable(VariableSubclass.Number) { - Name = $"{operation}({vars.First().view.Name}-{vars.Last().view.Name})", - _getterFunction = getter, - _setterFunction = WatchVariableSpecialUtilities.Defaults.DEFAULT_SETTER + getter = getter, + setter = SpecialVariableDefaults.DEFAULT_SETTER }; - panel.AddVariable(view); + panel.AddVariable(($"{operation}({vars.First().control.VarName}-{vars.Last().control.VarName})", result)); } void createDistanceMathOperationVariable(bool use3D) { + var cells = FilterNumberVariables(vars).ToArray(); bool satisfies2D = !use3D && vars.Count >= 4; bool satisfies3D = use3D && vars.Count >= 6; if (!satisfies2D && !satisfies3D) return; @@ -185,58 +205,58 @@ void createDistanceMathOperationVariable(bool use3D) string name = use3D ? string.Format( "({0},{1},{2}) to ({3},{4},{5})", - vars[0].VarName, - vars[1].VarName, - vars[2].VarName, - vars[3].VarName, - vars[4].VarName, - vars[5].VarName) + cells[0].control.VarName, + cells[1].control.VarName, + cells[2].control.VarName, + cells[3].control.VarName, + cells[4].control.VarName, + cells[5].control.VarName) : string.Format( "({0},{1}) to ({2},{3})", - vars[0].VarName, - vars[1].VarName, - vars[2].VarName, - vars[3].VarName); + cells[0].control.VarName, + cells[1].control.VarName, + cells[2].control.VarName, + cells[3].control.VarName); - var varValues = vars.Select(x => x.view.GetNumberValues().ToArray()).ToArray(); + var values = VariableUtilities.GetNumberValues(vars).Select(Enumerable.ToArray).ToArray(); - NamedVariableCollection.GetterFunction getter3D = () => + IVariable.ValueGetter getter3D = () => { - var x1 = varValues[0]; - var y1 = varValues[1]; - var z1 = varValues[2]; - var x2 = varValues[3]; - var y2 = varValues[4]; - var z2 = varValues[5]; - var min = varValues.Min(x => x.Length); + var x1 = values[0]; + var y1 = values[1]; + var z1 = values[2]; + var x2 = values[3]; + var y2 = values[4]; + var z2 = values[5]; + var min = values.Min(x => x.Length); var result = new List(min); for (int i = 0; i < min; i++) result.Add(new Vector3d(x2[i] - x1[i], y2[i] - y1[i], z2[i] - z1[i]).Length); return result; }; - NamedVariableCollection.GetterFunction getter2D = () => + IVariable.ValueGetter getter2D = () => { - var x1 = varValues[0]; - var y1 = varValues[1]; - var x2 = varValues[3]; - var y2 = varValues[4]; - var min = varValues.Min(x => x.Length); + var x1 = values[0]; + var y1 = values[1]; + var x2 = values[3]; + var y2 = values[4]; + var min = values.Min(x => x.Length); var result = new List(min); for (int i = 0; i < min; i++) result.Add(new Vector2d(x2[i] - x1[i], y2[i] - y1[i]).Length); return result; }; - NamedVariableCollection.SetterFunction setter3D = value => + IVariable.ValueSetter setter3D = value => { - var x1 = varValues[0]; - var y1 = varValues[1]; - var z1 = varValues[2]; - var x2 = varValues[3]; - var y2 = varValues[4]; - var z2 = varValues[5]; + var x1 = values[0]; + var y1 = values[1]; + var z1 = values[2]; + var x2 = values[3]; + var y2 = values[4]; + var z2 = values[5]; bool toggle = GlobalKeyboard.IsCtrlDown(); int off = toggle ? 0 : 3; - var min = varValues.Min(x => x.Length); + var min = values.Min(x => x.Length); var result = new List(min); for (int i = 0; i < min; i++) { @@ -250,20 +270,20 @@ void createDistanceMathOperationVariable(bool use3D) } b = a + Vector3d.Normalize(b - a) * value; - result.Add(vars[off].SetValue(b.X) && vars[off].SetValue(b.Y) && vars[off].SetValue(b.Z)); + result.Add(cells[off].SetValue(b.X) && cells[off].SetValue(b.Y) && cells[off].SetValue(b.Z)); } return result; }; - NamedVariableCollection.SetterFunction setter2D = value => + IVariable.ValueSetter setter2D = value => { - var x1 = varValues[0]; - var y1 = varValues[1]; - var x2 = varValues[2]; - var y2 = varValues[3]; + var x1 = values[0]; + var y1 = values[1]; + var x2 = values[2]; + var y2 = values[3]; bool toggle = GlobalKeyboard.IsCtrlDown(); int off = toggle ? 0 : 2; - var min = varValues.Min(x => x.Length); + var min = values.Min(x => x.Length); var result = new List(min); for (int i = 0; i < min; i++) { @@ -277,19 +297,18 @@ void createDistanceMathOperationVariable(bool use3D) } b = a + Vector2d.Normalize(b - a) * (double)value; - result.Add(vars[off].SetValue(b.X) && vars[off].SetValue(b.Y)); + result.Add(cells[off].SetValue(b.X) && cells[off].SetValue(b.Y)); } return result; }; - var view = new NamedVariableCollection.CustomView(typeof(WatchVariableNumberWrapper)) + var result = new CustomVariable(VariableSubclass.Number) { - Name = name, - _getterFunction = use3D ? getter3D : getter2D, - _setterFunction = use3D ? setter3D : setter2D + getter = use3D ? getter3D : getter2D, + setter = use3D ? setter3D : setter2D }; - panel.AddVariable(view); + panel.AddVariable((name, result)); } ToolStripMenuItem itemAddVariables = new ToolStripMenuItem("Add Variable(s)..."); @@ -316,13 +335,13 @@ void createDistanceMathOperationVariable(bool use3D) }, new List() { - () => createBinaryMathOperationVariable(BinaryMathOperation.Add), - () => createBinaryMathOperationVariable(BinaryMathOperation.Subtract), - () => createBinaryMathOperationVariable(BinaryMathOperation.Multiply), - () => createBinaryMathOperationVariable(BinaryMathOperation.Divide), - () => createBinaryMathOperationVariable(BinaryMathOperation.Modulo), - () => createBinaryMathOperationVariable(BinaryMathOperation.NonNegativeModulo), - () => createBinaryMathOperationVariable(BinaryMathOperation.Exponent), + () => createBinaryMathOperationVariable(BinaryOperationName.Add), + () => createBinaryMathOperationVariable(BinaryOperationName.Subtract), + () => createBinaryMathOperationVariable(BinaryOperationName.Multiply), + () => createBinaryMathOperationVariable(BinaryOperationName.Divide), + () => createBinaryMathOperationVariable(BinaryOperationName.Modulo), + () => createBinaryMathOperationVariable(BinaryOperationName.NonNegativeModulo), + () => createBinaryMathOperationVariable(BinaryOperationName.Exponent), () => { }, () => createAggregateMathOperationVariable(AggregateMathOperation.Mean), () => createAggregateMathOperationVariable(AggregateMathOperation.Median), @@ -349,7 +368,7 @@ void createDistanceMathOperationVariable(bool use3D) { string template = DialogUtilities.GetStringFromDialog("$"); if (template == null) return; - foreach (WatchVariableControl control in vars) + foreach (WinFormsVariableControl control in vars) { control.VarName = template.Replace("$", control.VarName); } @@ -360,8 +379,8 @@ void createDistanceMathOperationVariable(bool use3D) ToolStripMenuItem itemOpenController = new ToolStripMenuItem("Open Controller"); itemOpenController.Click += (sender, e) => new VariableControllerForm( - vars.ConvertAll(control => control.VarName), - vars.ConvertAll(control => control.WatchVarWrapper) + vars.ConvertAll(cell => cell.control.VarName), + vars ).Show(); itemList.Add(itemOpenController); @@ -369,7 +388,7 @@ void createDistanceMathOperationVariable(bool use3D) itemOpenPopOut.Click += (sender, e) => { VariablePopOutForm form = new VariablePopOutForm(); - form.Initialize(vars.ConvertAll(control => control.view)); + form.Initialize(vars); form.ShowForm(); }; itemList.Add(itemOpenPopOut); diff --git a/STROOP/Utilities/WatchVariableSpecialUtilities.cs b/STROOP/Utilities/VariableSpecialUtilities.cs similarity index 95% rename from STROOP/Utilities/WatchVariableSpecialUtilities.cs rename to STROOP/Utilities/VariableSpecialUtilities.cs index 47d13f2aa..2b4ec65c3 100644 --- a/STROOP/Utilities/WatchVariableSpecialUtilities.cs +++ b/STROOP/Utilities/VariableSpecialUtilities.cs @@ -1,64 +1,50 @@ -using System; +using STROOP.Controls.VariablePanel; +using System; using System.Collections.Generic; using System.Linq; using System.Text; -using STROOP.Controls.VariablePanel; -using STROOP.Core.Variables; +using STROOP.Core; +using STROOP.Core.Utilities; using STROOP.Models; using STROOP.Structs.Configurations; using STROOP.Ttc; using STROOP.Structs; +using STROOP.Tabs; +using STROOP.Variables; +using STROOP.Variables.SM64MemoryLayout; +using STROOP.Variables.Utilities; namespace STROOP.Utilities { - public static class WatchVariableSpecialUtilities + public static class VariableSpecialUtilities { - public class Defaults - { - public readonly static NamedVariableCollection.GetterFunction DEFAULT_GETTER = () => Array.Empty(); - public readonly static NamedVariableCollection.SetterFunction DEFAULT_SETTER = value => Array.Empty(); - public readonly static Func DEFAULT_SETTER_WITH_ADDRESS = (_, __) => false; - } + private static VariableSpecialDictionary dictionary => VariableSpecialDictionary.Instance; - public static WatchVariableSpecialDictionary dictionary { get; private set; } - - static WatchVariableSpecialUtilities() + static VariableSpecialUtilities() { - dictionary = new WatchVariableSpecialDictionary(); AddLiteralEntriesToDictionary(); AddGeneratedEntriesToDictionary(); AddPanEntriesToDictionary(); GeneralUtilities.ExecuteInitializers(); } - static IEnumerable> FilterNumberVariables(List controls) - { - foreach (var ctrl in controls) - { - if (ctrl.view is NamedVariableCollection.IView byteView) yield return byteView._getterFunction().Select(x => (double)x); - else if (ctrl.view is NamedVariableCollection.IView sbyteView) yield return sbyteView._getterFunction().Select(x => (double)x); - else if (ctrl.view is NamedVariableCollection.IView ushortView) yield return ushortView._getterFunction().Select(x => (double)x); - else if (ctrl.view is NamedVariableCollection.IView shortView) yield return shortView._getterFunction().Select(x => (double)x); - else if (ctrl.view is NamedVariableCollection.IView uintView) yield return uintView._getterFunction().Select(x => (double)x); - else if (ctrl.view is NamedVariableCollection.IView intView) yield return intView._getterFunction().Select(x => (double)x); - else if (ctrl.view is NamedVariableCollection.IView ulongView) yield return ulongView._getterFunction().Select(x => (double)x); - else if (ctrl.view is NamedVariableCollection.IView longView) yield return longView._getterFunction().Select(x => (double)x); - else if (ctrl.view is NamedVariableCollection.IView floatView) yield return floatView._getterFunction().Select(x => (double)x); - else if (ctrl.view is NamedVariableCollection.IView doubleView) yield return doubleView._getterFunction().Select(x => (double)x); - else if (ctrl.view is NamedVariableCollection.IView decmialView) yield return decmialView._getterFunction().Select(x => (double)x); - } - } + static IEnumerable CrossOperationOnControls(List controls, Func, double> op) + => CrossOperation(op, VariableUtilities.GetNumberValues(controls)); - static IEnumerable CrossOperationOnControls(List controls, Func, double> op) - => CrossOperation(op, FilterNumberVariables(controls).ToArray()); static IEnumerable CrossOperation(Func, TResult> op, params IEnumerable[] variableStreams) + => CrossOperation(op, (IEnumerable>)variableStreams); + + static IEnumerable CrossOperation( + Func, TResult> op, + IEnumerable> variableStreams + ) { int index; var streamEnumerators = variableStreams.Select(x => x.GetEnumerator()); do { - var nextResult = new List(variableStreams.Length); + var nextResult = new List(); index = 0; foreach (var enumerator in streamEnumerators) if (enumerator.MoveNext()) @@ -67,7 +53,7 @@ static IEnumerable CrossOperation(Func 0); } - public static NamedVariableCollection.GetterFunction AddAggregateMathOperationEntry(List controls, AggregateMathOperation operation) + public static IVariable.ValueGetter AddAggregateMathOperationEntry(List controls, AggregateMathOperation operation) { switch (operation) { @@ -143,11 +129,11 @@ public static void AddGeneratedEntriesToDictionary() () => PositionAngle.Mario.Yield(), () => PositionAngle.Holp.Yield(), () => PositionAngle.Camera.Yield(), - () => WatchVariableUtilities.GetBaseAddresses(BaseAddressType.Object).Select(x => PositionAngle.Obj(x)), - () => WatchVariableUtilities.GetBaseAddresses(BaseAddressType.Object).Select(x => PositionAngle.ObjHome(x)), - () => WatchVariableUtilities.GetBaseAddresses(BaseAddressType.Triangle).Select(x => PositionAngle.Tri(x, 1)), - () => WatchVariableUtilities.GetBaseAddresses(BaseAddressType.Triangle).Select(x => PositionAngle.Tri(x, 2)), - () => WatchVariableUtilities.GetBaseAddresses(BaseAddressType.Triangle).Select(x => PositionAngle.Tri(x, 3)), + () => VariableUtilities.GetBaseAddresses(BaseAddressType.Object).Select(x => PositionAngle.Obj(x)), + () => VariableUtilities.GetBaseAddresses(BaseAddressType.Object).Select(x => PositionAngle.ObjHome(x)), + () => VariableUtilities.GetBaseAddresses(BaseAddressType.Triangle).Select(x => PositionAngle.Tri(x, 1)), + () => VariableUtilities.GetBaseAddresses(BaseAddressType.Triangle).Select(x => PositionAngle.Tri(x, 2)), + () => VariableUtilities.GetBaseAddresses(BaseAddressType.Triangle).Select(x => PositionAngle.Tri(x, 3)), }; List posAngleStrings = @@ -286,7 +272,7 @@ public static void AddLiteralEntriesToDictionary() double dAngle = PositionAngle.GetDAngleTo(PositionAngle.Mario, PositionAngle.Obj(objAddress)); return MoreMath.MaybeNegativeModulus(dAngle, 512); }, - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("PitchMarioToObj", BaseAddressType.Object, @@ -296,7 +282,7 @@ public static void AddLiteralEntriesToDictionary() PositionAngle obj = PositionAngle.Obj(objAddress); return MoreMath.GetPitch(mario.X, mario.Y, mario.Z, obj.X, obj.Y, obj.Z); }, - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("DPitchMarioToObj", BaseAddressType.Object, @@ -321,7 +307,7 @@ public static void AddLiteralEntriesToDictionary() dictionary.Add("ObjectInGameDeltaYaw", BaseAddressType.Object, objAddress => GetDeltaInGameAngle(Config.Stream.GetUInt16(objAddress + ObjectConfig.YawFacingOffset)), - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("EffectiveHitboxRadius", BaseAddressType.Object, @@ -332,7 +318,7 @@ public static void AddLiteralEntriesToDictionary() float objHitboxRadius = Config.Stream.GetSingle(objAddress + ObjectConfig.HitboxRadiusOffset); return mObjHitboxRadius + objHitboxRadius; }, - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("EffectiveHurtboxRadius", BaseAddressType.Object, @@ -343,7 +329,7 @@ public static void AddLiteralEntriesToDictionary() float objHurtboxRadius = Config.Stream.GetSingle(objAddress + ObjectConfig.HurtboxRadiusOffset); return mObjHurtboxRadius + objHurtboxRadius; }, - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("MarioHitboxAwayFromObject", BaseAddressType.Object, @@ -490,7 +476,7 @@ public static void AddLiteralEntriesToDictionary() return marioHitboxAwayFromObject < 0 && marioHitboxAboveObject <= 0 && marioHitboxBelowObject <= 0; }, - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("MarioHurtboxAwayFromObject", BaseAddressType.Object, @@ -636,7 +622,7 @@ public static void AddLiteralEntriesToDictionary() return marioHurtboxAwayFromObject < 0 && marioHurtboxAboveObject <= 0 && marioHurtboxBelowObject <= 0; }, - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("MarioPunchAngleAway", BaseAddressType.Object, @@ -690,17 +676,17 @@ public static void AddLiteralEntriesToDictionary() return numOfCalls; }, - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("ObjectProcessGroup", BaseAddressType.ProcessGroup, processGroupUint => processGroupUint == uint.MaxValue ? (sbyte)(-1) : (sbyte)processGroupUint, - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("ObjectProcessGroupDescription", BaseAddressType.ProcessGroup, processGroupUint => ProcessGroupUtilities.GetProcessGroupDescription(processGroupUint), - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("ObjectRngIndex", BaseAddressType.Object, @@ -743,7 +729,7 @@ public static void AddLiteralEntriesToDictionary() int pendulumCountdown = GetPendulumCountdown(objAddress); return pendulumCountdown; }, - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("PendulumAmplitude", BaseAddressType.Object, @@ -795,12 +781,12 @@ public static void AddLiteralEntriesToDictionary() dictionary.Add("CogCountdown", BaseAddressType.Object, objAddress => GetCogNumFramesInRotation(objAddress), - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("CogEndingYaw", BaseAddressType.Object, objAddress => GetCogEndingYaw(objAddress), - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("CogRotationIndex", BaseAddressType.Object, @@ -810,7 +796,7 @@ public static void AddLiteralEntriesToDictionary() double rotationIndex = CogUtilities.GetRotationIndex(yawFacing) ?? Double.NaN; return rotationIndex; }, - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); // Object specific vars - Waypoint @@ -822,7 +808,7 @@ public static void AddLiteralEntriesToDictionary() GetWaypointSpecialVars(objAddress); return dotProduct; }, - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("ObjectDistanceToWaypointPlane", BaseAddressType.Object, @@ -832,7 +818,7 @@ public static void AddLiteralEntriesToDictionary() GetWaypointSpecialVars(objAddress); return distToWaypointPlane; }, - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("ObjectDistanceToWaypoint", BaseAddressType.Object, @@ -842,7 +828,7 @@ public static void AddLiteralEntriesToDictionary() GetWaypointSpecialVars(objAddress); return distToWaypoint; }, - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); // Object specific vars - Racing Penguin @@ -854,7 +840,7 @@ public static void AddLiteralEntriesToDictionary() GetRacingPenguinSpecialVars(objAddress); return effortTarget; }, - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("RacingPenguinEffortChange", BaseAddressType.Object, @@ -864,7 +850,7 @@ public static void AddLiteralEntriesToDictionary() GetRacingPenguinSpecialVars(objAddress); return effortChange; }, - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("RacingPenguinMinHSpeed", BaseAddressType.Object, @@ -874,7 +860,7 @@ public static void AddLiteralEntriesToDictionary() GetRacingPenguinSpecialVars(objAddress); return minHSpeed; }, - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("RacingPenguinHSpeedTarget", BaseAddressType.Object, @@ -884,7 +870,7 @@ public static void AddLiteralEntriesToDictionary() GetRacingPenguinSpecialVars(objAddress); return hSpeedTarget; }, - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("RacingPenguinDiffHSpeedTarget", BaseAddressType.Object, @@ -896,12 +882,12 @@ public static void AddLiteralEntriesToDictionary() double hSpeedDiff = hSpeed - hSpeedTarget; return hSpeedDiff; }, - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("RacingPenguinProgress", BaseAddressType.Object, objAddress => TableConfig.RacingPenguinWaypoints.GetProgress(objAddress), - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); // Object specific vars - Koopa the Quick @@ -912,7 +898,7 @@ public static void AddLiteralEntriesToDictionary() (double hSpeedTarget, double hSpeedChange) = GetKoopaTheQuickSpecialVars(objAddress); return hSpeedTarget; }, - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("KoopaTheQuickHSpeedChange", BaseAddressType.Object, @@ -921,22 +907,22 @@ public static void AddLiteralEntriesToDictionary() (double hSpeedTarget, double hSpeedChange) = GetKoopaTheQuickSpecialVars(objAddress); return hSpeedChange; }, - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("KoopaTheQuick1Progress", BaseAddressType.Object, objAddress => TableConfig.KoopaTheQuick1Waypoints.GetProgress(objAddress), - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("KoopaTheQuick2Progress", BaseAddressType.Object, objAddress => TableConfig.KoopaTheQuick2Waypoints.GetProgress(objAddress), - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("KoopaTheQuick1ProgressOld", BaseAddressType.Object, objAddress => PlushUtilities.GetProgress(Config.Stream.GetUInt32(MiscConfig.GlobalTimerAddress)), - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("KoopaTheQuick1ProgressDiff", BaseAddressType.Object, @@ -947,7 +933,7 @@ public static void AddLiteralEntriesToDictionary() double progressNew = TableConfig.KoopaTheQuick1Waypoints.GetProgress(objAddress); return progressNew - progressOld; }, - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); // Object specific vars - Fly Guy @@ -962,7 +948,7 @@ public static void AddLiteralEntriesToDictionary() if (heightDiff > -200) return "High"; return "Medium"; }, - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("FlyGuyRelativeHeight", BaseAddressType.Object, @@ -971,7 +957,7 @@ public static void AddLiteralEntriesToDictionary() int oscillationTimer = Config.Stream.GetInt32(objAddress + ObjectConfig.FlyGuyOscillationTimerOffset); return TableConfig.FlyGuyData.GetRelativeHeight(oscillationTimer); }, - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("FlyGuyMinHeight", BaseAddressType.Object, @@ -1126,7 +1112,7 @@ public static void AddLiteralEntriesToDictionary() dictionary.Add("ChuckyaAngleMod1024", BaseAddressType.Object, objAddress => Config.Stream.GetUInt16(objAddress + ObjectConfig.YawMovingOffset) % 1024, - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); // Object specific vars - Scuttlebug @@ -1211,7 +1197,7 @@ public static void AddLiteralEntriesToDictionary() int timer = Config.Stream.GetInt32(objAddress + ObjectConfig.BitfsPlatformGroupTimerOffset); return BitfsPlatformGroupTable.GetRelativeHeightFromMin(timer); }, - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("BitfsPlatformGroupDisplacedHeight", BaseAddressType.Object, @@ -1262,7 +1248,7 @@ public static void AddLiteralEntriesToDictionary() int missionIndex = Config.Stream.GetByte(objAddress + ObjectConfig.PowerStarMissionIndexOffset); return TableConfig.Missions.GetInGameMissionName(courseIndex, missionIndex); }, - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); // Object specific vars - Coordinates @@ -1541,7 +1527,7 @@ public static void AddLiteralEntriesToDictionary() }); return coordinates.Max(coord => MoreMath.GetDistanceBetween(objX, objY, objZ, coord.Item1, coord.Item2, coord.Item3)); }, - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); // Object specific vars - Rolling Log @@ -1571,7 +1557,7 @@ public static void AddLiteralEntriesToDictionary() float zCenter = Config.Stream.GetSingle(objAddress + ObjectConfig.RollingLogZCenterOffset); return MoreMath.GetDistanceBetween(xCenter, zCenter, x, z); }, - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); // Object specific vars - Object Spawner @@ -1709,21 +1695,21 @@ public static void AddLiteralEntriesToDictionary() int targetAngle = Config.Stream.GetInt32(objAddress + ObjectConfig.SwooperTargetYawOffset); return targetAngle + (short)(3000 * InGameTrigUtilities.InGameCosine(4000 * (int)globalTimer)); }, - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); // Mario vars dictionary.Add("RotationDisplacementX", () => GetRotationDisplacement().ToTuple().Item1, - Defaults.DEFAULT_SETTER); + SpecialVariableDefaults.DEFAULT_SETTER); dictionary.Add("RotationDisplacementY", () => GetRotationDisplacement().ToTuple().Item2, - Defaults.DEFAULT_SETTER); + SpecialVariableDefaults.DEFAULT_SETTER); dictionary.Add("RotationDisplacementZ", () => GetRotationDisplacement().ToTuple().Item3, - Defaults.DEFAULT_SETTER); + SpecialVariableDefaults.DEFAULT_SETTER); dictionary.Add("SpeedMultiplier", () => @@ -1755,7 +1741,7 @@ public static void AddLiteralEntriesToDictionary() double K = InGameTrigUtilities.InGameCosine(intendedDYaw) < 0 && hSpeed >= 0 ? 0.5 + 0.5 * hSpeed / 100 : 1; return (scaledMagnitude / 32) * InGameTrigUtilities.InGameCosine(intendedDYaw) * K * 0.02 + A; }, - Defaults.DEFAULT_SETTER); + SpecialVariableDefaults.DEFAULT_SETTER); dictionary.Add("DeFactoSpeed", () => GetMarioDeFactoSpeed(), @@ -1806,11 +1792,11 @@ public static void AddLiteralEntriesToDictionary() dictionary.Add("TwirlYawMod2048", () => Config.Stream.GetUInt16(MarioConfig.StructAddress + MarioConfig.TwirlYawOffset) % 2048, - Defaults.DEFAULT_SETTER); + SpecialVariableDefaults.DEFAULT_SETTER); dictionary.Add("FlyingEnergy", () => FlyingUtilities.GetEnergy(), - Defaults.DEFAULT_SETTER); + SpecialVariableDefaults.DEFAULT_SETTER); dictionary.Add("TrajectoryRemainingHeight", () => @@ -1900,7 +1886,7 @@ public static void AddLiteralEntriesToDictionary() float startX = Config.Stream.GetSingle(MiscConfig.HackedAreaAddress + 0x1C); return endX - startX; }, - Defaults.DEFAULT_SETTER); + SpecialVariableDefaults.DEFAULT_SETTER); dictionary.Add("MovementY", () => @@ -1909,7 +1895,7 @@ public static void AddLiteralEntriesToDictionary() float startY = Config.Stream.GetSingle(MiscConfig.HackedAreaAddress + 0x20); return endY - startY; }, - Defaults.DEFAULT_SETTER); + SpecialVariableDefaults.DEFAULT_SETTER); dictionary.Add("MovementZ", () => @@ -1918,7 +1904,7 @@ public static void AddLiteralEntriesToDictionary() float startZ = Config.Stream.GetSingle(MiscConfig.HackedAreaAddress + 0x24); return endZ - startZ; }, - Defaults.DEFAULT_SETTER); + SpecialVariableDefaults.DEFAULT_SETTER); dictionary.Add("MovementForwards", () => @@ -1936,7 +1922,7 @@ public static void AddLiteralEntriesToDictionary() MoreMath.GetComponentsFromVectorRelatively(movementHorizontal, movementAngle, marioAngle); return movementForwards; }, - Defaults.DEFAULT_SETTER); + SpecialVariableDefaults.DEFAULT_SETTER); dictionary.Add("MovementSideways", () => @@ -1954,7 +1940,7 @@ public static void AddLiteralEntriesToDictionary() MoreMath.GetComponentsFromVectorRelatively(movementHorizontal, movementAngle, marioAngle); return movementSideways; }, - Defaults.DEFAULT_SETTER); + SpecialVariableDefaults.DEFAULT_SETTER); dictionary.Add("MovementHorizontal", () => @@ -1967,7 +1953,7 @@ public static void AddLiteralEntriesToDictionary() float movementZ = endZ - startZ; return MoreMath.GetHypotenuse(movementX, movementZ); }, - Defaults.DEFAULT_SETTER); + SpecialVariableDefaults.DEFAULT_SETTER); dictionary.Add("MovementTotal", () => @@ -1983,7 +1969,7 @@ public static void AddLiteralEntriesToDictionary() float movementZ = endZ - startZ; return MoreMath.GetHypotenuse(movementX, movementY, movementZ); }, - Defaults.DEFAULT_SETTER); + SpecialVariableDefaults.DEFAULT_SETTER); dictionary.Add("MovementAngle", () => @@ -1996,7 +1982,7 @@ public static void AddLiteralEntriesToDictionary() float movementZ = endZ - startZ; return MoreMath.AngleTo_AngleUnits(movementX, movementZ); }, - Defaults.DEFAULT_SETTER); + SpecialVariableDefaults.DEFAULT_SETTER); dictionary.Add("QFrameCountEstimate", () => @@ -2017,19 +2003,19 @@ public static void AddLiteralEntriesToDictionary() return qframes; } , - Defaults.DEFAULT_SETTER); + SpecialVariableDefaults.DEFAULT_SETTER); dictionary.Add("DeltaYawIntendedFacing", () => GetDeltaYawIntendedFacing(), - Defaults.DEFAULT_SETTER); + SpecialVariableDefaults.DEFAULT_SETTER); dictionary.Add("DeltaYawIntendedBackwards", () => GetDeltaYawIntendedBackwards(), - Defaults.DEFAULT_SETTER); + SpecialVariableDefaults.DEFAULT_SETTER); dictionary.Add("MarioInGameDeltaYaw", () => GetDeltaInGameAngle(Config.Stream.GetUInt16(MarioConfig.StructAddress + MarioConfig.FacingYawOffset)), - Defaults.DEFAULT_SETTER); + SpecialVariableDefaults.DEFAULT_SETTER); dictionary.Add("FallHeight", () => @@ -2056,7 +2042,7 @@ public static void AddLiteralEntriesToDictionary() float sum = (hSpeed + remainder) * numFrames / 2; return sum - hSpeed; }, - Defaults.DEFAULT_SETTER); + SpecialVariableDefaults.DEFAULT_SETTER); dictionary.Add("ScheduleOffset", () => PositionAngle.ScheduleOffset, @@ -2122,32 +2108,32 @@ public static void AddLiteralEntriesToDictionary() dictionary.Add("Classification", BaseAddressType.Triangle, triAddress => TriangleDataModel.Create(triAddress).Classification.ToString(), - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("TriangleTypeDescription", BaseAddressType.Triangle, triAddress => TriangleDataModel.Create(triAddress).Description, - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("TriangleSlipperiness", BaseAddressType.Triangle, triAddress => TriangleDataModel.Create(triAddress).Slipperiness, - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("TriangleSlipperinessDescription", BaseAddressType.Triangle, triAddress => TriangleDataModel.Create(triAddress).SlipperinessDescription, - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("TriangleFrictionMultiplier", BaseAddressType.Triangle, triAddress => TriangleDataModel.Create(triAddress).FrictionMultiplier, - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("TriangleExertion", BaseAddressType.Triangle, triAddress => TriangleDataModel.Create(triAddress).Exertion, - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("TriangleHorizontalNormal", BaseAddressType.Triangle, @@ -2157,52 +2143,52 @@ public static void AddLiteralEntriesToDictionary() float normalZ = Config.Stream.GetSingle(triAddress + TriangleOffsetsConfig.NormZ); return (float)Math.Sqrt(normalX * normalX + normalZ * normalZ); }, - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("ClosestVertexIndex", BaseAddressType.Triangle, triAddress => GetClosestTriangleVertexIndex(triAddress), - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("ClosestVertexX", BaseAddressType.Triangle, triAddress => (short)GetClosestTriangleVertexPosition(triAddress).X, - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("ClosestVertexY", BaseAddressType.Triangle, triAddress => (short)GetClosestTriangleVertexPosition(triAddress).Y, - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("ClosestVertexZ", BaseAddressType.Triangle, triAddress => (short)GetClosestTriangleVertexPosition(triAddress).Z, - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("Steepness", BaseAddressType.Triangle, triAddress => MoreMath.RadiansToAngleUnits(Math.Acos(TriangleDataModel.Create(triAddress).NormY)), - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("UpHillAngle", BaseAddressType.Triangle, triAddress => GetTriangleUphillAngle(triAddress), - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("DownHillAngle", BaseAddressType.Triangle, triAddress => MoreMath.ReverseAngle(GetTriangleUphillAngle(triAddress)), - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("LeftHillAngle", BaseAddressType.Triangle, triAddress => MoreMath.RotateAngleCCW(GetTriangleUphillAngle(triAddress), 0x4000), - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("RightHillAngle", BaseAddressType.Triangle, triAddress => MoreMath.RotateAngleCW(GetTriangleUphillAngle(triAddress), 0x4000), - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("UpHillDeltaAngle", BaseAddressType.Triangle, @@ -2297,7 +2283,7 @@ public static void AddLiteralEntriesToDictionary() bool uphill = angleDiff >= -16384 && angleDiff <= 16384; return uphill ? "Uphill" : "Downhill"; }, - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("WallKickAngleAway", BaseAddressType.Triangle, @@ -2337,7 +2323,7 @@ public static void AddLiteralEntriesToDictionary() ushort wallAngle = InGameTrigUtilities.InGameATan(normZ, normX); return MoreMath.NormalizeAngleUshort(wallAngle - (marioAngle - wallAngle) + 32768); }, - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("WallHugAngleAway", BaseAddressType.Triangle, @@ -2463,27 +2449,27 @@ public static void AddLiteralEntriesToDictionary() TriangleDataModel triStruct = TriangleDataModel.Create(triAddress); return triStruct.GetHeightOnTriangle(marioPos.X, marioPos.Z); }, - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("MaxHSpeedUphill", BaseAddressType.Triangle, triAddress => GetMaxHorizontalSpeedOnTriangle(triAddress, true, false), - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("MaxHSpeedUphillAtAngle", BaseAddressType.Triangle, triAddress => GetMaxHorizontalSpeedOnTriangle(triAddress, true, true), - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("MaxHSpeedDownhill", BaseAddressType.Triangle, triAddress => GetMaxHorizontalSpeedOnTriangle(triAddress, false, false), - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("MaxHSpeedDownhillAtAngle", BaseAddressType.Triangle, triAddress => GetMaxHorizontalSpeedOnTriangle(triAddress, false, true), - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("TriangleCells", BaseAddressType.Triangle, @@ -2497,7 +2483,7 @@ public static void AddLiteralEntriesToDictionary() return string.Format("X:{0}-{1},Z:{2}-{3}", minCellX, maxCellX, minCellZ, maxCellZ); }, - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("MarioCell", () => @@ -2505,7 +2491,7 @@ public static void AddLiteralEntriesToDictionary() (int cellX, int cellZ) = GetMarioCell(); return string.Format("X:{0},Z:{1}", cellX, cellZ); }, - Defaults.DEFAULT_SETTER); + SpecialVariableDefaults.DEFAULT_SETTER); dictionary.Add("ObjectTriCount", () => @@ -2515,7 +2501,7 @@ public static void AddLiteralEntriesToDictionary() int objectTriangleCount = totalTriangleCount - levelTriangleCount; return objectTriangleCount; }, - Defaults.DEFAULT_SETTER); + SpecialVariableDefaults.DEFAULT_SETTER); dictionary.Add("CurrentTriangleIndex", BaseAddressType.Triangle, @@ -2557,7 +2543,7 @@ public static void AddLiteralEntriesToDictionary() return i; return null; }, - Defaults.DEFAULT_SETTER_WITH_ADDRESS + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS ); dictionary.Add("CurrentTriangleAddress", @@ -2586,67 +2572,67 @@ public static void AddLiteralEntriesToDictionary() return totalNodeCount - levelNodeCount; } , - Defaults.DEFAULT_SETTER); + SpecialVariableDefaults.DEFAULT_SETTER); dictionary.Add("TriMinX", BaseAddressType.Triangle, triAddress => TriangleDataModel.Create(triAddress).GetMinX(), - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("TriMaxX", BaseAddressType.Triangle, triAddress => TriangleDataModel.Create(triAddress).GetMaxX(), - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("TriMinY", BaseAddressType.Triangle, triAddress => TriangleDataModel.Create(triAddress).GetMinY(), - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("TriMaxY", BaseAddressType.Triangle, triAddress => TriangleDataModel.Create(triAddress).GetMaxY(), - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("TriMinZ", BaseAddressType.Triangle, triAddress => TriangleDataModel.Create(triAddress).GetMinZ(), - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("TriMaxZ", BaseAddressType.Triangle, triAddress => TriangleDataModel.Create(triAddress).GetMaxZ(), - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("TriRangeX", BaseAddressType.Triangle, triAddress => TriangleDataModel.Create(triAddress).GetRangeX(), - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("TriRangeY", BaseAddressType.Triangle, triAddress => TriangleDataModel.Create(triAddress).GetRangeY(), - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("TriRangeZ", BaseAddressType.Triangle, triAddress => TriangleDataModel.Create(triAddress).GetRangeZ(), - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("TriMidpointX", BaseAddressType.Triangle, triAddress => TriangleDataModel.Create(triAddress).GetMidpointX(), - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("TriMidpointY", BaseAddressType.Triangle, triAddress => TriangleDataModel.Create(triAddress).GetMidpointY(), - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("TriMidpointZ", BaseAddressType.Triangle, triAddress => TriangleDataModel.Create(triAddress).GetMidpointZ(), - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("DistanceToLine12", BaseAddressType.Triangle, @@ -2654,7 +2640,7 @@ public static void AddLiteralEntriesToDictionary() { PositionAngle marioPos = PositionAngle.Mario; TriangleDataModel triStruct = TriangleDataModel.Create(triAddress); - double signedDistToLine12 = MoreMath.GetSignedDistanceFromPointToLine( + double signedDistToLine12 = STROOPMath.GetSignedDistanceFromPointToLine( marioPos.X, marioPos.Z, triStruct.X1, triStruct.Z1, triStruct.X2, triStruct.Z2, @@ -2666,7 +2652,7 @@ public static void AddLiteralEntriesToDictionary() { PositionAngle marioPos = PositionAngle.Mario; TriangleDataModel triStruct = TriangleDataModel.Create(triAddress); - double signedDistToLine12 = MoreMath.GetSignedDistanceFromPointToLine( + double signedDistToLine12 = STROOPMath.GetSignedDistanceFromPointToLine( marioPos.X, marioPos.Z, triStruct.X1, triStruct.Z1, triStruct.X2, triStruct.Z2, @@ -2691,7 +2677,7 @@ public static void AddLiteralEntriesToDictionary() { PositionAngle marioPos = PositionAngle.Mario; TriangleDataModel triStruct = TriangleDataModel.Create(triAddress); - double signedDistToLine23 = MoreMath.GetSignedDistanceFromPointToLine( + double signedDistToLine23 = STROOPMath.GetSignedDistanceFromPointToLine( marioPos.X, marioPos.Z, triStruct.X1, triStruct.Z1, triStruct.X2, triStruct.Z2, @@ -2703,7 +2689,7 @@ public static void AddLiteralEntriesToDictionary() { PositionAngle marioPos = PositionAngle.Mario; TriangleDataModel triStruct = TriangleDataModel.Create(triAddress); - double signedDistToLine23 = MoreMath.GetSignedDistanceFromPointToLine( + double signedDistToLine23 = STROOPMath.GetSignedDistanceFromPointToLine( marioPos.X, marioPos.Z, triStruct.X1, triStruct.Z1, triStruct.X2, triStruct.Z2, @@ -2728,7 +2714,7 @@ public static void AddLiteralEntriesToDictionary() { PositionAngle marioPos = PositionAngle.Mario; TriangleDataModel triStruct = TriangleDataModel.Create(triAddress); - double signedDistToLine31 = MoreMath.GetSignedDistanceFromPointToLine( + double signedDistToLine31 = STROOPMath.GetSignedDistanceFromPointToLine( marioPos.X, marioPos.Z, triStruct.X1, triStruct.Z1, triStruct.X2, triStruct.Z2, @@ -2740,7 +2726,7 @@ public static void AddLiteralEntriesToDictionary() { PositionAngle marioPos = PositionAngle.Mario; TriangleDataModel triStruct = TriangleDataModel.Create(triAddress); - double signedDistToLine31 = MoreMath.GetSignedDistanceFromPointToLine( + double signedDistToLine31 = STROOPMath.GetSignedDistanceFromPointToLine( marioPos.X, marioPos.Z, triStruct.X1, triStruct.Z1, triStruct.X2, triStruct.Z2, @@ -2962,37 +2948,37 @@ public static void AddLiteralEntriesToDictionary() dictionary.Add("StarsInFile", BaseAddressType.File, fileAddress => AccessScope.content.GetTab().CalculateNumStars(fileAddress), - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); dictionary.Add("FileChecksumCalculated", BaseAddressType.File, fileAddress => AccessScope.content.GetTab().GetChecksum(fileAddress), - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); // Main Save vars dictionary.Add("MainSaveChecksumCalculated", BaseAddressType.MainSave, mainSaveAddress => AccessScope.content.GetTab().GetChecksum(mainSaveAddress), - Defaults.DEFAULT_SETTER_WITH_ADDRESS); + SpecialVariableDefaults.DEFAULT_SETTER_WITH_ADDRESS); // Action vars dictionary.Add("ActionDescription", () => TableConfig.MarioActions.GetActionName(), - Defaults.DEFAULT_SETTER); + SpecialVariableDefaults.DEFAULT_SETTER); dictionary.Add("PrevActionDescription", () => TableConfig.MarioActions.GetPrevActionName(), - Defaults.DEFAULT_SETTER); + SpecialVariableDefaults.DEFAULT_SETTER); dictionary.Add("ActionGroupDescription", () => TableConfig.MarioActions.GetGroupName(), - Defaults.DEFAULT_SETTER); + SpecialVariableDefaults.DEFAULT_SETTER); dictionary.Add("AnimationDescription", () => TableConfig.MarioAnimations.GetAnimationName(), - Defaults.DEFAULT_SETTER); + SpecialVariableDefaults.DEFAULT_SETTER); // Water vars @@ -3004,7 +2990,7 @@ public static void AddLiteralEntriesToDictionary() double waterAboveMedian = waterLevel - waterLevelMedian; return waterAboveMedian; }, - Defaults.DEFAULT_SETTER); + SpecialVariableDefaults.DEFAULT_SETTER); dictionary.Add("MarioAboveWater", () => @@ -3025,7 +3011,7 @@ public static void AddLiteralEntriesToDictionary() dictionary.Add("CurrentWater", () => WaterUtilities.GetCurrentWater(), - Defaults.DEFAULT_SETTER); + SpecialVariableDefaults.DEFAULT_SETTER); // Cam Hack Vars @@ -3411,7 +3397,7 @@ public static void AddLiteralEntriesToDictionary() dictionary.Add("GlobalTimerMod64", () => Config.Stream.GetUInt32(MiscConfig.GlobalTimerAddress), - Defaults.DEFAULT_SETTER); + SpecialVariableDefaults.DEFAULT_SETTER); dictionary.Add("RngIndex", () => RngIndexer.GetRngIndex(Config.Stream.GetUInt16(MiscConfig.RngAddress)), @@ -3420,7 +3406,7 @@ public static void AddLiteralEntriesToDictionary() dictionary.Add("RngIndexMod4", () => RngIndexer.GetRngIndex() % 4, - Defaults.DEFAULT_SETTER); + SpecialVariableDefaults.DEFAULT_SETTER); dictionary.Add("LastCoinRngIndex", BaseAddressType.Coin, @@ -3482,15 +3468,15 @@ public static void AddLiteralEntriesToDictionary() dictionary.Add("NumRngCalls", () => ObjectRngUtilities.GetNumRngUsages(), - Defaults.DEFAULT_SETTER); + SpecialVariableDefaults.DEFAULT_SETTER); dictionary.Add("NumberOfLoadedObjects", () => DataModels.ObjectProcessor.ActiveObjectCount, - Defaults.DEFAULT_SETTER); + SpecialVariableDefaults.DEFAULT_SETTER); dictionary.Add("PlayTime", () => GetRealTime(Config.Stream.GetUInt32(MiscConfig.GlobalTimerAddress)), - Defaults.DEFAULT_SETTER); + SpecialVariableDefaults.DEFAULT_SETTER); dictionary.Add("DemoCounterDescription", () => DemoCounterUtilities.GetDemoCounterDescription(), @@ -3529,7 +3515,7 @@ public static void AddLiteralEntriesToDictionary() uint gfxBufferEnd = Config.Stream.GetUInt32(0x8033B070); return gfxBufferEnd - gfxBufferStart; }, - Defaults.DEFAULT_SETTER); + SpecialVariableDefaults.DEFAULT_SETTER); dictionary.Add("SegmentedToVirtualAddress", () => { return SpecialConfig.SegmentedToVirtualAddress; } @@ -3543,7 +3529,7 @@ public static void AddLiteralEntriesToDictionary() dictionary.Add("SegmentedToVirtualOutput", () => SpecialConfig.SegmentedToVirtualOutput, - Defaults.DEFAULT_SETTER); + SpecialVariableDefaults.DEFAULT_SETTER); dictionary.Add("VirtualToSegmentedSegment", () => SpecialConfig.VirtualToSegmentedSegment, @@ -3565,7 +3551,7 @@ public static void AddLiteralEntriesToDictionary() dictionary.Add("VirtualToSegmentedOutput", () => SpecialConfig.VirtualToSegmentedOutput, - Defaults.DEFAULT_SETTER); + SpecialVariableDefaults.DEFAULT_SETTER); // Options vars @@ -3614,7 +3600,7 @@ public static void AddLiteralEntriesToDictionary() } ); - // TODO: Add WatchVariablePositionAngleWrapper I guess? + // TODO: Add VariablePositionAngleWrapper I guess? //dictionary.Add("PositionControllerRelativity", // () => PositionControllerRelativityConfig.RelativityPA, // (PositionAngle value) => @@ -3664,7 +3650,7 @@ public static void AddLiteralEntriesToDictionary() dictionary.Add("AreaTerrainDescription", () => { - short terrainType = Config.Stream.GetInt16(AreaConfig.SelectedAreaAddress + AreaConfig.TerrainTypeOffset); + short terrainType = Config.Stream.GetInt16(AreaTab.SelectedAreaAddress + AreaConfig.TerrainTypeOffset); return AreaUtilities.GetTerrainDescription(terrainType); }, (string terrainDescription) => @@ -3672,7 +3658,7 @@ public static void AddLiteralEntriesToDictionary() var type = AreaUtilities.GetTerrainType(terrainDescription); if (!type.HasValue) return false; - return Config.Stream.SetValue(type.Value, AreaConfig.SelectedAreaAddress + AreaConfig.TerrainTypeOffset); + return Config.Stream.SetValue(type.Value, AreaTab.SelectedAreaAddress + AreaConfig.TerrainTypeOffset); } ); @@ -3680,11 +3666,11 @@ public static void AddLiteralEntriesToDictionary() dictionary.Add("WarpNodesAddress", () => GetWarpNodesAddress(), - Defaults.DEFAULT_SETTER); + SpecialVariableDefaults.DEFAULT_SETTER); dictionary.Add("NumWarpNodes", () => GetNumWarpNodes(), - Defaults.DEFAULT_SETTER); + SpecialVariableDefaults.DEFAULT_SETTER); dictionary.Add("HorizontalMovement", () => @@ -3695,7 +3681,7 @@ public static void AddLiteralEntriesToDictionary() float pos15Z = Config.Stream.GetSingle(0x80372FE8); return MoreMath.GetDistanceBetween(pos01X, pos01Z, pos15X, pos15Z); }, - Defaults.DEFAULT_SETTER); + SpecialVariableDefaults.DEFAULT_SETTER); // Mupen vars diff --git a/STROOP/Utilities/WatchVariableUtilities.cs b/STROOP/Utilities/WatchVariableUtilities.cs deleted file mode 100644 index 708832bd2..000000000 --- a/STROOP/Utilities/WatchVariableUtilities.cs +++ /dev/null @@ -1,345 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using System.Text.RegularExpressions; -using System.Windows.Forms; -using STROOP.Controls.VariablePanel; -using STROOP.Core.Variables; -using STROOP.Structs; -using STROOP.Structs.Configurations; - -namespace STROOP.Utilities -{ - public static class IVariableViewExtensions - { - public static NamedVariableCollection.IView WithKeyedValue(this NamedVariableCollection.IView view, string key, TValue value) - { - view.SetValueByKey(key, value); - return view; - } - - public static string GetJsonName(this NamedVariableCollection.IView view) - { - var explicitJsonName = view.GetValueByKey("jsonName"); - if (explicitJsonName == "") - return null; - if (explicitJsonName != null) - return explicitJsonName; - return $"{view.Name}".Replace(' ', '_').ToLower(); - } - - public static IEnumerable GetNumberValues(this NamedVariableCollection.IView view) where T : struct, IConvertible - { - if (view.TryGetNumberValues(out var result)) - return result; - throw new InvalidOperationException($"'{view.GetType().FullName}' is not a vaild number type."); - } - - public static bool TryGetNumberValues(this NamedVariableCollection.IView view, out IEnumerable result) - where T : struct, IConvertible - { - bool Get(out IEnumerable innerResult) - { - innerResult = null; - if (view is NamedVariableCollection.IView qView) - { - innerResult = qView._getterFunction().Select(x => (T)Convert.ChangeType(x, typeof(T))); - return true; - } - - return false; - } - - return Get(out result) - || Get(out result) - || Get(out result) - || Get(out result) - || Get(out result) - || Get(out result) - || Get(out result) - || Get(out result) - || Get(out result) - || Get(out result) - ; - } - - public static IEnumerable TrySetValue(this NamedVariableCollection.IView view, T value) where T : IConvertible - { - IEnumerable Set() - { - Q convertedValue = default(Q); - try - { - convertedValue = (Q)Convert.ChangeType(value, typeof(Q)); - } - catch (Exception) - { - return null; - } - - if (view is NamedVariableCollection.IView qView) - return qView._setterFunction(convertedValue); - return null; - } - - return Set() - ?? Set() - ?? Set() - ?? Set() - ?? Set() - ?? Set() - ?? Set() - ?? Set() - ?? Set() - ?? Set() - ?? Array.Empty() - ; - } - - public static (CombinedValuesMeaning meaning, T value) CombineValues(this NamedVariableCollection.IView view) where T : struct, IConvertible - { - var values = view.GetNumberValues().ToArray(); - if (values.Length == 0) return (CombinedValuesMeaning.NoValue, default(T)); - T firstValue = values[0]; - for (int i = 1; i < values.Length; i++) - if (!Equals(values[i], firstValue)) - return (CombinedValuesMeaning.MultipleValues, default(T)); - return (CombinedValuesMeaning.SameValue, firstValue); - } - } - - public static class WatchVariableUtilities - { - private class WatchVariableWrapperFallback : WatchVariableWrapper - { - public WatchVariableWrapperFallback(NamedVariableCollection.IView watchVar, WatchVariableControl watchVarControl) - : base(watchVar, watchVarControl) - { - } - - public override void Edit(Control parent, Rectangle bounds) - { - } - - public override string GetClass() => "INVALID VARIABLE"; - - public override string GetValueText() => "INVALID VARIABLE"; - - public override bool TrySetValue(string value) => false; - - public override void Update() - { - } - } - - static readonly Dictionary> wrapperTypes = new Dictionary>(); - - static readonly Regex WatchVariableTypeNameRegex = new Regex("(?<=(^WatchVariable))[a-zA-Z0-9]+(?=(Wrapper))", RegexOptions.Compiled); - - static WatchVariableUtilities() - { - GeneralUtilities.ExecuteInitializers(); - foreach (var t in typeof(WatchVariableWrapper<>).Assembly.GetTypes()) - { - var match = WatchVariableTypeNameRegex.Match(t.Name); - if (match.Success) - if (!t.IsAbstract && t.IsPublic && TypeUtilities.MatchesGenericType(typeof(WatchVariableWrapper<>), t)) - { - foreach (var ctor in t.GetConstructors()) - { - var parameters = ctor.GetParameters(); - if (parameters[0].ParameterType.IsGenericType - && parameters[0].ParameterType.GetGenericTypeDefinition() == typeof(NamedVariableCollection.IView<>) - && parameters[1].ParameterType == typeof(WatchVariableControl)) - { - if (!wrapperTypes.TryGetValue(match.Value, out var wrapperTypeList)) - wrapperTypes[match.Value] = wrapperTypeList = new List<(Type wrapperType, Type typeRestriction)>(); - wrapperTypeList.Add((t, parameters[0].ParameterType.GetGenericArguments()[0])); - break; - } - } - - ; - } - } - } - - public static Type GetWrapperType(Type potentiallyNullableVariableType, string wrapperTypeName = "Number") - { - Type GetNonNullableWrapper(Type variableType) - { - int GenericTypeArgumentsLength((Type a, Type b) w) => w.a.GetGenericArguments().Length; - - bool Passt(Type restrictionType) => - (variableType == restrictionType - || variableType.IsSubclassOf(restrictionType) - || variableType.GetInterfaces().Any(i => i == restrictionType)); - - bool CanWrap((Type wrapperType, Type typeRestriction) wrapper, out Type result) - { - result = null; - if (wrapper.typeRestriction.IsGenericParameter - ? wrapper.typeRestriction.GetGenericParameterConstraints().All(r => Passt(r)) - : Passt(wrapper.typeRestriction) - ) - { - var innermostType = wrapper.wrapperType; - Stack genericTypeArguments = new Stack(); - genericTypeArguments.Push(wrapper.wrapperType); - - while (innermostType != null && innermostType.GetGenericArguments().Length == 2) - { - innermostType = innermostType.GetGenericArguments()[0]; - if (innermostType == null) - return false; - var newArgs = innermostType.GetGenericArguments(); - if (newArgs.Length > 2) - return false; - genericTypeArguments.Push(innermostType - .GetGenericParameterConstraints() - .FirstOrDefault(c => c.IsClass) - ?.GetGenericTypeDefinition() - ); - } - - if (wrapper.wrapperType.IsGenericType) - { - genericTypeArguments.Push(variableType); - while (genericTypeArguments.Count > 1) - { - var qualifiedType = genericTypeArguments.Pop(); - var genericType = genericTypeArguments.Pop(); - if (genericType == null) - return false; - genericTypeArguments.Push(genericType.MakeGenericType(genericType.GetGenericArguments().Length == 2 ? new[] { qualifiedType, variableType } : new[] { qualifiedType })); - } - } - - result = genericTypeArguments.Pop(); - } - else if (Passt(wrapper.typeRestriction)) - result = wrapper.wrapperType; - - return result != null; - } - - if (wrapperTypes.TryGetValue(wrapperTypeName, out var specificCandidateList)) - foreach (var specificCandidate in specificCandidateList.OrderBy(GenericTypeArgumentsLength)) - if (CanWrap(specificCandidate, out var specificWrapper)) - return specificWrapper; - - foreach (var fallbackCandidate in wrapperTypes.Values.SelectMany(list => list).OrderBy(GenericTypeArgumentsLength)) - if (CanWrap(fallbackCandidate, out var fallbackWrapper)) - return fallbackWrapper; - - return null; - } - - bool isNullable = potentiallyNullableVariableType.IsGenericType && potentiallyNullableVariableType.GetGenericTypeDefinition() == typeof(Nullable<>); - var nonNullableWrapper = GetNonNullableWrapper(isNullable ? potentiallyNullableVariableType.GetGenericArguments()[0] : potentiallyNullableVariableType); - if (nonNullableWrapper != null) - return isNullable - ? typeof(WatchVariableNullableWrapper<,>).MakeGenericType(nonNullableWrapper, nonNullableWrapper.GetGenericArguments()[0]) - : nonNullableWrapper; - - System.Diagnostics.Debugger.Break(); - throw new InvalidOperationException($"{potentiallyNullableVariableType.FullName} could not be wrapped!"); - } - - public static bool TryCreateWrapper(NamedVariableCollection.IView view, WatchVariableControl control, out WatchVariableWrapper result) - { - result = null; - var interfaceType = view.GetType().GetInterfaces().FirstOrDefault(x => x.Name == $"{nameof(NamedVariableCollection.IView)}`1"); - if (interfaceType == null) - { - result = new WatchVariableWrapperFallback(view, control); - return false; - } - - var wrapperType = view.GetWrapperType(); - var constructor = wrapperType.GetConstructor(new Type[] { interfaceType, typeof(WatchVariableControl) }); - if (constructor == null) - { - result = new WatchVariableWrapperFallback(view, control); - return false; - } - - result = (WatchVariableWrapper)constructor.Invoke(new object[] { view, control }); - return true; - } - - public static SortedDictionary>> baseAddressGetters = new SortedDictionary>>(); - - //TODO: Move some of these where they belong - [InitializeBaseAddress] - static void InitBaseAddresses() - { - baseAddressGetters[BaseAddressType.None] = GetBaseAddressListZero; - baseAddressGetters[BaseAddressType.Absolute] = GetBaseAddressListZero; - baseAddressGetters[BaseAddressType.Relative] = GetBaseAddressListZero; - - baseAddressGetters[BaseAddressType.Mario] = () => new List { MarioConfig.StructAddress }; - baseAddressGetters[BaseAddressType.MarioObj] = () => new List { Config.Stream.GetUInt32(MarioObjectConfig.PointerAddress) }; - - baseAddressGetters[BaseAddressType.Camera] = () => new List { CameraConfig.StructAddress }; - baseAddressGetters[BaseAddressType.CameraStruct] = () => new List { CameraConfig.CamStructAddress }; - baseAddressGetters[BaseAddressType.LakituStruct] = () => new List { CameraConfig.LakituStructAddress }; - baseAddressGetters[BaseAddressType.CameraModeInfo] = () => new List { CameraConfig.ModeInfoAddress }; - baseAddressGetters[BaseAddressType.CameraModeTransition] = () => new List { CameraConfig.ModeTransitionAddress }; - baseAddressGetters[BaseAddressType.CameraSettings] = () => - { - uint a1 = 0x8033B910; - uint a2 = Config.Stream.GetUInt32(a1); - uint a3 = Config.Stream.GetUInt32(a2 + 0x10); - uint a4 = Config.Stream.GetUInt32(a3 + 0x08); - uint a5 = Config.Stream.GetUInt32(a4 + 0x10); - return new List { a5 }; - }; - - baseAddressGetters[BaseAddressType.File] = () => new List { FileConfig.CurrentFileAddress }; - baseAddressGetters[BaseAddressType.MainSave] = () => new List { MainSaveConfig.CurrentMainSaveAddress }; - - baseAddressGetters[BaseAddressType.Object] = () => Config.ObjectSlotsManager.SelectedSlotsAddresses; - baseAddressGetters[BaseAddressType.ProcessGroup] = () => - Config.ObjectSlotsManager.SelectedObjects.ConvertAll(obj => obj.CurrentProcessGroup ?? uint.MaxValue); - - baseAddressGetters["Graphics"] = () => - Config.ObjectSlotsManager.SelectedSlotsAddresses.ConvertAll(objAddress => Config.Stream.GetUInt32(objAddress + ObjectConfig.BehaviorGfxOffset)); - - baseAddressGetters["Animation"] = () => - Config.ObjectSlotsManager.SelectedSlotsAddresses.ConvertAll(objAddress => Config.Stream.GetUInt32(objAddress + ObjectConfig.AnimationOffset)); - - baseAddressGetters["Waypoint"] = () => - Config.ObjectSlotsManager.SelectedSlotsAddresses.ConvertAll(objAddress => Config.Stream.GetUInt32(objAddress + ObjectConfig.WaypointOffset)); - - baseAddressGetters[BaseAddressType.Area] = () => new List { AreaConfig.SelectedAreaAddress }; - } - - public static WatchVariableSubclass GetSubclass(string stringValue) - { - if (stringValue == null) return WatchVariableSubclass.Number; - return (WatchVariableSubclass)Enum.Parse(typeof(WatchVariableSubclass), stringValue); - } - - public static Coordinate GetCoordinate(string stringValue) - { - return (Coordinate)Enum.Parse(typeof(Coordinate), stringValue); - } - - public static List ParseVariableGroupList(string stringValue) => - new List(Array.ConvertAll(stringValue.Split('|', ','), _ => _.Trim())); - - public static readonly List BaseAddressListZero = new List { 0 }; - public static readonly List BaseAddressListEmpty = new List { }; - private static List GetBaseAddressListZero() => BaseAddressListZero; - private static List GetBaseAddressListEmpty() => BaseAddressListEmpty; - - public static IEnumerable GetBaseAddresses(string baseAddressType) - { - if (baseAddressGetters.TryGetValue(baseAddressType, out var result)) - return result(); - return new List(); - } - } -} diff --git a/STROOP/Utilities/WaterUtilities.cs b/STROOP/Utilities/WaterUtilities.cs index 337c052f3..a56a4d913 100644 --- a/STROOP/Utilities/WaterUtilities.cs +++ b/STROOP/Utilities/WaterUtilities.cs @@ -1,4 +1,5 @@ using STROOP.Structs.Configurations; +using STROOP.Variables.SM64MemoryLayout; using System.Collections.Generic; namespace STROOP.Structs diff --git a/STROOP/Utilities/XmlConfigParser.cs b/STROOP/Utilities/XmlConfigParser.cs index e9ce9f259..836314d23 100644 --- a/STROOP/Utilities/XmlConfigParser.cs +++ b/STROOP/Utilities/XmlConfigParser.cs @@ -1,4 +1,7 @@ -using System; +using STROOP.Controls.VariablePanel; +using STROOP.Core; +using STROOP.Core.GameMemoryAccess; +using System; using System.Collections.Generic; using System.Linq; using System.Xml.Linq; @@ -11,7 +14,10 @@ using System.Xml; using STROOP.Structs.Configurations; using STROOP.Tabs.MapTab; -using STROOP.Core.Variables; +using STROOP.Variables; +using STROOP.Variables.SM64MemoryLayout; +using STROOP.Variables.Utilities; +using STROOP.Variables.VariablePanel; namespace STROOP.Utilities { @@ -115,13 +121,10 @@ public static XDocument OpenConfig(string path) return doc; } - public static List OpenWatchVariables(string path) => OpenWatchVariableControlPrecursors(path); - - public static List OpenWatchVariableControlPrecursors(string path) + public static List OpenVariableControlPrecursors(string path) { string schemaFile = "MiscDataSchema.xsd"; - var objectData = new List(); - var assembly = Assembly.GetExecutingAssembly(); + var objectData = new List(); // Create schema set var schemaSet = new XmlSchemaSet() { XmlResolver = new ResourceXmlResolver() }; @@ -137,9 +140,9 @@ public static XDocument OpenConfig(string path) { if (element.Name.ToString() != "Data") continue; - var view = NamedVariableCollection.ParseXml(element); - if (view != null) - objectData.Add(view); + var parsed = VariableCellFactory.ParseXml(element, VariableSpecialDictionary.Instance); + if (parsed.var != null) + objectData.Add(parsed); } return objectData; @@ -265,12 +268,12 @@ public static ObjectAssociations OpenObjectAssoc(string path) rotates = bool.Parse(element.Element(XName.Get("MapImage")).Attribute(XName.Get("rotates")).Value); } - List precursors = new List(); + var precursors = new List(); foreach (var subElement in element.Elements().Where(x => x.Name == "Data")) { - var variableView = NamedVariableCollection.ParseXml(subElement); - if (variableView != null) - precursors.Add(variableView); + var parsed = VariableCellFactory.ParseXml(subElement, VariableSpecialDictionary.Instance); + if (parsed.var != null) + precursors.Add(parsed); } var newBehavior = new ObjectBehaviorAssociation()