static void Postfix(MonsterAI __instance, ZNetView ___m_nview, Character ___m_character, Tameable ___m_tamable, List <ItemDrop> ___m_consumeItems, float dt, bool __result) { if (!modEnabled.Value || !isOn.Value || __result || !___m_nview.IsOwner() || ___m_tamable == null || !___m_tamable.IsHungry() || ___m_consumeItems == null || ___m_consumeItems.Count == 0) { return; } string name = GetPrefabName(__instance.gameObject.name); if (animalDisallowTypes.Value.Split(',').Contains(name)) { return; } var nearbyContainers = GetNearbyContainers(___m_character.gameObject.transform.position, containerRange.Value, __instance); using (List <ItemDrop> .Enumerator enumerator = __instance.m_consumeItems.GetEnumerator()) { while (enumerator.MoveNext()) { foreach (Container c in nearbyContainers) { if (Utils.DistanceXZ(c.transform.position, __instance.transform.position) < moveProximity.Value && Mathf.Abs(c.transform.position.y - __instance.transform.position.y) > moveProximity.Value) { continue; } ItemDrop.ItemData item = c.GetInventory().GetItem(enumerator.Current.m_itemData.m_shared.m_name); if (item != null) { if (feedDisallowTypes.Value.Split(',').Contains(item.m_dropPrefab.name)) { continue; } if (Time.time - lastFeed < 0.1) { feedCount++; FeedAnimal(__instance, ___m_tamable, ___m_character, c, item, feedCount * 33); } else { feedCount = 0; lastFeed = Time.time; FeedAnimal(__instance, ___m_tamable, ___m_character, c, item, 0); } return; } } } } }
public static async void FeedAnimal(MonsterAI monsterAI, Tameable tamable, Character character, Container c, ItemDrop.ItemData item, int delay) { await Task.Delay(delay); if (!tamable.IsHungry()) { return; } if (requireOnlyFood.Value) { foreach (ItemDrop.ItemData temp in c.GetInventory().GetAllItems()) { if (!monsterAI.m_consumeItems.Exists(i => i.m_itemData.m_shared.m_name == temp.m_shared.m_name)) { return; } } } if (requireMove.Value) { //Dbgl($"{monsterAI.gameObject.name} {monsterAI.transform.position} trying to move to {c.transform.position} {Utils.DistanceXZ(monsterAI.transform.position, c.transform.position)}"); ZoneSystem.instance.GetGroundHeight(c.transform.position, out float ground); Vector3 groundTarget = new Vector3(c.transform.position.x, ground, c.transform.position.z); Traverse traverseAI = Traverse.Create(monsterAI); traverseAI.Field("m_lastFindPathTime").SetValue(0); if (!traverseAI.Method("MoveTo", new object[] { 0.05f, groundTarget, moveProximity.Value, false }).GetValue <bool>()) { return; } if (Mathf.Abs(c.transform.position.y - monsterAI.transform.position.y) > moveProximity.Value) { return; } /* * Vector3 characterPos = monsterAI.transform.position; * bool snap1 = (bool)typeof(Pathfinding).GetMethod("SnapToNavMesh", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(Pathfinding.instance, new object[] { characterPos, typeof(Pathfinding).GetMethod("GetSettings", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(Pathfinding.instance, new object[] { Pathfinding.AgentType.Humanoid }) }); * bool snap2 = (bool)typeof(Pathfinding).GetMethod("SnapToNavMesh", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(Pathfinding.instance, new object[] { groundTarget, typeof(Pathfinding).GetMethod("GetSettings", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(Pathfinding.instance, new object[] { Pathfinding.AgentType.Humanoid }) }); * * object settings = typeof(Pathfinding).GetMethod("GetSettings", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(Pathfinding.instance, new object[] { Pathfinding.AgentType.Humanoid }); * typeof(Pathfinding).GetMethod("SnapToNavMesh", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(Pathfinding.instance, new object[] { groundTarget, settings }); * * NavMeshQueryFilter filter = new NavMeshQueryFilter * { * agentTypeID = ((NavMeshBuildSettings)settings.GetType().GetField("m_build", BindingFlags.Public | BindingFlags.Instance).GetValue(settings)).agentTypeID, * areaMask = (int)settings.GetType().GetField("m_areaMask", BindingFlags.Public | BindingFlags.Instance).GetValue(settings) * }; * * bool path = NavMesh.CalculatePath(characterPos, groundTarget, filter, (NavMeshPath)typeof(Pathfinding).GetField("m_path", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(Pathfinding.instance)); * * Dbgl($"snapped1 {snap1}"); * Dbgl($"snapped2 {snap2}"); * Dbgl($"path exists {path} {((NavMeshPath)typeof(Pathfinding).GetField("m_path", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(Pathfinding.instance)).status}"); * Dbgl($"found path {traverseAI.Method("FindPath", new object[] { groundTarget }).GetValue<bool>()}"); * Dbgl($"{Time.time - traverseAI.Field("m_lastFindPathTime").GetValue<float>()} {traverseAI.Field("m_lastFindPathTarget").GetValue<Vector3>()} {traverseAI.Field("m_lastFindPathResult").GetValue<bool>()} {traverseAI.Field("m_pathAgentType").GetValue<Pathfinding.AgentType>()}"); * //Dbgl($"{monsterAI.gameObject.name} moved to"); */ traverseAI.Method("LookAt", new object[] { c.transform.position }).GetValue(); if (!traverseAI.Method("IsLookingAt", new object[] { c.transform.position, 90f }).GetValue <bool>()) { return; } traverseAI.Field("m_aiStatus").SetValue("Consume item"); //Dbgl($"{monsterAI.gameObject.name} looking at"); } Dbgl($"{monsterAI.gameObject.name} {monsterAI.transform.position} consuming {item.m_dropPrefab.name} at {c.transform.position}, distance {Utils.DistanceXZ(monsterAI.transform.position, c.transform.position)}"); ConsumeItem(item, monsterAI, character); c.GetInventory().RemoveItem(item.m_shared.m_name, 1); typeof(Inventory).GetMethod("Changed", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(c.GetInventory(), new object[] { }); typeof(Container).GetMethod("Save", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(c, new object[] { }); }
static bool Prefix(MonsterAI __instance, float dt, ref ZNetView ___m_nview, ref Character ___m_character, ref float ___m_fleeIfLowHealth, ref float ___m_timeSinceHurt, ref string ___m_aiStatus, ref Vector3 ___arroundPointTarget, ref float ___m_jumpInterval, ref float ___m_jumpTimer, ref float ___m_randomMoveUpdateTimer, ref bool ___m_alerted, ref Tameable ___m_tamable) { if (!___m_nview.IsOwner()) { return(false); } if (!___m_character.IsTamed()) { return(true); } if (!__instance.name.Contains("Greyling")) { return(true); } if (__instance.IsSleeping()) { Invoke(__instance, "UpdateSleep", new object[] { dt }); Dbgl($"{___m_character.GetHoverName()}: Sleep updated"); return(false); } BaseAI_UpdateAI_ReversePatch.UpdateAI(__instance, dt, ___m_nview, ref ___m_jumpInterval, ref ___m_jumpTimer, ref ___m_randomMoveUpdateTimer, ref ___m_timeSinceHurt, ref ___m_alerted); int instanceId = InitInstanceIfNeeded(__instance); Dbgl("GetInstanceID ok"); ___m_aiStatus = ""; Vector3 greylingPosition = ___m_character.transform.position; if (___m_timeSinceHurt < 20f) { __instance.Alert(); var fleeFrom = m_attacker == null ? ___m_character.transform.position : m_attacker.transform.position; Invoke(__instance, "Flee", new object[] { dt, fleeFrom }); ___m_aiStatus = UpdateAiStatus(___m_nview, "Got hurt, flee!"); return(false); } else { m_attacker = null; Invoke(__instance, "SetAlerted", new object[] { false }); } if ((bool)__instance.GetFollowTarget()) { Invoke(__instance, "Follow", new object[] { __instance.GetFollowTarget(), dt }); ___m_aiStatus = UpdateAiStatus(___m_nview, "Follow"); Invoke(__instance, "SetAlerted", new object[] { false }); m_assignment[instanceId].Clear(); m_fetchitems[instanceId].Clear(); m_assigned[instanceId] = false; m_spottedItem[instanceId] = null; m_containers[instanceId].Clear(); m_searchcontainer[instanceId] = false; m_stateChangeTimer[instanceId] = 0; return(false); } if (AvoidFire(__instance, dt, m_assigned[instanceId] ? m_assignment[instanceId].Peek().Position : __instance.transform.position)) { ___m_aiStatus = UpdateAiStatus(___m_nview, "Avoiding fire"); if (m_assignment[instanceId].Any() && m_assignment[instanceId].Peek().IsClose(___m_character.transform.position)) { m_assigned[instanceId] = false; } return(false); } if (!__instance.IsAlerted() && (bool)Invoke(__instance, "UpdateConsumeItem", new object[] { ___m_character as Humanoid, dt })) { ___m_aiStatus = UpdateAiStatus(___m_nview, "Consume item"); return(false); } if (___m_tamable.IsHungry()) { ___m_aiStatus = UpdateAiStatus(___m_nview, "Is hungry, no work a do"); if (m_searchcontainer[instanceId] && m_containers[instanceId].Any()) { bool containerIsInvalid = m_containers[instanceId].Peek()?.GetComponent <ZNetView>()?.IsValid() == false; if (containerIsInvalid) { m_containers[instanceId].Pop(); m_searchcontainer[instanceId] = false; return(false); } bool isCloseToContainer = Vector3.Distance(greylingPosition, m_containers[instanceId].Peek().transform.position) < 1.5; if (!isCloseToContainer) { Invoke(__instance, "MoveAndAvoid", new object[] { dt, m_containers[instanceId].Peek().transform.position, 0.5f, false }); return(false); } else { ItemDrop foodItem = __instance.m_consumeItems.ElementAt <ItemDrop>(0); ItemDrop.ItemData item = m_containers[instanceId].Peek()?.GetInventory()?.GetItem(foodItem.m_itemData.m_shared.m_name); if (item == null) { ___m_aiStatus = UpdateAiStatus(___m_nview, "No Resin in chest"); Container nearbyChest = FindRandomNearbyContainer(greylingPosition, m_containers[instanceId]); if (nearbyChest != null) { m_containers[instanceId].Push(nearbyChest); m_searchcontainer[instanceId] = true; return(false); } else { m_containers[instanceId].Clear(); m_searchcontainer[instanceId] = false; return(false); } } else { ___m_aiStatus = UpdateAiStatus(___m_nview, "Resin in chest"); m_containers[instanceId].Peek().GetInventory().RemoveItem(item, 1); typeof(Container).GetMethod("Save", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(m_containers[instanceId].Peek(), new object[] { }); typeof(Inventory).GetMethod("Changed", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(m_containers[instanceId].Peek().GetInventory(), new object[] { }); __instance.m_onConsumedItem(foodItem); ___m_aiStatus = UpdateAiStatus(___m_nview, "Consume item"); m_assigned[instanceId] = false; m_spottedItem[instanceId] = null; m_searchcontainer[instanceId] = false; m_stateChangeTimer[instanceId] = 0; return(false); } } } else { Container nearbyChest = FindRandomNearbyContainer(greylingPosition, m_containers[instanceId]); if (nearbyChest != null) { m_containers[instanceId].Push(nearbyChest); m_searchcontainer[instanceId] = true; return(false); } else { m_searchcontainer[instanceId] = false; return(false); } } } // Here starts the fun. //Assigned timeout-function m_assignedTimer[instanceId] += dt; if (m_assignedTimer[instanceId] > GreylingsConfig.TimeLimitOnAssignment.Value) { m_assigned[instanceId] = false; } //Assignment timeout-function foreach (Assignment assignment in m_assignment[instanceId]) { assignment.AssignmentTime += dt; int multiplicator = 1; if (assignment.TypeOfAssignment.ComponentType == typeof(Fireplace)) { multiplicator = 3; } if (assignment.AssignmentTime > GreylingsConfig.TimeBeforeAssignmentCanBeRepeated.Value * multiplicator) { ___m_aiStatus = UpdateAiStatus(___m_nview, $"removing outdated Assignment of {m_assignment[instanceId].Count()}"); m_assignment[instanceId].Remove(assignment); ___m_aiStatus = UpdateAiStatus(___m_nview, $"remaining Assignments {m_assignment[instanceId].Count()}"); if (!m_assignment[instanceId].Any()) { m_assigned[instanceId] = false; } break; } } //stateChangeTimer Updated m_stateChangeTimer[instanceId] += dt; if (m_stateChangeTimer[instanceId] < 1) { return(false); } if (!m_assigned[instanceId]) { if (FindRandomNearbyAssignment(instanceId, greylingPosition)) { ___m_aiStatus = UpdateAiStatus(___m_nview, $"Doing assignment: {m_assignment[instanceId].Peek().TypeOfAssignment.Name}"); return(false); } else { //___m_aiStatus = UpdateAiStatus(___m_nview, $"No new assignments found"); m_assignment[instanceId].Clear(); } } if (m_assigned[instanceId]) { var humanoid = ___m_character as Humanoid; Assignment assignment = m_assignment[instanceId].Peek(); bool assignmentIsInvalid = assignment?.AssignmentObject?.GetComponent <ZNetView>()?.IsValid() == false; if (assignmentIsInvalid) { m_assignment[instanceId].Pop(); m_assigned[instanceId] = false; return(false); } bool knowWhattoFetch = m_fetchitems[instanceId].Any(); bool isCarryingItem = m_carrying[instanceId] != null; if ((!knowWhattoFetch || isCarryingItem) && !assignment.IsClose(greylingPosition)) { ___m_aiStatus = UpdateAiStatus(___m_nview, $"Move To Assignment: {assignment.TypeOfAssignment.Name} "); Invoke(__instance, "MoveAndAvoid", new object[] { dt, assignment.Position, 0.5f, false }); if (m_stateChangeTimer[instanceId] < 30) { return(false); } } bool isLookingAtAssignment = (bool)Invoke(__instance, "IsLookingAt", new object[] { assignment.Position, 20f }); if (isCarryingItem && assignment.IsClose(greylingPosition) && !isLookingAtAssignment) { ___m_aiStatus = UpdateAiStatus(___m_nview, $"Looking at Assignment: {assignment.TypeOfAssignment.Name} "); humanoid.SetMoveDir(Vector3.zero); Invoke(__instance, "LookAt", new object[] { assignment.Position }); return(false); } if (isCarryingItem && assignment.IsCloseEnough(greylingPosition)) { humanoid.SetMoveDir(Vector3.zero); var needFuel = assignment.NeedFuel; var needOre = assignment.NeedOre; bool isCarryingFuel = m_carrying[instanceId].m_shared.m_name == needFuel?.m_shared?.m_name; bool isCarryingMatchingOre = needOre?.Any(c => m_carrying[instanceId].m_shared.m_name == c?.m_shared?.m_name) ?? false; if (isCarryingFuel) { ___m_aiStatus = UpdateAiStatus(___m_nview, $"Unload to {assignment.TypeOfAssignment.Name} -> Fuel"); assignment.AssignmentObject.GetComponent <ZNetView>().InvokeRPC("AddFuel", new object[] { }); humanoid.GetInventory().RemoveOneItem(m_carrying[instanceId]); } else if (isCarryingMatchingOre) { ___m_aiStatus = UpdateAiStatus(___m_nview, $"Unload to {assignment.TypeOfAssignment.Name} -> Ore"); assignment.AssignmentObject.GetComponent <ZNetView>().InvokeRPC("AddOre", new object[] { GetPrefabName(m_carrying[instanceId].m_dropPrefab.name) }); humanoid.GetInventory().RemoveOneItem(m_carrying[instanceId]); } else { ___m_aiStatus = UpdateAiStatus(___m_nview, Localization.instance.Localize($"Dropping {m_carrying[instanceId].m_shared.m_name} on the ground")); humanoid.DropItem(humanoid.GetInventory(), m_carrying[instanceId], 1); } humanoid.UnequipItem(m_carrying[instanceId], false); m_carrying[instanceId] = null; m_fetchitems[instanceId].Clear(); m_stateChangeTimer[instanceId] = 0; return(false); } if (!knowWhattoFetch && assignment.IsCloseEnough(greylingPosition)) { humanoid.SetMoveDir(Vector3.zero); ___m_aiStatus = UpdateAiStatus(___m_nview, "Checking assignment for task"); var needFuel = assignment.NeedFuel; var needOre = assignment.NeedOre; Dbgl($"Ore:{needOre.Join(j => j.m_shared.m_name)}, Fuel:{needFuel?.m_shared.m_name}"); if (needFuel != null) { m_fetchitems[instanceId].Add(needFuel); ___m_aiStatus = UpdateAiStatus(___m_nview, Localization.instance.Localize($"Adding {needFuel.m_shared.m_name} to search list")); } if (needOre.Any()) { m_fetchitems[instanceId].AddRange(needOre); ___m_aiStatus = UpdateAiStatus(___m_nview, Localization.instance.Localize($"Adding {needOre.Join(o => o.m_shared.m_name)} to search list")); } if (!m_fetchitems[instanceId].Any()) { m_assigned[instanceId] = false; } m_stateChangeTimer[instanceId] = 0; return(false); } bool hasSpottedAnItem = m_spottedItem[instanceId] != null; bool searchForItemToPickup = knowWhattoFetch && !hasSpottedAnItem && !isCarryingItem && !m_searchcontainer[instanceId]; if (searchForItemToPickup) { ___m_aiStatus = UpdateAiStatus(___m_nview, "Search the ground for item to pickup"); ItemDrop spottedItem = GetNearbyItem(greylingPosition, m_fetchitems[instanceId], GreylingsConfig.ItemSearchRadius.Value); if (spottedItem != null) { m_spottedItem[instanceId] = spottedItem; m_stateChangeTimer[instanceId] = 0; return(false); } ___m_aiStatus = UpdateAiStatus(___m_nview, "Trying to remeber content of known Chests"); foreach (Container chest in m_containers[instanceId]) { foreach (var fetchItem in m_fetchitems[instanceId]) { ItemDrop.ItemData item = chest?.GetInventory()?.GetItem(fetchItem.m_shared.m_name); if (item == null) { continue; } else { ___m_aiStatus = UpdateAiStatus(___m_nview, "Item found in old chest"); m_containers[instanceId].Remove(chest); m_containers[instanceId].Push(chest); m_searchcontainer[instanceId] = true; m_stateChangeTimer[instanceId] = 0; return(false); } } } ___m_aiStatus = UpdateAiStatus(___m_nview, "Search for nerby Chests"); Container nearbyChest = FindRandomNearbyContainer(greylingPosition, m_containers[instanceId]); if (nearbyChest != null) { ___m_aiStatus = UpdateAiStatus(___m_nview, "Chest found"); m_containers[instanceId].Push(nearbyChest); m_searchcontainer[instanceId] = true; m_stateChangeTimer[instanceId] = 0; return(false); } } if (m_searchcontainer[instanceId]) { bool containerIsInvalid = m_containers[instanceId].Peek()?.GetComponent <ZNetView>()?.IsValid() == false; if (containerIsInvalid) { m_containers[instanceId].Pop(); m_searchcontainer[instanceId] = false; return(false); } bool isCloseToContainer = Vector3.Distance(greylingPosition, m_containers[instanceId].Peek().transform.position) < 1.5; if (!isCloseToContainer) { ___m_aiStatus = UpdateAiStatus(___m_nview, "Heading to Container"); Invoke(__instance, "MoveAndAvoid", new object[] { dt, m_containers[instanceId].Peek().transform.position, 0.5f, false }); return(false); } else { humanoid.SetMoveDir(Vector3.zero); ___m_aiStatus = UpdateAiStatus(___m_nview, $"Chest inventory:{m_containers[instanceId].Peek()?.GetInventory().GetAllItems().Join(i => i.m_shared.m_name)} from Chest "); var wantedItemsInChest = m_containers[instanceId].Peek()?.GetInventory()?.GetAllItems()?.Where(i => m_fetchitems[instanceId].Contains(i)); foreach (var fetchItem in m_fetchitems[instanceId]) { ItemDrop.ItemData item = m_containers[instanceId].Peek()?.GetInventory()?.GetItem(fetchItem.m_shared.m_name); if (item == null) { continue; } else { ___m_aiStatus = UpdateAiStatus(___m_nview, $"Trying to Pickup {item} from Chest "); var pickedUpInstance = humanoid.PickupPrefab(item.m_dropPrefab); humanoid.GetInventory().Print(); humanoid.EquipItem(pickedUpInstance); m_containers[instanceId].Peek().GetInventory().RemoveItem(item, 1); typeof(Container).GetMethod("Save", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(m_containers[instanceId].Peek(), new object[] { }); typeof(Inventory).GetMethod("Changed", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(m_containers[instanceId].Peek().GetInventory(), new object[] { }); m_carrying[instanceId] = pickedUpInstance; m_spottedItem[instanceId] = null; m_fetchitems[instanceId].Clear(); m_searchcontainer[instanceId] = false; m_stateChangeTimer[instanceId] = 0; return(false); } } m_searchcontainer[instanceId] = false; m_stateChangeTimer[instanceId] = 0; return(false); } } if (hasSpottedAnItem) { bool isNotCloseToPickupItem = Vector3.Distance(greylingPosition, m_spottedItem[instanceId].transform.position) > 1; if (isNotCloseToPickupItem) { ___m_aiStatus = UpdateAiStatus(___m_nview, "Heading to pickup item"); Invoke(__instance, "MoveAndAvoid", new object[] { dt, m_spottedItem[instanceId].transform.position, 0.5f, false }); return(false); } else // Pickup item from ground { humanoid.SetMoveDir(Vector3.zero); ___m_aiStatus = UpdateAiStatus(___m_nview, $"Trying to Pickup {m_spottedItem[instanceId].gameObject.name}"); var pickedUpInstance = humanoid.PickupPrefab(m_spottedItem[instanceId].m_itemData.m_dropPrefab); humanoid.GetInventory().Print(); humanoid.EquipItem(pickedUpInstance); if (m_spottedItem[instanceId].m_itemData.m_stack == 1) { if (___m_nview.GetZDO() == null) { Destroy(m_spottedItem[instanceId].gameObject); } else { ZNetScene.instance.Destroy(m_spottedItem[instanceId].gameObject); } } else { m_spottedItem[instanceId].m_itemData.m_stack--; Traverse.Create(m_spottedItem[instanceId]).Method("Save").GetValue(); } m_carrying[instanceId] = pickedUpInstance; m_spottedItem[instanceId] = null; m_fetchitems[instanceId].Clear(); m_stateChangeTimer[instanceId] = 0; return(false); } } ___m_aiStatus = UpdateAiStatus(___m_nview, $"Done with assignment"); if (m_carrying[instanceId] != null) { humanoid.UnequipItem(m_carrying[instanceId], false); m_carrying[instanceId] = null; ___m_aiStatus = UpdateAiStatus(___m_nview, $"Dropping unused item"); } m_fetchitems[instanceId].Clear(); m_spottedItem[instanceId] = null; m_containers[instanceId].Clear(); m_searchcontainer[instanceId] = false; m_assigned[instanceId] = false; m_stateChangeTimer[instanceId] = 0; return(false); } ___m_aiStatus = UpdateAiStatus(___m_nview, "Random movement (No new assignments found)"); typeof(MonsterAI).GetMethod("IdleMovement", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(__instance, new object[] { dt }); return(false); }