diff --git a/.github/workflows/reloaded.yml b/.github/workflows/reloaded.yml new file mode 100644 index 0000000..9631108 --- /dev/null +++ b/.github/workflows/reloaded.yml @@ -0,0 +1,147 @@ +# Script to build and publish a Reloaded Mod. +# by Sewer56 + +# Produces: +# - Build to Upload to GameBanana +# - Build to Upload to GitHub +# - Build to Upload to NuGet +# - Changelog + +# When pushing a tag +# - Upload to GitHub Releases +# - Upload to Reloaded NuGet Repository (if GitHub Secret RELOADED_NUGET_KEY is specified) + +name: Build and Publish Reloaded Mod + +on: + push: + branches: [ master ] + tags: + - '*' + pull_request: + branches: [ master ] + workflow_dispatch: + +env: + PUBLISH_COMMON_PATH: ./Publish/ToUpload/ + + PUBLISH_GAMEBANANA_PATH: ./Publish/ToUpload/GameBanana + PUBLISH_GITHUB_PATH: ./Publish/ToUpload/Generic + PUBLISH_NUGET_PATH: ./Publish/ToUpload/NuGet + + PUBLISH_CHANGELOG_PATH: ./Publish/Changelog.md + PUBLISH_PATH: ./Publish + + # Default value is official Reloaded package server. + NUGET_URL: http://packages.sewer56.moe:5000/v3/index.json + + IS_RELEASE: ${{ startsWith(github.ref, 'refs/tags/') }} + RELEASE_TAG: ${{ github.ref_name }} + +jobs: + build: + runs-on: windows-latest + defaults: + run: + shell: pwsh + + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + submodules: 'recursive' + + - name: Setup .NET Core SDK (5.0) + uses: actions/setup-dotnet@v1.8.2 + with: + dotnet-version: 5.0.x + + - name: Setup .NET Core SDK (6.0) + uses: actions/setup-dotnet@v1.8.2 + with: + dotnet-version: 6.0.x + + - name: Setup Node.js + uses: actions/setup-node@v2 + with: + node-version: '14' + + - name: Setup AutoChangelog + run: npm install -g auto-changelog + + - name: Create Changelog + run: | + [System.IO.Directory]::CreateDirectory("$env:PUBLISH_PATH") + if ($env:IS_RELEASE -eq 'true') { + auto-changelog --sort-commits date --hide-credit --template keepachangelog --commit-limit false --starting-version "$env:RELEASE_TAG" --output "$env:PUBLISH_CHANGELOG_PATH" + } + else { + auto-changelog --sort-commits date --hide-credit --template keepachangelog --commit-limit false --unreleased --output "$env:PUBLISH_CHANGELOG_PATH" + } + + - name: Build + run: ./Publish.ps1 -ChangelogPath "$env:PUBLISH_CHANGELOG_PATH" + + - name: Upload GitHub Release Artifact + uses: actions/upload-artifact@v2.2.4 + with: + # Artifact name + name: GitHub Release + # A file, directory or wildcard pattern that describes what to upload + path: | + ${{ env.PUBLISH_GITHUB_PATH }}/* + + - name: Upload GameBanana Release Artifact + uses: actions/upload-artifact@v2.2.4 + with: + # Artifact name + name: GameBanana Release + # A file, directory or wildcard pattern that describes what to upload + path: | + ${{ env.PUBLISH_GAMEBANANA_PATH }}/* + + - name: Upload NuGet Release Artifact + uses: actions/upload-artifact@v2.2.4 + with: + # Artifact name + name: NuGet Release + # A file, directory or wildcard pattern that describes what to upload + path: | + ${{ env.PUBLISH_NUGET_PATH }}/* + + - name: Upload Changelog Artifact + uses: actions/upload-artifact@v2.2.4 + with: + # Artifact name + name: Changelog + # A file, directory or wildcard pattern that describes what to upload + path: ${{ env.PUBLISH_CHANGELOG_PATH }} + retention-days: 0 + + - name: Upload to GitHub Releases (on Tag) + uses: softprops/action-gh-release@v0.1.14 + if: env.IS_RELEASE == 'true' + with: + # Path to load note-worthy description of changes in release from + body_path: ${{ env.PUBLISH_CHANGELOG_PATH }} + # Newline-delimited list of path globs for asset files to upload + files: | + ${{ env.PUBLISH_GITHUB_PATH }}/* + + - name: Push to NuGet (on Tag) + env: + NUGET_KEY: ${{ secrets.RELOADED_NUGET_KEY }} + if: env.IS_RELEASE == 'true' + run: | + if ([string]::IsNullOrEmpty("$env:NUGET_KEY")) + { + Write-Host "NuGet Repository Key (GitHub Secrets -> RELOADED_NUGET_KEY) Not Specified. Skipping." + return + } + + $items = Get-ChildItem -Path "$env:PUBLISH_NUGET_PATH/*.nupkg" + Foreach ($item in $items) + { + Write-Host "Pushing $item" + dotnet nuget push "$item" -k "$env:NUGET_KEY" -s "$env:NUGET_URL" --skip-duplicate + } \ No newline at end of file diff --git a/Heroes.Fun.AuraColorizer/BuildLinked.ps1 b/Heroes.Fun.AuraColorizer/BuildLinked.ps1 new file mode 100644 index 0000000..8baf289 --- /dev/null +++ b/Heroes.Fun.AuraColorizer/BuildLinked.ps1 @@ -0,0 +1,9 @@ +# Set Working Directory +Split-Path $MyInvocation.MyCommand.Path | Push-Location +[Environment]::CurrentDirectory = $PWD + +Remove-Item "$env:RELOADEDIIMODS/sonicheroes.fun.colourizer/*" -Force -Recurse +dotnet publish "./Heroes.Fun.AuraColorizer.csproj" -c Release -o "$env:RELOADEDIIMODS/sonicheroes.fun.colourizer" /p:OutputPath="./bin/Release" /p:ReloadedILLink="true" + +# Restore Working Directory +Pop-Location \ No newline at end of file diff --git a/Heroes.Fun.AuraColorizer/Collections/BarrierColours.cs b/Heroes.Fun.AuraColorizer/Collections/BarrierColours.cs index b6b0ac7..54651af 100644 --- a/Heroes.Fun.AuraColorizer/Collections/BarrierColours.cs +++ b/Heroes.Fun.AuraColorizer/Collections/BarrierColours.cs @@ -1,17 +1,13 @@ -using System; -using System.Collections.Generic; -using System.Text; -using Heroes.Fun.AuraColorizer.Heroes; +using Heroes.Fun.AuraColorizer.Heroes; -namespace Heroes.Fun.AuraColorizer.Collections +namespace Heroes.Fun.AuraColorizer.Collections; + +public static class BarrierColours { - public static class BarrierColours + public static unsafe RgbaColorComponentPtrSet[] Colours = { - public static unsafe RgbaColorComponentPtrSet[] Colours = - { - new RgbaColorComponentPtrSet((byte*) 0x47244D, (byte*) 0x472452, (byte*) 0x472457, (byte*) 0x472443), // Power barrier - new RgbaColorComponentPtrSet((byte*) 0x47245E, (byte*) 0x472463, (byte*) 0x472468, (byte*) 0x472443), // Flight Barrier - new RgbaColorComponentPtrSet((byte*) 0x47246F, (byte*) 0x472474, (byte*) 0x472479, (byte*) 0x472443) // Speed Barrier - }; - } -} + new RgbaColorComponentPtrSet((byte*) 0x47244D, (byte*) 0x472452, (byte*) 0x472457, (byte*) 0x472443), // Power barrier + new RgbaColorComponentPtrSet((byte*) 0x47245E, (byte*) 0x472463, (byte*) 0x472468, (byte*) 0x472443), // Flight Barrier + new RgbaColorComponentPtrSet((byte*) 0x47246F, (byte*) 0x472474, (byte*) 0x472479, (byte*) 0x472443) // Speed Barrier + }; +} \ No newline at end of file diff --git a/Heroes.Fun.AuraColorizer/Config/Config.cs b/Heroes.Fun.AuraColorizer/Config/Config.cs index c6eae53..0d5600a 100644 --- a/Heroes.Fun.AuraColorizer/Config/Config.cs +++ b/Heroes.Fun.AuraColorizer/Config/Config.cs @@ -1,25 +1,23 @@ using System.ComponentModel; -using System.IO; using Heroes.Fun.AuraColorizer.Configuration; -namespace Heroes.Fun.AuraColorizer.Config +namespace Heroes.Fun.AuraColorizer.Config; + +public class Config : Configurable { - public class Config : Configurable - { - [DisplayName("Jump Ball Hue Cycle")] - [Description("Control the hue cycle effects on the characters' jumping ball.")] - public HueCycleEffectSettings BallColourHueCycle { get; set; } = new HueCycleEffectSettings(true, 1337, 60); + [DisplayName("Jump Ball Hue Cycle")] + [Description("Control the hue cycle effects on the characters' jumping ball.")] + public HueCycleEffectSettings BallColourHueCycle { get; set; } = new HueCycleEffectSettings(true, 1337, 60); - [DisplayName("Tornado Colour Hue Cycle")] - [Description("Control the hue cycle effects on the speed characters' tornado ability.")] - public HueCycleEffectSettings TornadoColourHueCycle { get; set; } = new HueCycleEffectSettings(true, 1337, 60); + [DisplayName("Tornado Colour Hue Cycle")] + [Description("Control the hue cycle effects on the speed characters' tornado ability.")] + public HueCycleEffectSettings TornadoColourHueCycle { get; set; } = new HueCycleEffectSettings(true, 1337, 60); - [DisplayName("Jump Trail Hue Cycle")] - [Description("Control the hue cycle effects on the trails left by the characters when performing an air dash/homing attack.")] - public HueCycleEffectSettings TrailColourHueCycle { get; set; } = new HueCycleEffectSettings(true, 1337, 60); + [DisplayName("Jump Trail Hue Cycle")] + [Description("Control the hue cycle effects on the trails left by the characters when performing an air dash/homing attack.")] + public HueCycleEffectSettings TrailColourHueCycle { get; set; } = new HueCycleEffectSettings(true, 1337, 60); - [DisplayName("Formation Gate Hue Cycle")] - [Description("Control the hue cycle effects on the individual formation switch gates.")] - public HueCycleEffectSettings FormationGateColourHueCycle { get; set; } = new HueCycleEffectSettings(true, 1337, 60); - } -} + [DisplayName("Formation Gate Hue Cycle")] + [Description("Control the hue cycle effects on the individual formation switch gates.")] + public HueCycleEffectSettings FormationGateColourHueCycle { get; set; } = new HueCycleEffectSettings(true, 1337, 60); +} \ No newline at end of file diff --git a/Heroes.Fun.AuraColorizer/Config/HueCycleEffectSettings.cs b/Heroes.Fun.AuraColorizer/Config/HueCycleEffectSettings.cs index ccde595..f731620 100644 --- a/Heroes.Fun.AuraColorizer/Config/HueCycleEffectSettings.cs +++ b/Heroes.Fun.AuraColorizer/Config/HueCycleEffectSettings.cs @@ -1,28 +1,27 @@ using System.ComponentModel; -namespace Heroes.Fun.AuraColorizer.Config -{ - public class HueCycleEffectSettings - { - [DefaultValue(true)] - public bool Enable { get; set; } +namespace Heroes.Fun.AuraColorizer.Config; - [Description("The duration of an entire indvidual hue cycle.")] - [DefaultValue(1337)] - public int Duration { get; set; } +public class HueCycleEffectSettings +{ + [DefaultValue(true)] + public bool Enable { get; set; } - [Description("How many times the hue is changed during the Duration of one cycle.")] - [DefaultValue(60.0f)] - public float Framerate { get; set; } + [Description("The duration of an entire indvidual hue cycle.")] + [DefaultValue(1337)] + public int Duration { get; set; } - public HueCycleEffectSettings() { } - public HueCycleEffectSettings(bool enable, int duration, float framerate) - { - Enable = enable; - Duration = duration; - Framerate = framerate; - } + [Description("How many times the hue is changed during the Duration of one cycle.")] + [DefaultValue(60.0f)] + public float Framerate { get; set; } - public override string ToString() => $"Enabled: {Enable}, Duration: {Duration}, Framerate: {Framerate}"; + public HueCycleEffectSettings() { } + public HueCycleEffectSettings(bool enable, int duration, float framerate) + { + Enable = enable; + Duration = duration; + Framerate = framerate; } -} + + public override string ToString() => $"Enabled: {Enable}, Duration: {Duration}, Framerate: {Framerate}"; +} \ No newline at end of file diff --git a/Heroes.Fun.AuraColorizer/Configuration/Configurable.cs b/Heroes.Fun.AuraColorizer/Configuration/Configurable.cs index a3d5b48..feaff5d 100644 --- a/Heroes.Fun.AuraColorizer/Configuration/Configurable.cs +++ b/Heroes.Fun.AuraColorizer/Configuration/Configurable.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.IO; -using System.Text; +using System.ComponentModel; using System.Text.Json; using System.Text.Json.Serialization; using Reloaded.Messaging.Interfaces; @@ -10,144 +6,143 @@ using Reloaded.Messaging.Serializer.SystemTextJson; using Reloaded.Mod.Interfaces; -namespace Heroes.Fun.AuraColorizer.Configuration +namespace Heroes.Fun.AuraColorizer.Configuration; + +public class Configurable : IUpdatableConfigurable, ISerializable where TParentType : Configurable, new() { - public class Configurable : IUpdatableConfigurable, ISerializable where TParentType : Configurable, new() + // Default Serialization Options + // If you wish to change the serializer used, refer to Reloaded.Messaging documentation: https://github.com/Reloaded-Project/Reloaded.Messaging + public static JsonSerializerOptions SerializerOptions { get; } = new JsonSerializerOptions() { - // Default Serialization Options - // If you wish to change the serializer used, refer to Reloaded.Messaging documentation: https://github.com/Reloaded-Project/Reloaded.Messaging - public static JsonSerializerOptions SerializerOptions { get; } = new JsonSerializerOptions() - { - Converters = { new JsonStringEnumConverter() }, - WriteIndented = true - }; - - public ISerializer GetSerializer() => new SystemTextJsonSerializer(SerializerOptions); - public ICompressor GetCompressor() => null; - - /* Events */ - - /// - /// Automatically executed when the external configuration file is updated. - /// Passes a new instance of the configuration as parameter. - /// Inside your event handler, replace the variable storing the configuration with the new one. - /// - [Browsable(false)] - public event Action ConfigurationUpdated; - - /* Class Properties */ - - /// - /// Full path to the configuration file. - /// - [JsonIgnore] - [Browsable(false)] - public string FilePath { get; private set; } - - /// - /// The name of the configuration file. - /// - [JsonIgnore] - [Browsable(false)] - public string ConfigName { get; private set; } - - /// - /// Receives events on whenever the file is actively changed or updated. - /// - [JsonIgnore] - [Browsable(false)] - private FileSystemWatcher ConfigWatcher { get; set; } - - /* Construction */ - public Configurable() { } - - private void Initialize(string filePath, string configName) - { - // Initializes an instance after construction by e.g. a serializer. - FilePath = filePath; - ConfigName = configName; + Converters = { new JsonStringEnumConverter() }, + WriteIndented = true + }; + + public ISerializer GetSerializer() => new SystemTextJsonSerializer(SerializerOptions); + public ICompressor GetCompressor() => null; + + /* Events */ + + /// + /// Automatically executed when the external configuration file is updated. + /// Passes a new instance of the configuration as parameter. + /// Inside your event handler, replace the variable storing the configuration with the new one. + /// + [Browsable(false)] + public event Action ConfigurationUpdated; + + /* Class Properties */ + + /// + /// Full path to the configuration file. + /// + [JsonIgnore] + [Browsable(false)] + public string FilePath { get; private set; } + + /// + /// The name of the configuration file. + /// + [JsonIgnore] + [Browsable(false)] + public string ConfigName { get; private set; } + + /// + /// Receives events on whenever the file is actively changed or updated. + /// + [JsonIgnore] + [Browsable(false)] + private FileSystemWatcher ConfigWatcher { get; set; } + + /* Construction */ + public Configurable() { } + + private void Initialize(string filePath, string configName) + { + // Initializes an instance after construction by e.g. a serializer. + FilePath = filePath; + ConfigName = configName; - MakeConfigWatcher(); - Save = OnSave; - } + MakeConfigWatcher(); + Save = OnSave; + } - /* Cleanup */ - public void DisposeEvents() - { - // Halts the FilesystemWatcher and all events associated with this instance. - ConfigWatcher?.Dispose(); - ConfigurationUpdated = null; - } + /* Cleanup */ + public void DisposeEvents() + { + // Halts the FilesystemWatcher and all events associated with this instance. + ConfigWatcher?.Dispose(); + ConfigurationUpdated = null; + } - /* Load/Save support. */ - - /// - /// Saves the configuration to the hard disk. - /// - [JsonIgnore] - [Browsable(false)] - public Action Save { get; private set; } - - /// - /// Safety lock for when changed event gets raised twice on file save. - /// - [Browsable(false)] - private static object _readLock = new object(); - - /// - /// Loads a specified configuration from the hard disk, or creates a default if it does not exist. - /// - /// The full file path of the config. - /// The name of the configuration. - public static TParentType FromFile(string filePath, string configName) => ReadFrom(filePath, configName); - - /* Event */ - - /// - /// Creates a that will automatically raise an - /// event when the config file is changed. - /// - /// - private void MakeConfigWatcher() - { - ConfigWatcher = new FileSystemWatcher(Path.GetDirectoryName(FilePath), Path.GetFileName(FilePath)); - ConfigWatcher.Changed += (sender, e) => OnConfigurationUpdated(); - ConfigWatcher.EnableRaisingEvents = true; - } + /* Load/Save support. */ + + /// + /// Saves the configuration to the hard disk. + /// + [JsonIgnore] + [Browsable(false)] + public Action Save { get; private set; } + + /// + /// Safety lock for when changed event gets raised twice on file save. + /// + [Browsable(false)] + private static object _readLock = new object(); + + /// + /// Loads a specified configuration from the hard disk, or creates a default if it does not exist. + /// + /// The full file path of the config. + /// The name of the configuration. + public static TParentType FromFile(string filePath, string configName) => ReadFrom(filePath, configName); + + /* Event */ + + /// + /// Creates a that will automatically raise an + /// event when the config file is changed. + /// + /// + private void MakeConfigWatcher() + { + ConfigWatcher = new FileSystemWatcher(Path.GetDirectoryName(FilePath), Path.GetFileName(FilePath)); + ConfigWatcher.Changed += (sender, e) => OnConfigurationUpdated(); + ConfigWatcher.EnableRaisingEvents = true; + } - /// - /// Reloads the configuration from the hard disk and raises the updated event. - /// - private void OnConfigurationUpdated() + /// + /// Reloads the configuration from the hard disk and raises the updated event. + /// + private void OnConfigurationUpdated() + { + lock (_readLock) { - lock (_readLock) - { - // Load and copy events. - // Note: External program might still be writing to file while this is being executed, so we need to keep retrying. - var newConfig = Utilities.TryGetValue(() => ReadFrom(this.FilePath, this.ConfigName), 250, 2); - newConfig.ConfigurationUpdated = ConfigurationUpdated; - - // Disable events for this instance. - DisposeEvents(); - - // Call subscribers through the new config. - newConfig.ConfigurationUpdated?.Invoke(newConfig); - } - } + // Load and copy events. + // Note: External program might still be writing to file while this is being executed, so we need to keep retrying. + var newConfig = Utilities.TryGetValue(() => ReadFrom(this.FilePath, this.ConfigName), 250, 2); + newConfig.ConfigurationUpdated = ConfigurationUpdated; - private void OnSave() - { - File.WriteAllBytes(FilePath, ((TParentType)this).Serialize()); - } + // Disable events for this instance. + DisposeEvents(); - /* Utility */ - private static TParentType ReadFrom(string filePath, string configName) - { - var result = File.Exists(filePath) - ? (TParentType)Serializable.Deserialize(File.ReadAllBytes(filePath)) - : new TParentType(); - result.Initialize(filePath, configName); - return result; + // Call subscribers through the new config. + newConfig.ConfigurationUpdated?.Invoke(newConfig); } } -} + + private void OnSave() + { + File.WriteAllBytes(FilePath, ((TParentType)this).Serialize()); + } + + /* Utility */ + private static TParentType ReadFrom(string filePath, string configName) + { + var result = File.Exists(filePath) + ? (TParentType)Serializable.Deserialize(File.ReadAllBytes(filePath)) + : new TParentType(); + result.Initialize(filePath, configName); + return result; + } +} \ No newline at end of file diff --git a/Heroes.Fun.AuraColorizer/Configuration/Configurator.cs b/Heroes.Fun.AuraColorizer/Configuration/Configurator.cs index 167c167..55812b8 100644 --- a/Heroes.Fun.AuraColorizer/Configuration/Configurator.cs +++ b/Heroes.Fun.AuraColorizer/Configuration/Configurator.cs @@ -1,79 +1,74 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; -using Reloaded.Mod.Interfaces; +using Reloaded.Mod.Interfaces; -namespace Heroes.Fun.AuraColorizer.Configuration +namespace Heroes.Fun.AuraColorizer.Configuration; + +public class Configurator : IConfiguratorV1 { - public class Configurator : IConfigurator - { - /* For latest documentation: - - See the interface! (Go To Definition) or if not available - - Google the Source Code! - */ + /* For latest documentation: + - See the interface! (Go To Definition) or if not available + - Google the Source Code! + */ - /// - /// Full path to the mod folder. - /// - public string ModFolder { get; private set; } + /// + /// Full path to the mod folder. + /// + public string ModFolder { get; private set; } - /// - /// Returns a list of configurations. - /// - public IUpdatableConfigurable[] Configurations => _configurations ?? MakeConfigurations(); - private IUpdatableConfigurable[] _configurations; + /// + /// Returns a list of configurations. + /// + public IUpdatableConfigurable[] Configurations => _configurations ?? MakeConfigurations(); + private IUpdatableConfigurable[] _configurations; - private IUpdatableConfigurable[] MakeConfigurations() + private IUpdatableConfigurable[] MakeConfigurations() + { + _configurations = new IUpdatableConfigurable[] { - _configurations = new IUpdatableConfigurable[] - { - // Add more configurations here if needed. - Configurable.FromFile(Path.Combine(ModFolder, "Config.json"), "Colourizer Config") - }; + // Add more configurations here if needed. + Configurable.FromFile(Path.Combine(ModFolder, "Config.json"), "Colourizer Config") + }; - // Add self-updating to configurations. - for (int x = 0; x < Configurations.Length; x++) + // Add self-updating to configurations. + for (int x = 0; x < Configurations.Length; x++) + { + var xCopy = x; + Configurations[x].ConfigurationUpdated += configurable => { - var xCopy = x; - Configurations[x].ConfigurationUpdated += configurable => - { - Configurations[xCopy] = configurable; - }; - } - - return _configurations; + Configurations[xCopy] = configurable; + }; } - public Configurator() { } - public Configurator(string modDirectory) : this() - { - ModFolder = modDirectory; - } + return _configurations; + } - /* Configurator */ + public Configurator() { } + public Configurator(string modDirectory) : this() + { + ModFolder = modDirectory; + } - /// - /// Gets an individual user configuration. - /// - public TType GetConfiguration(int index) => (TType)Configurations[index]; + /* Configurator */ - /* IConfigurator. */ + /// + /// Gets an individual user configuration. + /// + public TType GetConfiguration(int index) => (TType)Configurations[index]; - /// - /// Sets the mod directory for the Configurator. - /// - public void SetModDirectory(string modDirectory) => ModFolder = modDirectory; + /* IConfigurator. */ - /// - /// Returns a list of user configurations. - /// - public IConfigurable[] GetConfigurations() => Configurations; + /// + /// Sets the mod directory for the Configurator. + /// + public void SetModDirectory(string modDirectory) => ModFolder = modDirectory; - /// - /// Allows for custom launcher/configurator implementation. - /// If you have your own configuration program/code, run that code here and return true, else return false. - /// - public bool TryRunCustomConfiguration() => false; - } -} + /// + /// Returns a list of user configurations. + /// + public IConfigurable[] GetConfigurations() => Configurations; + + /// + /// Allows for custom launcher/configurator implementation. + /// If you have your own configuration program/code, run that code here and return true, else return false. + /// + public bool TryRunCustomConfiguration() => false; +} \ No newline at end of file diff --git a/Heroes.Fun.AuraColorizer/Configuration/Utilities.cs b/Heroes.Fun.AuraColorizer/Configuration/Utilities.cs index c10cefb..df0c2c1 100644 --- a/Heroes.Fun.AuraColorizer/Configuration/Utilities.cs +++ b/Heroes.Fun.AuraColorizer/Configuration/Utilities.cs @@ -1,45 +1,40 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Text; -using System.Threading; +using System.Diagnostics; -namespace Heroes.Fun.AuraColorizer.Configuration +namespace Heroes.Fun.AuraColorizer.Configuration; + +public class Utilities { - public class Utilities + /// Function that retrieves the value. + /// The timeout in milliseconds. + /// Amount of sleep per iteration/attempt. + /// Token that allows for cancellation of the task. + /// Timeout expired. + public static T TryGetValue(Func getValue, int timeout, int sleepTime, CancellationToken token = default) { - /// Function that retrieves the value. - /// The timeout in milliseconds. - /// Amount of sleep per iteration/attempt. - /// Token that allows for cancellation of the task. - /// Timeout expired. - public static T TryGetValue(Func getValue, int timeout, int sleepTime, CancellationToken token = default) + Stopwatch watch = new Stopwatch(); + watch.Start(); + bool valueSet = false; + T value = default; + + while (watch.ElapsedMilliseconds < timeout) { - Stopwatch watch = new Stopwatch(); - watch.Start(); - bool valueSet = false; - T value = default; + if (token.IsCancellationRequested) + return value; - while (watch.ElapsedMilliseconds < timeout) + try { - if (token.IsCancellationRequested) - return value; - - try - { - value = getValue(); - valueSet = true; - break; - } - catch (Exception) { /* Ignored */ } - - Thread.Sleep(sleepTime); + value = getValue(); + valueSet = true; + break; } + catch (Exception) { /* Ignored */ } - if (valueSet == false) - throw new Exception($"Timeout limit {timeout} exceeded."); - - return value; + Thread.Sleep(sleepTime); } + + if (valueSet == false) + throw new Exception($"Timeout limit {timeout} exceeded."); + + return value; } -} +} \ No newline at end of file diff --git a/Heroes.Fun.AuraColorizer/Enums/BallColourAddress.cs b/Heroes.Fun.AuraColorizer/Enums/BallColourAddress.cs index 0609f01..557c175 100644 --- a/Heroes.Fun.AuraColorizer/Enums/BallColourAddress.cs +++ b/Heroes.Fun.AuraColorizer/Enums/BallColourAddress.cs @@ -1,26 +1,25 @@ -namespace Heroes.Fun.AuraColorizer.Enums +namespace Heroes.Fun.AuraColorizer.Enums; + +public enum BallColourAddress : int { - public enum BallColourAddress : int - { - /* Speed */ - Sonic = 0x008C729C, - Shadow = 0x008C72A0, - Amy = 0x008C72A4, - Espio = 0x008C72A8, - SonicOverdriveSpeed = 0x008C72AC, + /* Speed */ + Sonic = 0x008C729C, + Shadow = 0x008C72A0, + Amy = 0x008C72A4, + Espio = 0x008C72A8, + SonicOverdriveSpeed = 0x008C72AC, - /* Power */ - Knuckles = 0x781F6C, - Omega = 0x781F70, - Big = 0x781F74, - Vector = 0x781F78, - SonicOverdrivePower = 0x781F7C, + /* Power */ + Knuckles = 0x781F6C, + Omega = 0x781F70, + Big = 0x781F74, + Vector = 0x781F78, + SonicOverdrivePower = 0x781F7C, - /* Flight */ - Tails = 0x782584, - Rouge = 0x782588, - Cream = 0x78258C, - Charmy = 0x782590, - SonicOverdriveFlight = 0x782594 - } + /* Flight */ + Tails = 0x782584, + Rouge = 0x782588, + Cream = 0x78258C, + Charmy = 0x782590, + SonicOverdriveFlight = 0x782594 } \ No newline at end of file diff --git a/Heroes.Fun.AuraColorizer/Enums/TornadoColourAddress.cs b/Heroes.Fun.AuraColorizer/Enums/TornadoColourAddress.cs index 7adbc75..97afb80 100644 --- a/Heroes.Fun.AuraColorizer/Enums/TornadoColourAddress.cs +++ b/Heroes.Fun.AuraColorizer/Enums/TornadoColourAddress.cs @@ -1,10 +1,9 @@ -namespace Heroes.Fun.AuraColorizer.Enums +namespace Heroes.Fun.AuraColorizer.Enums; + +public enum TornadoColourAddress : int { - public enum TornadoColourAddress : int - { - Sonic = 0x008DE4F8, - Shadow = 0x008DE4FC, - Amy = 0x008DE500, - Espio = 0x008DE504 - } + Sonic = 0x008DE4F8, + Shadow = 0x008DE4FC, + Amy = 0x008DE500, + Espio = 0x008DE504 } \ No newline at end of file diff --git a/Heroes.Fun.AuraColorizer/Enums/TrailColourAddress.cs b/Heroes.Fun.AuraColorizer/Enums/TrailColourAddress.cs index b8795df..3870fd0 100644 --- a/Heroes.Fun.AuraColorizer/Enums/TrailColourAddress.cs +++ b/Heroes.Fun.AuraColorizer/Enums/TrailColourAddress.cs @@ -1,18 +1,17 @@ -namespace Heroes.Fun.AuraColorizer.Enums +namespace Heroes.Fun.AuraColorizer.Enums; + +public enum TrailColourAddress : int { - public enum TrailColourAddress : int - { - Sonic = 0x008CF694, - Knuckles = 0x008CF698, - Tails = 0x008CF69C, - Shadow = 0x008CF6A0, - Omega = 0x008CF6A4, - Rouge = 0x008CF6A8, - Amy = 0x008CF6AC, - Big = 0x008CF6B0, - Cream = 0x008CF6B4, - Espio = 0x008CF6B8, - Vector = 0x008CF6BC, - Charmy = 0x008CF6C0 - } + Sonic = 0x008CF694, + Knuckles = 0x008CF698, + Tails = 0x008CF69C, + Shadow = 0x008CF6A0, + Omega = 0x008CF6A4, + Rouge = 0x008CF6A8, + Amy = 0x008CF6AC, + Big = 0x008CF6B0, + Cream = 0x008CF6B4, + Espio = 0x008CF6B8, + Vector = 0x008CF6BC, + Charmy = 0x008CF6C0 } \ No newline at end of file diff --git a/Heroes.Fun.AuraColorizer/Heroes.Fun.AuraColorizer.csproj b/Heroes.Fun.AuraColorizer/Heroes.Fun.AuraColorizer.csproj index bfc4a25..5f45eee 100644 --- a/Heroes.Fun.AuraColorizer/Heroes.Fun.AuraColorizer.csproj +++ b/Heroes.Fun.AuraColorizer/Heroes.Fun.AuraColorizer.csproj @@ -1,16 +1,30 @@  - netcoreapp3.0 + net5.0-windows + 10.0 false true - - WinExe - true $(RELOADEDIIMODS)\sonicheroes.fun.colourizer + enable + + + true + + + + + + + + + + @@ -26,10 +40,10 @@ - - - - + + + + diff --git a/Heroes.Fun.AuraColorizer/Heroes/IRgbaColor.cs b/Heroes.Fun.AuraColorizer/Heroes/IRgbaColor.cs index e8b43c2..eecd0d1 100644 --- a/Heroes.Fun.AuraColorizer/Heroes/IRgbaColor.cs +++ b/Heroes.Fun.AuraColorizer/Heroes/IRgbaColor.cs @@ -1,25 +1,21 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Windows.Media; +using System.Windows.Media; -namespace Heroes.Fun.AuraColorizer.Heroes +namespace Heroes.Fun.AuraColorizer.Heroes; + +public interface IRgbaColor { - public interface IRgbaColor - { - /// - /// Changes Windows' memory permissions to allow the colour to be changed. - /// - unsafe void GiveWritePermission(); + /// + /// Changes Windows' memory permissions to allow the colour to be changed. + /// + unsafe void GiveWritePermission(); - /// - /// Assigns a new color. - /// - unsafe void SetColor(RgbaColor color); + /// + /// Assigns a new color. + /// + unsafe void SetColor(RgbaColor color); - /// - /// Retrieves the colour. - /// - Color GetColor(); - } -} + /// + /// Retrieves the colour. + /// + Color GetColor(); +} \ No newline at end of file diff --git a/Heroes.Fun.AuraColorizer/Heroes/RgbaColor.cs b/Heroes.Fun.AuraColorizer/Heroes/RgbaColor.cs index 35af26a..4cd493c 100644 --- a/Heroes.Fun.AuraColorizer/Heroes/RgbaColor.cs +++ b/Heroes.Fun.AuraColorizer/Heroes/RgbaColor.cs @@ -1,50 +1,49 @@ using System.Windows.Media; -namespace Heroes.Fun.AuraColorizer.Heroes +namespace Heroes.Fun.AuraColorizer.Heroes; + +/// +/// Represents a colour formed using the R,G,B,A components. +/// +public struct RgbaColor { /// - /// Represents a colour formed using the R,G,B,A components. + /// Range 0 - 255. /// - public struct RgbaColor - { - /// - /// Range 0 - 255. - /// - public byte R; + public byte R; - /// - /// Range 0 - 255. - /// - public byte G; - - /// - /// Range 0 - 255. - /// - public byte B; + /// + /// Range 0 - 255. + /// + public byte G; - /// - /// Range 0 - 255. - /// - public byte A; + /// + /// Range 0 - 255. + /// + public byte B; - /// - /// Creates an RGBA colour. - /// - /// Range 0 - 255. - /// Range 0 - 255. - /// Range 0 - 255. - /// Range 0 - 255. - public RgbaColor(byte r, byte g, byte b, byte a) - { - R = r; - G = g; - B = b; - A = a; - } + /// + /// Range 0 - 255. + /// + public byte A; - public static RgbaColor FromColor(Color color) => new RgbaColor(color.R, color.G, color.B, color.A); - public static Color ToColor(RgbaColor color) => Color.FromArgb(color.A, color.R, color.G, color.B); - public static implicit operator Color(RgbaColor color) => ToColor(color); - public static implicit operator RgbaColor(Color color) => FromColor(color); + /// + /// Creates an RGBA colour. + /// + /// Range 0 - 255. + /// Range 0 - 255. + /// Range 0 - 255. + /// Range 0 - 255. + public RgbaColor(byte r, byte g, byte b, byte a) + { + R = r; + G = g; + B = b; + A = a; } -} + + public static RgbaColor FromColor(Color color) => new RgbaColor(color.R, color.G, color.B, color.A); + public static Color ToColor(RgbaColor color) => Color.FromArgb(color.A, color.R, color.G, color.B); + public static implicit operator Color(RgbaColor color) => ToColor(color); + public static implicit operator RgbaColor(Color color) => FromColor(color); +} \ No newline at end of file diff --git a/Heroes.Fun.AuraColorizer/Heroes/RgbaColorComponentPtrSet.cs b/Heroes.Fun.AuraColorizer/Heroes/RgbaColorComponentPtrSet.cs index ba4d152..2aa5858 100644 --- a/Heroes.Fun.AuraColorizer/Heroes/RgbaColorComponentPtrSet.cs +++ b/Heroes.Fun.AuraColorizer/Heroes/RgbaColorComponentPtrSet.cs @@ -1,73 +1,69 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Windows.Media; +using System.Windows.Media; using Reloaded.Memory.Kernel32; using Reloaded.Memory.Sources; -namespace Heroes.Fun.AuraColorizer.Heroes +namespace Heroes.Fun.AuraColorizer.Heroes; + +/// +/// A version of where each of the four components is stored in a different memory location. +/// +public unsafe struct RgbaColorComponentPtrSet : IRgbaColor { /// - /// A version of where each of the four components is stored in a different memory location. + /// Range 0 - 255. /// - public unsafe struct RgbaColorComponentPtrSet : IRgbaColor - { - /// - /// Range 0 - 255. - /// - public byte* R; + public byte* R; - /// - /// Range 0 - 255. - /// - public byte* G; + /// + /// Range 0 - 255. + /// + public byte* G; - /// - /// Range 0 - 255. - /// - public byte* B; + /// + /// Range 0 - 255. + /// + public byte* B; - /// - /// Range 0 - 255. - /// - public byte* A; + /// + /// Range 0 - 255. + /// + public byte* A; - public RgbaColorComponentPtrSet(byte* r, byte* g, byte* b, byte* a) - { - R = r; - G = g; - B = b; - A = a; - } + public RgbaColorComponentPtrSet(byte* r, byte* g, byte* b, byte* a) + { + R = r; + G = g; + B = b; + A = a; + } - /// - /// Changes Windows' memory permissions to allow the colour to be changed. - /// - public void GiveWritePermission() - { - Memory.Instance.ChangePermission((IntPtr) R, sizeof(byte), Kernel32.MEM_PROTECTION.PAGE_EXECUTE_READWRITE); - Memory.Instance.ChangePermission((IntPtr) G, sizeof(byte), Kernel32.MEM_PROTECTION.PAGE_EXECUTE_READWRITE); - Memory.Instance.ChangePermission((IntPtr) B, sizeof(byte), Kernel32.MEM_PROTECTION.PAGE_EXECUTE_READWRITE); - Memory.Instance.ChangePermission((IntPtr) A, sizeof(byte), Kernel32.MEM_PROTECTION.PAGE_EXECUTE_READWRITE); - } + /// + /// Changes Windows' memory permissions to allow the colour to be changed. + /// + public void GiveWritePermission() + { + Memory.Instance.ChangePermission((nuint)R, sizeof(byte), Kernel32.MEM_PROTECTION.PAGE_EXECUTE_READWRITE); + Memory.Instance.ChangePermission((nuint)G, sizeof(byte), Kernel32.MEM_PROTECTION.PAGE_EXECUTE_READWRITE); + Memory.Instance.ChangePermission((nuint)B, sizeof(byte), Kernel32.MEM_PROTECTION.PAGE_EXECUTE_READWRITE); + Memory.Instance.ChangePermission((nuint)A, sizeof(byte), Kernel32.MEM_PROTECTION.PAGE_EXECUTE_READWRITE); + } - /// - /// Assigns a new color. - /// - public void SetColor(RgbaColor color) - { - *R = color.R; - *G = color.G; - *B = color.B; - *A = color.A; - } + /// + /// Assigns a new color. + /// + public void SetColor(RgbaColor color) + { + *R = color.R; + *G = color.G; + *B = color.B; + *A = color.A; + } - /// - /// Retrieves the colour. - /// - public Color GetColor() => ToColor(this); + /// + /// Retrieves the colour. + /// + public Color GetColor() => ToColor(this); - public static Color ToColor(RgbaColorComponentPtrSet colorComponent) => Color.FromArgb(*colorComponent.A, *colorComponent.R, *colorComponent.G, *colorComponent.B); - public static implicit operator Color(RgbaColorComponentPtrSet colorComponent) => ToColor(colorComponent); - } -} + public static Color ToColor(RgbaColorComponentPtrSet colorComponent) => Color.FromArgb(*colorComponent.A, *colorComponent.R, *colorComponent.G, *colorComponent.B); + public static implicit operator Color(RgbaColorComponentPtrSet colorComponent) => ToColor(colorComponent); +} \ No newline at end of file diff --git a/Heroes.Fun.AuraColorizer/Heroes/RgbaColorPtr.cs b/Heroes.Fun.AuraColorizer/Heroes/RgbaColorPtr.cs index 5bd263c..6472beb 100644 --- a/Heroes.Fun.AuraColorizer/Heroes/RgbaColorPtr.cs +++ b/Heroes.Fun.AuraColorizer/Heroes/RgbaColorPtr.cs @@ -1,38 +1,36 @@ -using System; -using System.Windows.Media; +using System.Windows.Media; using Reloaded.Memory.Kernel32; using Reloaded.Memory.Sources; -namespace Heroes.Fun.AuraColorizer.Heroes +namespace Heroes.Fun.AuraColorizer.Heroes; + +/// +/// Represents a colour formed using the R,G,B,A components. +/// +public unsafe struct RgbaColorPtr : IRgbaColor { /// - /// Represents a colour formed using the R,G,B,A components. + /// Range 0 - 255. /// - public unsafe struct RgbaColorPtr : IRgbaColor - { - /// - /// Range 0 - 255. - /// - public RgbaColor* Color; - - /// - /// Creates an RGBA colour. - /// - public RgbaColorPtr(RgbaColor* color) - { - Color = color; - } + public RgbaColor* Color; - /// - /// Creates an RGBA colour. - /// - public RgbaColorPtr(long colorPtr) - { - Color = (RgbaColor*) colorPtr; - } + /// + /// Creates an RGBA colour. + /// + public RgbaColorPtr(RgbaColor* color) + { + Color = color; + } - public void GiveWritePermission() => Memory.Instance.ChangePermission((IntPtr) Color, sizeof(RgbaColor), Kernel32.MEM_PROTECTION.PAGE_EXECUTE_READWRITE); - public void SetColor(RgbaColor color) => *Color = color; - public Color GetColor() => *Color; + /// + /// Creates an RGBA colour. + /// + public RgbaColorPtr(long colorPtr) + { + Color = (RgbaColor*) colorPtr; } -} + + public void GiveWritePermission() => Memory.Instance.ChangePermission((nuint) Color, sizeof(RgbaColor), Kernel32.MEM_PROTECTION.PAGE_EXECUTE_READWRITE); + public void SetColor(RgbaColor color) => *Color = color; + public Color GetColor() => *Color; +} \ No newline at end of file diff --git a/Heroes.Fun.AuraColorizer/ModConfig.json b/Heroes.Fun.AuraColorizer/ModConfig.json index fa7c859..3f0eae0 100644 --- a/Heroes.Fun.AuraColorizer/ModConfig.json +++ b/Heroes.Fun.AuraColorizer/ModConfig.json @@ -1,8 +1,8 @@ -{ +{ "ModId": "sonicheroes.fun.colourizer", "ModName": "Sonic Heroes: Colourizer", "ModAuthor": "Sewer56", - "ModVersion": "1.1.0", + "ModVersion": "1.1.1", "ModDescription": "Sonic Heroes but a bit more like a Corsair Keyboard.", "ModDll": "Heroes.Fun.AuraColorizer.dll", "ModIcon": "Preview.png", @@ -18,6 +18,12 @@ "DefaultRepositoryUrls": [ "http://packages.sewer56.moe:5000/v3/index.json" ] + }, + "GitHubRelease": { + "UserName": "Sewer56", + "RepositoryName": "https://github.com/Sewer56/Heroes.Colourizer.ReloadedII", + "UseReleaseTag": true, + "AssetFileName": "Mod.zip" } }, "IsUniversalMod": false, @@ -25,5 +31,6 @@ "OptionalDependencies": [], "SupportedAppId": [ "tsonic_win.exe" - ] + ], + "ProjectUrl": "https://github.com/Sewer56/Heroes.Colourizer.ReloadedII" } diff --git a/Heroes.Fun.AuraColorizer/Preview.png b/Heroes.Fun.AuraColorizer/Preview.png index e983655..8622a46 100644 Binary files a/Heroes.Fun.AuraColorizer/Preview.png and b/Heroes.Fun.AuraColorizer/Preview.png differ diff --git a/Heroes.Fun.AuraColorizer/Program.cs b/Heroes.Fun.AuraColorizer/Program.cs index 1647923..80c76f0 100644 --- a/Heroes.Fun.AuraColorizer/Program.cs +++ b/Heroes.Fun.AuraColorizer/Program.cs @@ -1,7 +1,4 @@ -using System; -using System.Linq; -using System.Threading.Tasks; -using Heroes.Fun.AuraColorizer.Collections; +using Heroes.Fun.AuraColorizer.Collections; using Heroes.Fun.AuraColorizer.Configuration; using Heroes.Fun.AuraColorizer.Enums; using Heroes.Fun.AuraColorizer.Heroes; @@ -9,108 +6,106 @@ using Reloaded.Mod.Interfaces.Internal; using static Heroes.Fun.AuraColorizer.Utility; -namespace Heroes.Fun.AuraColorizer +namespace Heroes.Fun.AuraColorizer; + +public class Program : IMod { - public class Program : IMod - { - private const string ThisModId = "sonicheroes.fun.colourizer"; - private object _lock = new object(); - private IModLoader _modLoader; + private const string ThisModId = "sonicheroes.fun.colourizer"; + private object _lock = new object(); + private IModLoader _modLoader; - private RgbaColourAnimation[] _jumpBallAnimations; - private RgbaColourAnimation[] _tornadoAnimations; - private RgbaColourAnimation[] _trailAnimations; - private RgbaColourAnimation[] _formationGateAnimations; + private RgbaColourAnimation[] _jumpBallAnimations; + private RgbaColourAnimation[] _tornadoAnimations; + private RgbaColourAnimation[] _trailAnimations; + private RgbaColourAnimation[] _formationGateAnimations; - private Config.Config _config; - private ILogger _logger; - private string _modDirectory; + private Config.Config _config; + private ILogger _logger; + private string _modDirectory; - private Task _setupColourizer; - private Configurator _configurator; + private Task _setupColourizer; + private Configurator _configurator; - public static void Main() { } - public unsafe void Start(IModLoaderV1 loader) - { - _modLoader = (IModLoader) loader; - _logger = (ILogger) _modLoader.GetLogger(); - _modDirectory = _modLoader.GetDirectoryForModId(ThisModId); + public unsafe void Start(IModLoaderV1 loader) + { + _modLoader = (IModLoader) loader; + _logger = (ILogger) _modLoader.GetLogger(); + _modDirectory = _modLoader.GetDirectoryForModId(ThisModId); - /* Your mod code starts here. */ - _modLoader.OnModLoaderInitialized += OnModLoaderInitialized; - _setupColourizer = Task.Run(() => + /* Your mod code starts here. */ + _modLoader.OnModLoaderInitialized += OnModLoaderInitialized; + _setupColourizer = Task.Run(() => + { + _configurator = new Configurator(_modDirectory); + _config = _configurator.GetConfiguration(0); + _config.ConfigurationUpdated += configurable => { - _configurator = new Configurator(_modDirectory); - _config = _configurator.GetConfiguration(0); - _config.ConfigurationUpdated += configurable => + _config = (Config.Config)configurable; + _logger.WriteLine("[Colorizer] Config file changed. Cancelling current effects and applying new.", _logger.ColorGreenLight); + lock (_lock) { - _config = (Config.Config)configurable; - _logger.WriteLine("[Colorizer] Config file changed. Cancelling current effects and applying new.", _logger.ColorGreenLight); - lock (_lock) - { - CancelAll(); - Initialize(); - } - }; - - Initialize(); - }); - } - - private void OnModLoaderInitialized() - { - _setupColourizer.Wait(); - _modLoader.OnModLoaderInitialized -= OnModLoaderInitialized; - } + CancelAll(); + Initialize(); + } + }; - private void CancelAll() - { - _jumpBallAnimations.ForEach(animation => animation.Cancel()); - _tornadoAnimations.ForEach(animation => animation.Cancel()); - _trailAnimations.ForEach(animation => animation.Cancel()); - _formationGateAnimations.ForEach(animation => animation.Cancel()); - } + Initialize(); + }); + } - private void Initialize() - { - _jumpBallAnimations = GetEnumValues().Select(x => new RgbaColourAnimation(new RgbaColorPtr((long)x), _config.BallColourHueCycle.Duration, _config.BallColourHueCycle.Framerate)).ToArray(); - _tornadoAnimations = GetEnumValues().Select(x => new RgbaColourAnimation(new RgbaColorPtr((long)x), _config.TornadoColourHueCycle.Duration, _config.TornadoColourHueCycle.Framerate)).ToArray(); - _trailAnimations = GetEnumValues().Select(x => new RgbaColourAnimation(new RgbaColorPtr((long)x), _config.TrailColourHueCycle.Duration, _config.TrailColourHueCycle.Framerate)).ToArray(); - _formationGateAnimations = BarrierColours.Colours.Select(x => new RgbaColourAnimation(x, _config.FormationGateColourHueCycle.Duration, _config.FormationGateColourHueCycle.Framerate)).ToArray(); - - if (_config.BallColourHueCycle.Enable) _jumpBallAnimations.ForEach(animation => animation.Start()); - if (_config.TornadoColourHueCycle.Enable) _tornadoAnimations.ForEach(animation => animation.Start()); - if (_config.TrailColourHueCycle.Enable) _trailAnimations.ForEach(animation => animation.Start()); - if (_config.FormationGateColourHueCycle.Enable) _formationGateAnimations.ForEach(animation => animation.Start()); - } - - /* Mod loader actions. */ - public void Suspend() - { - if (_config.BallColourHueCycle.Enable) _jumpBallAnimations.ForEach(animation => animation.Suspend()); - if (_config.TornadoColourHueCycle.Enable) _tornadoAnimations.ForEach(animation => animation.Suspend()); - if (_config.TrailColourHueCycle.Enable) _trailAnimations.ForEach(animation => animation.Suspend()); - if (_config.FormationGateColourHueCycle.Enable) _formationGateAnimations.ForEach(animation => animation.Suspend()); - } + private void OnModLoaderInitialized() + { + _setupColourizer.Wait(); + _modLoader.OnModLoaderInitialized -= OnModLoaderInitialized; + } - public void Resume() - { - if (_config.BallColourHueCycle.Enable) _jumpBallAnimations.ForEach(animation => animation.Resume()); - if (_config.TornadoColourHueCycle.Enable) _tornadoAnimations.ForEach(animation => animation.Resume()); - if (_config.TrailColourHueCycle.Enable) _trailAnimations.ForEach(animation => animation.Resume()); - if (_config.FormationGateColourHueCycle.Enable) _formationGateAnimations.ForEach(animation => animation.Resume()); - } + private void CancelAll() + { + _jumpBallAnimations.ForEach(animation => animation.Cancel()); + _tornadoAnimations.ForEach(animation => animation.Cancel()); + _trailAnimations.ForEach(animation => animation.Cancel()); + _formationGateAnimations.ForEach(animation => animation.Cancel()); + } - public void Unload() - { - Suspend(); - CancelAll(); - } + private void Initialize() + { + _jumpBallAnimations = GetEnumValues().Select(x => new RgbaColourAnimation(new RgbaColorPtr((long)x), _config.BallColourHueCycle.Duration, _config.BallColourHueCycle.Framerate)).ToArray(); + _tornadoAnimations = GetEnumValues().Select(x => new RgbaColourAnimation(new RgbaColorPtr((long)x), _config.TornadoColourHueCycle.Duration, _config.TornadoColourHueCycle.Framerate)).ToArray(); + _trailAnimations = GetEnumValues().Select(x => new RgbaColourAnimation(new RgbaColorPtr((long)x), _config.TrailColourHueCycle.Duration, _config.TrailColourHueCycle.Framerate)).ToArray(); + _formationGateAnimations = BarrierColours.Colours.Select(x => new RgbaColourAnimation(x, _config.FormationGateColourHueCycle.Duration, _config.FormationGateColourHueCycle.Framerate)).ToArray(); + + if (_config.BallColourHueCycle.Enable) _jumpBallAnimations.ForEach(animation => animation.Start()); + if (_config.TornadoColourHueCycle.Enable) _tornadoAnimations.ForEach(animation => animation.Start()); + if (_config.TrailColourHueCycle.Enable) _trailAnimations.ForEach(animation => animation.Start()); + if (_config.FormationGateColourHueCycle.Enable) _formationGateAnimations.ForEach(animation => animation.Start()); + } - public bool CanUnload() => true; - public bool CanSuspend() => true; + /* Mod loader actions. */ + public void Suspend() + { + if (_config.BallColourHueCycle.Enable) _jumpBallAnimations.ForEach(animation => animation.Suspend()); + if (_config.TornadoColourHueCycle.Enable) _tornadoAnimations.ForEach(animation => animation.Suspend()); + if (_config.TrailColourHueCycle.Enable) _trailAnimations.ForEach(animation => animation.Suspend()); + if (_config.FormationGateColourHueCycle.Enable) _formationGateAnimations.ForEach(animation => animation.Suspend()); + } - /* Automatically called by the mod loader when the mod is about to be unloaded. */ - public Action Disposing { get; } + public void Resume() + { + if (_config.BallColourHueCycle.Enable) _jumpBallAnimations.ForEach(animation => animation.Resume()); + if (_config.TornadoColourHueCycle.Enable) _tornadoAnimations.ForEach(animation => animation.Resume()); + if (_config.TrailColourHueCycle.Enable) _trailAnimations.ForEach(animation => animation.Resume()); + if (_config.FormationGateColourHueCycle.Enable) _formationGateAnimations.ForEach(animation => animation.Resume()); + } + + public void Unload() + { + Suspend(); + CancelAll(); } -} + + public bool CanUnload() => true; + public bool CanSuspend() => true; + + /* Automatically called by the mod loader when the mod is about to be unloaded. */ + public Action Disposing { get; } +} \ No newline at end of file diff --git a/Heroes.Fun.AuraColorizer/Publish.ps1 b/Heroes.Fun.AuraColorizer/Publish.ps1 new file mode 100644 index 0000000..b8bf417 --- /dev/null +++ b/Heroes.Fun.AuraColorizer/Publish.ps1 @@ -0,0 +1,408 @@ +<# +.SYNOPSIS + Builds and Publishes a Reloaded II Mod +.DESCRIPTION + Windows script to Build and Publish a Reloaded Mod. + By default, published items will be output to a directory called `Publish/ToUpload`. + + If you acquired this script by creating a new Reloaded Mod in VS. Then most likely everything + (aside from delta updates) should be preconfigured here. + +.PARAMETER ProjectPath + Path to the project to be built. + Useful if using this script from another script for the purpose of building multiple mods. + +.PARAMETER PackageName + Name of the package to be built. + Affects the name of the output files of the publish. + +.PARAMETER PublishOutputDir + Default: "Publish/ToUpload" + Declares the directory for placing the output files. + +.PARAMETER BuildR2R + Default: $False + + Builds the mod using an optimisation called `Ready to Run`, which sacrifices file size for potentially + faster startup time. This is only worth enabling on mods with a lot of code, usually it is best left disabled. + + For more details see: https://docs.microsoft.com/en-us/dotnet/core/deploying/ready-to-run + +.PARAMETER ChangelogPath + Full or relative path to a file containing the changelog for the mod. + The changelog should be written in Markdown format. + +.PARAMETER ReadmePath + Full or relative path to a file containing the changelog for the mod. + The changelog should be written in Markdown format. + +.PARAMETER IsPrerelease + Default: $False + + If set to true, the version downloaded for delta package generation will be the latest pre-release + as opposed to the latest stable version. + +.PARAMETER MakeDelta + Default: $False + + Set to true to create Delta packages. + Usually this is true in a CI/CD environment when creating a release, else false in development. + + If this is true, you should set UseGitHubDelta, UseGameBananaDelta, UseNuGetDelta or equivalent to true. + +.PARAMETER MetadataFileName + Default: Sewer56.Update.ReleaseMetadata.json + Name of the release metadata file used to download the delta package. + +.PARAMETER UseGitHubDelta + Default: $False + If true, sources the last version of the package to publish from GitHub. + +.PARAMETER UseGameBananaDelta + Default: $False + If true, sources the last version of the package to publish from GameBanana. + +.PARAMETER UseNuGetDelta + Default: $False + If true, sources the last version of the package to publish from NuGet. + +.PARAMETER GitHubUserName + [Use if UseGitHubDelta is true] + Sets the username used for obtaining Deltas from GitHub. + +.PARAMETER GitHubRepoName + [Use if UseGitHubDelta is true] + Sets the repository used for obtaining Deltas from GitHub. + +.PARAMETER GitHubFallbackPattern + [Use if UseGitHubDelta is true] + Allows you to specify a Wildcard pattern (e.g. *Update.zip) for the file to be downloaded. + This is a fallback used in cases no Release Metadata file can be found. + +.PARAMETER GitHubInheritVersionFromTag + [Use if UseGitHubDelta is true] + Uses version determined from release tag (in GitHub Releases) as opposed to the + Release Metadata file in latest release. + +.PARAMETER GameBananaItemId + [Use if UseGameBananaDelta is true] + Example: 150118 + + Unique identifier for the individual mod. This is the last number of a GameBanana Mod Page URL + e.g. https://gamebanana.com/mods/150118 -> 150118 + +.PARAMETER NuGetPackageId + [Use if UseNuGetDelta is true] + Example: reloaded.sharedlib.hooks + + The ID of the package to use as delta. + +.PARAMETER NuGetFeedUrl + [Use if UseNuGetDelta is true] + Example: http://packages.sewer56.moe:5000/v3/index.json + + The URL of the NuGet feed to download the delta from. + +.PARAMETER NuGetAllowUnlisted + [Use if UseNuGetDelta is true] + Default: $False + + Allows for the downloading of unlisted packages. + +.PARAMETER PublishGeneric + Default: $True + + Publishes a generic package that can be uploaded to any other website. + +.PARAMETER PublishNuGet + Default: $True + + Publishes a package that can be uploaded to any NuGet Source. + +.PARAMETER PublishGameBanana + Default: $True + + Publishes a package that can be uploaded to GameBanana. + +.PARAMETER Build + Default: $True + + Whether the project should be built. + Setting this to false lets you use the publish part of the script standalone in a non .NET environment. + +.PARAMETER RemoveExe + Default: $True + + Removes executables from build output. Useful when performing R2R Optimisation. + +.PARAMETER UseScriptDirectory + Default: $True + + Uses script directory for performing build. Otherwise uses current directory. + +.EXAMPLE + .\Publish.ps1 -ProjectPath "Reloaded.Hooks.ReloadedII/Reloaded.Hooks.ReloadedII.csproj" -PackageName "Reloaded.Hooks.ReloadedII" -PublishOutputDir "Publish/ToUpload" + +.EXAMPLE + .\Publish.ps1 -MakeDelta true -BuildR2R true -UseGitHubDelta True + +.EXAMPLE + .\Publish.ps1 -BuildR2R true + +#> +[cmdletbinding()] +param ( + $IsPrerelease=$False, + $MakeDelta=$False, + $ChangelogPath="", + $ReadmePath="", + $Build=$True, + $BuildR2R=$False, + $RemoveExe=$True, + $UseScriptDirectory=$True, + + ## => User Config <= ## + $ProjectPath = "sonicheroes.fun.colourizer.csproj", + $PackageName = "sonicheroes.fun.colourizer", + $PublishOutputDir = "Publish/ToUpload", + + ## => User: Delta Config + # Pick one and configure settings below. + $MetadataFileName = "Sewer56.Update.ReleaseMetadata.json", + $UseGitHubDelta = $False, # GitHub Releases + $UseGameBananaDelta = $False, + $UseNuGetDelta = $False, + + $GitHubUserName = "", # Name of the GitHub user where the mod is contained + $GitHubRepoName = "", # Name of the GitHub repo where the mod is contained + $GitHubFallbackPattern = "", # For migrating from legacy build script. + $GitHubInheritVersionFromTag = $True, # Uses version determined from release tag as opposed to metadata file in latest release. + + $GameBananaItemId = 333681, # From mod page URL. + + $NuGetPackageId = "sonicheroes.fun.colourizer", + $NuGetFeedUrl = "http://packages.sewer56.moe:5000/v3/index.json", + $NuGetAllowUnlisted = $False, + + ## => User: Publish Config + $PublishGeneric = $True, + $PublishNuGet = $True, + $PublishGameBanana = $True +) + +## => User: Publish Output +$publishBuildDirectory = "Publish/Builds/CurrentVersion" # Build directory for current version of the mod. +$deltaDirectory = "Publish/Builds/LastVersion" # Path to last version of the mod. + +$PublishGenericDirectory = "$PublishOutputDir/Generic" # Publish files for any target not listed below. +$PublishNuGetDirectory = "$PublishOutputDir/NuGet" # Publish files for NuGet +$PublishGameBananaDirectory = "$PublishOutputDir/GameBanana" # Publish files for GameBanana + +## => User Config <= ## +# Tools +$reloadedToolsPath = "./Publish/Tools/Reloaded-Tools" # Used to check if tools are installed. +$updateToolsPath = "./Publish/Tools/Update-Tools" # Used to check if update tools are installed. +$reloadedToolPath = "$reloadedToolsPath/Reloaded.Publisher.exe" # Path to Reloaded publishing tool. +$updateToolPath = "$updateToolsPath/Sewer56.Update.Tool.dll" # Path to Update tool. +$changelogFullPath = $null +$readmeFullPath = $null +if ($ChangelogPath) { $changelogFullPath = [System.IO.Path]::GetFullPath($ChangelogPath) } +if ($ReadmePath) { $readmeFullPath = [System.IO.Path]::GetFullPath($ReadmePath) } + +## => Script <= ## +# Set Working Directory +$UseScriptDirectory = [bool]::Parse($UseScriptDirectory) +if ($UseScriptDirectory) { + Split-Path $MyInvocation.MyCommand.Path | Push-Location + [Environment]::CurrentDirectory = $PWD +} + +# Convert Booleans +$IsPrerelease = [bool]::Parse($IsPrerelease) +$MakeDelta = [bool]::Parse($MakeDelta) +$Build = [bool]::Parse($Build) +$BuildR2R = [bool]::Parse($BuildR2R) +$RemoveExe = [bool]::Parse($RemoveExe) +$UseGitHubDelta = [bool]::Parse($UseGitHubDelta) +$UseGameBananaDelta = [bool]::Parse($UseGameBananaDelta) +$UseNuGetDelta = [bool]::Parse($UseNuGetDelta) +$NuGetAllowUnlisted = [bool]::Parse($NuGetAllowUnlisted) +$PublishGeneric = [bool]::Parse($PublishGeneric) +$PublishNuGet = [bool]::Parse($PublishNuGet) +$PublishGameBanana = [bool]::Parse($PublishGameBanana) +$GitHubInheritVersionFromTag = [bool]::Parse($GitHubInheritVersionFromTag) +$TempDirectory = [System.IO.Path]::GetTempPath() + [System.IO.Path]::GetRandomFileName() +$TempDirectoryBuild = "$TempDirectory/build" + +function Get-Tools { + # Download Tools (if needed) + $ProgressPreference = 'SilentlyContinue' + if (-not(Test-Path -Path $reloadedToolsPath -PathType Any)) { + Write-Host "Downloading Reloaded Tools" + Invoke-WebRequest -Uri "https://github.com/Reloaded-Project/Reloaded-II/releases/latest/download/Tools.zip" -OutFile "$TempDirectory/Tools.zip" + Expand-Archive -LiteralPath "$TempDirectory/Tools.zip" -DestinationPath $reloadedToolsPath + + # Remove Items + Remove-Item "$TempDirectory/Tools.zip" -ErrorAction SilentlyContinue + } + + if ($MakeDelta -and -not(Test-Path -Path $updateToolsPath -PathType Any)) { + Write-Host "Downloading Update Library Tools" + Invoke-WebRequest -Uri "https://github.com/Sewer56/Update/releases/latest/download/Sewer56.Update.Tool.zip" -OutFile "$TempDirectory/Sewer56.Update.Tool.zip" + Expand-Archive -LiteralPath "$TempDirectory/Sewer56.Update.Tool.zip" -DestinationPath $updateToolsPath + + # Remove Items + Remove-Item "$TempDirectory/Sewer56.Update.Tool.zip" -ErrorAction SilentlyContinue + } +} + +# Publish for targets +function Build { + # Clean anything in existing Release directory. + Remove-Item $publishBuildDirectory -Recurse -ErrorAction SilentlyContinue + New-Item $publishBuildDirectory -ItemType Directory -ErrorAction SilentlyContinue + + # Build + dotnet restore $ProjectPath + dotnet clean $ProjectPath + + if ($BuildR2R) { + dotnet publish $ProjectPath -c Release -r win-x86 --self-contained false -o "$publishBuildDirectory/x86" /p:PublishReadyToRun=true /p:OutputPath="$TempDirectoryBuild/x86" + dotnet publish $ProjectPath -c Release -r win-x64 --self-contained false -o "$publishBuildDirectory/x64" /p:PublishReadyToRun=true /p:OutputPath="$TempDirectoryBuild/x64" + + # Remove Redundant Files + Move-Item -Path "$publishBuildDirectory/x86/ModConfig.json" -Destination "$publishBuildDirectory/ModConfig.json" -ErrorAction SilentlyContinue + Move-Item -Path "$publishBuildDirectory/x86/Preview.png" -Destination "$publishBuildDirectory/Preview.png" -ErrorAction SilentlyContinue + Remove-Item "$publishBuildDirectory/x64/Preview.png" -ErrorAction SilentlyContinue + Remove-Item "$publishBuildDirectory/x64/ModConfig.json" -ErrorAction SilentlyContinue + } + else { + dotnet publish $ProjectPath -c Release --self-contained false -o "$publishBuildDirectory" /p:OutputPath="$TempDirectoryBuild" + } + + # Cleanup Unnecessary Files + Remove-Item $TempDirectoryBuild -Recurse -ErrorAction SilentlyContinue + if ($RemoveExe) { + Get-ChildItem $publishBuildDirectory -Include *.exe -Recurse | Remove-Item -Force -Recurse + } + + Get-ChildItem $publishBuildDirectory -Include *.pdb -Recurse | Remove-Item -Force -Recurse + Get-ChildItem $publishBuildDirectory -Include *.xml -Recurse | Remove-Item -Force -Recurse +} + +function Get-Last-Version { + + Remove-Item $deltaDirectory -Recurse -ErrorAction SilentlyContinue + New-Item $deltaDirectory -ItemType Directory -ErrorAction SilentlyContinue + $arguments = "DownloadPackage --extract --outputpath `"$deltaDirectory`" --allowprereleases `"$IsPrerelease`" --metadatafilename `"$MetadataFileName`"" + + if ($UseGitHubDelta) { + $arguments += " --source GitHub --githubusername `"$GitHubUserName`" --githubrepositoryname `"$GitHubRepoName`" --githublegacyfallbackpattern `"$GitHubFallbackPattern`" --githubinheritversionfromtag `"$GitHubInheritVersionFromTag`"" + } + elseif ($UseNuGetDelta) { + $arguments += " --source NuGet --nugetpackageid `"$NuGetPackageId`" --nugetfeedurl `"$NuGetFeedUrl`" --nugetallowunlisted `"$NuGetAllowUnlisted`"" + } + elseif ($UseGameBananaDelta) { + $arguments += " --source GameBanana --gamebananaitemid `"$GameBananaItemId`"" + } + + Invoke-Expression "dotnet `"$updateToolPath`" $arguments" +} + +function Get-Common-Publish-Args { + + param ( + $AllowDeltas=$True + ) + + $arguments = "--modfolder `"$publishBuildDirectory`" --packagename `"$PackageName`"" + if ($ChangelogPath) { + $arguments += " --changelogpath `"$changelogFullPath`"" + } + + if ($ReadmePath) { + $arguments += " --readmepath `"$readmeFullPath`"" + } + + if ($AllowDeltas -and $MakeDelta) { + $arguments += " --olderversionfolders `"$deltaDirectory`"" + } + + return $arguments +} + +function Publish-Common { + + param ( + $Directory="", + $AllowDeltas=$True, + $PublishTarget="" + ) + + Remove-Item $Directory -Recurse -ErrorAction SilentlyContinue + New-Item $Directory -ItemType Directory -ErrorAction SilentlyContinue + $arguments = "$(Get-Common-Publish-Args -AllowDeltas $AllowDeltas) --outputfolder `"$Directory`" --publishtarget $PublishTarget" + $command = "$reloadedToolPath $arguments" + Write-Host "$command`r`n`r`n" + Invoke-Expression $command +} + +function Publish-GameBanana { + Publish-Common -Directory $PublishGameBananaDirectory -PublishTarget GameBanana +} + +function Publish-NuGet { + Publish-Common -Directory $PublishNuGetDirectory -PublishTarget NuGet -AllowDeltas $False +} + +function Publish-Generic { + Publish-Common -Directory $PublishGenericDirectory -PublishTarget Default +} + +function Cleanup { + Remove-Item $PublishOutputDir -Recurse -ErrorAction SilentlyContinue + Remove-Item $PublishNuGetDirectory -Recurse -ErrorAction SilentlyContinue + Remove-Item $PublishGenericDirectory -Recurse -ErrorAction SilentlyContinue + Remove-Item $publishBuildDirectory -Recurse -ErrorAction SilentlyContinue + Remove-Item $deltaDirectory -Recurse -ErrorAction SilentlyContinue +} + +# Build & Publish +New-Item $TempDirectory -ItemType Directory -ErrorAction SilentlyContinue +Cleanup +Get-Tools + +if ($MakeDelta) { + Write-Host "Downloading Delta (Last Version)" + Get-Last-Version +} + +if ($Build) { + Write-Host "Building Mod" + Build +} + +if ($PublishGeneric) { + Write-Host "Publishing Mod for Default Target" + Publish-Generic +} + +if ($PublishNuGet) { + Write-Host "Publishing Mod for NuGet Target" + Publish-NuGet +} + +if ($PublishGameBanana) { + Write-Host "Publishing Mod for GameBanana Target" + Publish-GameBanana +} + +# Remove Temp Folder +Remove-Item $TempDirectory -Recurse -ErrorAction SilentlyContinue + +# Restore Working Directory +Write-Host "Done." +Write-Host "Upload the files in folder `"$PublishOutputDir`" to respective location or website." +if ($UseScriptDirectory) { + Pop-Location +} \ No newline at end of file diff --git a/Heroes.Fun.AuraColorizer/Reloaded.Trimming.targets b/Heroes.Fun.AuraColorizer/Reloaded.Trimming.targets new file mode 100644 index 0000000..b4a56d8 --- /dev/null +++ b/Heroes.Fun.AuraColorizer/Reloaded.Trimming.targets @@ -0,0 +1,149 @@ + + + + + + + + false + + + false + + + + + + + + + + + + + <__PDBToLink Include="@(ResolvedFileToPublish)" Exclude="@(ManagedAssemblyToLink->'%(RelativeDir)%(Filename).pdb')" /> + <_PDBToLink Include="@(ResolvedFileToPublish)" Exclude="@(__PDBToLink)" /> + + + + <_LinkedResolvedFileToPublishCandidate Include="@(ManagedAssemblyToLink->'$(IntermediateLinkDir)%(Filename)%(Extension)')" /> + <_LinkedResolvedFileToPublishCandidate Include="@(_PDBToLink->'$(IntermediateLinkDir)%(Filename)%(Extension)')" /> + + + + + + + true + + + + + link + + copy + $(TreatWarningsAsErrors) + <_ExtraTrimmerArgs>--skip-unresolved true $(_ExtraTrimmerArgs) + true + + + + + + + + + + + + + + + + + + + + + $(TrimmerDefaultAction) + + + + $(TrimMode) + + + + + + + + Input Assembly: %(filename) [Mode: %(ManagedAssemblyToLink.TrimMode)] + + + + + + + + + + + + + + + + <_LinkedResolvedFileToPublish Include="@(_LinkedResolvedFileToPublishCandidate)" Condition="Exists('%(Identity)')" /> + + + + + + + \ No newline at end of file diff --git a/Heroes.Fun.AuraColorizer/RgbaColourAnimation.cs b/Heroes.Fun.AuraColorizer/RgbaColourAnimation.cs index 5fb1e19..986a564 100644 --- a/Heroes.Fun.AuraColorizer/RgbaColourAnimation.cs +++ b/Heroes.Fun.AuraColorizer/RgbaColourAnimation.cs @@ -1,105 +1,96 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using System.Windows.Media; +using System.Windows.Media; using Heroes.Fun.AuraColorizer.Heroes; -using Reloaded.Memory.Kernel32; -using Reloaded.Memory.Pointers; -using Reloaded.Memory.Sources; using Reloaded.WPF.Animations.Samples; -namespace Heroes.Fun.AuraColorizer +namespace Heroes.Fun.AuraColorizer; + +/// +/// Allows for animation of a given at a provided address. +/// +public class RgbaColourAnimation : IDisposable where TRgbaColor : IRgbaColor { /// - /// Allows for animation of a given at a provided address. + /// Allows to manipulate individual colour. + /// + public TRgbaColor Color; + + /// + /// The animation object executed. + /// + public CycleColorAnimation ColorAnimation { get; set; } + + /// + /// Length of the animation in milliseconds. + /// + public int Duration { get; private set; } + + /// + /// Frames per second for the animation. + /// + public float FramesPerSecond { get; private set; } + + /// + /// The amount of times the animation should be repeated. Set for infinite repetitions. + /// + public ulong Repeat { get; set; } + + private Color _originalColor; + + public unsafe RgbaColourAnimation(TRgbaColor color, int duration, float framesPerSecond, ulong repeat = ulong.MaxValue) + { + Color = color; + Duration = duration; + FramesPerSecond = framesPerSecond; + Repeat = repeat; + + Color.GiveWritePermission(); + + _originalColor = Color.GetColor(); + ColorAnimation = new CycleColorAnimation(color => Color.SetColor(color), _originalColor, duration, framesPerSecond); + } + + /// + /// Starts the colour animation. + /// If an animation is already running, cancels the animation and starts a new one. /// - public class RgbaColourAnimation : IDisposable where TRgbaColor : IRgbaColor + public void Start() + { + ColorAnimation.Animate(); + } + + /// + /// Resumes the colour animation. + /// + public void Resume() + { + ColorAnimation.Resume(); + } + + /// + /// Pauses the colour animation. + /// + public void Suspend() + { + ColorAnimation.Pause(); + } + + /// + /// Cancels the current animation. + /// + public void Cancel() + { + Color.SetColor(_originalColor); + ColorAnimation.Cancel(100); + } + + ~RgbaColourAnimation() + { + Dispose(); + } + + public void Dispose() { - /// - /// Allows to manipulate individual colour. - /// - public TRgbaColor Color; - - /// - /// The animation object executed. - /// - public CycleColorAnimation ColorAnimation { get; set; } - - /// - /// Length of the animation in milliseconds. - /// - public int Duration { get; private set; } - - /// - /// Frames per second for the animation. - /// - public float FramesPerSecond { get; private set; } - - /// - /// The amount of times the animation should be repeated. Set for infinite repetitions. - /// - public ulong Repeat { get; set; } - - private Color _originalColor; - - public unsafe RgbaColourAnimation(TRgbaColor color, int duration, float framesPerSecond, ulong repeat = ulong.MaxValue) - { - Color = color; - Duration = duration; - FramesPerSecond = framesPerSecond; - Repeat = repeat; - - Color.GiveWritePermission(); - - _originalColor = Color.GetColor(); - ColorAnimation = new CycleColorAnimation(color => Color.SetColor(color), _originalColor, duration, framesPerSecond); - } - - /// - /// Starts the colour animation. - /// If an animation is already running, cancels the animation and starts a new one. - /// - public void Start() - { - ColorAnimation.Animate(); - } - - /// - /// Resumes the colour animation. - /// - public void Resume() - { - ColorAnimation.Resume(); - } - - /// - /// Pauses the colour animation. - /// - public void Suspend() - { - ColorAnimation.Pause(); - } - - /// - /// Cancels the current animation. - /// - public void Cancel() - { - Color.SetColor(_originalColor); - ColorAnimation.Cancel(100); - } - - ~RgbaColourAnimation() - { - Dispose(); - } - - public void Dispose() - { - ColorAnimation?.Dispose(); - GC.SuppressFinalize(this); - } + ColorAnimation?.Dispose(); + GC.SuppressFinalize(this); } -} +} \ No newline at end of file diff --git a/Heroes.Fun.AuraColorizer/Utility.cs b/Heroes.Fun.AuraColorizer/Utility.cs index 41a611c..af545d4 100644 --- a/Heroes.Fun.AuraColorizer/Utility.cs +++ b/Heroes.Fun.AuraColorizer/Utility.cs @@ -1,22 +1,17 @@ -using System; -using System.Collections.Generic; -using System.Text; +namespace Heroes.Fun.AuraColorizer; -namespace Heroes.Fun.AuraColorizer +public static class Utility { - public static class Utility + public static void ForEach(this IEnumerable enumeration, Action action) { - public static void ForEach(this IEnumerable enumeration, Action action) + foreach (T item in enumeration) { - foreach (T item in enumeration) - { - action(item); - } + action(item); } + } - public static TSource[] GetEnumValues() - { - return (TSource[])Enum.GetValues(typeof(TSource)); - } + public static TSource[] GetEnumValues() + { + return (TSource[])Enum.GetValues(typeof(TSource)); } -} +} \ No newline at end of file diff --git a/Publish.ps1 b/Publish.ps1 index b0396cc..e0e7cf8 100644 --- a/Publish.ps1 +++ b/Publish.ps1 @@ -1,367 +1,5 @@ -<# -.SYNOPSIS - Builds and Publishes a Reloaded II Mod -.DESCRIPTION - Windows script to Build and Publish a Reloaded Mod. - By default, published items will be output to a directory called `Publish/ToUpload`. - - If you acquired this script by creating a new Reloaded Mod in VS. Then most likely everything - (aside from delta updates) should be preconfigured here. - -.PARAMETER ProjectPath - Path to the project to be built. - Useful if using this script from another script for the purpose of building multiple mods. - -.PARAMETER PackageName - Name of the package to be built. - Affects the name of the output files of the publish. - -.PARAMETER PublishOutputDir - Default: "Publish/ToUpload" - Declares the directory for placing the output files. - -.PARAMETER BuildR2R - Default: $False - - Builds the mod using an optimisation called `Ready to Run`, which sacrifices file size for potentially - faster startup time. This is only worth enabling on mods with a lot of code, usually it is best left disabled. - - For more details see: https://docs.microsoft.com/en-us/dotnet/core/deploying/ready-to-run - -.PARAMETER ChangelogPath - Full or relative path to a file containing the changelog for the mod. - The changelog should be written in Markdown format. - -.PARAMETER IsPrerelease - Default: $False - - If set to true, the version downloaded for delta package generation will be the latest pre-release - as opposed to the latest stable version. - -.PARAMETER MakeDelta - Default: $False - - Set to true to create Delta packages. - Usually this is true in a CI/CD environment when creating a release, else false in development. - - If this is true, you should set UseGitHubDelta, UseGameBananaDelta, UseNuGetDelta or equivalent to true. - -.PARAMETER MetadataFileName - Default: Sewer56.Update.ReleaseMetadata.json - Name of the release metadata file used to download the delta package. - -.PARAMETER UseGitHubDelta - Default: $False - If true, sources the last version of the package to publish from GitHub. - -.PARAMETER UseGameBananaDelta - Default: $False - If true, sources the last version of the package to publish from GameBanana. - -.PARAMETER UseNuGetDelta - Default: $False - If true, sources the last version of the package to publish from NuGet. - -.PARAMETER GitHubUserName - [Use if UseGitHubDelta is true] - Sets the username used for obtaining Deltas from GitHub. - -.PARAMETER GitHubRepoName - [Use if UseGitHubDelta is true] - Sets the repository used for obtaining Deltas from GitHub. - -.PARAMETER GitHubFallbackPattern - [Use if UseGitHubDelta is true] - Allows you to specify a Wildcard pattern (e.g. *Update.zip) for the file to be downloaded. - This is a fallback used in cases no Release Metadata file can be found. - -.PARAMETER GitHubInheritVersionFromTag - [Use if UseGitHubDelta is true] - Uses version determined from release tag (in GitHub Releases) as opposed to the - Release Metadata file in latest release. - -.PARAMETER GameBananaItemId - [Use if UseGameBananaDelta is true] - Example: 150118 - - Unique identifier for the individual mod. This is the last number of a GameBanana Mod Page URL - e.g. https://gamebanana.com/mods/150118 -> 150118 - -.PARAMETER NuGetPackageId - [Use if UseNuGetDelta is true] - Example: reloaded.sharedlib.hooks - - The ID of the package to use as delta. - -.PARAMETER NuGetFeedUrl - [Use if UseNuGetDelta is true] - Example: http://packages.sewer56.moe:5000/v3/index.json - - The URL of the NuGet feed to download the delta from. - -.PARAMETER NuGetAllowUnlisted - [Use if UseNuGetDelta is true] - Default: $False - - Allows for the downloading of unlisted packages. - -.PARAMETER PublishGeneric - Default: $True - - Publishes a generic package that can be uploaded to any other website. - -.PARAMETER PublishNuGet - Default: $True - - Publishes a package that can be uploaded to any NuGet Source. - -.PARAMETER PublishGameBanana - Default: $True - - Publishes a package that can be uploaded to GameBanana. - -.PARAMETER Build - Default: $True - - Whether the project should be built. - Setting this to false lets you use the publish part of the script standalone in a non .NET environment. - -.EXAMPLE - .\Publish.ps1 -ProjectPath "Reloaded.Hooks.ReloadedII/Reloaded.Hooks.ReloadedII.csproj" -PackageName "Reloaded.Hooks.ReloadedII" -PublishOutputDir "Publish/ToUpload" - -.EXAMPLE - .\Publish.ps1 -MakeDelta true -BuildR2R true -UseGitHubDelta True - -.EXAMPLE - .\Publish.ps1 -BuildR2R true - -#> -[cmdletbinding()] -param ( - $IsPrerelease=$False, - $MakeDelta=$False, - $ChangelogPath="", - $Build=$True, - $BuildR2R=$False, - - ## => User Config <= ## - $ProjectPath = "Heroes.Fun.AuraColorizer/Heroes.Fun.AuraColorizer.csproj", - $PackageName = "Heroes.Fun.AuraColorizer", - $PublishOutputDir = "Publish/ToUpload", - - ## => User: Delta Config - # Pick one and configure settings below. - $MetadataFileName = "Sewer56.Update.ReleaseMetadata.json", - $UseGitHubDelta = $False, - $UseGameBananaDelta = $False, - $UseNuGetDelta = $False, - - $GitHubUserName = "Sewer56", - $GitHubRepoName = "Reloaded.SharedLib.Hooks.ReloadedII", - $GitHubFallbackPattern = "reloaded.sharedlib.hooks.zip", # For migrating from legacy. - $GitHubInheritVersionFromTag = $True, # Uses version determined from release tag as opposed to metadata file in latest release. - - $GameBananaItemId = 333681, # From mod page URL. - - $NuGetPackageId = "reloaded.sharedlib.hooks", - $NuGetFeedUrl = "http://packages.sewer56.moe:5000/v3/index.json", - $NuGetAllowUnlisted = $False, - - ## => User: Publish Config - $PublishGeneric = $True, - $PublishNuGet = $True, - $PublishGameBanana = $True -) - -## => User: Publish Output -$publishBuildDirectory = "Publish/Builds/CurrentVersion" # Build directory for current version of the mod. -$deltaDirectory = "Publish/Builds/LastVersion" # Path to last version of the mod. - -$PublishGenericDirectory = "$PublishOutputDir/Generic" # Publish files for any target not listed below. -$PublishNuGetDirectory = "$PublishOutputDir/NuGet" # Publish files for NuGet -$PublishGameBananaDirectory = "$PublishOutputDir/GameBanana" # Publish files for GameBanana - -## => User Config <= ## -# Tools -$reloadedToolsPath = "./Publish/Tools/Reloaded-Tools" # Used to check if tools are installed. -$updateToolsPath = "./Publish/Tools/Update-Tools" # Used to check if update tools are installed. -$reloadedToolPath = "$reloadedToolsPath/Reloaded.Publisher.exe" # Path to Reloaded publishing tool. -$updateToolPath = "$updateToolsPath/Sewer56.Update.Tool.dll" # Path to Update tool. - -## => Script <= ## -# Set Working Directory -Split-Path $MyInvocation.MyCommand.Path | Push-Location -[Environment]::CurrentDirectory = $PWD - -# Convert Booleans -$IsPrerelease = [bool]::Parse($IsPrerelease) -$MakeDelta = [bool]::Parse($MakeDelta) -$Build = [bool]::Parse($Build) -$BuildR2R = [bool]::Parse($BuildR2R) -$UseGitHubDelta = [bool]::Parse($UseGitHubDelta) -$UseGameBananaDelta = [bool]::Parse($UseGameBananaDelta) -$UseNuGetDelta = [bool]::Parse($UseNuGetDelta) -$NuGetAllowUnlisted = [bool]::Parse($NuGetAllowUnlisted) -$PublishGeneric = [bool]::Parse($PublishGeneric) -$PublishNuGet = [bool]::Parse($PublishNuGet) -$PublishGameBanana = [bool]::Parse($PublishGameBanana) -$GitHubInheritVersionFromTag = [bool]::Parse($GitHubInheritVersionFromTag) - -function Get-Tools { - # Download Tools (if needed) - $ProgressPreference = 'SilentlyContinue' - if (-not(Test-Path -Path $reloadedToolsPath -PathType Any)) { - Write-Host "Downloading Reloaded Tools" - Invoke-WebRequest -Uri "https://github.com/Reloaded-Project/Reloaded-II/releases/latest/download/Tools.zip" -OutFile "$env:TEMP/Tools.zip" - Expand-Archive -LiteralPath "$env:TEMP/Tools.zip" -DestinationPath $reloadedToolsPath - - # Remove Items - Remove-Item "$env:TEMP/Tools.zip" -ErrorAction SilentlyContinue - } - - if ($MakeDelta -and -not(Test-Path -Path $updateToolsPath -PathType Any)) { - Write-Host "Downloading Update Library Tools" - Invoke-WebRequest -Uri "https://github.com/Sewer56/Update/releases/latest/download/Sewer56.Update.Tool.zip" -OutFile "$env:TEMP/Sewer56.Update.Tool.zip" - Expand-Archive -LiteralPath "$env:TEMP/Sewer56.Update.Tool.zip" -DestinationPath $updateToolsPath - - # Remove Items - Remove-Item "$env:TEMP/Sewer56.Update.Tool.zip" -ErrorAction SilentlyContinue - } -} - -# Publish for targets -function Build { - # Clean anything in existing Release directory. - Remove-Item $publishBuildDirectory -Recurse -ErrorAction SilentlyContinue - New-Item $publishBuildDirectory -ItemType Directory -ErrorAction SilentlyContinue - - # Build - dotnet restore $ProjectPath - dotnet clean $ProjectPath - - if ($BuildR2R) { - dotnet publish $ProjectPath -c Release -r win-x86 --self-contained false -o "$publishBuildDirectory/x86" /p:PublishReadyToRun=true - dotnet publish $ProjectPath -c Release -r win-x64 --self-contained false -o "$publishBuildDirectory/x64" /p:PublishReadyToRun=true - - # Remove Redundant Files - Move-Item -Path "$publishBuildDirectory/x86/ModConfig.json" -Destination "$publishBuildDirectory/ModConfig.json" -ErrorAction SilentlyContinue - Move-Item -Path "$publishBuildDirectory/x86/Preview.png" -Destination "$publishBuildDirectory/Preview.png" -ErrorAction SilentlyContinue - Remove-Item "$publishBuildDirectory/x64/Preview.png" -ErrorAction SilentlyContinue - Remove-Item "$publishBuildDirectory/x64/ModConfig.json" -ErrorAction SilentlyContinue - } - else { - dotnet publish $ProjectPath -c Release --self-contained false -o "$publishBuildDirectory" - } - - # Cleanup Unnecessary Files - Get-ChildItem $publishBuildDirectory -Include *.exe -Recurse | Remove-Item -Force -Recurse - Get-ChildItem $publishBuildDirectory -Include *.pdb -Recurse | Remove-Item -Force -Recurse - Get-ChildItem $publishBuildDirectory -Include *.xml -Recurse | Remove-Item -Force -Recurse -} - -function Get-Last-Version { - - Remove-Item $deltaDirectory -Recurse -ErrorAction SilentlyContinue - New-Item $deltaDirectory -ItemType Directory -ErrorAction SilentlyContinue - $arguments = "DownloadPackage --extract --outputpath `"$deltaDirectory`" --allowprereleases `"$IsPrerelease`" --metadatafilename `"$MetadataFileName`"" - - if ($UseGitHubDelta) { - $arguments += " --source GitHub --githubusername `"$GitHubUserName`" --githubrepositoryname `"$GitHubRepoName`" --githublegacyfallbackpattern `"$GitHubFallbackPattern`" --githubinheritversionfromtag `"$GitHubInheritVersionFromTag`"" - } - elseif ($UseNuGetDelta) { - $arguments += " --source NuGet --nugetpackageid `"$NuGetPackageId`" --nugetfeedurl `"$NuGetFeedUrl`" --nugetallowunlisted `"$NuGetAllowUnlisted`"" - } - elseif ($UseGameBananaDelta) { - $arguments += " --source GameBanana --gamebananaitemid `"$GameBananaItemId`"" - } - - Invoke-Expression "dotnet `"$updateToolPath`" $arguments" -} - -function Get-Common-Publish-Args { - - param ( - $AllowDeltas=$True - ) - - $arguments = "--modfolder `"$publishBuildDirectory`" --packagename `"$PackageName`"" - if ($ChangelogPath) { - $arguments += " --changelogpath `"$ChangelogPath`"" - } - - if ($AllowDeltas -and $MakeDelta) { - $arguments += " --olderversionfolders `"$deltaDirectory`"" - } - - return $arguments -} - -function Publish-Common { - - param ( - $Directory="", - $AllowDeltas=$True, - $PublishTarget="" - ) - - Remove-Item $Directory -Recurse -ErrorAction SilentlyContinue - New-Item $Directory -ItemType Directory -ErrorAction SilentlyContinue - $arguments = "$(Get-Common-Publish-Args -AllowDeltas $AllowDeltas) --outputfolder `"$Directory`" --publishtarget $PublishTarget" - $command = "$reloadedToolPath $arguments" - Write-Host "$command`r`n`r`n" - Invoke-Expression $command -} - -function Publish-GameBanana { - Publish-Common -Directory $PublishGameBananaDirectory -PublishTarget GameBanana -} - -function Publish-NuGet { - Publish-Common -Directory $PublishNuGetDirectory -PublishTarget NuGet -AllowDeltas $False -} - -function Publish-Generic { - Publish-Common -Directory $PublishGenericDirectory -PublishTarget Default -} - -function Cleanup { - Remove-Item $PublishOutputDir -Recurse -ErrorAction SilentlyContinue - Remove-Item $PublishNuGetDirectory -Recurse -ErrorAction SilentlyContinue - Remove-Item $PublishGenericDirectory -Recurse -ErrorAction SilentlyContinue - Remove-Item $publishBuildDirectory -Recurse -ErrorAction SilentlyContinue - Remove-Item $deltaDirectory -Recurse -ErrorAction SilentlyContinue -} - -# Build & Publish -Cleanup -Get-Tools - -if ($MakeDelta) { - Write-Host "Downloading Delta (Last Version)" - Get-Last-Version -} - -if ($Build) { - Write-Host "Building Mod" - Build -} - -if ($PublishGeneric) { - Write-Host "Publishing Mod for Default Target" - Publish-Generic -} - -if ($PublishNuGet) { - Write-Host "Publishing Mod for NuGet Target" - Publish-NuGet -} - -if ($PublishGameBanana) { - Write-Host "Publishing Mod for GameBanana Target" - Publish-GameBanana -} - -# Restore Working Directory -Write-Host "Done." -Write-Host "Upload the files in folder `"$PublishOutputDir`" to respective location or website." -Pop-Location \ No newline at end of file +./Heroes.Fun.AuraColorizer/Publish.ps1 @args ` +-UseScriptDirectory false ` +-ProjectPath "Heroes.Fun.AuraColorizer/Heroes.Fun.AuraColorizer.csproj" ` +-PackageName "sonicheroes.fun.colourizer" ` +-ReadmePath README.md \ No newline at end of file diff --git a/README-MOD.md b/README-MOD.md new file mode 100644 index 0000000..daa93c5 --- /dev/null +++ b/README-MOD.md @@ -0,0 +1,23 @@ +
+

Heroes Colorizer

+ +

+ Sonic Heroes, but a bit more like a Corsair keyboard.
+Id: sonicheroes.fun.colorizer +
+ +# About This Project + +The following project is a [Reloaded II](https://github.com/Reloaded-Project/Reloaded-II) Mod Loader mod for Sonic Heroes. It makes things quite colourful. + +![image](https://thumbs.gfycat.com/PerkyDismalGlassfrog-size_restricted.gif) + +## Misc Features + +- Real Time Reloading: Edit the config, save it and changes will be automatically applied in realtime. + +## How to Use + +**A.** Install Reloaded mod as usual. +**B.** Config mod (if necessary). +**C.** Enable mod and run the game. diff --git a/README.md b/README.md index 6c48694..daa93c5 100644 --- a/README.md +++ b/README.md @@ -14,12 +14,10 @@ The following project is a [Reloaded II](https://github.com/Reloaded-Project/Rel ## Misc Features -- Real Time Reloading: Edit the config, save it and changes will be automatically applied in realtime. +- Real Time Reloading: Edit the config, save it and changes will be automatically applied in realtime. ## How to Use -**A.** Install Reloaded mods as usual. (Extract to mod directory) - -**B.** Enable mod and run the game. (This auto-generates the config files: `Config.json`) - -**C.** Adjust configuration. (If necessary). \ No newline at end of file +**A.** Install Reloaded mod as usual. +**B.** Config mod (if necessary). +**C.** Enable mod and run the game.