diff --git a/.gitignore b/.gitignore
index aa981d0..fa3181d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,4 +4,6 @@ obj/
riderModule.iml
/_ReSharper.Caches/
.idea/
-LogicWorld/
\ No newline at end of file
+LogicWorld
+HarmonyForLogicWorld
+EccsLogicWorldAPI
diff --git a/CriticalPathAnalyzer.sln b/CriticalPathAnalyzer.sln
index 5769d30..772f06f 100644
--- a/CriticalPathAnalyzer.sln
+++ b/CriticalPathAnalyzer.sln
@@ -2,6 +2,8 @@
Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CriticalPathAnalyzer", "CriticalPathAnalyzer\CriticalPathAnalyzer.csproj", "{0328A941-5B63-44F5-B7BF-BF036CC9A5FE}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EccsLogicWorldAPI", "EccsLogicWorldAPI\EccsLogicWorldAPI.csproj", "{EDBF6818-E1D2-4A57-AC4B-647B69858817}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -12,5 +14,9 @@ Global
{0328A941-5B63-44F5-B7BF-BF036CC9A5FE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0328A941-5B63-44F5-B7BF-BF036CC9A5FE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0328A941-5B63-44F5-B7BF-BF036CC9A5FE}.Release|Any CPU.Build.0 = Release|Any CPU
+ {EDBF6818-E1D2-4A57-AC4B-647B69858817}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {EDBF6818-E1D2-4A57-AC4B-647B69858817}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {EDBF6818-E1D2-4A57-AC4B-647B69858817}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {EDBF6818-E1D2-4A57-AC4B-647B69858817}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
diff --git a/CriticalPathAnalyzer/CriticalPathAnalyzer.csproj b/CriticalPathAnalyzer/CriticalPathAnalyzer.csproj
index 97144c8..0dc01cc 100644
--- a/CriticalPathAnalyzer/CriticalPathAnalyzer.csproj
+++ b/CriticalPathAnalyzer/CriticalPathAnalyzer.csproj
@@ -8,6 +8,9 @@
+
+ ..\HarmonyForLogicWorld\HarmonyForLogicWorld\assemblies\client\0Harmony.dll
+
..\LogicWorld\Logic_World_Data\Managed\FancyInput.dll
@@ -20,12 +23,45 @@
..\LogicWorld\Logic_World_Data\Managed\LogicLog.dll
+
+ ..\LogicWorld\Logic_World_Data\Managed\LogicUI.dll
+
+
+ ..\LogicWorld\Logic_World_Data\Managed\LogicWorld.Building.dll
+
+
+ ..\LogicWorld\Logic_World_Data\Managed\LogicWorld.BuildingManagement.dll
+
+
+ ..\LogicWorld\Logic_World_Data\Managed\LogicWorld.Players.dll
+
+
+ ..\LogicWorld\Logic_World_Data\Managed\LogicWorld.Physics.dll
+
+
+ ..\LogicWorld\Logic_World_Data\Managed\LogicWorld.GameStates.dll
+
+
+ ..\LogicWorld\Logic_World_Data\Managed\LogicWorld.Input.dll
+
+
+ ..\LogicWorld\Logic_World_Data\Managed\LogicWorld.Interfaces.dll
+
..\LogicWorld\Logic_World_Data\Managed\LogicWorld.Modding.dll
+
+ ..\LogicWorld\Logic_World_Data\Managed\LogicWorld.Outlines.dll
+
..\LogicWorld\Logic_World_Data\Managed\LogicWorld.SharedCode.dll
+
+ ..\LogicWorld\Logic_World_Data\Managed\UnityEngine.CoreModule.dll
+
+
+
+
diff --git a/CriticalPathAnalyzer/CriticalPathAnalyzer/FancyInput/ContextMetadata.jecs b/CriticalPathAnalyzer/CriticalPathAnalyzer/FancyInput/ContextMetadata.jecs
index 0a7f323..f4ccc8e 100644
--- a/CriticalPathAnalyzer/CriticalPathAnalyzer/FancyInput/ContextMetadata.jecs
+++ b/CriticalPathAnalyzer/CriticalPathAnalyzer/FancyInput/ContextMetadata.jecs
@@ -1,3 +1,6 @@
CriticalPathAnalyzer.CriticalPathAnalyzer:
+ InjectTriggersInto:
+ - MHG.BuildActions
Triggers:
- - CriticalPathAnalyzer.AnalyzeCriticalPath
+ - CriticalPathAnalyzer.AnalyzePathStart
+ - CriticalPathAnalyzer.AnalyzePathEnd
diff --git a/CriticalPathAnalyzer/CriticalPathAnalyzer/FancyInput/TriggerMetadata.jecs b/CriticalPathAnalyzer/CriticalPathAnalyzer/FancyInput/TriggerMetadata.jecs
index 475f9d8..414fe7a 100644
--- a/CriticalPathAnalyzer/CriticalPathAnalyzer/FancyInput/TriggerMetadata.jecs
+++ b/CriticalPathAnalyzer/CriticalPathAnalyzer/FancyInput/TriggerMetadata.jecs
@@ -1,4 +1,10 @@
-CriticalPathAnalyzer.AnalyzeCriticalPath:
+CriticalPathAnalyzer.AnalyzePathStart:
+ Heading: "CriticalPathAnalyzer"
+ DefaultBinding:
+ Options:
+ - I
+
+CriticalPathAnalyzer.AnalyzePathEnd:
Heading: "CriticalPathAnalyzer"
DefaultBinding:
Options:
diff --git a/CriticalPathAnalyzer/CriticalPathAnalyzer/languages/English/English_input.jecs b/CriticalPathAnalyzer/CriticalPathAnalyzer/languages/English/English_input.jecs
index 91470e4..5c08852 100644
--- a/CriticalPathAnalyzer/CriticalPathAnalyzer/languages/English/English_input.jecs
+++ b/CriticalPathAnalyzer/CriticalPathAnalyzer/languages/English/English_input.jecs
@@ -1,6 +1,11 @@
MHG.SettingsMenu.Pages.Controls.Headings.CriticalPathAnalyzer: "Mod: Critical Path Analyzer"
-FancyInput.Trigger.CriticalPathAnalyzer.AnalyzeCriticalPath: "Analyze Critical Path"
-FancyInput.Trigger.CriticalPathAnalyzer.AnalyzeCriticalPath.Description : """
- Press once to select the start of the path and a second time to select the end.
+FancyInput.Trigger.CriticalPathAnalyzer.AnalyzePathStart: "Select start of path"
+FancyInput.Trigger.CriticalPathAnalyzer.AnalyzePathStart.Description : """
+ Press to select the start of the path to be analyzed.
+ """
+
+FancyInput.Trigger.CriticalPathAnalyzer.AnalyzePathEnd: "Select end of path"
+FancyInput.Trigger.CriticalPathAnalyzer.AnalyzePathEnd.Description : """
+ Press to select the end of the path to be analyzed.
"""
diff --git a/CriticalPathAnalyzer/CriticalPathAnalyzer/src/client/CriticalPathAnalyzerClient.cs b/CriticalPathAnalyzer/CriticalPathAnalyzer/src/client/CriticalPathAnalyzerClient.cs
index 7432e56..5064e8f 100644
--- a/CriticalPathAnalyzer/CriticalPathAnalyzer/src/client/CriticalPathAnalyzerClient.cs
+++ b/CriticalPathAnalyzer/CriticalPathAnalyzer/src/client/CriticalPathAnalyzerClient.cs
@@ -1,16 +1,27 @@
using CriticalPathAnalyzer.Client.Keybindings;
+using EccsLogicWorldAPI.Client.Injectors;
using FancyInput;
using LogicAPI.Client;
+using LogicLog;
namespace CriticalPathAnalyzer.Client {
public class CriticalPathAnalyzerClient : ClientMod {
+ public static ILogicLogger LoggerInstance;
protected override void Initialize() {
+ LoggerInstance = Logger;
Logger.Info("CriticalPathAnalyzer mod loading");
+ // Register keybindings in the settings menu
CustomInput.Register("CriticalPathAnalyzer");
+ // Inject our own game state
+ GameStateInjector.inject(CriticalPathAnalyzerGameState.Id, typeof(CriticalPathAnalyzerGameState));
+
+ // Inject a hook into the game code to check for our keybindings
+ KeybindingsInjector.Inject();
+
Logger.Info("CriticalPathAnalyzer mod loaded");
}
}
diff --git a/CriticalPathAnalyzer/CriticalPathAnalyzer/src/client/CriticalPathAnalyzerGameState.cs b/CriticalPathAnalyzer/CriticalPathAnalyzer/src/client/CriticalPathAnalyzerGameState.cs
new file mode 100644
index 0000000..85613c7
--- /dev/null
+++ b/CriticalPathAnalyzer/CriticalPathAnalyzer/src/client/CriticalPathAnalyzerGameState.cs
@@ -0,0 +1,39 @@
+using System.Collections.Generic;
+using CriticalPathAnalyzer.Client.Keybindings;
+using CriticalPathAnalyzer.Client.tool;
+using FancyInput;
+using LogicUI;
+using LogicWorld.GameStates;
+
+namespace CriticalPathAnalyzer.Client {
+ public class CriticalPathAnalyzerGameState : GameState {
+ public const string Id = "CriticalPathAnalyzer.Analyzing";
+
+ public override bool MouseLocked => true;
+ public override string TextID => Id;
+
+ public override IEnumerable HelpScreenTriggers => new InputTrigger[] {
+ UITrigger.Back,
+ CriticalPathAnalyzerTrigger.AnalyzePathStart,
+ CriticalPathAnalyzerTrigger.AnalyzePathEnd,
+ };
+
+ public override void OnEnter() {
+ CriticalPathAnalyzerClient.LoggerInstance.Info("CPA enter");
+ }
+
+ public override void OnRun() {
+ if (CustomInput.DownThisFrame(UITrigger.Back)) {
+ GameStateManager.TransitionBackToBuildingState();
+ } else if (CustomInput.DownThisFrame(CriticalPathAnalyzerTrigger.AnalyzePathStart)) {
+ CriticalPathAnalyzerTool.SelectPathStart();
+ } else if (CustomInput.DownThisFrame(CriticalPathAnalyzerTrigger.AnalyzePathEnd)) {
+ CriticalPathAnalyzerTool.SelectPathEnd();
+ }
+ }
+
+ public override void OnExit() {
+ CriticalPathAnalyzerClient.LoggerInstance.Info("CPA exit");
+ }
+ }
+}
\ No newline at end of file
diff --git a/CriticalPathAnalyzer/CriticalPathAnalyzer/src/client/KeybindingsInjector.cs b/CriticalPathAnalyzer/CriticalPathAnalyzer/src/client/KeybindingsInjector.cs
new file mode 100644
index 0000000..41d52ea
--- /dev/null
+++ b/CriticalPathAnalyzer/CriticalPathAnalyzer/src/client/KeybindingsInjector.cs
@@ -0,0 +1,31 @@
+using CriticalPathAnalyzer.Client.Keybindings;
+using EccsLogicWorldAPI.Shared.AccessHelper;
+using FancyInput;
+using HarmonyLib;
+using LogicWorld.Building;
+using LogicWorld.GameStates;
+
+namespace CriticalPathAnalyzer.Client {
+ public class KeybindingsInjector {
+ // Fairly generic hook into adding custom keybindings to the main building game state of LW.
+ // Allows to add keybindings to open new GUI elements or add new core building actions (which are not build-operations).
+ public static void Inject() {
+ var methodTarget = Methods.getPrivateStatic(typeof(StuffDeleter), "RunFirstPersonWireDeleting");
+ var methodHook = Methods.getPrivateStatic(typeof(KeybindingsInjector), nameof(Hook));
+ var harmony = new Harmony(nameof(CriticalPathAnalyzer));
+ harmony.Patch(methodTarget, prefix: new HarmonyMethod(methodHook));
+ }
+
+ private static bool Hook(out bool deletedWire) {
+ if (CustomInput.DownThisFrame(CriticalPathAnalyzerTrigger.AnalyzePathStart)) {
+ GameStateManager.TransitionTo(CriticalPathAnalyzerGameState.Id);
+
+ deletedWire = true; // True = Cancel remaining keybinding handling.
+ return false; // Prevent execution of the original/further functionality.
+ }
+
+ deletedWire = false; // Default, might be overwritten. False = Do not cancel remaining keybinding handling.
+ return true; // Allow original/further functionality.
+ }
+ }
+}
\ No newline at end of file
diff --git a/CriticalPathAnalyzer/CriticalPathAnalyzer/src/client/keybindings/CriticalPathAnalyzerTrigger.cs b/CriticalPathAnalyzer/CriticalPathAnalyzer/src/client/keybindings/CriticalPathAnalyzerTrigger.cs
index 23fe0d9..a40cece 100644
--- a/CriticalPathAnalyzer/CriticalPathAnalyzer/src/client/keybindings/CriticalPathAnalyzerTrigger.cs
+++ b/CriticalPathAnalyzer/CriticalPathAnalyzer/src/client/keybindings/CriticalPathAnalyzerTrigger.cs
@@ -1,6 +1,7 @@
namespace CriticalPathAnalyzer.Client.Keybindings {
public enum CriticalPathAnalyzerTrigger {
None,
- AnalyzeCriticalPath
+ AnalyzePathStart,
+ AnalyzePathEnd,
}
}
\ No newline at end of file
diff --git a/CriticalPathAnalyzer/CriticalPathAnalyzer/src/client/tool/CriticalPathAnalyzerTool.cs b/CriticalPathAnalyzer/CriticalPathAnalyzer/src/client/tool/CriticalPathAnalyzerTool.cs
new file mode 100644
index 0000000..32a32a4
--- /dev/null
+++ b/CriticalPathAnalyzer/CriticalPathAnalyzer/src/client/tool/CriticalPathAnalyzerTool.cs
@@ -0,0 +1,51 @@
+using LogicAPI.Data;
+using LogicWorld.Interfaces;
+using LogicWorld.Physics;
+using LogicWorld.Players;
+
+namespace CriticalPathAnalyzer.Client.tool {
+ public class CriticalPathAnalyzerTool {
+ private static PegAddress _startPegAddress;
+ private static PegAddress _endPegAddress;
+
+ private static PegAddress? RayCastPeg() {
+ // Ray-cast into the world to find what the player is looking at
+ HitInfo hitInfo = PlayerCaster.CameraCast(Masks.Environment | Masks.Structure | Masks.Peg | Masks.Wire);
+ if (!hitInfo.HitSomething) {
+ return null;
+ }
+
+ // Resolve hit target:
+ if (hitInfo.HitPeg) {
+ CriticalPathAnalyzerClient.LoggerInstance.Info("Hit peg");
+ return _startPegAddress = hitInfo.pAddress;
+ }
+
+ if (hitInfo.HitWire) {
+ CriticalPathAnalyzerClient.LoggerInstance.Info("Hit wire");
+ WireAddress wireAddress = hitInfo.wAddress;
+ Wire wire = Instances.MainWorld.Data.Lookup(wireAddress);
+ // Assume that wire is never null, as we did just ray-casted it.
+ return wire.Point1.IsInputAddress() ? wire.Point1 : wire.Point2;
+ }
+
+ return null;
+ }
+
+ public static void SelectPathStart() {
+ CriticalPathAnalyzerClient.LoggerInstance.Info("Analyze Path Start");
+ PegAddress? pegAddress = RayCastPeg();
+ if (pegAddress != null) {
+ _startPegAddress = pegAddress.Value;
+ }
+ }
+
+ public static void SelectPathEnd() {
+ CriticalPathAnalyzerClient.LoggerInstance.Info("Analyze Path End");
+ PegAddress? pegAddress = RayCastPeg();
+ if (pegAddress != null) {
+ _endPegAddress = pegAddress.Value;
+ }
+ }
+ }
+}
\ No newline at end of file