diff --git a/src/Artemis.Plugins.Games.Ultrakill/Artemis.Plugins.Games.Ultrakill.GSI/Artemis.Plugins.Games.Ultrakill.GSI.csproj b/src/Artemis.Plugins.Games.Ultrakill/Artemis.Plugins.Games.Ultrakill.GSI/Artemis.Plugins.Games.Ultrakill.GSI.csproj new file mode 100644 index 0000000..372ace7 --- /dev/null +++ b/src/Artemis.Plugins.Games.Ultrakill/Artemis.Plugins.Games.Ultrakill.GSI/Artemis.Plugins.Games.Ultrakill.GSI.csproj @@ -0,0 +1,25 @@ + + + + net472 + Full + latest + + + + + Assembly-CSharp.dll + all + + + + + + + + + + + + + diff --git a/src/Artemis.Plugins.Games.Ultrakill/Artemis.Plugins.Games.Ultrakill.GSI/ArtemisGsiPlugin.cs b/src/Artemis.Plugins.Games.Ultrakill/Artemis.Plugins.Games.Ultrakill.GSI/ArtemisGsiPlugin.cs new file mode 100644 index 0000000..0897aae --- /dev/null +++ b/src/Artemis.Plugins.Games.Ultrakill/Artemis.Plugins.Games.Ultrakill.GSI/ArtemisGsiPlugin.cs @@ -0,0 +1,85 @@ +using Artemis.Plugins.Games.Ultrakill.GSI.Patches; +using BepInEx; +using HarmonyLib; +using System; +using System.Linq; +using UnityEngine; +using UnityEngine.SceneManagement; + +namespace Artemis.Plugins.Games.Ultrakill.GSI +{ + [BepInPlugin("com.artemis.gsi", "Artemis GSI", "0.1")] + public class ArtemisGsiPlugin : BaseUnityPlugin + { + public static ArtemisWebClient ArtemisWebClient => _artemisWebClient; + private static ArtemisWebClient _artemisWebClient; + + private NewMovement player = null; + private GunControl guns = null; + + public void Awake() + { + try + { + _artemisWebClient = new ArtemisWebClient(); + } + catch (Exception e) + { + Debug.Log(e); + return; + } + //Harmony harmony = new Harmony("com.artemis.gsi"); + // harmony.PatchAll(); + + Debug.Log("patched artemis"); + ArtemisWebClient.StartTimer(); + } + + public void Start() + { + SceneManager.activeSceneChanged += OnSceneChanged; + } + + private void OnSceneChanged(Scene from, Scene to) + { + Debug.Log($"Scene changed to {to.name}"); + player = null; + if (SceneManager.GetActiveScene().name.StartsWith("Level") || SceneManager.GetActiveScene().name == "uk_construct") + { + player = FindObjectOfType(); + Debug.Log($"Found player! name:{player.gameObject.name}"); + } + if (guns == null) + { + guns = MonoSingleton.Instance; + } + } + + public void Update() + { + if (player != null) + { + //Debug.Log($"Health: {player.hp}"); + //Debug.Log($"Speed: {player.rb.velocity.magnitude}"); + //Debug.Log($"Stamina: {player.boostCharge}"); + //Debug.Log($"Jumping: {player.jumping}"); + //Debug.Log($"Dead: {player.dead}"); + //Debug.Log($"Gun slot: {guns.currentSlot}"); + //Debug.Log($"variation: {guns.currentVariation}"); + + ArtemisPlayer.Health = player.hp; + ArtemisPlayer.Speed = player.rb.velocity.magnitude; + ArtemisPlayer.Stamina = player.boostCharge; + ArtemisPlayer.Jumping = player.jumping; + ArtemisPlayer.Dead = player.dead; + ArtemisPlayer.CurrentGun = guns.currentSlot; + ArtemisPlayer.CurrentGunVariation = guns.currentVariation; + } + } + + public void OnApplicationQuit() + { + ArtemisWebClient?.StopTimer(); + } + } +} diff --git a/src/Artemis.Plugins.Games.Ultrakill/Artemis.Plugins.Games.Ultrakill.GSI/ArtemisPlayer.cs b/src/Artemis.Plugins.Games.Ultrakill/Artemis.Plugins.Games.Ultrakill.GSI/ArtemisPlayer.cs new file mode 100644 index 0000000..367a346 --- /dev/null +++ b/src/Artemis.Plugins.Games.Ultrakill/Artemis.Plugins.Games.Ultrakill.GSI/ArtemisPlayer.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace Artemis.Plugins.Games.Ultrakill.GSI +{ + public static class ArtemisPlayer + { + public static float Health; + public static float Speed; + public static float Stamina; + public static bool Jumping; + public static bool Dead; + public static int CurrentGun; + public static int CurrentGunVariation; + + public static string ToJson() + { + var b = new StringBuilder(); + b.Append('{'); + + b.AppendTypeAndValue("health", Health); + b.Append(','); + b.AppendTypeAndValue("speed", Speed); + b.Append(','); + b.AppendTypeAndValue("stamina", Stamina); + b.Append(','); + b.AppendTypeAndValue("jumping", Jumping); + b.Append(','); + b.AppendTypeAndValue("dead", Dead); + b.Append(','); + b.AppendTypeAndValue("currentGun", CurrentGun); + b.Append(','); + b.AppendTypeAndValue("currentGunVariation", CurrentGunVariation); + + b.Append('}'); + + return b.ToString(); + } + } +} diff --git a/src/Artemis.Plugins.Games.Ultrakill/Artemis.Plugins.Games.Ultrakill.GSI/ArtemisWebClient.cs b/src/Artemis.Plugins.Games.Ultrakill/Artemis.Plugins.Games.Ultrakill.GSI/ArtemisWebClient.cs new file mode 100644 index 0000000..6124b2b --- /dev/null +++ b/src/Artemis.Plugins.Games.Ultrakill/Artemis.Plugins.Games.Ultrakill.GSI/ArtemisWebClient.cs @@ -0,0 +1,89 @@ +using BepInEx.Logging; +using System; +using System.IO; +using System.Timers; +using UnityEngine; +using UnityEngine.Networking; +using SystemTimer = System.Timers.Timer; + +namespace Artemis.Plugins.Games.Ultrakill.GSI +{ + public class ArtemisWebClient + { + private const string CONFIG_PATH = @"C:\ProgramData\Artemis\webserver.txt"; + private const string PLUGIN_GUID = "ef19ca95-9716-406a-a708-b73c81dbc859"; + + private readonly SystemTimer timer; + private readonly string _baseUri; + + public ArtemisWebClient() + { + if (!File.Exists(CONFIG_PATH)) + throw new FileNotFoundException("Artemis: Webserver file not found"); + + string uri; + try + { + uri = File.ReadAllText(CONFIG_PATH); + } + catch (IOException) + { + Debug.Log("Artemis: Error reading webserver config file"); + throw; + } + + Debug.Log($"Found artemis web api uri: {uri}"); + + var request = UnityWebRequest.Get($"{uri}plugins"); + try + { + request.SendWithTimeout(TimeSpan.FromMilliseconds(500)); + } + catch (Exception e) + { + Debug.Log("Artemis: Failed connecting to webserver"); + Debug.Log(e); + + throw new Exception("Failed to connect to Artemis, exiting..."); + } + + _baseUri = $"{uri}plugins/{PLUGIN_GUID}"; + + Debug.Log("Connected to Artemis, starting timer."); + + timer = new SystemTimer(100); + timer.Elapsed += OnTimerElapsed; + } + + public void StartTimer() => timer.Start(); + public void StopTimer() => timer.Stop(); + + private void OnTimerElapsed(object sender, ElapsedEventArgs e) + { + Debug.Log("meme"); + SendJson("update", ArtemisPlayer.ToJson()); + } + + private void SendJson(string endpoint, string json) + { + try + { + UnityWebRequest request = UnityWebRequest.Put($"{_baseUri}/{endpoint}", json); + request.method = "POST"; + request.SetRequestHeader("Content-Type", "application/json"); + request.SendWithTimeout(TimeSpan.FromMilliseconds(100)); + } + catch (Exception e) + { + Debug.Log(e); + Debug.Log("Artemis: Stopping timer"); + StopTimer(); + } + } + + public void SendEvent(string endpoint, string args) + { + SendJson(endpoint, args); + } + } +} diff --git a/src/Artemis.Plugins.Games.Ultrakill/Artemis.Plugins.Games.Ultrakill.GSI/Assembly-CSharp.dll b/src/Artemis.Plugins.Games.Ultrakill/Artemis.Plugins.Games.Ultrakill.GSI/Assembly-CSharp.dll new file mode 100644 index 0000000..e3a7ca0 Binary files /dev/null and b/src/Artemis.Plugins.Games.Ultrakill/Artemis.Plugins.Games.Ultrakill.GSI/Assembly-CSharp.dll differ diff --git a/src/Artemis.Plugins.Games.Ultrakill/Artemis.Plugins.Games.Ultrakill.GSI/JsonWriter.cs b/src/Artemis.Plugins.Games.Ultrakill/Artemis.Plugins.Games.Ultrakill.GSI/JsonWriter.cs new file mode 100644 index 0000000..d295ade --- /dev/null +++ b/src/Artemis.Plugins.Games.Ultrakill/Artemis.Plugins.Games.Ultrakill.GSI/JsonWriter.cs @@ -0,0 +1,82 @@ +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using UnityEngine; + +namespace Artemis.Plugins.Games.Ultrakill.GSI +{ + internal static class JsonWriter + { + private static void AppendPropertyName(this StringBuilder b, string name) + { + b.Append('"'); + b.Append(name); + b.Append('"'); + + b.Append(':'); + } + + private static void AppendTypeAndValueInternal(this StringBuilder b, string name, string value, bool quotes) + { + b.AppendPropertyName(name); + + if (quotes) + b.Append('"'); + + b.Append(value); + + if (quotes) + b.Append('"'); + } + + internal static void AppendTypeAndValue(this StringBuilder b, string name, string value) + => AppendTypeAndValueInternal(b, name, value, true); + + internal static void AppendTypeAndValue(this StringBuilder b, string name, float value) + => AppendTypeAndValueInternal(b, name, value.ToString(CultureInfo.InvariantCulture), false); + + internal static void AppendTypeAndValue(this StringBuilder b, string name, int value) + => AppendTypeAndValueInternal(b, name, value.ToString(CultureInfo.InvariantCulture), false); + + internal static void AppendTypeAndValue(this StringBuilder b, string name, byte value) + => AppendTypeAndValueInternal(b, name, value.ToString(CultureInfo.InvariantCulture), false); + + internal static void AppendTypeAndValue(this StringBuilder b, string name, bool value) + => AppendTypeAndValueInternal(b, name, value ? "true" : "false", false); + + internal static void AppendTypeAndValue(this StringBuilder b, string name, IEnumerable values) + { + b.AppendPropertyName(name); + + b.Append('['); + + foreach (var item in values) + { + b.Append('"'); + b.Append(item); + b.Append('"'); + + b.Append(','); + } + //remove trailing comma + if (values.Any()) + b.Remove(b.Length - 1, 1); + + b.Append(']'); + } + + internal static void AppendTypeAndValue(this StringBuilder b, string name, Color value) + { + b.AppendPropertyName(name); + + b.Append("{"); + b.AppendTypeAndValue("Red", (byte)(value.r * 255)); + b.Append(','); + b.AppendTypeAndValue("Green", (byte)(value.g * 255)); + b.Append(','); + b.AppendTypeAndValue("Blue", (byte)(value.b * 255)); + b.Append("}"); + } + } +} diff --git a/src/Artemis.Plugins.Games.Ultrakill/Artemis.Plugins.Games.Ultrakill.GSI/Patches/V2Patch.cs b/src/Artemis.Plugins.Games.Ultrakill/Artemis.Plugins.Games.Ultrakill.GSI/Patches/V2Patch.cs new file mode 100644 index 0000000..a1fa347 --- /dev/null +++ b/src/Artemis.Plugins.Games.Ultrakill/Artemis.Plugins.Games.Ultrakill.GSI/Patches/V2Patch.cs @@ -0,0 +1,25 @@ +using HarmonyLib; + +namespace Artemis.Plugins.Games.Ultrakill.GSI.Patches +{ + [HarmonyPatch(typeof(HealthBar), "Update")] + public static class Patches + { + public static float MovementSpeed { get; set; } + public static float Health { get; set; } + + public static void Postfix(ref float ___hp) + { + Health = ___hp; + } + } + + [HarmonyPatch(typeof(NewMovement), "Update")] + public static class PlayerIThink + { + public static void PostFix() + { + + } + } +} diff --git a/src/Artemis.Plugins.Games.Ultrakill/Artemis.Plugins.Games.Ultrakill.GSI/UnityWebRequestExtensions.cs b/src/Artemis.Plugins.Games.Ultrakill/Artemis.Plugins.Games.Ultrakill.GSI/UnityWebRequestExtensions.cs new file mode 100644 index 0000000..064209b --- /dev/null +++ b/src/Artemis.Plugins.Games.Ultrakill/Artemis.Plugins.Games.Ultrakill.GSI/UnityWebRequestExtensions.cs @@ -0,0 +1,21 @@ +using System; +using UnityEngine.Networking; + +namespace Artemis.Plugins.Games.Ultrakill.GSI +{ + public static class UnityWebRequestExtensions + { + public static void SendWithTimeout(this UnityWebRequest request, TimeSpan timeout) + { + var startTime = DateTime.UtcNow; + request.SendWebRequest(); + while (!request.isDone) + { + if (DateTime.UtcNow > startTime + timeout) + { + throw new TimeoutException(); + } + } + } + } +} diff --git a/src/Artemis.Plugins.Games.Ultrakill/Artemis.Plugins.Games.Ultrakill.GSI/nuget.config b/src/Artemis.Plugins.Games.Ultrakill/Artemis.Plugins.Games.Ultrakill.GSI/nuget.config new file mode 100644 index 0000000..0cde3f0 --- /dev/null +++ b/src/Artemis.Plugins.Games.Ultrakill/Artemis.Plugins.Games.Ultrakill.GSI/nuget.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/Artemis.Plugins.Games.Ultrakill/Artemis.Plugins.Games.Ultrakill.Module/Artemis.Plugins.Games.Ultrakill.Module.csproj b/src/Artemis.Plugins.Games.Ultrakill/Artemis.Plugins.Games.Ultrakill.Module/Artemis.Plugins.Games.Ultrakill.Module.csproj new file mode 100644 index 0000000..58d2d6d --- /dev/null +++ b/src/Artemis.Plugins.Games.Ultrakill/Artemis.Plugins.Games.Ultrakill.Module/Artemis.Plugins.Games.Ultrakill.Module.csproj @@ -0,0 +1,20 @@ + + + net7.0 + x64 + true + enable + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + \ No newline at end of file diff --git a/src/Artemis.Plugins.Games.Ultrakill/Artemis.Plugins.Games.Ultrakill.Module/DataModels/UltrakillDataModel.cs b/src/Artemis.Plugins.Games.Ultrakill/Artemis.Plugins.Games.Ultrakill.Module/DataModels/UltrakillDataModel.cs new file mode 100644 index 0000000..b7e39c9 --- /dev/null +++ b/src/Artemis.Plugins.Games.Ultrakill/Artemis.Plugins.Games.Ultrakill.Module/DataModels/UltrakillDataModel.cs @@ -0,0 +1,15 @@ +using Artemis.Core.Modules; + +namespace Artemis.Plugins.Games.Ultrakill.Module.DataModels +{ + public class UltrakillDataModel : DataModel + { + public float Health { get; set; } + public float Speed { get; set; } + public float Stamina { get; set; } + public bool Jumping { get; set; } + public bool Dead { get; set; } + public int CurrentGun { get; set; } + public int CurrentGunVariation { get; set; } + } +} \ No newline at end of file diff --git a/src/Artemis.Plugins.Games.Ultrakill/Artemis.Plugins.Games.Ultrakill.Module/Properties/launchSettings.json b/src/Artemis.Plugins.Games.Ultrakill/Artemis.Plugins.Games.Ultrakill.Module/Properties/launchSettings.json new file mode 100644 index 0000000..f33a755 --- /dev/null +++ b/src/Artemis.Plugins.Games.Ultrakill/Artemis.Plugins.Games.Ultrakill.Module/Properties/launchSettings.json @@ -0,0 +1,12 @@ +{ + "profiles": { + "Windows": { + "commandName": "Executable", + "executablePath": "C:\\Program Files\\Artemis\\Artemis.UI.Windows.exe" + }, + "Windows Dev": { + "commandName": "Executable", + "executablePath": "$(SolutionDir)\\..\\Artemis\\src\\Artemis.UI.Windows\\bin\\Artemis.UI.Windows.exe" + } + } +} \ No newline at end of file diff --git a/src/Artemis.Plugins.Games.Ultrakill/Artemis.Plugins.Games.Ultrakill.Module/UltrakillModule.cs b/src/Artemis.Plugins.Games.Ultrakill/Artemis.Plugins.Games.Ultrakill.Module/UltrakillModule.cs new file mode 100644 index 0000000..9625850 --- /dev/null +++ b/src/Artemis.Plugins.Games.Ultrakill/Artemis.Plugins.Games.Ultrakill.Module/UltrakillModule.cs @@ -0,0 +1,55 @@ +using System; +using Artemis.Core; +using Artemis.Core.Modules; +using Artemis.Core.Services; +using Artemis.Plugins.Games.Ultrakill.Module.DataModels; +using System.Collections.Generic; +using System.Threading.Tasks; +using Serilog; + +namespace Artemis.Plugins.Games.Ultrakill.Module +{ + [PluginFeature(AlwaysEnabled = true)] + public class UltrakillModule : Module + { + private readonly IWebServerService _webServerService; + private readonly ILogger _logger; + private DataModelJsonPluginEndPoint? _updateEndpoint; + + public override List ActivationRequirements { get; } = new() + { + new ProcessActivationRequirement("ULTRAKILL") + }; + + public UltrakillModule(IWebServerService webServerService, ILogger logger) + { + _webServerService = webServerService; + _logger = logger; + } + + public override void ModuleActivated(bool isOverride) + { + + } + + public override void ModuleDeactivated(bool isOverride) + { + + } + + public override void Enable() + { + _updateEndpoint = _webServerService.AddDataModelJsonEndPoint(this, "update"); + } + + public override void Disable() + { + _webServerService.RemovePluginEndPoint(_updateEndpoint!); + } + + public override void Update(double deltaTime) + { + + } + } +} \ No newline at end of file diff --git a/src/Artemis.Plugins.Games.Ultrakill/Artemis.Plugins.Games.Ultrakill.Module/plugin.json b/src/Artemis.Plugins.Games.Ultrakill/Artemis.Plugins.Games.Ultrakill.Module/plugin.json new file mode 100644 index 0000000..0d808a4 --- /dev/null +++ b/src/Artemis.Plugins.Games.Ultrakill/Artemis.Plugins.Games.Ultrakill.Module/plugin.json @@ -0,0 +1,15 @@ +{ + "Guid": "ef19ca95-9716-406a-a708-b73c81dbc859", + "Name": "Ultrakill", + "Description": "Ultrakill", + "Author": "diogotr7", + "Website": "", + "Repository": "", + "Icon": "QuestionMark", + "Version": "1.0.0.0", + "Main": "Artemis.Plugins.Games.Ultrakill.Module.dll", + "AutoEnableProperties": true, + "RequiresAdmin": false, + "Platforms": "Windows,Linux,OSX", + "Api": "1.0.0" +} \ No newline at end of file diff --git a/src/Artemis.Plugins.Games.sln b/src/Artemis.Plugins.Games.sln index 4c4c2d2..b20eed8 100644 --- a/src/Artemis.Plugins.Games.sln +++ b/src/Artemis.Plugins.Games.sln @@ -43,6 +43,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Artemis.Plugins.Games.CSGO" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Artemis.Plugins.Games.Dota2", "Artemis.Plugins.Games.Dota2\Artemis.Plugins.Games.Dota2.csproj", "{5F5D7E46-822A-44CC-AB2A-7BC7EE3314FB}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Artemis.Plugins.Games.Ultrakill", "Artemis.Plugins.Games.Ultrakill", "{44C98467-5AA8-4ED0-9CDD-13A53E96F834}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Artemis.Plugins.Games.Ultrakill.GSI", "Artemis.Plugins.Games.Ultrakill\Artemis.Plugins.Games.Ultrakill.GSI\Artemis.Plugins.Games.Ultrakill.GSI.csproj", "{99856A1A-3722-4944-AA80-5BA69B0FE77B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Artemis.Plugins.Games.Ultrakill.Module", "Artemis.Plugins.Games.Ultrakill\Artemis.Plugins.Games.Ultrakill.Module\Artemis.Plugins.Games.Ultrakill.Module.csproj", "{EB9FEFF9-EBC2-4171-822B-A6CD970D4F53}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -105,6 +111,14 @@ Global {5F5D7E46-822A-44CC-AB2A-7BC7EE3314FB}.Debug|x64.Build.0 = Debug|x64 {5F5D7E46-822A-44CC-AB2A-7BC7EE3314FB}.Release|x64.ActiveCfg = Release|x64 {5F5D7E46-822A-44CC-AB2A-7BC7EE3314FB}.Release|x64.Build.0 = Release|x64 + {99856A1A-3722-4944-AA80-5BA69B0FE77B}.Debug|x64.ActiveCfg = Debug|Any CPU + {99856A1A-3722-4944-AA80-5BA69B0FE77B}.Debug|x64.Build.0 = Debug|Any CPU + {99856A1A-3722-4944-AA80-5BA69B0FE77B}.Release|x64.ActiveCfg = Release|Any CPU + {99856A1A-3722-4944-AA80-5BA69B0FE77B}.Release|x64.Build.0 = Release|Any CPU + {EB9FEFF9-EBC2-4171-822B-A6CD970D4F53}.Debug|x64.ActiveCfg = Debug|x64 + {EB9FEFF9-EBC2-4171-822B-A6CD970D4F53}.Debug|x64.Build.0 = Debug|x64 + {EB9FEFF9-EBC2-4171-822B-A6CD970D4F53}.Release|x64.ActiveCfg = Release|x64 + {EB9FEFF9-EBC2-4171-822B-A6CD970D4F53}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -117,6 +131,8 @@ Global {1F65207D-0861-4BC1-BE29-16893BD2610F} = {5EB44938-DE19-4F1C-AF63-A236815EB7E2} {A2038F27-F3F4-49CC-9041-3D48731B2B47} = {45532261-3F70-4BBD-8313-35C454A4CB5A} {E18E9C84-3B6C-4EBE-9DC9-9318453F344F} = {45532261-3F70-4BBD-8313-35C454A4CB5A} + {99856A1A-3722-4944-AA80-5BA69B0FE77B} = {44C98467-5AA8-4ED0-9CDD-13A53E96F834} + {EB9FEFF9-EBC2-4171-822B-A6CD970D4F53} = {44C98467-5AA8-4ED0-9CDD-13A53E96F834} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {D7098FD1-41F0-40AE-BDBC-B028EE85ADCC}