C#:
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("Custom Homing Target", "BadCop23", "1.1.0")]
public class CustomHomingTarget : RustPlugin
{
private ConfigData configData;
private readonly HashSet<string> _exactPrefabs = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
private readonly List<string> _directoryPrefixes = new List<string>();
#region config
//added directory function if i want to cover multiple prefabs eg under vehicle module entities to target any of them rather than listing individually.
private class ConfigData
{
[JsonProperty("Target Prefabs")]
public List<PrefabEntry> TargetPrefabs { get; set; } = new List<PrefabEntry>();
}
private class PrefabEntry
{
[JsonProperty("Path")]
public string Path { get; set; }
[JsonProperty("Is Directory")]
public bool IsDirectory { get; set; }
}
protected override void LoadDefaultConfig()
{
PrintWarning("Creating a new config.");
configData = new ConfigData
{
TargetPrefabs = new List<PrefabEntry>
{
new PrefabEntry { Path = "assets/content/vehicles/boats/tugboat/tugboat.prefab", IsDirectory = false },
new PrefabEntry { Path = "assets/content/vehicles/boats/rowboat/rowboat.prefab", IsDirectory = false },
new PrefabEntry { Path = "assets/content/vehicles/boats/rhib/rhib.prefab", IsDirectory = false },
new PrefabEntry { Path = "assets/prefabs/npc/m2bradley/bradleyapc.prefab", IsDirectory = false },
// new PrefabEntry { Path = "assets/content/vehicles/modularcar/module_entities/", IsDirectory = true }
}
};
SaveConfig();
}
protected override void LoadConfig()
{
base.LoadConfig();
try
{
configData = Config.ReadObject<ConfigData>();
if (configData == null)
throw new Exception();
}
catch
{
PrintWarning("Config load failed, recreating.");
LoadDefaultConfig();
}
ValidateConfig();
BuildPrefabCaches();
SaveConfig();
}
protected override void SaveConfig()
{
Config.WriteObject(configData, true);
}
private void ValidateConfig()
{
if (configData.TargetPrefabs == null)
configData.TargetPrefabs = new List<PrefabEntry>();
}
private void BuildPrefabCaches()
{
_exactPrefabs.Clear();
_directoryPrefixes.Clear();
for (int i = 0; i < configData.TargetPrefabs.Count; i++)
{
PrefabEntry entry = configData.TargetPrefabs[i];
if (entry == null || string.IsNullOrWhiteSpace(entry.Path))
continue;
string path = formatthepath(entry.Path);
if (entry.IsDirectory)
{
if (!path.EndsWith("/", StringComparison.Ordinal))
path += "/";
_directoryPrefixes.Add(path);
}
else
{
_exactPrefabs.Add(path);
}
}
}
private static string formatthepath(string path)
{
return path?.Trim();
}
#endregion
#region hooks
private void OnServerInitialized()
{
foreach (BaseNetworkable networkable in BaseNetworkable.serverEntities)
{
BaseEntity entity = networkable as BaseEntity;
if (entity == null)
continue;
string prefabName = entity.PrefabName;
if (string.IsNullOrEmpty(prefabName))
continue;
if (!IsTargetPrefab(prefabName))
continue;
RegisterCustomHomingTarget(entity);
}
}
private void OnEntitySpawned(BaseNetworkable networkable)
{
BaseEntity entity = networkable as BaseEntity;
if (entity == null)
return;
string prefabName = entity.PrefabName;
if (string.IsNullOrEmpty(prefabName))
return;
if (!IsTargetPrefab(prefabName))
return;
RegisterCustomHomingTarget(entity);
}
private void Unload()
{
foreach (BaseNetworkable networkable in BaseNetworkable.serverEntities)
{
BaseEntity entity = networkable as BaseEntity;
if (entity == null)
continue;
CustomHomingTargetComponent component = entity.GetComponent<CustomHomingTargetComponent>();
if (component == null)
continue;
UnityEngine.Object.Destroy(component);
}
}
#endregion
#region helpers
private bool IsTargetPrefab(string prefabName)
{
if (_exactPrefabs.Contains(prefabName))
return true;
for (int i = 0; i < _directoryPrefixes.Count; i++)
{
if (prefabName.StartsWith(_directoryPrefixes[i], StringComparison.OrdinalIgnoreCase))
return true;
}
return false;
}
private void RegisterCustomHomingTarget(BaseEntity entity)
{
if (entity == null || entity.IsDestroyed)
return;
if (entity.GetComponent<CustomHomingTargetComponent>() != null)
return;
entity.gameObject.AddComponent<CustomHomingTargetComponent>();
}
#endregion
#region main
private sealed class CustomHomingTargetComponent : MonoBehaviour, SeekerTarget.ISeekerTargetOwner
{
private BaseEntity _entity;
private void Awake()
{
_entity = GetComponent<BaseEntity>();
if (_entity == null || _entity.IsDestroyed)
return;
SeekerTarget.SetSeekerTarget(this, SeekerTarget.SeekerStrength.LOW);
}
public Vector3 CenterPoint()
{
return _entity != null ? _entity.CenterPoint() : transform.position;
}
public bool InSafeZone()
{
return _entity != null && !_entity.IsDestroyed && _entity.InSafeZone();
}
public bool IsValidHomingTarget()
{
return _entity != null && !_entity.IsDestroyed && _entity.isActiveAndEnabled;
}
public bool IsVisible(Vector3 position, float maxDistance)
{
return _entity != null && !_entity.IsDestroyed && _entity.IsVisible(position, maxDistance);
}
public void OnEntityMessage(BaseEntity from, string msg) // incoming missile notice to targeted vehicle, might be useful alongside something like sound library for incoming missile alert
{
}
/*
private void OnDestroy()
{
if (_entity != null && !_entity.IsDestroyed)
SeekerTarget.SetSeekerTarget(this, SeekerTarget.SeekerStrength.OFF);
}
*/
private void OnDestroy()
{
SeekerTarget.SetSeekerTarget(this, SeekerTarget.SeekerStrength.OFF);
}
}
#endregion
}
}