Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ActionSemaphore and pooling patches for VisibilityCache #52

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions LowVisibility/LowVisibility/LowVisibility.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -37,34 +37,43 @@
<ItemGroup>
<Reference Include="0Harmony">
<HintPath>E:\steam\SteamApps\common\BATTLETECH\BattleTech_Data\Managed\0Harmony.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Assembly-CSharp, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>E:\steam\SteamApps\common\BATTLETECH\BattleTech_Data\Managed\Assembly-CSharp.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Assembly-CSharp-firstpass, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>E:\steam\SteamApps\common\BATTLETECH\BattleTech_Data\Managed\Assembly-CSharp-firstpass.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="CustomActivatableEquipment">
<HintPath>E:\steam\SteamApps\common\BATTLETECH\Mods\CustomActivatableEquipment\CustomActivatableEquipment.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="CustomAmmoCategories">
<HintPath>E:\steam\SteamApps\common\BATTLETECH\Mods\CustomAmmoCategories\CustomAmmoCategories.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="CustomComponents">
<HintPath>E:\steam\SteamApps\common\BATTLETECH\Mods\CustomComponents\CustomComponents.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="IRBTModUtils, Version=1.6.1.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>E:\steam\SteamApps\common\BATTLETECH\Mods\IRBTModUtils\IRBTModUtils.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="MechEngineer">
<HintPath>E:\steam\SteamApps\common\BATTLETECH\Mods\MechEngineer\MechEngineer.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>E:\steam\SteamApps\common\BATTLETECH\BattleTech_Data\Managed\Newtonsoft.Json.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
Expand All @@ -74,26 +83,33 @@
<Reference Include="System.Xml" />
<Reference Include="Unity.TextMeshPro">
<HintPath>E:\steam\SteamApps\common\BATTLETECH\BattleTech_Data\Managed\Unity.TextMeshPro.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="UnityEngine, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>E:\steam\SteamApps\common\BATTLETECH\BattleTech_Data\Managed\UnityEngine.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="UnityEngine.AssetBundleModule">
<HintPath>E:\steam\SteamApps\common\BATTLETECH\BattleTech_Data\Managed\UnityEngine.AssetBundleModule.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="UnityEngine.CoreModule">
<HintPath>E:\steam\SteamApps\common\BATTLETECH\BattleTech_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="UnityEngine.ParticleSystemModule">
<HintPath>E:\steam\SteamApps\common\BATTLETECH\BattleTech_Data\Managed\UnityEngine.ParticleSystemModule.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="UnityEngine.PhysicsModule">
<HintPath>E:\steam\SteamApps\common\BATTLETECH\BattleTech_Data\Managed\UnityEngine.PhysicsModule.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="UnityEngine.UI, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>E:\steam\SteamApps\common\BATTLETECH\BattleTech_Data\Managed\UnityEngine.UI.dll</HintPath>
<Private>False</Private>
</Reference>
</ItemGroup>
<ItemGroup>
Expand All @@ -104,11 +120,13 @@
<Compile Include="Helper\VfxHelper.cs" />
<Compile Include="Helper\VisualLockHelper.cs" />
<Compile Include="Helper\WeaponHelper.cs" />
<Compile Include="Object\ActionSemaphore.cs" />
<Compile Include="Object\EWState.cs" />
<Compile Include="Helper\MapHelper.cs" />
<Compile Include="ModInit.cs" />
<Compile Include="Object\MarkGOContainer.cs" />
<Compile Include="Object\Visibility.cs" />
<Compile Include="Object\VisibilityCacheGate.cs" />
<Compile Include="Patch\AbilityPatches.cs" />
<Compile Include="Patch\AI\AIUtilPatches.cs" />
<Compile Include="Patch\ArmorAndStructPatches.cs" />
Expand Down
64 changes: 64 additions & 0 deletions LowVisibility/LowVisibility/Object/ActionSemaphore.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LowVisibility.Object
{
public abstract class ActionSemaphore
{
protected Func<bool> shouldTakeaction;

protected Action actionToTake;

protected int counter;

protected ActionSemaphore(Func<bool> shouldTakeaction, Action actionToTake)
{
this.shouldTakeaction = shouldTakeaction;
this.actionToTake = actionToTake;
}

public int Counter => counter;

public virtual void ResetSemaphore() {
counter = 0;
}

public virtual void Enter()
{
++counter;
if (shouldTakeaction()) {
actionToTake();
}
}

public virtual void Exit()
{
--counter;
counter = counter < 0 ? 0 : counter;
if (shouldTakeaction()) {
actionToTake();
}
}

public virtual void ResetHard() {
counter = 0;
if (shouldTakeaction()) {
actionToTake();
}
}

public virtual void ResetSoft() {
while (counter-- > 0) {
if (shouldTakeaction()) {
actionToTake();
}
}

if (counter < 0)
ResetHard();
}
}
}
86 changes: 86 additions & 0 deletions LowVisibility/LowVisibility/Object/VisibilityCacheGate.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using BattleTech;

namespace LowVisibility.Object
{
/// <summary>
/// Pool all requests to rebuild the visibility cache into one place.
/// </summary>
public class VisibilityCacheGate : ActionSemaphore
{
private static VisibilityCacheGate cacheGate = new VisibilityCacheGate();

private readonly HashSet<AbstractActor> actors = new HashSet<AbstractActor>();

private VisibilityCacheGate()
: base(null, null)
{
shouldTakeaction = () => counter == 0;
actionToTake = () =>
{
List<ICombatant> combatants = UnityGameInstance.BattleTechGame.Combat.GetAllLivingCombatants();
List<ICombatant> uniDirectionalList = new List<ICombatant>();
List<ICombatant> biDirectionalList = new List<ICombatant>();

foreach (ICombatant combatant in combatants)
{
if (actors.Contains(combatant))
{
uniDirectionalList.Add(combatant);
}
else
{
biDirectionalList.Add(combatant);
}
}

foreach (AbstractActor actor in actors)
{
actor.VisibilityCache?.UpdateCacheReciprocal(biDirectionalList);
actor.VisibilityCache?.RebuildCache(uniDirectionalList);
}

actors.Clear();
};
}

public static bool Active => cacheGate.counter > 0;

public static int GetCounter => cacheGate.counter;

public static void EnterGate()
{
cacheGate.Enter();
}

public static void ExitGate()
{
cacheGate.Exit();
}

public static void ExitAll() {
cacheGate.ResetHard();
}

public static void Reset() {
cacheGate.ResetSemaphore();
}

public static void AddActorToRefresh(AbstractActor actor) {
cacheGate.actors.Add(actor);
}

#region Overrides of ActionSemaphore

public override void ResetSemaphore() {
base.ResetSemaphore();
actors.Clear();
}

#endregion
}
}
28 changes: 28 additions & 0 deletions LowVisibility/LowVisibility/Patch/AbstractActorPatches.cs
Original file line number Diff line number Diff line change
Expand Up @@ -278,5 +278,33 @@ public static void Prefix(AbstractActor __instance) {
}
}

[HarmonyPatch(typeof(AbstractActor), nameof(AbstractActor.HandleDeath))]
public static class AbstractActor_HandleDeath {

private static int counter = 0;

public static bool GateActive = false;

[HarmonyPriority(900)]
public static void Prefix(AbstractActor __instance) {
VisibilityCacheGate.EnterGate();
GateActive = true;
counter = VisibilityCacheGate.GetCounter;
}

[HarmonyPriority(0)]
public static void Postfix(AbstractActor __instance) {
VisibilityCacheGate.ExitGate();
GateActive = false;

int exitCounter = VisibilityCacheGate.GetCounter;
if (exitCounter < counter) {
Mod.Log.Debug?.Write($"Reset or unsymmetrical larger number of ExitGate() are call.");
}
else if (exitCounter > counter) {
Mod.Log.Error?.Write($"Fewer calls to ExitGate() than EnterGate().");
}
}
}
}

6 changes: 6 additions & 0 deletions LowVisibility/LowVisibility/Patch/CombatGameStatePatches.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ static void Postfix()
Mod.Log.Trace?.Write("CGS:OCGD - entered.");

ModState.Reset();
VisibilityCacheGate.Reset();
}
}

Expand All @@ -57,6 +58,11 @@ public static void Postfix()
Mod.Log.Error?.Write($"Something has gone wrong in refreshing visibility cache, resetting.");
EWState.ResetCache();
}

if (AbstractActor_HandleDeath.GateActive) {
Mod.Log.Error?.Write($"Something has gone wrong in handling actor death, resetting VisibilityCacheGate.");
VisibilityCacheGate.ExitAll();
}
}
}
}
78 changes: 51 additions & 27 deletions LowVisibility/LowVisibility/Patch/VisibilityCachePatches.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,40 +9,64 @@

namespace LowVisibility.Patch
{
[HarmonyPatch(typeof(VisibilityCache), nameof(VisibilityCache.RebuildCache))]
public static class VisibilityCache_RebuildCache
public static class VisibilityCachePatches
{
// Lowest priority
[HarmonyPriority(0)]
public static void Prefix()
{
EWState.InBatchProcess = true;
EWState.EWStateCache.Clear();
}
public delegate AbstractActor OwningActor(VisibilityCache cache);

// Highest priority
[HarmonyPriority(900)]
public static void Postfix()
{
EWState.InBatchProcess = false;
}
}
public static OwningActor GetOwningActor =
(OwningActor) Delegate.CreateDelegate(typeof(OwningActor), typeof(VisibilityCache).GetProperty("OwningActor", AccessTools.all).GetMethod);

[HarmonyPatch(typeof(VisibilityCache), nameof(VisibilityCache.UpdateCacheReciprocal))]
public static class VisibilityCache_UpdateCacheReciprocal
{
// Lowest priority
[HarmonyPriority(0)]
public static void Prefix()
[HarmonyPatch(typeof(VisibilityCache), nameof(VisibilityCache.RebuildCache))]
public static class VisibilityCache_RebuildCache
{
EWState.InBatchProcess = true;
EWState.EWStateCache.Clear();
// Lowest priority
[HarmonyPriority(0)]
public static bool Prefix(VisibilityCache __instance)
{
EWState.InBatchProcess = true;
EWState.EWStateCache.Clear();

if (VisibilityCacheGate.Active)
{
VisibilityCacheGate.AddActorToRefresh(GetOwningActor(__instance));
return false;
}

return true;
}

// Highest priority
[HarmonyPriority(900)]
public static void Postfix()
{
EWState.InBatchProcess = false;
}
}

[HarmonyPriority(900)]
public static void Postfix()
[HarmonyPatch(typeof(VisibilityCache), nameof(VisibilityCache.UpdateCacheReciprocal))]
public static class VisibilityCache_UpdateCacheReciprocal
{
EWState.InBatchProcess = false;
// Lowest priority
[HarmonyPriority(0)]
public static bool Prefix(VisibilityCache __instance)
{
EWState.InBatchProcess = true;
EWState.EWStateCache.Clear();

if (VisibilityCacheGate.Active)
{
VisibilityCacheGate.AddActorToRefresh(GetOwningActor(__instance));
return false;
}

return true;
}

[HarmonyPriority(900)]
public static void Postfix()
{
EWState.InBatchProcess = false;
}
}
}
}