C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Oxide.Core;
using System;
using System.Collections.Generic;
using UnityEngine;
using Oxide.Core.Plugins;
using Oxide.Plugins.NpcHordeRustEditExtensionMethods;
namespace Oxide.Plugins {
[Info("NpcHordeRustEdit", "KpucTaJl", "1.0.6")]
internal class NpcHordeRustEdit : RustPlugin {
#region Data
private const bool En = true;
public class ItemConfig {
[JsonProperty("ShortName")]
public string ShortName {
get;
set;
}
[JsonProperty(En ? "Minimum" : "Минимальное кол-во")]
public int MinAmount {
get;
set;
}
[JsonProperty(En ? "Maximum" : "Максимальное кол-во")]
public int MaxAmount {
get;
set;
}
[JsonProperty(En ? "Chance [0.0-100.0]" : "Шанс выпадения предмета [0.0-100.0]")]
public float Chance {
get;
set;
}
[JsonProperty(En ? "Is this a blueprint? [true/false]" : "Это чертеж? [true/false]")]
public bool IsBluePrint {
get;
set;
}
[JsonProperty("SkinID (0 - default)")]
public ulong SkinID {
get;
set;
}
[JsonProperty(En ? "Name (empty - default)" : "Название (empty - default)")]
public string Name {
get;
set;
}
}
public class LootTableConfig {
[JsonProperty(En ? "Minimum numbers of items" : "Минимальное кол-во элементов")]
public int Min {
get;
set;
}
[JsonProperty(En ? "Maximum numbers of items" : "Максимальное кол-во элементов")]
public int Max {
get;
set;
}
[JsonProperty(En ? "Use minimum and maximum values? [true/false]" : "Использовать минимальное и максимальное значение? [true/false]")]
public bool UseCount {
get;
set;
}
[JsonProperty(En ? "List of items" : "Список предметов")]
public List<ItemConfig> Items {
get;
set;
}
}
public class PrefabConfig {
[JsonProperty(En ? "Chance [0.0-100.0]" : "Шанс выпадения [0.0-100.0]")]
public float Chance {
get;
set;
}
[JsonProperty(En ? "The path to the prefab" : "Путь к prefab-у")]
public string PrefabDefinition {
get;
set;
}
}
public class PrefabLootTableConfig {
[JsonProperty(En ? "Minimum numbers of prefabs" : "Минимальное кол-во prefab-ов")]
public int Min {
get;
set;
}
[JsonProperty(En ? "Maximum numbers of prefabs" : "Максимальное кол-во prefab-ов")]
public int Max {
get;
set;
}
[JsonProperty(En ? "Use minimum and maximum values? [true/false]" : "Использовать минимальное и максимальное значение? [true/false]")]
public bool UseCount {
get;
set;
}
[JsonProperty(En ? "List of prefabs" : "Список prefab-ов")]
public List<PrefabConfig> Prefabs {
get;
set;
}
}
public class NpcBelt {
[JsonProperty("ShortName")]
public string ShortName {
get;
set;
}
[JsonProperty("SkinID (0 - default)")]
public ulong SkinID {
get;
set;
}
[JsonProperty(En ? "Mods" : "Модификации на оружие")]
public HashSet<string> Mods {
get;
set;
}
[JsonProperty(En ? "Ammo" : "Боеприпасы")]
public string Ammo {
get;
set;
}
[JsonProperty(En ? "Probability Percent [0.0-100.0]" : "Вероятность [0.0-100.0]")]
public float Chance {
get;
set;
}
}
public class NpcWear {
[JsonProperty("ShortName")]
public string ShortName {
get;
set;
}
[JsonProperty("SkinID (0 - default)")]
public ulong SkinID {
get;
set;
}
}
public class PresetConfig {
[JsonProperty(En ? "Minimum" : "Минимальное кол-во")]
public int Min {
get;
set;
}
[JsonProperty(En ? "Maximum" : "Максимальное кол-во")]
public int Max {
get;
set;
}
[JsonProperty(En ? "List of locations" : "Список расположений")]
public List<string> Positions {
get;
set;
}
[JsonProperty(En ? "NPCs setting" : "Настройки NPC")]
public NpcConfig Config {
get;
set;
}
[JsonProperty(En ? "Which loot table should the plugin use? (0 - default; 1 - own; 2 - AlphaLoot; 3 - CustomLoot; 4 - loot table of the Rust objects; 5 - combine the 1 and 4 methods)" : "Какую таблицу предметов необходимо использовать? (0 - стандартную; 1 - собственную; 2 - AlphaLoot; 3 - CustomLoot; 4 - таблица предметов объектов Rust; 5 - совместить 1 и 4 методы)")]
public int TypeLootTable {
get;
set;
}
[JsonProperty(En ? "Loot table from prefabs (if the loot table type is 4 or 5)" : "Таблица предметов из prefab-ов (если тип таблицы предметов - 4 или 5)")]
public PrefabLootTableConfig PrefabLootTable {
get;
set;
}
[JsonProperty(En ? "Own loot table (if the loot table type is 1 or 5)" : "Собственная таблица предметов (если тип таблицы предметов - 1 или 5)")]
public LootTableConfig OwnLootTable {
get;
set;
}
}
public class NpcConfig {
[JsonProperty(En ? "Name" : "Название")]
public string Name {
get;
set;
}
[JsonProperty(En ? "Health" : "Кол-во ХП")]
public float Health {
get;
set;
}
[JsonProperty(En ? "Chase Range" : "Дальность погони за целью")]
public float ChaseRange {
get;
set;
}
[JsonProperty(En ? "Attack Range Multiplier" : "Множитель радиуса атаки")]
public float AttackRangeMultiplier {
get;
set;
}
[JsonProperty(En ? "Sense Range" : "Радиус обнаружения цели")]
public float SenseRange {
get;
set;
}
[JsonProperty(En ? "Target Memory Duration [sec.]" : "Длительность памяти цели [sec.]")]
public float MemoryDuration {
get;
set;
}
[JsonProperty(En ? "Scale damage" : "Множитель урона")]
public float DamageScale {
get;
set;
}
[JsonProperty(En ? "Aim Cone Scale" : "Множитель разброса")]
public float AimConeScale {
get;
set;
}
[JsonProperty(En ? "Speed" : "Скорость")]
public float Speed {
get;
set;
}
[JsonProperty(En ? "Disable radio effects? [true/false]" : "Отключать эффекты рации? [true/false]")]
public bool DisableRadio {
get;
set;
}
[JsonProperty(En ? "Remove a corpse after death? (it is recommended to use the true value to improve performance) [true/false]" : "Удалять труп после смерти? (рекомендуется использовать значение true для повышения производительности) [true/false]")]
public bool IsRemoveCorpse {
get;
set;
}
[JsonProperty(En ? "Wear items" : "Одежда")]
public HashSet<NpcWear> WearItems {
get;
set;
}
[JsonProperty(En ? "Belt items" : "Быстрые слоты")]
public HashSet<NpcBelt> BeltItems {
get;
set;
}
[JsonProperty(En ? "Kit (it is recommended to use the previous 2 settings to improve performance)" : "Kit (рекомендуется использовать предыдущие 2 пункта настройки для повышения производительности)")]
public string Kit {
get;
set;
}
}
public class SensorConfig {
[JsonProperty(En ? "Sensor position" : "Позиция сенсора")]
public string Position {
get;
set;
}
[JsonProperty(En ? "Minimum time between the appearance of new NPCs [sec.]" : "Минимальное время между появлением новых NPC [sec.]")]
public float Time {
get;
set;
}
[JsonProperty(En ? "Presets setting" : "Настройка пресетов")]
public HashSet<PresetConfig> Npc {
get;
set;
}
}
public class CustomMapConfig {
[JsonProperty(En ? "ID" : "Идентификатор")]
public string ID {
get;
set;
}
[JsonProperty(En ? "List of sensors" : "Список датчиков")]
public HashSet<SensorConfig> Sensors {
get;
set;
}
}
private void LoadCustomMapConfigs() {
Puts("Loading files on the /oxide/data/NpcHordeRustEdit/ path has started...");
foreach (string name in Interface.Oxide.DataFileSystem.GetFiles("NpcHordeRustEdit/")) {
string fileName = name.Split('/').Last().Split('.').First();
CustomMapConfig config = Interface.Oxide.DataFileSystem.ReadObject<CustomMapConfig>($"NpcHordeRustEdit/{fileName}");
if (config == null) {
PrintError($"File {fileName} is corrupted and cannot be loaded!");
continue;
}
if (!string.IsNullOrEmpty(config.ID) && !_ids.Any(x => Math.Abs(x - Convert.ToSingle(config.ID)) < 0.001f)) {
PrintWarning($"File {fileName} cannot be loaded on the current map!");
continue;
}
Puts($"File {fileName} has been loaded successfully!");
foreach (SensorConfig sensor in config.Sensors) {
foreach (PresetConfig preset in sensor.Npc) {
CheckLootTable(preset.OwnLootTable);
CheckPrefabLootTable(preset.PrefabLootTable);
}
_sensors.Add(sensor);
}
Interface.Oxide.DataFileSystem.WriteObject($"NpcHordeRustEdit/{fileName}", config);
}
}
private readonly HashSet<SensorConfig> _sensors = new HashSet<SensorConfig>();
private readonly HashSet<float> _ids = new HashSet<float>();
private void LoadIDs() {
foreach (RANDSwitch entity in BaseNetworkable.serverEntities.OfType<RANDSwitch>()) _ids.Add(entity.transform.position.x + entity.transform.position.y + entity.transform.position.z);
}
#endregion Data
#region Oxide Hooks
private object OnSensorDetect(HBHFSensor sensor, BasePlayer target) {
if (!target.IsPlayer()) return null;
SensorConfig config = _sensors.FirstOrDefault(x => Vector3.Distance(x.Position.ToVector3(), sensor.transform.position) < 1f);
if (config == null) return null;
ulong sensorID = sensor.net.ID.Value;
if (_data.Any(x => x.ID == sensorID)) return null;
SensorData data = new SensorData {
ID = sensorID, Scientists = new HashSet<ScientistNPC>()
}
;
foreach (PresetConfig preset in config.Npc) {
int count = UnityEngine.Random.Range(preset.Min, preset.Max + 1);
List<Vector3> positions = preset.Positions.Select(x => x.ToVector3());
JObject cfg = GetObjectConfig(preset.Config, sensor.transform.position.ToString());
for (int i = 0; i < count; i++) {
Vector3 pos = positions.GetRandom();
positions.Remove(pos);
ScientistNPC npc = (ScientistNPC)NpcSpawn.Call("SpawnNpc", pos, cfg);
if (npc != null) data.Scientists.Add(npc);
}
}
_data.Add(data);
timer.In(config.Time, () => {
foreach (ScientistNPC npc in data.Scientists) if (npc.IsExists()) npc.Kill();
_data.Remove(data);
}
);
return null;
}
private void OnServerInitialized() {
LoadIDs();
LoadCustomMapConfigs();
}
private void Unload() {
foreach (SensorData data in _data) foreach (ScientistNPC npc in data.Scientists) if (npc.IsExists()) npc.Kill();
}
#endregion Oxide Hooks
#region Helpers
[PluginReference]
private readonly Plugin NpcSpawn;
public class SensorData {
public ulong ID;
public HashSet<ScientistNPC> Scientists;
}
private readonly HashSet<SensorData> _data = new HashSet<SensorData>();
private JObject GetObjectConfig(NpcConfig config, string homePos) {
float chance = UnityEngine.Random.Range(0.0f, 100.0f);
NpcBelt belt = config.BeltItems.WhereToList(x => chance <= x.Chance).GetRandom();
JArray belts = new JArray {
new JObject {
["ShortName"]
= belt.ShortName, ["Amount"] = 1, ["SkinID"] = belt.SkinID, ["Mods"] = new JArray {
belt.Mods
}
, ["Ammo"] = belt.Ammo
}
, new JObject {
["ShortName"]
= "grenade.beancan", ["Amount"] = 1, ["SkinID"] = 0, ["Mods"] = new JArray(), ["Ammo"] = string.Empty
}
}
;
return new JObject {
["Name"]
= config.Name, ["WearItems"] = new JArray {
config.WearItems.Select(x => new JObject {
["ShortName"]
= x.ShortName, ["SkinID"] = x.SkinID
}
)
}
, ["BeltItems"] = belts, ["Kit"] = config.Kit, ["Health"] = config.Health, ["RoamRange"] = 10f, ["ChaseRange"] = config.ChaseRange, ["SenseRange"] = config.SenseRange, ["ListenRange"] = config.SenseRange / 2f, ["AttackRangeMultiplier"] = config.AttackRangeMultiplier, ["CheckVisionCone"] = false, ["VisionCone"] = 135f, ["HostileTargetsOnly"] = false, ["DamageScale"] = config.DamageScale, ["TurretDamageScale"] = 1f, ["AimConeScale"] = config.AimConeScale, ["DisableRadio"] = config.DisableRadio, ["CanRunAwayWater"] = true, ["CanSleep"] = true, ["SleepDistance"] = 100f, ["Speed"] = config.Speed, ["AreaMask"] = 1, ["AgentTypeID"] = -1372625422, ["HomePosition"] = homePos, ["MemoryDuration"] = config.MemoryDuration, ["States"] = new JArray {
"RoamState", "ChaseState", "CombatState"
}
}
;
}
#endregion Helpers
#region Spawn Loot
private void OnCorpsePopulate(ScientistNPC entity, NPCPlayerCorpse corpse) {
if (entity == null) return;
SensorData data = _data.FirstOrDefault(x => x.Scientists.Contains(entity));
if (data != null) {
data.Scientists.Remove(entity);
PresetConfig preset = GetPreset(entity.displayName);
NextTick(() => {
if (corpse == null) return;
ItemContainer container = corpse.containers[0];
if (preset.TypeLootTable == 0) {
for (int i = container.itemList.Count - 1; i >= 0; i--) {
Item item = container.itemList[i];
if (preset.Config.WearItems.Any(x => x.ShortName == item.info.shortname)) {
item.RemoveFromContainer();
item.Remove();
}
}
return;
}
if (preset.TypeLootTable == 2 || preset.TypeLootTable == 3) {
if (preset.Config.IsRemoveCorpse && !corpse.IsDestroyed) corpse.Kill();
return;
}
container.ClearItemsContainer();
if (preset.TypeLootTable == 4 || preset.TypeLootTable == 5) AddToContainerPrefab(container, preset.PrefabLootTable);
if (preset.TypeLootTable == 1 || preset.TypeLootTable == 5) AddToContainerItem(container, preset.OwnLootTable);
if (preset.Config.IsRemoveCorpse && !corpse.IsDestroyed) corpse.Kill();
}
);
}
}
private object CanPopulateLoot(ScientistNPC entity, NPCPlayerCorpse corpse) {
if (entity == null || corpse == null) return null;
if (_data.Any(x => x.Scientists.Contains(entity))) {
PresetConfig preset = GetPreset(entity.displayName);
if (preset.TypeLootTable == 2) return null;
else return true;
}
return null;
}
private object OnCustomLootNPC(NetworkableId netID) {
SensorData data = _data.FirstOrDefault(x => x.Scientists.Any(y => y.IsExists() && y.net.ID.Value == netID.Value));
if (data == null) return null;
ScientistNPC entity = data.Scientists.FirstOrDefault(x => x.IsExists() && x.net.ID.Value == netID.Value);
if (entity != null) {
PresetConfig preset = GetPreset(entity.displayName);
if (preset.TypeLootTable == 3) return null;
else return true;
}
return null;
}
private PresetConfig GetPreset(string name) {
foreach (SensorConfig sensor in _sensors) foreach (PresetConfig preset in sensor.Npc) if (preset.Config.Name == name) return preset;
return null;
}
private void AddToContainerPrefab(ItemContainer container, PrefabLootTableConfig lootTable) {
HashSet<string> prefabsInContainer = new HashSet<string>();
if (lootTable.UseCount) {
int count = UnityEngine.Random.Range(lootTable.Min, lootTable.Max + 1);
while (prefabsInContainer.Count < count) {
foreach (PrefabConfig prefab in lootTable.Prefabs) {
if (prefabsInContainer.Contains(prefab.PrefabDefinition)) continue;
if (UnityEngine.Random.Range(0.0f, 100.0f) <= prefab.Chance) {
if (_allLootSpawnSlots.ContainsKey(prefab.PrefabDefinition)) {
LootContainer.LootSpawnSlot[] lootSpawnSlots = _allLootSpawnSlots[prefab.PrefabDefinition];
foreach (LootContainer.LootSpawnSlot lootSpawnSlot in lootSpawnSlots) for (int j = 0; j < lootSpawnSlot.numberToSpawn; j++) if (UnityEngine.Random.Range(0f, 1f) <= lootSpawnSlot.probability) lootSpawnSlot.definition.SpawnIntoContainer(container);
}
else _allLootSpawn[prefab.PrefabDefinition].SpawnIntoContainer(container);
prefabsInContainer.Add(prefab.PrefabDefinition);
if (prefabsInContainer.Count == count) return;
}
}
}
}
else {
foreach (PrefabConfig prefab in lootTable.Prefabs) {
if (prefabsInContainer.Contains(prefab.PrefabDefinition)) continue;
if (UnityEngine.Random.Range(0.0f, 100.0f) <= prefab.Chance) {
if (_allLootSpawnSlots.ContainsKey(prefab.PrefabDefinition)) {
LootContainer.LootSpawnSlot[] lootSpawnSlots = _allLootSpawnSlots[prefab.PrefabDefinition];
foreach (LootContainer.LootSpawnSlot lootSpawnSlot in lootSpawnSlots) for (int j = 0; j < lootSpawnSlot.numberToSpawn; j++) if (UnityEngine.Random.Range(0f, 1f) <= lootSpawnSlot.probability) lootSpawnSlot.definition.SpawnIntoContainer(container);
}
else _allLootSpawn[prefab.PrefabDefinition].SpawnIntoContainer(container);
prefabsInContainer.Add(prefab.PrefabDefinition);
}
}
}
}
private void AddToContainerItem(ItemContainer container, LootTableConfig lootTable) {
HashSet<int> indexMove = new HashSet<int>();
if (lootTable.UseCount) {
int count = UnityEngine.Random.Range(lootTable.Min, lootTable.Max + 1);
while (indexMove.Count < count) {
foreach (ItemConfig item in lootTable.Items) {
if (indexMove.Contains(lootTable.Items.IndexOf(item))) continue;
if (UnityEngine.Random.Range(0.0f, 100.0f) <= item.Chance) {
Item newItem = item.IsBluePrint ? ItemManager.CreateByName("blueprintbase") : ItemManager.CreateByName(item.ShortName, UnityEngine.Random.Range(item.MinAmount, item.MaxAmount + 1), item.SkinID);
if (newItem == null) {
PrintWarning($"Failed to create item! ({item.ShortName})");
continue;
}
if (item.IsBluePrint) newItem.blueprintTarget = ItemManager.FindItemDefinition(item.ShortName).itemid;
if (!string.IsNullOrEmpty(item.Name)) newItem.name = item.Name;
if (container.capacity < container.itemList.Count + 1) container.capacity++;
if (!newItem.MoveToContainer(container)) newItem.Remove();
else {
indexMove.Add(lootTable.Items.IndexOf(item));
if (indexMove.Count == count) return;
}
}
}
}
}
else {
foreach (ItemConfig item in lootTable.Items) {
if (indexMove.Contains(lootTable.Items.IndexOf(item))) continue;
if (UnityEngine.Random.Range(0.0f, 100.0f) <= item.Chance) {
Item newItem = item.IsBluePrint ? ItemManager.CreateByName("blueprintbase") : ItemManager.CreateByName(item.ShortName, UnityEngine.Random.Range(item.MinAmount, item.MaxAmount + 1), item.SkinID);
if (newItem == null) {
PrintWarning($"Failed to create item! ({item.ShortName})");
continue;
}
if (item.IsBluePrint) newItem.blueprintTarget = ItemManager.FindItemDefinition(item.ShortName).itemid;
if (!string.IsNullOrEmpty(item.Name)) newItem.name = item.Name;
if (container.capacity < container.itemList.Count + 1) container.capacity++;
if (!newItem.MoveToContainer(container)) newItem.Remove();
else indexMove.Add(lootTable.Items.IndexOf(item));
}
}
}
}
private static void CheckLootTable(LootTableConfig lootTable) {
lootTable.Items = lootTable.Items.OrderBy(x => x.Chance);
if (lootTable.Max > lootTable.Items.Count) lootTable.Max = lootTable.Items.Count;
if (lootTable.Min > lootTable.Max) lootTable.Min = lootTable.Max;
}
private void CheckPrefabLootTable(PrefabLootTableConfig lootTable) {
HashSet<PrefabConfig> prefabs = new HashSet<PrefabConfig>();
foreach (PrefabConfig prefabConfig in lootTable.Prefabs) {
if (prefabs.Any(x => x.PrefabDefinition == prefabConfig.PrefabDefinition)) PrintWarning($"Duplicate prefab removed from loot table! ({prefabConfig.PrefabDefinition})");
else {
GameObject gameObject = GameManager.server.FindPrefab(prefabConfig.PrefabDefinition);
global : : HumanNPC humanNpc = gameObject.GetComponent<global : : HumanNPC>();
ScarecrowNPC scarecrowNPC = gameObject.GetComponent<ScarecrowNPC>();
LootContainer lootContainer = gameObject.GetComponent<LootContainer>();
if (humanNpc != null && humanNpc.LootSpawnSlots.Length != 0) {
if (!_allLootSpawnSlots.ContainsKey(prefabConfig.PrefabDefinition)) _allLootSpawnSlots.Add(prefabConfig.PrefabDefinition, humanNpc.LootSpawnSlots);
prefabs.Add(prefabConfig);
}
else if (scarecrowNPC != null && scarecrowNPC.LootSpawnSlots.Length != 0) {
if (!_allLootSpawnSlots.ContainsKey(prefabConfig.PrefabDefinition)) _allLootSpawnSlots.Add(prefabConfig.PrefabDefinition, scarecrowNPC.LootSpawnSlots);
prefabs.Add(prefabConfig);
}
else if (lootContainer != null && lootContainer.LootSpawnSlots.Length != 0) {
if (!_allLootSpawnSlots.ContainsKey(prefabConfig.PrefabDefinition)) _allLootSpawnSlots.Add(prefabConfig.PrefabDefinition, lootContainer.LootSpawnSlots);
prefabs.Add(prefabConfig);
}
else if (lootContainer != null && lootContainer.lootDefinition != null) {
if (!_allLootSpawn.ContainsKey(prefabConfig.PrefabDefinition)) _allLootSpawn.Add(prefabConfig.PrefabDefinition, lootContainer.lootDefinition);
prefabs.Add(prefabConfig);
}
else PrintWarning($"Unknown prefab removed! ({prefabConfig.PrefabDefinition})");
}
}
lootTable.Prefabs = prefabs.OrderBy(x => x.Chance);
if (lootTable.Max > lootTable.Prefabs.Count) lootTable.Max = lootTable.Prefabs.Count;
if (lootTable.Min > lootTable.Max) lootTable.Min = lootTable.Max;
}
private readonly Dictionary<string, LootSpawn> _allLootSpawn = new Dictionary<string, LootSpawn>();
private readonly Dictionary<string, LootContainer.LootSpawnSlot[]> _allLootSpawnSlots = new Dictionary<string, LootContainer.LootSpawnSlot[]>();
#endregion Spawn Loot
}
}
namespace Oxide.Plugins.NpcHordeRustEditExtensionMethods {
public static class ExtensionMethods {
public static bool Any<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) {
using (var enumerator = source.GetEnumerator()) while (enumerator.MoveNext()) if (predicate(enumerator.Current)) return true;
return false;
}
public static List<TSource> WhereToList<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) {
List<TSource> result = new List<TSource>();
using (var enumerator = source.GetEnumerator()) while (enumerator.MoveNext()) if (predicate(enumerator.Current)) result.Add(enumerator.Current);
return result;
}
public static TSource FirstOrDefault<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) {
using (var enumerator = source.GetEnumerator()) while (enumerator.MoveNext()) if (predicate(enumerator.Current)) return enumerator.Current;
return default(TSource);
}
public static HashSet<TResult> Select<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> predicate) {
HashSet<TResult> result = new HashSet<TResult>();
using (var enumerator = source.GetEnumerator()) while (enumerator.MoveNext()) result.Add(predicate(enumerator.Current));
return result;
}
public static List<TResult> Select<TSource, TResult>(this IList<TSource> source, Func<TSource, TResult> predicate) {
List<TResult> result = new List<TResult>();
for (int i = 0; i < source.Count; i++) {
TSource element = source[i];
result.Add(predicate(element));
}
return result;
}
public static HashSet<T> OfType<T>(this IEnumerable<BaseNetworkable> source) {
HashSet<T> result = new HashSet<T>();
using (var enumerator = source.GetEnumerator()) while (enumerator.MoveNext()) if (enumerator.Current is T) result.Add((T)(object)enumerator.Current);
return result;
}
public static List<TSource> ToList<TSource>(this IEnumerable<TSource> source) {
List<TSource> result = new List<TSource>();
using (var enumerator = source.GetEnumerator()) while (enumerator.MoveNext()) result.Add(enumerator.Current);
return result;
}
public static TSource First<TSource>(this IList<TSource> source) => source[0];
public static TSource Last<TSource>(this IList<TSource> source) => source[source.Count - 1];
public static List<TSource> OrderBy<TSource>(this IEnumerable<TSource> source, Func<TSource, float> predicate) {
List<TSource> result = source.ToList();
for (int i = 0; i < result.Count; i++) {
for (int j = 0; j < result.Count - 1; j++) {
if (predicate(result[j]) > predicate(result[j + 1])) {
TSource z = result[j];
result[j] = result[j + 1];
result[j + 1] = z;
}
}
}
return result;
}
public static bool IsPlayer(this BasePlayer player) => player != null && player.userID.IsSteamId();
public static bool IsExists(this BaseNetworkable entity) => entity != null && !entity.IsDestroyed;
public static void ClearItemsContainer(this ItemContainer container) {
for (int i = container.itemList.Count - 1; i >= 0; i--) {
Item item = container.itemList[i];
item.RemoveFromContainer();
item.Remove();
}
}
}
}