|
- using System;
- using System.Collections;
- using System.Reflection;
- using CLre.API.Utility;
- using HarmonyLib;
- using Svelto.DataStructures;
- using Svelto.ECS;
-
- namespace CLre.Fixes
- {
- [Bugfix(name = "CooldownCrossSlotSync",
- more = "https://trello.com/c/65FPrTjK/12-no-cooldown-between-inventory-slots",
- description = "Apply cooldown to all weapons",
- component = BugfixType.HarmonyPatch, id = 4)]
- [HarmonyPatch]
- class WeaponCooldownEngine_OnQuickAttackStateChange_Patch
- {
- public static bool Enable = true;
-
- private static bool isRunningTick = false;
-
- [HarmonyPostfix]
- public static void AfterMethodCall(object __instance, int characterId, bool isPerformingQuickAttack)
- {
- if (!Enable) return;
- // TODO optimise this... a lot
- // build functions for retrieving internal Game.Handhelds.CharacterWeaponCooldownEntityView object
- IEntitiesDB entitiesDB = (IEntitiesDB)
- AccessTools.PropertyGetter(AccessTools.TypeByName("Game.Handhelds.WeaponCooldownEngine"), "entitiesDB")
- .Invoke(__instance, new object[0]);
- Reflection.ExistsV2 cwcevExists =
- Reflection.MethodAsDelegate<Reflection.ExistsV2>(
- "Svelto.ECS.IEntitiesDB:Exists",
- new[] {typeof(int), typeof(int)},
- new[] {AccessTools.TypeByName("Game.Handhelds.CharacterWeaponCooldownEntityView")},
- entitiesDB);
- Reflection.QueryEntityViewV2<object> queryCWCEV =
- Reflection.MethodAsDelegate<Reflection.QueryEntityViewV2<object>>(
- typeof(IEntitiesDB),
- "QueryEntityView",
- parameters: new[] {typeof(int), typeof(ExclusiveGroup.ExclusiveGroupStruct)},
- generics: new[] {AccessTools.TypeByName("Game.Handhelds.CharacterWeaponCooldownEntityView")},
- entitiesDB);
- // retrieve Game.Handhelds.CharacterWeaponCooldownEntityView
- if (!cwcevExists(characterId, (int) DEPRECATED_SveltoExtensions.DEPRECATED_GROUP))
- {
- //API.Utility.Logging.MetaDebugLog($"No CharacterWeaponCooldownEntityView with id {characterId} found");
- return;
- }
-
- object cwcevOriginal = queryCWCEV(characterId,
- (ExclusiveGroup.ExclusiveGroupStruct) DEPRECATED_SveltoExtensions.DEPRECATED_GROUP);
- // get id because that's important
- int toolId = Traverse.Create(cwcevOriginal).Field("handheldEquipmentComponent")
- .Property("equippedHandheldId")
- .GetValue<DispatchOnChange<int>>().value;
- //API.Utility.Logging.MetaLog("Got CharacterWeaponCooldownEntityView object using nasty code");
- // build functions for retrieving internal Game.Handhelds.WeaponCooldownEntityView object
- Reflection.ExistsV2 wcevExists =
- Reflection.MethodAsDelegate<Reflection.ExistsV2>(
- "Svelto.ECS.IEntitiesDB:Exists",
- new[] {typeof(int), typeof(int)},
- new[] {AccessTools.TypeByName("Game.Handhelds.WeaponCooldownEntityView")},
- entitiesDB);
- Reflection.QueryEntityViewV2<object> queryWCEV =
- Reflection.MethodAsDelegate<Reflection.QueryEntityViewV2<object>>(
- typeof(IEntitiesDB),
- "QueryEntityView",
- parameters: new[] {typeof(int), typeof(ExclusiveGroup.ExclusiveGroupStruct)},
- generics: new[] {AccessTools.TypeByName("Game.Handhelds.WeaponCooldownEntityView")},
- entitiesDB);
- ExclusiveGroup baseGroup = (ExclusiveGroup) AccessTools
- .Field(AccessTools.TypeByName("Game.Handhelds.HandheldGroups"), "BaseGroup").GetValue(null);
- // retrieve WeaponCooldownEntityView
- if (!wcevExists(toolId, (int) baseGroup))
- {
- //API.Utility.Logging.MetaDebugLog($"No WeaponCooldownEntityView with id {toolId} found");
- return;
- }
-
- object wcevOriginal = queryWCEV(toolId, baseGroup);
- float cooldownLeft =
- Traverse.Create(wcevOriginal).Field("weaponCooldownComponent").Property<float>("cooldownLeft").Value;
- bool isInCooldown =
- Traverse.Create(wcevOriginal).Field("weaponCooldownComponent").Property<bool>("isInCooldown").Value;
- //API.Utility.Logging.MetaLog($"Cooling down? {isInCooldown} for {cooldownLeft}s");
- // build functions for querying all Game.Handhelds.WeaponCooldownEntityView objects
- Type protoRaw =
- typeof(Reflection.QueryEntityViews<>)
- .MakeGenericType(
- AccessTools.TypeByName("Game.Handhelds.WeaponCooldownEntityView"));
- Delegate queryAllWCEV =
- Reflection.MethodAsDelegateRaw(
- typeof(IEntitiesDB),
- protoRaw,
- "QueryEntityViews",
- parameters: new[] {typeof(int)},
- generics: new[] {AccessTools.TypeByName("Game.Handhelds.WeaponCooldownEntityView")},
- entitiesDB);
- object collectionStruct =
- queryAllWCEV.DynamicInvoke((int) baseGroup);
- int count = Traverse.Create(collectionStruct).Field<int>("_count").Value;
- PropertyInfo indexer = typeof(Svelto.DataStructures.ReadOnlyCollectionStruct<>)
- .MakeGenericType(AccessTools.TypeByName("Game.Handhelds.WeaponCooldownEntityView"))
- .GetIndexer();
-
- if (!isRunningTick)
- {
- isRunningTick = true;
- cooldownTickEverything(characterId, cwcevExists, queryCWCEV, queryWCEV, queryAllWCEV, indexer, baseGroup).Run();
- }
- /*object[] indexParams = {0};
- for (int index = 0; index < count; index++)
- {
- #if DEBUG
- API.Utility.Logging.MetaLog("Syncing cooldown with another weapon");
- #endif
- indexParams[0] = index;
- object wcev = indexer.GetValue(collectionStruct, indexParams);
- Traverse.Create(wcev)
- .Field("weaponCooldownComponent")
- .Property<float>("cooldownLeft")
- .Value = cooldownLeft;
-
- Traverse.Create(wcev)
- .Field("weaponCooldownComponent")
- .Property<bool>("isInCooldown").Value = isInCooldown;
- }*/
- }
-
- [HarmonyTargetMethod]
- public static MethodBase Target()
- {
- return AccessTools.Method("Game.Handhelds.WeaponCooldownEngine:OnQuickAttackStateChange",
- new[] {typeof(int), typeof(bool)});
- }
-
- private static IEnumerator cooldownTickEverything(int characterId, Reflection.ExistsV2 cwcevExists, Reflection.QueryEntityViewV2<object> cwcevQuery, Reflection.QueryEntityViewV2<object> wcevQuery, Delegate wcevQueryAll, PropertyInfo indexer, ExclusiveGroup baseGroup)
- {
- while (cwcevExists(characterId, (int) DEPRECATED_SveltoExtensions.DEPRECATED_GROUP))
- {
- // get equipped handheld info
- object cwcevOriginal = cwcevQuery(characterId,
- (ExclusiveGroup.ExclusiveGroupStruct) DEPRECATED_SveltoExtensions.DEPRECATED_GROUP);
- int toolId = Traverse.Create(cwcevOriginal).Field("handheldEquipmentComponent")
- .Property("equippedHandheldId")
- .GetValue<DispatchOnChange<int>>().value;
- // get cooldown info for equipped item
- object wcevOriginal = wcevQuery(toolId, baseGroup);
- object collectionStruct =
- wcevQueryAll.DynamicInvoke((int)baseGroup);
- int count = Traverse.Create(collectionStruct).Field<int>("_count").Value;
- float cooldownLeft =
- Traverse.Create(wcevOriginal).Field("weaponCooldownComponent").Property<float>("cooldownLeft").Value;
- bool isInCooldown =
- Traverse.Create(wcevOriginal).Field("weaponCooldownComponent").Property<bool>("isInCooldown").Value;
- object[] indexParams = {0};
- // iterate over other handhelds and sync their cooldowns to the held item
- API.Utility.Logging.MetaDebugLog($"Syncing {count} weapon cooldowns with the held item {toolId}");
- for (int index = 0; index < count; index++)
- {
- indexParams[0] = index;
- object wcev = indexer.GetValue(collectionStruct, indexParams);
- Traverse.Create(wcev)
- .Field("weaponCooldownComponent")
- .Property<float>("cooldownLeft")
- .Value = cooldownLeft;
-
- Traverse.Create(wcev)
- .Field("weaponCooldownComponent")
- .Property<bool>("isInCooldown").Value = isInCooldown;
- }
- // stop running this task after one final sync to set every handheld to non-cooldown state
- if (!isInCooldown && cooldownLeft <= 0) break;
- yield return null;
- }
- // cleanup
- API.Utility.Logging.MetaDebugLog("Custom cooldown ticks complete");
- isRunningTick = false;
- yield return null;
- }
- }
- }
|