601 lines
25 KiB
C#
601 lines
25 KiB
C#
using KFCommonUtilityLib.Scripts.ConsoleCmd;
|
|
using KFCommonUtilityLib.Scripts.Utilities;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using UniLinq;
|
|
using UnityEngine;
|
|
|
|
namespace KFCommonUtilityLib.Scripts.StaticManagers
|
|
{
|
|
//concept: maintain an entityID-AltActionIndice mapping on both server and client
|
|
//and get the correct action before calling ItemAction.*
|
|
//always set MinEventParams.itemActionData
|
|
//done: set meta and ammoindex on switching mode, keep current mode in metadata
|
|
//should take care of accuracy updating
|
|
//partially done: should support shared meta
|
|
//alt actions should be considered primary, redirect index == 0 to custom method
|
|
//redirect ItemClass.Actions[0] to custom method
|
|
//however, player input handling is redirected to action0 so that alternative module can dispatch it to correct action.
|
|
//patch GameManager.updateSendClientPlayerPositionToServer to sync data, so that mode change always happens after holding item change
|
|
|
|
public struct MultiActionIndice
|
|
{
|
|
public const int MAX_ACTION_COUNT = 3;
|
|
public unsafe fixed sbyte indices[MAX_ACTION_COUNT];
|
|
public unsafe fixed sbyte metaIndice[MAX_ACTION_COUNT];
|
|
public readonly byte modeCount;
|
|
|
|
public unsafe MultiActionIndice(ItemClass item)
|
|
{
|
|
ItemAction[] actions = item.Actions;
|
|
indices[0] = 0;
|
|
metaIndice[0] = 0;
|
|
byte last = 1;
|
|
for (sbyte i = 3; i < actions.Length && last < MAX_ACTION_COUNT; i++)
|
|
{
|
|
if (actions[i] != null)
|
|
{
|
|
indices[last] = i;
|
|
if (actions[i].Properties.Values.TryGetValue("ShareMetaWith", out string str) && sbyte.TryParse(str, out sbyte shareWith))
|
|
{
|
|
metaIndice[last] = shareWith;
|
|
}
|
|
else
|
|
{
|
|
metaIndice[last] = i;
|
|
}
|
|
last++;
|
|
}
|
|
}
|
|
modeCount = last;
|
|
for (; last < MAX_ACTION_COUNT; last++)
|
|
{
|
|
indices[last] = -1;
|
|
metaIndice[last] = -1;
|
|
}
|
|
}
|
|
|
|
public unsafe int GetActionIndexForMode(int mode)
|
|
{
|
|
return indices[mode];
|
|
}
|
|
|
|
public unsafe int GetMetaIndexForMode(int mode)
|
|
{
|
|
return metaIndice[mode];
|
|
}
|
|
|
|
public unsafe int GetMetaIndexForActionIndex(int actionIndex)
|
|
{
|
|
return metaIndice[GetModeForAction(actionIndex)];
|
|
}
|
|
|
|
public int GetModeForAction(int actionIndex)
|
|
{
|
|
int mode = -1;
|
|
for (int i = 0; i < MultiActionIndice.MAX_ACTION_COUNT; i++)
|
|
{
|
|
unsafe
|
|
{
|
|
if (indices[i] == actionIndex)
|
|
{
|
|
mode = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return mode;
|
|
}
|
|
}
|
|
|
|
//MultiActionMapping instance should be changed on ItemAction.StartHolding, so we only need to send curIndex.
|
|
public class MultiActionMapping
|
|
{
|
|
public const string STR_MULTI_ACTION_INDEX = "MultiActionIndex";
|
|
public readonly MultiActionIndice indices;
|
|
private int slotIndex;
|
|
private int curIndex;
|
|
private int lastDisplayMode = -1;
|
|
private readonly bool[] unlocked;
|
|
private ActionModuleAlternative.AlternativeData altData;
|
|
public EntityAlive entity;
|
|
public string toggleSound;
|
|
|
|
public ItemValue ItemValue
|
|
{
|
|
get
|
|
{
|
|
var res = entity.inventory.GetItem(slotIndex).itemValue;
|
|
if (res.IsEmpty())
|
|
{
|
|
return null;
|
|
}
|
|
return res;
|
|
}
|
|
}
|
|
|
|
public int SlotIndex => slotIndex;
|
|
|
|
/// <summary>
|
|
/// when set CurIndex from local input, also set manager to dirty to update the index on other clients
|
|
/// </summary>
|
|
public int CurMode
|
|
{
|
|
get => curIndex;
|
|
set
|
|
{
|
|
unsafe
|
|
{
|
|
if (value < 0)
|
|
value = 0;
|
|
else
|
|
{
|
|
while (value < MultiActionIndice.MAX_ACTION_COUNT)
|
|
{
|
|
if (unlocked[value])
|
|
break;
|
|
value++;
|
|
}
|
|
//mostly for CurIndex++, cycle through available indices
|
|
if (value >= MultiActionIndice.MAX_ACTION_COUNT || indices.indices[value] == -1)
|
|
value = 0;
|
|
}
|
|
if (curIndex == value)
|
|
return;
|
|
|
|
SaveMeta();
|
|
|
|
//load current meta and ammo index from metadata
|
|
curIndex = value;
|
|
ReadMeta();
|
|
entity.emodel?.avatarController?.UpdateInt(MultiActionUtils.ExecutingActionIndexHash, CurActionIndex, false);
|
|
//altData.OverrideMuzzleTransform(curIndex);
|
|
}
|
|
}
|
|
}
|
|
|
|
//for ItemClass.Actions access
|
|
public int CurActionIndex => indices.GetActionIndexForMode(curIndex);
|
|
|
|
//for meta saving on mode switch only?
|
|
public int CurMetaIndex => indices.GetMetaIndexForMode(curIndex);
|
|
|
|
public int ModeCount => indices.modeCount;
|
|
|
|
//mapping object is created on StartHolding
|
|
//we set the curIndex field instead of the property, according to following situations:
|
|
//1. it's a newly created ItemValue, meta and ammo index belongs to action0, no saving is needed;
|
|
//2. it's an existing ItemValue, meta and ammo index is set to its action index, still saving is unnecessary.
|
|
internal MultiActionMapping(ActionModuleAlternative.AlternativeData altData, MultiActionIndice indices, EntityAlive entity, ItemValue itemValueTemp, string toggleSound, int slotIndex, bool[] unlocked)
|
|
{
|
|
this.altData = altData;
|
|
this.indices = indices;
|
|
this.entity = entity;
|
|
this.slotIndex = slotIndex;
|
|
this.unlocked = unlocked;
|
|
object res = itemValueTemp.GetMetadata(STR_MULTI_ACTION_INDEX);
|
|
if (res is false || res is null)
|
|
{
|
|
itemValueTemp.SetMetadata(STR_MULTI_ACTION_INDEX, 0, TypedMetadataValue.TypeTag.Integer);
|
|
curIndex = 0;
|
|
}
|
|
else
|
|
{
|
|
curIndex = (int)res;
|
|
ReadMeta();
|
|
}
|
|
|
|
unsafe
|
|
{
|
|
for (int i = 0; i < MultiActionIndice.MAX_ACTION_COUNT; i++)
|
|
{
|
|
int metaIndex = indices.metaIndice[i];
|
|
if (metaIndex < 0)
|
|
break;
|
|
if (!itemValueTemp.HasMetadata(MultiActionUtils.ActionMetaNames[metaIndex]))
|
|
{
|
|
itemValueTemp.SetMetadata(MultiActionUtils.ActionMetaNames[metaIndex], 0, TypedMetadataValue.TypeTag.Integer);
|
|
}
|
|
#if DEBUG
|
|
else
|
|
{
|
|
Log.Out($"{MultiActionUtils.ActionMetaNames[metaIndex]}: {itemValueTemp.GetMetadata(MultiActionUtils.ActionMetaNames[metaIndex]).ToString()}");
|
|
}
|
|
#endif
|
|
if (!itemValueTemp.HasMetadata(MultiActionUtils.ActionSelectedAmmoNames[metaIndex]))
|
|
{
|
|
itemValueTemp.SetMetadata(MultiActionUtils.ActionSelectedAmmoNames[metaIndex], 0, TypedMetadataValue.TypeTag.Integer);
|
|
}
|
|
#if DEBUG
|
|
else
|
|
{
|
|
Log.Out($"{MultiActionUtils.ActionSelectedAmmoNames[metaIndex]}: {itemValueTemp.GetMetadata(MultiActionUtils.ActionSelectedAmmoNames[metaIndex]).ToString()}");
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
this.toggleSound = toggleSound;
|
|
entity.emodel?.avatarController?.UpdateInt(MultiActionUtils.ExecutingActionIndexHash, CurActionIndex, false);
|
|
#if DEBUG
|
|
Log.Out($"MultiAction mode {curIndex}, meta {itemValueTemp.Meta}, ammo index {itemValueTemp.SelectedAmmoTypeIndex}\n {StackTraceUtility.ExtractStackTrace()}");
|
|
#endif
|
|
}
|
|
|
|
public void SaveMeta(ItemValue _itemValue = null)
|
|
{
|
|
//save previous meta and ammo index to metadata
|
|
int curMetaIndex = CurMetaIndex;
|
|
ItemValue itemValue = _itemValue ?? ItemValue;
|
|
if (itemValue == null)
|
|
return;
|
|
ItemAction[] actions = itemValue.ItemClass.Actions;
|
|
if (CurActionIndex < 0 || CurActionIndex >= actions.Length)
|
|
return;
|
|
ItemActionAttack itemActionAttack = actions[CurActionIndex] as ItemActionAttack;
|
|
if (itemActionAttack == null)
|
|
return;
|
|
if (ConsoleCmdReloadLog.LogInfo)
|
|
{
|
|
Log.Out($"Saving meta for item {itemValue.ItemClass.Name}");
|
|
}
|
|
itemValue.SetMetadata(MultiActionUtils.ActionMetaNames[curMetaIndex], itemValue.Meta, TypedMetadataValue.TypeTag.Integer);
|
|
itemValue.SetMetadata(MultiActionUtils.ActionSelectedAmmoNames[curMetaIndex], (int)itemValue.SelectedAmmoTypeIndex, TypedMetadataValue.TypeTag.Integer);
|
|
if (itemValue.SelectedAmmoTypeIndex > itemActionAttack.MagazineItemNames.Length)
|
|
{
|
|
Log.Error($"SAVING META ERROR: AMMO INDEX LARGER THAN AMMO ITEM COUNT!\n{StackTraceUtility.ExtractStackTrace()}");
|
|
}
|
|
if (ConsoleCmdReloadLog.LogInfo)
|
|
{
|
|
ConsoleCmdMultiActionItemValueDebug.LogMeta(itemValue);
|
|
Log.Out($"Save Meta stacktrace:\n{StackTraceUtility.ExtractStackTrace()}");
|
|
}
|
|
}
|
|
|
|
public void ReadMeta(ItemValue _itemValue = null)
|
|
{
|
|
int curMetaIndex = CurMetaIndex;
|
|
ItemValue itemValue = _itemValue ?? ItemValue;
|
|
if (itemValue == null)
|
|
return;
|
|
itemValue.SetMetadata(STR_MULTI_ACTION_INDEX, curIndex, TypedMetadataValue.TypeTag.Integer);
|
|
object res = itemValue.GetMetadata(MultiActionUtils.ActionMetaNames[curMetaIndex]);
|
|
if (res is false || res is null)
|
|
{
|
|
itemValue.SetMetadata(MultiActionUtils.ActionMetaNames[curMetaIndex], 0, TypedMetadataValue.TypeTag.Integer);
|
|
itemValue.Meta = 0;
|
|
}
|
|
else
|
|
{
|
|
itemValue.Meta = (int)res;
|
|
}
|
|
res = itemValue.GetMetadata(MultiActionUtils.ActionSelectedAmmoNames[curMetaIndex]);
|
|
if (res is false || res is null)
|
|
{
|
|
itemValue.SetMetadata(MultiActionUtils.ActionSelectedAmmoNames[curMetaIndex], 0, TypedMetadataValue.TypeTag.Integer);
|
|
itemValue.SelectedAmmoTypeIndex = 0;
|
|
}
|
|
else
|
|
{
|
|
itemValue.SelectedAmmoTypeIndex = (byte)(int)res;
|
|
}
|
|
if (ConsoleCmdReloadLog.LogInfo)
|
|
{
|
|
ConsoleCmdMultiActionItemValueDebug.LogMeta(itemValue);
|
|
Log.Out($"Read Meta stacktrace:\n{StackTraceUtility.ExtractStackTrace()}");
|
|
}
|
|
}
|
|
|
|
public int SetupRadial(XUiC_Radial _xuiRadialWindow, EntityPlayerLocal _epl)
|
|
{
|
|
_xuiRadialWindow.ResetRadialEntries();
|
|
int preSelectedIndex = -1;
|
|
string[] magazineItemNames = ((ItemActionAttack)_epl.inventory.holdingItem.Actions[CurActionIndex]).MagazineItemNames;
|
|
bool[] disableStates = CommonUtilityPatch.GetUnusableItemEntries(magazineItemNames, _epl, CurActionIndex);
|
|
for (int i = 0; i < magazineItemNames.Length; i++)
|
|
{
|
|
ItemClass ammoClass = ItemClass.GetItemClass(magazineItemNames[i], false);
|
|
if (ammoClass != null && (!_epl.isHeadUnderwater || ammoClass.UsableUnderwater) && !disableStates[i])
|
|
{
|
|
int ammoCount = _xuiRadialWindow.xui.PlayerInventory.GetItemCount(ammoClass.Id);
|
|
bool isCurrentUsing = _epl.inventory.holdingItemItemValue.SelectedAmmoTypeIndex == i;
|
|
_xuiRadialWindow.CreateRadialEntry(i, ammoClass.GetIconName(), (ammoCount > 0) ? "ItemIconAtlas" : "ItemIconAtlasGreyscale", ammoCount.ToString(), ammoClass.GetLocalizedItemName(), isCurrentUsing);
|
|
if (isCurrentUsing)
|
|
{
|
|
preSelectedIndex = i;
|
|
}
|
|
}
|
|
}
|
|
|
|
return preSelectedIndex;
|
|
}
|
|
|
|
public bool CheckDisplayMode()
|
|
{
|
|
if (lastDisplayMode == CurMode)
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
lastDisplayMode = CurMode;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
public bool IsActionUnlocked(int actionIndex)
|
|
{
|
|
if (actionIndex >= MultiActionIndice.MAX_ACTION_COUNT || actionIndex < 0)
|
|
return false;
|
|
return unlocked[actionIndex];
|
|
}
|
|
}
|
|
|
|
public static class MultiActionManager
|
|
{
|
|
//clear on game load
|
|
private static readonly Dictionary<int, MultiActionMapping> dict_mappings = new Dictionary<int, MultiActionMapping>();
|
|
private static readonly Dictionary<int, MultiActionIndice> dict_indice = new Dictionary<int, MultiActionIndice>();
|
|
private static readonly Dictionary<int, FastTags<TagGroup.Global>[]> dict_item_action_exclude_tags = new Dictionary<int, FastTags<TagGroup.Global>[]>();
|
|
private static readonly Dictionary<int, int[][]> dict_item_action_exclude_mod_property = new Dictionary<int, int[][]>();
|
|
private static readonly Dictionary<int, int[][]> dict_item_action_exclude_mod_passive = new Dictionary<int, int[][]>();
|
|
private static readonly Dictionary<int, int[][]> dict_item_action_exclude_mod_trigger = new Dictionary<int, int[][]>();
|
|
|
|
//should set to true when:
|
|
//mode switch input received;
|
|
//start holding new multi action weapon.?
|
|
//if true, send local curIndex to other clients in updateSendClientPlayerPositionToServer.
|
|
public static bool LocalModeChanged { get; set; }
|
|
|
|
public static void PostloadCleanup()
|
|
{
|
|
dict_mappings.Clear();
|
|
dict_indice.Clear();
|
|
}
|
|
|
|
public static void PreloadCleanup()
|
|
{
|
|
dict_item_action_exclude_tags.Clear();
|
|
dict_item_action_exclude_mod_property.Clear();
|
|
dict_item_action_exclude_mod_passive.Clear();
|
|
dict_item_action_exclude_mod_trigger.Clear();
|
|
}
|
|
|
|
public static void ParseItemActionExcludeTagsAndModifiers(ItemClass item)
|
|
{
|
|
if (item == null)
|
|
return;
|
|
FastTags<TagGroup.Global>[] tags = null;
|
|
int[][] properties = null, passives = null, triggers = null;
|
|
for (int i = 0; i < item.Actions.Length; i++)
|
|
{
|
|
if (item.Actions[i] != null)
|
|
{
|
|
if (item.Actions[i].Properties.Values.TryGetValue("ExcludeTags", out string str))
|
|
{
|
|
if (tags == null)
|
|
{
|
|
tags = new FastTags<TagGroup.Global>[ItemClass.cMaxActionNames];
|
|
dict_item_action_exclude_tags.Add(item.Id, tags);
|
|
}
|
|
tags[i] = FastTags<TagGroup.Global>.Parse(str);
|
|
}
|
|
if (item.Actions[i].Properties.Values.TryGetValue("ExcludeMods", out str))
|
|
{
|
|
if (properties == null)
|
|
{
|
|
properties = new int[ItemClass.cMaxActionNames][];
|
|
dict_item_action_exclude_mod_property.Add(item.Id, properties);
|
|
}
|
|
properties[i] = str.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
|
|
.Where(s => !string.IsNullOrEmpty(s))
|
|
.Select(s => ItemClass.GetItemClass(s, false))
|
|
.Where(_item => _item != null)
|
|
.Select(_item => _item.Id)
|
|
.ToArray();
|
|
//Log.Out($"EXCLUDE PROPERTIES FROM ITEM {item.Name} ITEMID {item.Id} ACTION {i} : {string.Join(" ", properties[i])}");
|
|
}
|
|
if (item.Actions[i].Properties.Values.TryGetValue("ExcludePassives", out str))
|
|
{
|
|
if (passives == null)
|
|
{
|
|
passives = new int[ItemClass.cMaxActionNames][];
|
|
dict_item_action_exclude_mod_passive.Add(item.Id, passives);
|
|
}
|
|
passives[i] = str.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
|
|
.Where(s => !string.IsNullOrEmpty(s))
|
|
.Select(s => ItemClass.GetItemClass(s, false))
|
|
.Where(_item => _item != null)
|
|
.Select(_item => _item.Id)
|
|
.ToArray();
|
|
//Log.Out($"EXCLUDE PASSIVES FROM ITEM {item.Name} ITEMID {item.Id} ACTION {i} : {string.Join(" ", passives[i])}");
|
|
}
|
|
if (item.Actions[i].Properties.Values.TryGetValue("ExcludeTriggers", out str))
|
|
{
|
|
if (triggers == null)
|
|
{
|
|
triggers = new int[ItemClass.cMaxActionNames][];
|
|
dict_item_action_exclude_mod_trigger.Add(item.Id, triggers);
|
|
}
|
|
triggers[i] = str.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
|
|
.Where(s => !string.IsNullOrEmpty(s))
|
|
.Select(s => ItemClass.GetItemClass(s, false))
|
|
.Where(_item => _item != null)
|
|
.Select(_item => _item.Id)
|
|
.ToArray();
|
|
//Log.Out($"EXCLUDE TRIGGERS FROM ITEM {item.Name} ITEMID {item.Id} ACTION {i} : {string.Join(" ", triggers[i])}");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void ModifyItemTags(ItemValue itemValue, ItemActionData actionData, ref FastTags<TagGroup.Global> tags)
|
|
{
|
|
if (itemValue == null || actionData == null || !dict_item_action_exclude_tags.TryGetValue(itemValue.type, out var arr_tags))
|
|
{
|
|
return;
|
|
}
|
|
|
|
tags = tags.Remove(arr_tags[actionData.indexInEntityOfAction]);
|
|
}
|
|
|
|
public static bool ShouldExcludeProperty(int itemId, int modId, int actionIndex)
|
|
{
|
|
return dict_item_action_exclude_mod_property.TryGetValue(itemId, out var arr_exclude) && arr_exclude[actionIndex] != null && Array.IndexOf(arr_exclude[actionIndex], modId) >= 0;
|
|
}
|
|
|
|
public static bool ShouldExcludePassive(int itemId, int modId, int actionIndex)
|
|
{
|
|
return dict_item_action_exclude_mod_passive.TryGetValue(itemId, out var arr_exclude) && arr_exclude[actionIndex] != null && Array.IndexOf(arr_exclude[actionIndex], modId) >= 0;
|
|
}
|
|
|
|
public static bool ShouldExcludeTrigger(int itemId, int modId, int actionIndex)
|
|
{
|
|
return dict_item_action_exclude_mod_trigger.TryGetValue(itemId, out var arr_exclude) && arr_exclude[actionIndex] != null && Array.IndexOf(arr_exclude[actionIndex], modId) >= 0;
|
|
}
|
|
|
|
public static void UpdateLocalMetaSave(int playerID)
|
|
{
|
|
if (dict_mappings.TryGetValue(playerID, out MultiActionMapping mapping))
|
|
{
|
|
mapping?.SaveMeta();
|
|
}
|
|
}
|
|
|
|
public static MultiActionIndice GetActionIndiceForItemID(int itemID)
|
|
{
|
|
if (dict_indice.TryGetValue(itemID, out MultiActionIndice indice))
|
|
return indice;
|
|
ItemClass item = ItemClass.GetForId(itemID);
|
|
if (item == null)
|
|
return indice;
|
|
indice = new MultiActionIndice(item);
|
|
dict_indice[itemID] = indice;
|
|
return indice;
|
|
}
|
|
|
|
public static void ToggleLocalActionIndex(EntityPlayerLocal player)
|
|
{
|
|
if (player == null || !dict_mappings.TryGetValue(player.entityId, out MultiActionMapping mapping))
|
|
return;
|
|
|
|
if (mapping.ModeCount <= 1 || player.inventory.IsHoldingItemActionRunning())
|
|
return;
|
|
int prevMode = mapping.CurMode;
|
|
mapping.CurMode++;
|
|
if (prevMode != mapping.CurMode)
|
|
{
|
|
FireToggleModeEvent(player, mapping);
|
|
player.inventory.CallOnToolbeltChangedInternal();
|
|
}
|
|
}
|
|
|
|
public static void FireToggleModeEvent(EntityPlayerLocal player, MultiActionMapping mapping)
|
|
{
|
|
player.PlayOneShot(mapping.toggleSound);
|
|
LocalModeChanged = true;
|
|
player.MinEventContext.ItemActionData = player.inventory.holdingItemData.actionData[mapping.CurActionIndex];
|
|
player.FireEvent(CustomEnums.onSelfItemSwitchMode);
|
|
}
|
|
|
|
public static void SetMappingForEntity(int entityID, MultiActionMapping mapping)
|
|
{
|
|
dict_mappings[entityID] = mapping;
|
|
//Log.Out($"current item index mapping: {((mapping == null || mapping.itemValue == null) ? "null" : mapping.itemValue.ItemClass.Name)}");
|
|
}
|
|
|
|
public static bool SetModeForEntity(int entityID, int mode)
|
|
{
|
|
if (dict_mappings.TryGetValue(entityID, out MultiActionMapping mapping) && mapping != null)
|
|
{
|
|
int prevMode = mapping.CurMode;
|
|
mapping.CurMode = mode;
|
|
return prevMode != mapping.CurMode;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public static int GetModeForEntity(int entityID)
|
|
{
|
|
if (!dict_mappings.TryGetValue(entityID, out MultiActionMapping mapping) || mapping == null)
|
|
return 0;
|
|
return mapping.CurMode;
|
|
}
|
|
|
|
public static int GetActionIndexForEntity(EntityAlive entity)
|
|
{
|
|
if (entity == null || !dict_mappings.TryGetValue(entity.entityId, out var mapping) || mapping == null)
|
|
return 0;
|
|
return mapping.CurActionIndex;
|
|
}
|
|
|
|
public static int GetMetaIndexForEntity(int entityID)
|
|
{
|
|
if (!dict_mappings.TryGetValue(entityID, out var mapping) || mapping == null)
|
|
return 0;
|
|
return mapping.CurMetaIndex;
|
|
}
|
|
|
|
public static int GetMetaIndexForActionIndex(int entityID, int actionIndex)
|
|
{
|
|
if (!dict_mappings.TryGetValue(entityID, out var mapping) || mapping == null)
|
|
{
|
|
return actionIndex;
|
|
}
|
|
|
|
int mode = mapping.indices.GetModeForAction(actionIndex);
|
|
if (mode > 0)
|
|
{
|
|
unsafe
|
|
{
|
|
return mapping.indices.metaIndice[mode];
|
|
}
|
|
}
|
|
return actionIndex;
|
|
}
|
|
|
|
public static MultiActionMapping GetMappingForEntity(int entityID)
|
|
{
|
|
dict_mappings.TryGetValue(entityID, out var mapping);
|
|
return mapping;
|
|
}
|
|
|
|
internal static float inputCD = 0;
|
|
internal static void UpdateLocalInput(EntityPlayerLocal player, PlayerActionsLocal localActions, bool isUIOpen, float _dt)
|
|
{
|
|
if (inputCD > 0)
|
|
{
|
|
inputCD = Math.Max(0, inputCD - _dt);
|
|
}
|
|
if (isUIOpen || inputCD > 0 || player.emodel.IsRagdollActive || player.IsDead() || player.AttachedToEntity != null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (PlayerActionKFLib.Instance.ToggleActionMode && PlayerActionKFLib.Instance.ToggleActionMode.WasPressed)
|
|
{
|
|
var mapping = GetMappingForEntity(player.entityId);
|
|
|
|
if (mapping == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (player.inventory.IsHoldingItemActionRunning())
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (localActions.Reload.WasPressed || localActions.PermanentActions.Reload.WasPressed)
|
|
{
|
|
inputCD = 0.1f;
|
|
return;
|
|
}
|
|
|
|
player.inventory.Execute(mapping.CurActionIndex, true, localActions);
|
|
localActions.Primary.ClearInputState();
|
|
ToggleLocalActionIndex(player);
|
|
}
|
|
}
|
|
}
|
|
}
|