using System; using System.Collections.Generic; using Oxide.Core; using UnityEngine; using System.Reflection; using System.Linq; using Oxide.Core.Configuration; using Oxide.Core.Plugins; using Oxide.Plugins; using Oxide.Core.Libraries; using Newtonsoft.Json; using System.Globalization; namespace Oxide.Plugins { [Info("HooksExtended", "Calytic @ RustServers.IO", "0.0.12", ResourceId = 2239)] public class HooksExtended : RustPlugin { #region Variables private List WoodMaterial = new List() { 3655341 }; private List RockMaterial = new List() { 3506021, 3712324229 }; private List MetalMaterial = new List() { 103787271, 4214819287 }; private List SnowMaterial = new List() { 3535235 }; private List GrassMaterial = new List() { 98615734 }; private List SandMaterial = new List() { 3522692 }; private Vector3 eyesPosition = new Vector3(0f, 0.5f, 0f); private static readonly FieldInfo modelStateField = typeof(BasePlayer).GetField("modelState", BindingFlags.Instance | BindingFlags.NonPublic); private static int playerLayer = LayerMask.GetMask("Player (Server)"); private static int useLayer = LayerMask.GetMask(new string[] { "Player (Server)", "Construction", "Deployed", "Tree", "Resource", "Terrain" }); private readonly FieldInfo serverinput = typeof(BasePlayer).GetField("serverInput", (BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic)); private List inputCooldown = new List(); private Dictionary> spotCooldown = new Dictionary>(); int spottingMask = LayerMask.GetMask(new string[] { "Player (Server)", "AI" }); public PluginSettings settings; [OnlinePlayers] Hash onlinePlayers = new Hash(); #endregion #region Boilerplate class PlayerProfile { public BasePlayer Player; public ProfileMetabolism Metabolism; private ModelState _modelState; public ModelState modelState { get { if (_modelState is ModelState) { return _modelState; } return _modelState = (ModelState)modelStateField.GetValue(this.Player); } } public bool wasDucked; public bool wasDrowning; public bool wasSprinting; public Item activeItem; } class ProfileMetabolism { public enum MetaAction { Start, Stop } float wetness; float radiation_poison; float radiation_level; float poison; float comfort; float bleeding; float oxygen; public ProfileMetabolism(PlayerMetabolism metabolism) { this.Set(metabolism); } private void Set(PlayerMetabolism metabolism) { this.wetness = metabolism.wetness.value; this.radiation_poison = metabolism.radiation_poison.value; this.radiation_level = metabolism.radiation_level.value; this.poison = metabolism.poison.value; this.comfort = metabolism.comfort.value; this.bleeding = metabolism.bleeding.value; } public Dictionary DetectChange(PlayerMetabolism metabolism) { Dictionary actions = new Dictionary(); if (metabolism.wetness.value != wetness) { if (metabolism.wetness.value == metabolism.wetness.min) { actions.Add("Wetness", MetaAction.Stop); } else if (wetness == metabolism.wetness.min) { actions.Add("Wetness", MetaAction.Start); } } if (metabolism.poison.value != poison) { if (metabolism.poison.value == metabolism.poison.min) { actions.Add("Poison", MetaAction.Stop); } else if (poison == metabolism.poison.min) { actions.Add("Poison", MetaAction.Start); } } if (metabolism.oxygen.value != oxygen) { if (metabolism.oxygen.value == metabolism.oxygen.min) { actions.Add("Drowning", MetaAction.Stop); } else if (oxygen == metabolism.oxygen.min) { actions.Add("Drowning", MetaAction.Start); } } if (metabolism.radiation_level.value != radiation_level) { if (metabolism.radiation_level.value == metabolism.radiation_level.min) { actions.Add("Radiation", MetaAction.Stop); } else if (radiation_level == metabolism.radiation_level.min) { actions.Add("Radiation", MetaAction.Start); } } if (metabolism.radiation_poison.value != radiation_poison) { if (metabolism.radiation_poison.value == metabolism.radiation_poison.min) { actions.Add("RadiationPoison", MetaAction.Stop); } else if (radiation_poison == metabolism.radiation_poison.min) { actions.Add("RadiationPoison", MetaAction.Start); } } if (metabolism.comfort.value != comfort) { if (metabolism.comfort.value == metabolism.comfort.min) { actions.Add("Comfort", MetaAction.Stop); } else if (comfort == metabolism.comfort.min) { actions.Add("Comfort", MetaAction.Start); } } if (metabolism.bleeding.value != bleeding) { if (metabolism.bleeding.value == metabolism.bleeding.min) { actions.Add("Bleeding", MetaAction.Stop); } else if (bleeding == metabolism.bleeding.min) { actions.Add("Bleeding", MetaAction.Start); } } this.Set(metabolism); return actions; } } public class PluginSettings { public HookSettings HookSettings; public string VERSION; } public class HookSettings { public bool OnPlayerTick = false; public bool OnPlayerAttack = false; public bool OnRunPlayerMetabolism = false; public bool OnItemDeployed = false; public bool OnEntityTakeDamage = false; public bool OnConsumeFuel = false; public bool OnEntityDeath = false; public bool OnItemAddedToContainer = false; public bool OnItemRemovedFromContainer = false; public bool OnPlayerInput = false; public bool OnItemCraft = false; public bool OnItemCraftCancelled = false; public bool OnItemCraftFinished = false; public bool OnEntitySpawned = false; } #endregion #region Initialization & Configuration void Init() { UnsubscribeHooks(); } void OnServerInitialized() { if (settings == null) { LoadConfigValues(); } SubscribeHooks(); } void UnsubscribeHooks() { Unsubscribe(nameof(OnPlayerTick)); Unsubscribe(nameof(OnPlayerAttack)); Unsubscribe(nameof(OnRunPlayerMetabolism)); Unsubscribe(nameof(OnItemDeployed)); Unsubscribe(nameof(OnEntityTakeDamage)); Unsubscribe(nameof(OnConsumeFuel)); Unsubscribe(nameof(OnEntityDeath)); Unsubscribe(nameof(OnItemAddedToContainer)); Unsubscribe(nameof(OnItemRemovedFromContainer)); Unsubscribe(nameof(OnPlayerInput)); Unsubscribe(nameof(OnItemCraft)); Unsubscribe(nameof(OnItemCraftCancelled)); Unsubscribe(nameof(OnItemCraftFinished)); Unsubscribe(nameof(OnEntitySpawned)); } void SubscribeHooks() { if (settings == null) { PrintError("Settings invalid"); return; } if (settings.HookSettings == null) { PrintError("Hook Settings invalid"); return; } if (settings.HookSettings.OnPlayerTick) Subscribe(nameof(OnPlayerTick)); if (settings.HookSettings.OnPlayerAttack) Subscribe(nameof(OnPlayerAttack)); if (settings.HookSettings.OnRunPlayerMetabolism) Subscribe(nameof(OnRunPlayerMetabolism)); if (settings.HookSettings.OnItemDeployed) Subscribe(nameof(OnItemDeployed)); if (settings.HookSettings.OnEntityTakeDamage) Subscribe(nameof(OnEntityTakeDamage)); if (settings.HookSettings.OnConsumeFuel) Subscribe(nameof(OnConsumeFuel)); if (settings.HookSettings.OnEntityDeath) Subscribe(nameof(OnEntityDeath)); if (settings.HookSettings.OnItemAddedToContainer) Subscribe(nameof(OnItemAddedToContainer)); if (settings.HookSettings.OnItemRemovedFromContainer) Subscribe(nameof(OnItemRemovedFromContainer)); if (settings.HookSettings.OnPlayerInput) Subscribe(nameof(OnPlayerInput)); if (settings.HookSettings.OnItemCraft) Subscribe(nameof(OnItemCraft)); if (settings.HookSettings.OnItemCraftCancelled) Subscribe(nameof(OnItemCraftCancelled)); if (settings.HookSettings.OnItemCraftFinished) Subscribe(nameof(OnItemCraftFinished)); if (settings.HookSettings.OnEntitySpawned) Subscribe(nameof(OnEntitySpawned)); } void EnableHook(string hookName, bool save = true) { ConfigureHook(hookName, true, save); } void EnableHooks(params string[] hookNames) { foreach (string hookName in hookNames) { EnableHook(hookName, false); } SaveSettings(); UnsubscribeHooks(); SubscribeHooks(); } void DisableHook(string hookName, bool save = true) { ConfigureHook(hookName, false, save); } void DisableHooks(params string[] hookNames) { foreach (string hookName in hookNames) { DisableHook(hookName, false); } SaveSettings(); UnsubscribeHooks(); SubscribeHooks(); } void ConfigureHook(string hookName, bool setting, bool save = true) { switch (hookName) { case "OnPlayerTick": settings.HookSettings.OnPlayerTick = setting; break; case "OnPlayerAttack": settings.HookSettings.OnPlayerAttack = setting; break; case "OnRunPlayerMetabolism": settings.HookSettings.OnRunPlayerMetabolism = setting; break; case "OnItemDeployed": settings.HookSettings.OnItemDeployed = setting; break; case "OnEntityTakeDamage": settings.HookSettings.OnEntityTakeDamage = setting; break; case "OnConsumeFuel": settings.HookSettings.OnConsumeFuel = setting; break; case "OnEntityDeath": settings.HookSettings.OnEntityDeath = setting; break; case "OnItemAddedToContainer": settings.HookSettings.OnItemAddedToContainer = setting; break; case "OnItemRemovedFromContainer": settings.HookSettings.OnItemRemovedFromContainer = setting; break; case "OnPlayerInput": settings.HookSettings.OnPlayerInput = setting; break; case "OnItemCraft": settings.HookSettings.OnItemCraft = setting; break; case "OnItemCraftCancelled": settings.HookSettings.OnItemCraftCancelled = setting; break; case "OnItemCraftFinished": settings.HookSettings.OnItemCraftFinished = setting; break; case "OnEntitySpawned": settings.HookSettings.OnEntitySpawned = setting; break; } if (save) { SaveSettings(); UnsubscribeHooks(); SubscribeHooks(); } } protected override void LoadDefaultConfig() { settings = new PluginSettings() { HookSettings = new HookSettings(), VERSION = Version.ToString() }; SaveSettings(); } protected void SaveSettings() { Config.WriteObject(settings, true); } void LoadConfigValues() { settings = Config.ReadObject(); } #endregion #region Console Commands [ConsoleCommand("hookx")] void ccHooksExtendedStatus(ConsoleSystem.Arg arg) { if (arg.Connection == null) { if (arg.Args == null) { Puts("Hook Configuration:"); foreach (var prop in typeof(HookSettings).GetFields()) { var val = prop.GetValue(settings.HookSettings); if(val == null) { val = false; } Puts("{0} = {1}", prop.Name, val); } } else if (arg.Args.Length > 0) { var cmd = arg.Args[0]; UnsubscribeHooks(); switch (cmd) { case "enable": foreach (var prop in typeof(HookSettings).GetFields()) { prop.SetValue(settings.HookSettings, true); } Puts("All hooks enabled"); break; case "disable": foreach (var prop in typeof(HookSettings).GetFields()) { prop.SetValue(settings.HookSettings, false); } Puts("All hooks disabled"); break; } SubscribeHooks(); } } } #endregion #region Extended Hooks /// /// ON CATEGORY CRAFT /// /// /// private object OnItemCraft(ItemCraftTask task) { string category = task.blueprint.targetItem.category.ToString(); return Interface.Oxide.CallHook("On" + category + "Craft", task); } /// /// ON CATEGORY CRAFT CANCELLED /// /// private void OnItemCraftCancelled(ItemCraftTask task) { string category = task.blueprint.targetItem.category.ToString(); Interface.Oxide.CallHook("On" + category + "CraftCancelled", task); } /// /// ON CATEGORY CRAFT FINISHED /// /// /// private void OnItemCraftFinished(ItemCraftTask task, Item item) { string category = item.info.category.ToString(); Interface.Oxide.CallHook("On" + category + "CraftFinished", task, item); } /// /// ON ACTIVATE /// ON DEACTIVATE /// ON DUCK /// ON STAND /// ON BEGIN SPRINT /// ON END SPRINT /// /// private void OnPlayerTick(BasePlayer player) { PlayerProfile profile; if (!TryGetPlayer(player, out profile)) { return; } Item item = player.GetActiveItem(); if (item != null && item != profile.activeItem) { Interface.CallHook("OnItemActivate", player, item); profile.activeItem = item; } else if (item == null) { if (profile.activeItem != null) { Interface.CallHook("OnItemDeactivate", player, item); } profile.activeItem = item; } if (player.IsDucked()) { if (!profile.wasDucked) { profile.wasDucked = true; Interface.CallHook("OnPlayerDuck", player); } } else { if (profile.wasDucked) { profile.wasDucked = false; Interface.CallHook("OnPlayerStand", player); } } if (player.IsRunning()) { if (!profile.wasSprinting) { profile.wasSprinting = true; Interface.CallHook("OnStartSprint", player); } } else { if (profile.wasSprinting) { profile.wasSprinting = false; Interface.CallHook("OnStopSprint", player); } } } /// /// ON HIT RESOURCE /// ON HIT WOOD /// ON HIT ROCK /// /// /// private void OnPlayerAttack(BasePlayer attacker, HitInfo info) { if (info.Weapon == null) { return; } if (info.HitEntity != null) { var resourceDispenser = info.HitEntity.GetComponentInParent(); if (resourceDispenser != null) { Interface.CallHook("OnHitResource", attacker, info); return; } if (info.HitEntity.name.Contains("junkpile")) { Interface.CallHook("OnHitJunk", attacker, info); return; } } if (WoodMaterial.Contains(info.HitMaterial)) { Interface.CallHook("OnHitWood", attacker, info); } else if (RockMaterial.Contains(info.HitMaterial)) { Interface.CallHook("OnHitRock", attacker, info); } else if (MetalMaterial.Contains(info.HitMaterial)) { Interface.CallHook("OnHitMetal", attacker, info); } else if (SnowMaterial.Contains(info.HitMaterial)) { Interface.CallHook("OnHitSnow", attacker, info); } else if (GrassMaterial.Contains(info.HitMaterial)) { Interface.CallHook("OnHitGrass", attacker, info); } else if (SandMaterial.Contains(info.HitMaterial)) { Interface.CallHook("OnHitSand", attacker, info); } } /// /// ON START WETNESS /// ON STOP WETNESS /// ON START POISON /// ON STOP POISON /// ON START RADIATION /// ON STOP RADIATION /// ON START RADIATION POISON /// ON STOP RADIATION POISON /// ON START COMFORT /// ON STOP COMFORT /// ON START BLEEDING /// ON STOP BLEEDING /// /// /// private void OnRunPlayerMetabolism(PlayerMetabolism metabolism, BaseCombatEntity source) { if (source is BasePlayer) { BasePlayer player = (BasePlayer)source; PlayerProfile profile; if (onlinePlayers.TryGetValue(player, out profile)) { if (profile.Metabolism == null) { profile.Metabolism = new ProfileMetabolism(metabolism); return; } Dictionary changes = profile.Metabolism.DetectChange(metabolism); foreach(KeyValuePair kvp in changes) { if (kvp.Value == ProfileMetabolism.MetaAction.Start) { Interface.CallHook("OnStart" + kvp.Key, player); } else { Interface.CallHook("OnStop" + kvp.Key, player); } } } } } /// /// ON CUPBOARD DEPLOYED /// ON TURRET DEPLOYED /// ON DOOR DEPLOYED /// ON SLEEPING BAG DEPLOYED /// ON STOCKING DEPLOYED /// ON BARRICADE DEPLOYED /// ON CONTAINER DEPLOYED /// ON SIGN DEPLOYED /// ON FURNACE DEPLOYED /// ON CAMPFIRE DEPLOYED /// ON LIGHT DEPLOYED /// /// /// private void OnItemDeployed(Deployer deployer, BaseEntity entity) { BasePlayer player = deployer.GetOwnerPlayer(); if (entity is BuildingPrivlidge) { Interface.Oxide.CallHook("OnCupboardDeployed", player, deployer, entity); } else if (entity is AutoTurret) { Interface.Oxide.CallHook("OnTurretDeployed", player, deployer, entity); } else if (entity is Door) { Interface.Oxide.CallHook("OnDoorDeployed", player, deployer, entity); } else if (entity is SleepingBag) { Interface.Oxide.CallHook("OnSleepingBagDeployed", player, deployer, entity); } else if (entity is Stocking) { Interface.Oxide.CallHook("OnStockingDeployed", player, deployer, entity); } else if (entity is Barricade) { Interface.Oxide.CallHook("OnBarricadeDeployed", player, deployer, entity); } else if (entity is StorageContainer) { Interface.Oxide.CallHook("OnContainerDeployed", player, deployer, entity); } else if (entity is Signage) { Interface.Oxide.CallHook("OnSignDeployed", player, deployer, entity); } else if (entity is BaseOven) { if (entity.name.Contains("furnace")) { Interface.Oxide.CallHook("OnFurnaceDeployed", player, deployer, entity); } else if (entity.name.Contains("campfire")) { Interface.Oxide.CallHook("OnCampfireDeployed", player, deployer, entity); } else if (entity is CeilingLight || entity.name.Contains("lantern")) { Interface.Oxide.CallHook("OnLightDeployed", player, deployer, entity); } } } /// /// ON ANIMAL ATTACK /// ON HELICOPTER ATTACK /// ON STRUCTURE DAMAGE /// ON PLAYER DAMAGE /// ON TURRET DAMAGE /// ON HELICOPTER DAMAGE /// ON CUPBOARD DAMAGE /// ON CORPSE DAMAGE /// ON SLEEPING BAG DAMAGE /// ON NPC DAMAGE /// /// /// private void OnEntityTakeDamage(BaseCombatEntity entity, HitInfo info) { if (info.Initiator != null && info.Initiator is BaseNpc) { Interface.CallHook("OnAnimalAttack", entity, (BaseNpc)info.Initiator, info); } if (info.Initiator != null && info.Initiator.name.Contains("patrolhelicopter.prefab") && !info.Initiator.name.Contains("gibs")) { Interface.CallHook("OnHelicopterAttack", entity, info.Initiator, info); } if (entity is BuildingBlock) { Interface.CallHook("OnStructureDamage", (BuildingBlock)entity, info); } else if (entity is BasePlayer) { Interface.CallHook("OnPlayerDamage", (BasePlayer)entity, info); } else if (entity is AutoTurret) { Interface.CallHook("OnTurretDamage", (AutoTurret)entity, info); } else if (entity is BaseHelicopter) { Interface.CallHook("OnHelicopterDamage", (BaseHelicopter)entity, info); } else if (entity is BuildingPrivlidge) { Interface.CallHook("OnCupboardDamage", (BuildingPrivlidge)entity, info); } else if (entity is BaseCorpse) { Interface.CallHook("OnCorpseDamage", (BaseCorpse)entity, info); } else if (entity is SleepingBag) { Interface.CallHook("OnSleepingBagDamage", (SleepingBag)entity, info); } else if (entity is BaseNpc) { Interface.CallHook("OnNPCDamage", (BaseNpc)entity, info); } } private void OnEntitySpawned(BaseNetworkable entity) { if (entity is SupplyDrop) { Interface.Oxide.CallHook("OnSupplyDropSpawned", entity); } else if (entity is BaseHelicopter) { Interface.Oxide.CallHook("OnHelicopterSpawned", entity); } else if (entity is HelicopterDebris) { Interface.Oxide.CallHook("OnHelicopterDebrisSpawned", entity); } else if (entity is BaseNpc) { Interface.Oxide.CallHook("OnNPCSpawned", entity); } else if (entity is LootContainer) { Interface.Oxide.CallHook("OnLootContainerSpawned", entity); } else if (entity is BuildingPrivlidge) { Interface.Oxide.CallHook("OnCupboardSpawned", entity); } else if (entity is AutoTurret) { Interface.Oxide.CallHook("OnTurretSpawned", entity); } } /// /// ON COOK FURNACE /// ON COOK FIRE /// ON FUEL LIGHT /// /// /// /// private void OnConsumeFuel(BaseOven oven, Item fuel, ItemModBurnable burnable) { if (oven.name.Contains("furnace")) { Interface.CallHook("OnCookFurnace", oven, fuel, burnable); } else if (oven.name.Contains("campfire")) { Interface.CallHook("OnCookFire", oven, fuel, burnable); } else if (oven.name.Contains("light") || oven.name.Contains("lantern")) { Interface.CallHook("OnFuelLight", oven, fuel, burnable); } } /// /// ON STRUCTURE DEATH /// ON PLAYER DEATH /// ON TURRET DEATH /// ON HELICOPTER DEATH /// ON CUPBOARD DEATH /// ON SLEEPING BAG DEATH /// ON NPC DEATH /// /// /// private void OnEntityDeath(BaseCombatEntity entity, HitInfo info) { if (entity is BuildingBlock) { Interface.CallHook("OnStructureDeath", (BuildingBlock)entity, info); } else if (entity is BasePlayer) { Interface.CallHook("OnPlayerDeath", (BasePlayer)entity, info); } else if (entity is AutoTurret) { Interface.CallHook("OnTurretDeath", (AutoTurret)entity, info); } else if (entity is BaseHelicopter) { Interface.CallHook("OnHelicopterDeath", (BaseHelicopter)entity, info); } else if (entity is BuildingPrivlidge) { Interface.CallHook("OnCupboardDeath", (BuildingPrivlidge)entity, info); } else if (entity is BaseCorpse) { Interface.CallHook("OnCorpseDeath", (BaseCorpse)entity, info); } else if (entity is SleepingBag) { Interface.CallHook("OnSleepingBagDeath", (SleepingBag)entity, info); } else if (entity is BaseNpc) { Interface.CallHook("OnNPCDeath", (BaseNpc)entity, info); } } /// /// ON EQUIP /// /// /// private void OnItemAddedToContainer(ItemContainer container, Item item) { BasePlayer player = container.playerOwner; if (!(player is BasePlayer)) { return; } if (player.inventory.containerWear == container) { Interface.CallHook("OnEquip", player, item); } else if (player.inventory.containerBelt == container && item.CanBeHeld()) { Interface.CallHook("OnEquip", player, item); } } /// /// ON UNEQUIP /// /// /// private void OnItemRemovedFromContainer(ItemContainer container, Item item) { BasePlayer player = container.playerOwner; if (!(player is BasePlayer)) { return; } if (player.inventory.containerWear == container) { Interface.CallHook("OnUnequip", player, item); } else if (player.inventory.containerBelt == container && item.CanBeHeld()) { Interface.CallHook("OnUnequip", player, item); } } /// /// ON SPOT PLAYER /// ON SPOT NPC /// ON SPOT TURRET /// ON SPOT HELICOPTER /// ON SPOT RESOURCE /// ON USE PLAYER /// ON USE TERRAIN /// ON USE NPC /// ON USE BUILDING /// ON USE CUPBOARD /// ON USE SLEEPINGBAG /// ON USE PLANT /// ON USE RESOURCE /// /// /// void OnPlayerInput(BasePlayer player, InputState input) { if (input.IsDown(BUTTON.FIRE_SECONDARY) && !this.inputCooldown.Contains(player)) { TriggerSpotting(player, input); } if (input.WasJustPressed(BUTTON.USE)) { TriggerUse(player, input); } if (input.WasJustPressed(BUTTON.JUMP)) { Interface.Oxide.CallHook("OnPlayerJump", player); } } #endregion #region Helpers void TriggerUse(BasePlayer player, InputState input) { Quaternion currentRot; TryGetPlayerView(player, out currentRot); var hitpoints = Physics.RaycastAll(new Ray(player.eyes.position, currentRot * Vector3.forward), 5f, useLayer, QueryTriggerInteraction.Collide); GamePhysics.Sort(hitpoints); for (var i = 0; i < hitpoints.Length; i++) { var hit = hitpoints[i]; var target = hit.collider; if (target.name == "Terrain") { Interface.Oxide.CallHook("OnUseTerrain", player, target); return; } if (target.name == "MeshColliderBatch") { target = RaycastHitEx.GetCollider(hit); } BaseEntity targetEntity; ResourceDispenser targetDispenser; if ((targetEntity = target.GetComponentInParent()) != null) { Interface.Oxide.CallHook("OnUsePlayer", player, targetEntity); break; } else if ((targetEntity = target.GetComponentInParent()) != null) { Interface.Oxide.CallHook("OnUseNPC", player, targetEntity); break; } else if ((targetEntity = target.GetComponentInParent()) != null) { Interface.Oxide.CallHook("OnUseBuilding", player, targetEntity); break; } else if ((targetEntity = target.GetComponentInParent()) != null) { Interface.Oxide.CallHook("OnUseSleepingBag", player, targetEntity); break; } else if ((targetEntity = target.GetComponentInParent()) != null) { Interface.Oxide.CallHook("OnUsePlant", player, targetEntity); break; } else if ((targetDispenser = target.GetComponentInParent()) != null) { Interface.Oxide.CallHook("OnUseResource", player, targetDispenser); break; } } } void TriggerSpotting(BasePlayer player, InputState input) { Item activeItem = player.GetActiveItem(); if (activeItem == null) { return; } if (activeItem.info.category != ItemCategory.Weapon) { return; } this.inputCooldown.Add(player); bool spot = false; RaycastHit hit; if (Physics.Raycast(player.eyes.position, Quaternion.Euler(input.current.aimAngles) * Vector3.forward, out hit, 2000, spottingMask)) { BaseEntity hitEntity = hit.GetEntity(); ResourceDispenser dispenser = hitEntity.GetComponentInParent(); if(hitEntity == null) { return; } if (hitEntity is BasePlayer) { spot = true; } else if (hitEntity is BaseNpc) { spot = true; } else if (hitEntity is AutoTurret) { spot = true; } else if (hitEntity is BaseHelicopter) { spot = true; } else if (dispenser is ResourceDispenser) { spot = true; } if (spot) { SpotTarget(player, hitEntity); } } timer.Once(1, delegate() { this.inputCooldown.Remove(player); }); } void SpotTarget(BasePlayer player, BaseEntity hitEntity) { MonoBehaviour target = hitEntity as MonoBehaviour; ResourceDispenser dispenser = hitEntity.GetComponentInParent(); float distanceTo = player.Distance(hitEntity); if (!spotCooldown.ContainsKey(player)) { spotCooldown.Add(player, new List()); } if (!spotCooldown[player].Contains(target)) { spotCooldown[player].Add(target); if (hitEntity is BaseNpc) { Interface.Oxide.CallHook("OnSpotNPC", player, hitEntity, distanceTo); } else if (hitEntity is BasePlayer) { Interface.Oxide.CallHook("OnSpotPlayer", player, hitEntity, distanceTo); } else if (hitEntity is AutoTurret) { Interface.Oxide.CallHook("OnSpotTurret", player, hitEntity, distanceTo); } else if (hitEntity is BaseHelicopter) { Interface.Oxide.CallHook("OnSpotHelicopter", player, hitEntity, distanceTo); } else if (dispenser is ResourceDispenser) { Interface.Oxide.CallHook("OnSpotResource", player, hitEntity, distanceTo); } timer.Once(6, delegate() { this.spotCooldown[player].Remove(target); }); } } bool TryGetPlayer(BasePlayer player, out PlayerProfile profile) { return onlinePlayers.TryGetValue(player, out profile); } bool TryGetPlayerView(BasePlayer player, out Quaternion viewAngle) { viewAngle = new Quaternion(0f, 0f, 0f, 0f); var input = serverinput.GetValue(player) as InputState; if (input.current == null) return false; viewAngle = Quaternion.Euler(input.current.aimAngles); return true; } #endregion } }