178 lines
8.5 KiB
C#
178 lines
8.5 KiB
C#
using HarmonyLib;
|
|
using KFCommonUtilityLib;
|
|
using KFCommonUtilityLib.Scripts.Attributes;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Reflection.Emit;
|
|
using UniLinq;
|
|
|
|
[TypeTarget(typeof(ItemActionRanged))]
|
|
public class ActionModuleMetaConsumer
|
|
{
|
|
public string[] consumeDatas;
|
|
public FastTags<TagGroup.Global>[] consumeTags;
|
|
private float[] consumeStocks;
|
|
private float[] consumeValues;
|
|
private static FastTags<TagGroup.Global> TagsConsumption = FastTags<TagGroup.Global>.Parse("ConsumptionValue");
|
|
|
|
[HarmonyPatch(nameof(ItemAction.ReadFrom)), MethodTargetPostfix]
|
|
private void Postfix_ReadFrom(DynamicProperties _props, ItemAction __instance)
|
|
{
|
|
string consumeData = string.Empty;
|
|
_props.Values.TryGetValue("ConsumeData", out consumeData);
|
|
_props.Values.TryGetValue("ConsumeTags", out string tags);
|
|
FastTags<TagGroup.Global> commonTags = string.IsNullOrEmpty(tags) ? FastTags<TagGroup.Global>.none : FastTags<TagGroup.Global>.Parse(tags);
|
|
if (string.IsNullOrEmpty(consumeData))
|
|
{
|
|
Log.Error($"No consume data found on item {__instance.item.Name} action {__instance.ActionIndex}");
|
|
return;
|
|
}
|
|
|
|
consumeDatas = consumeData.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(s => s.Trim()).ToArray();
|
|
consumeTags = consumeDatas.Select(s => FastTags<TagGroup.Global>.Parse(s) | commonTags | TagsConsumption).ToArray();
|
|
consumeStocks = new float[consumeDatas.Length];
|
|
consumeValues = new float[consumeDatas.Length];
|
|
}
|
|
|
|
[HarmonyPatch(typeof(ItemActionRanged), nameof(ItemAction.ExecuteAction)), MethodTargetTranspiler]
|
|
private static IEnumerable<CodeInstruction> Transpiler_ItemActionRanged_ExecuteAction(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
|
{
|
|
var codes = instructions.ToList();
|
|
|
|
var fld_started = AccessTools.Field(typeof(ItemActionRanged.ItemActionDataRanged), nameof(ItemActionRanged.ItemActionDataRanged.burstShotStarted));
|
|
var fld_infinite = AccessTools.Field(typeof(ItemActionAttack), nameof(ItemActionAttack.InfiniteAmmo));
|
|
var mtd_consume = AccessTools.Method(typeof(ItemActionRanged), nameof(ItemActionRanged.ConsumeAmmo));
|
|
var lbd_module = generator.DeclareLocal(typeof(ActionModuleMetaConsumer));
|
|
var prop_instance = AccessTools.PropertyGetter(typeof(IModuleContainerFor<ActionModuleMetaConsumer>), nameof(IModuleContainerFor<ActionModuleMetaConsumer>.Instance));
|
|
var prop_itemvalue = AccessTools.PropertyGetter(typeof(ItemInventoryData), nameof(ItemInventoryData.itemValue));
|
|
|
|
for (int i = 0; i < codes.Count; i++)
|
|
{
|
|
if (codes[i].opcode == OpCodes.Stloc_S && ((LocalBuilder)codes[i].operand).LocalIndex == 6)
|
|
{
|
|
codes.InsertRange(i - 4, new[]
|
|
{
|
|
new CodeInstruction(OpCodes.Ldarg_0).WithLabels(codes[i - 4].ExtractLabels()),
|
|
new CodeInstruction(OpCodes.Castclass, typeof(IModuleContainerFor<ActionModuleMetaConsumer>)),
|
|
new CodeInstruction(OpCodes.Callvirt, prop_instance),
|
|
new CodeInstruction(OpCodes.Stloc_S, lbd_module),
|
|
});
|
|
i += 4;
|
|
}
|
|
else if (codes[i].StoresField(fld_started) && codes[i - 1].LoadsConstant(1))
|
|
{
|
|
var lbl = generator.DefineLabel();
|
|
var original = codes[i - 2];
|
|
codes.InsertRange(i - 2, new[]
|
|
{
|
|
new CodeInstruction(OpCodes.Ldloc_S, lbd_module).WithLabels(original.ExtractLabels()),
|
|
new CodeInstruction(OpCodes.Ldloc_0),
|
|
CodeInstruction.LoadField(typeof(ItemActionData), nameof(ItemActionData.invData)),
|
|
new CodeInstruction(OpCodes.Callvirt, prop_itemvalue),
|
|
new CodeInstruction(OpCodes.Ldloc_S, 6),
|
|
new CodeInstruction(OpCodes.Ldarg_0),
|
|
CodeInstruction.LoadField(typeof(ItemActionAttack), nameof(ItemActionAttack.soundEmpty)),
|
|
CodeInstruction.Call(typeof(ActionModuleMetaConsumer), nameof(CheckAndCacheMetaData)),
|
|
new CodeInstruction(OpCodes.Brtrue_S, lbl),
|
|
new CodeInstruction(OpCodes.Ret)
|
|
});
|
|
original.WithLabels(lbl);
|
|
i += 10;
|
|
}
|
|
else if (codes[i].Calls(mtd_consume))
|
|
{
|
|
var lbl = generator.DefineLabel();
|
|
for (int j = i - 1; j >= 0; j--)
|
|
{
|
|
if (codes[j].LoadsField(fld_infinite) && codes[j + 1].Branches(out _))
|
|
{
|
|
codes[j + 1].operand = lbl;
|
|
break;
|
|
}
|
|
}
|
|
codes.InsertRange(i + 1, new[]
|
|
{
|
|
new CodeInstruction(OpCodes.Ldloc_S, lbd_module).WithLabels(lbl),
|
|
new CodeInstruction(OpCodes.Ldloc_0),
|
|
CodeInstruction.LoadField(typeof(ItemActionData), nameof(ItemActionData.invData)),
|
|
new CodeInstruction(OpCodes.Callvirt, prop_itemvalue),
|
|
new CodeInstruction(OpCodes.Ldloc_S, 6),
|
|
CodeInstruction.Call(typeof(ActionModuleMetaConsumer), nameof(ConsumeMetaData)),
|
|
});
|
|
break;
|
|
}
|
|
}
|
|
|
|
return codes;
|
|
}
|
|
|
|
public bool CheckAndCacheMetaData(ItemValue itemValue, EntityAlive holdingEntity, string soundEmpty)
|
|
{
|
|
for (int i = 0; i < consumeDatas.Length; i++)
|
|
{
|
|
string consumeData = consumeDatas[i];
|
|
float stock = (float)itemValue.GetMetadata(consumeData);
|
|
float consumption = EffectManager.GetValue(CustomEnums.CustomTaggedEffect, itemValue, float.MaxValue, holdingEntity, null, consumeTags[i]);
|
|
if (stock < consumption)
|
|
{
|
|
holdingEntity.PlayOneShot(soundEmpty);
|
|
return false;
|
|
}
|
|
consumeStocks[i] = stock;
|
|
consumeValues[i] = consumption;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public void ConsumeMetaData(ItemValue itemValue, EntityAlive holdingEntity)
|
|
{
|
|
for (int i = 0; i < consumeDatas.Length; i++)
|
|
{
|
|
itemValue.SetMetadata(consumeDatas[i], consumeStocks[i] - consumeValues[i], TypedMetadataValue.TypeTag.Float);
|
|
holdingEntity.MinEventContext.Tags = consumeTags[i];
|
|
holdingEntity.FireEvent(CustomEnums.onRechargeValueUpdate, true);
|
|
}
|
|
}
|
|
|
|
//[HarmonyPatch(nameof(ItemAction.ExecuteAction)), MethodTargetPrefix]
|
|
//private bool Prefix_ExecuteAction(ItemActionData _actionData, bool _bReleased, ItemActionRanged __instance)
|
|
//{
|
|
// ItemActionRanged.ItemActionDataRanged _data = _actionData as ItemActionRanged.ItemActionDataRanged;
|
|
// EntityAlive holdingEntity = _actionData.invData.holdingEntity;
|
|
// ItemValue itemValue = _actionData.invData.itemValue;
|
|
// if (!_bReleased)
|
|
// {
|
|
// int burstCount = __instance.GetBurstCount(_actionData);
|
|
// if (holdingEntity.inventory.holdingItemItemValue.PercentUsesLeft <= 0f || (_data.curBurstCount >= burstCount && burstCount != -1) || (!__instance.InfiniteAmmo && itemValue.Meta <= 0))
|
|
// {
|
|
// return true;
|
|
// }
|
|
|
|
// for (int i = 0; i < consumeDatas.Length; i++)
|
|
// {
|
|
// string consumeData = consumeDatas[i];
|
|
// float stock = (float)itemValue.GetMetadata(consumeData);
|
|
// float consumption = EffectManager.GetValue(CustomEnums.CustomTaggedEffect, itemValue, float.MaxValue, _actionData.invData.holdingEntity, null, consumeTags[i]);
|
|
// if (stock < consumption)
|
|
// {
|
|
// if (!_data.bPressed)
|
|
// {
|
|
// holdingEntity.PlayOneShot(__instance.soundEmpty);
|
|
// _data.bPressed = true;
|
|
// }
|
|
// return false;
|
|
// }
|
|
// consumeStocks[i] = stock;
|
|
// consumeValues[i] = consumption;
|
|
// }
|
|
|
|
// for (int i = 0; i < consumeDatas.Length; i++)
|
|
// {
|
|
// itemValue.SetMetadata(consumeDatas[i], consumeStocks[i] - consumeValues[i], TypedMetadataValue.TypeTag.Float);
|
|
// holdingEntity.MinEventContext.Tags = consumeTags[i];
|
|
// holdingEntity.FireEvent(CustomEnums.onRechargeValueUpdate, true);
|
|
// }
|
|
// }
|
|
// return true;
|
|
//}
|
|
} |