C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using Oxide.Core.Plugins;
using Oxide.Core;
using Newtonsoft.Json;
using UnityEngine;
using System.Collections.Generic;
namespace Oxide.Plugins {
[Info("Traffic Drivers", "walkinrey", "1.4.2")]
public class TrafficDrivers : RustPlugin {
public static TrafficDrivers Instance;
[PluginReference]
private Plugin SpawnModularCar, Convoy, MarkerManager, CarTurrets;
private SpawnManager _spawner;
private List<Vector3[]> _roadPathes = new List<Vector3[]>();
private Dictionary<ulong, TrafficCompanion> _driverCompanions = new Dictionary<ulong, TrafficCompanion>();
private Dictionary<ulong, TrafficDriver> _carsDrivers = new Dictionary<ulong, TrafficDriver>();
private Dictionary<ulong, List<BaseNetworkable>> _debugMarkers = new Dictionary<ulong, List<BaseNetworkable>>();
private Dictionary<ulong, PlayerPathRecorder> _recorders = new Dictionary<ulong, PlayerPathRecorder>();
private TrafficCompanion GetCompanion(ulong playerNetID) {
if(_driverCompanions.ContainsKey(playerNetID)) {
var value = _driverCompanions[playerNetID];
if(value == null) return null;
return value;
}
return null;
}
private TrafficDriver GetDriver(ulong playerNetID) {
if(_carsDrivers.ContainsKey(playerNetID)) {
var value = _carsDrivers[playerNetID];
if(value == null) return null;
return value;
}
return null;
}
#region Конфиг
private Configuration _config;
public class Configuration {
[JsonProperty("Enable path recorder?")]
public bool enableRecording = false;
[JsonProperty("Cooldown between points in secodns (when using path recorder)")]
public float cooldownSecondsRecorder = 0.25f;
[JsonProperty("Vehicle presets")]
public Dictionary<string, CarPreset> carPresets = new Dictionary<string, CarPreset>();
[JsonProperty("Driver presets")]
public Dictionary<string, DriverPreset> driverPresets = new Dictionary<string, DriverPreset>();
[JsonProperty("Limits, spawn and interaction setup")]
public Limits limits = new Limits();
public class Limits {
[JsonProperty("Maximum amount of cars")]
public MinMax maxCars = new MinMax();
[JsonProperty("Minimum road length")]
public int minRoadLength = 100;
[JsonProperty("After how many seconds destroy stuck car?")]
public float stuckDespawnTime = 60f;
[JsonProperty("Delay between spawn next car")]
public int spawnCooldown = 5;
[JsonProperty("Prevent bots from attacking drivers and companions?")]
public bool blockTrafficTarget = true;
[JsonProperty("Despawn vehicle if it collides with next prefabs")]
public string[] despawnPrefabs = new string[] {
"train_wagon", "trainwagon"
}
;
[JsonProperty("Fully despawn vehicle (no detonator) if it collides with next prefabs")]
public string[] fullDespawnPrefabs = new string[] {
"bradleyapc"
}
;
[JsonProperty("Destroy prefab when despawning a car?")]
public bool destroyPrefab = false;
[JsonProperty("Convoy plugin support")]
public ConvoySupport convoy = new ConvoySupport();
public class ConvoySupport {
[JsonProperty("Enable the Convoy plugin support?")]
public bool enableConvoySupport = false;
[JsonProperty("Destroy traffic vehicles at the start of the Convoy plugin event?")]
public bool destroyCarsOnEvent = false;
[JsonProperty("Destroy traffic vehicles when colliding with Convoy plugin event vehicles?")]
public bool destroyCarsOnHit = false;
}
}
public class DriverPreset {
[JsonProperty("Display driver name")]
public string name = "Водитель Ярик";
[JsonProperty("Spawn as scientist npc?")]
public bool spawnAsScientist = false;
[JsonProperty("Bot skin (0 - random, not work if scientist)")]
public ulong skin = 0;
[JsonProperty("Bot health")]
public MinMax health = new MinMax();
[JsonProperty("Bot loot (not work if scientist)")]
public List<LootInfo> loot = new List<LootInfo>();
[JsonProperty("Driver will be moving with default speed (1) or will be increase max.speed for a while (2) when attacked?")]
public int attackBehaviour = 1;
[JsonProperty("Damage receive rate")]
public float damageReceiveRate = 0.5f;
[JsonProperty("Spawn bag with items instead of corpse on death?")]
public bool spawnBagOnDeath = false;
[JsonProperty("Clothes")]
public List<ClothInfo> clothes = new List<ClothInfo>();
[JsonProperty("Companion")]
public CompanionSetup companion = new CompanionSetup();
[JsonProperty("Lock player inventory containers (not work if scientist)")]
public ContainerLock containerLock = new ContainerLock();
public class ContainerLock {
[JsonProperty("Lock player main inventory container?")]
public bool lockMain = false;
[JsonProperty("Lock player wear inventory container?")]
public bool lockWear = false;
[JsonProperty("Lock player belt inventory container?")]
public bool lockBelt = false;
}
public class CompanionSetup {
[JsonProperty("Spawn companion for driver? (he will shoot and protect him)")]
public bool enableCompanion = false;
[JsonProperty("Display companion name")]
public string name = "Компаньон-защитник";
[JsonProperty("Prevent companion from attacking first?")]
public bool preventAttackFirst = true;
[JsonProperty("Spawn bag with items instead of corpse on death?")]
public bool spawnBagOnDeath = false;
[JsonProperty("Companion health")]
public MinMax health = new MinMax();
[JsonProperty("Clothes")]
public List<ClothInfo> clothes = new List<ClothInfo>();
[JsonProperty("Weapons")]
public List<ClothInfo> weapons = new List<ClothInfo>();
[JsonProperty("Damage receive rate")]
public float damageReceiveRate = 0.5f;
[JsonProperty("Damage rate")]
public float damageHurtRate = 2f;
}
public class LootInfo : ClothInfo {
[JsonProperty("Item name", Order = -1)]
public string name;
[JsonProperty("Spawn chance", Order = 3)]
public float chance;
[JsonProperty("Item amount", Order = 4)]
public MinMax amount;
[JsonProperty("Target container (main, belt, wear)", Order = 5)]
public string container;
}
public class ClothInfo {
[JsonProperty("Item shortname")]
public string shortname;
[JsonProperty("Item skin")]
public ulong skin;
}
}
public class CarPreset {
[JsonProperty("Random modules count (2-4, 0 for random count)")]
public int modulesCount;
[JsonProperty("Modules (if you enter modules here the random modules option will not work)")]
public string[] modules = new string[] {
}
;
[JsonProperty("Add codelock?")]
public bool addCodeLock = false;
[JsonProperty("Add door lock?")]
public bool addDoorLock = false;
[JsonProperty("Engine parts tier (0-3, 0 to spawn without parts)")]
public int enginePartsTier = 3;
[JsonProperty("Fuel amount (-1 for max amount)")]
public int fuelAmount = -1;
[JsonProperty("Water amount for fuel tank (not necessary, -1 for max amount)")]
public int waterAmount = 0;
[JsonProperty("Max speed")]
public float maxSpeed = 15;
[JsonProperty("Enable infinite fuel")]
public bool infiniteFuel = true;
[JsonProperty("Driver preset name (leave blank to spawn random driver)")]
public string driverPreset = "";
[JsonProperty("Destroy car after driver death?")]
public bool destroyCarAfterDeath = false;
[JsonProperty("Block access to engine parts?")]
public bool blockEngineLooting = true;
[JsonProperty("Destroy engine parts after driver death?")]
public bool destroyEngineParts = true;
[JsonProperty("Destroy engine parts after full car despawn?")]
public bool destroyEnginePartsAtFullDespawn = true;
[JsonProperty("Add flashing lights to car driver module?")]
public bool enableBlueLights = false;
[JsonProperty("Vehicle and passenger immortal time after spawn")]
public float immortalTime = 5f;
[JsonProperty("Make vehicle immortal?")]
public bool enableImmortal = false;
[JsonProperty("Full destroy vehicle (no detonation) when driver is killed by Bradley APC?")]
public bool fullDestroyBradley = true;
[JsonProperty("Offset from the road edge")]
public float roadEdgeOffset = 4f;
[JsonProperty("Detonator (for vehicle despawn)")]
public Detonator detonator = new Detonator();
[JsonProperty("Loot in Storage Module")]
public StorageLoot storage = new StorageLoot();
[JsonProperty("Passengers")]
public List<Passenger> passengers = new List<Passenger>();
[JsonProperty("Passengers as Companions")]
public List<PassengerCompanion> passengerCompanions = new List<PassengerCompanion>();
[JsonProperty("Car Headlights")]
public CarHeadlights carHeadlights = new CarHeadlights();
[JsonProperty("Hackable Crate")]
public CarHackableCrate carHackableCrate = new CarHackableCrate();
[JsonProperty("Car Turret")]
public CarTurret turret = new CarTurret();
public class CarTurret {
[JsonProperty("Deploy auto turret on car? (requires CarTurrets plugin)")]
public bool enableDeployTurret = false;
[JsonProperty("Default weapon shortname")]
public string defaultWeapon = "rifle.ak";
[JsonProperty("Ammo amount")]
public int ammoAmount = 999;
}
public class CarHackableCrate {
[JsonProperty("Spawn hackable crate on car destroy?")]
public bool spawnCrate = false;
[JsonProperty("Position offset")]
public Vector3 posOffset = new Vector3(0, 1f, 0);
[JsonProperty("Use custom loot?")]
public bool enableCustomLoot = false;
[JsonProperty("Custom loot")]
public List<DriverPreset.LootInfo> loot = new List<DriverPreset.LootInfo>();
}
public class CarHeadlights {
[JsonProperty("Enable car headlights?")]
public bool enableHeadlights = true;
[JsonProperty("Enable headlights only at night?")]
public bool onlyAtNightMode = true;
}
public class PassengerCompanion {
[JsonProperty("Spawn chance")]
public float chance = 50f;
[JsonProperty("Companion setup")]
public DriverPreset.CompanionSetup companionSetup;
}
public class Passenger {
[JsonProperty("Spawn chance")]
public float chance = 50f;
[JsonProperty("Passenger display name")]
public string displayName = "Passenger";
[JsonProperty("Passenger skin (0 for random)")]
public ulong id = 0;
[JsonProperty("Spawn bag with items instead of corpse on death?")]
public bool spawnBagOnDeath = false;
[JsonProperty("Passenger health")]
public MinMax health = new MinMax();
[JsonProperty("Passenger loot")]
public List<DriverPreset.LootInfo> loot = new List<DriverPreset.LootInfo>();
[JsonProperty("Passenger lock inventory containers")]
public DriverPreset.ContainerLock lockInventory = new DriverPreset.ContainerLock();
}
public class Detonator {
[JsonProperty("Add a detonator to the car after the death of the driver (useful to despawn cars)")]
public bool enableDetonator = true;
[JsonProperty("In how many seconds detonator will be blow up")]
public float timer = 300f;
[JsonProperty("Detonator position offset on the car")]
public Vector3 offset = new Vector3(0, 0.5f, 0);
}
public class StorageLoot {
[JsonProperty("Add loot to Storage Module")]
public bool enableLoot = true;
[JsonProperty("Loot")]
public List<ItemInfo> lootInfo = new List<ItemInfo>();
public struct ItemInfo {
[JsonProperty("Item shortname")]
public string shortname;
[JsonProperty("Item skin")]
public ulong skin;
[JsonProperty("Item name (not necessary)")]
public string name;
[JsonProperty("Spawn chance")]
public float chance;
[JsonProperty("Item amount")]
public MinMax amount;
}
}
public Dictionary<string, object> ConvertForAPI() {
var dict = new Dictionary<string, object>();
dict.Add("Modules", modules);
dict.Add("CodeLock", addCodeLock);
dict.Add("KeyLock", addDoorLock);
dict.Add("EnginePartsTier", enginePartsTier);
dict.Add("FuelAmount", fuelAmount);
dict.Add("FreshWaterAmount", waterAmount);
return dict;
}
}
public class MinMax {
[JsonProperty("Minimum")]
public float min = 1;
[JsonProperty("Maximum")]
public float max = 5;
public MinMax(float minimum = 1, float maximum = 5) {
min = minimum;
max = maximum;
}
public float Randomize() => UnityEngine.Random.Range(min, max);
}
}
protected override void LoadDefaultConfig() {
_config = new Configuration();
_config.carPresets.Add("3 module vehicle", new Configuration.CarPreset {
modules = new string[] {
"vehicle.1mod.engine", "vehicle.1mod.storage", "vehicle.1mod.cockpit.with.engine"
}
, maxSpeed = 10, storage = new Configuration.CarPreset.StorageLoot {
enableLoot = true, lootInfo = new List<Configuration.CarPreset.StorageLoot.ItemInfo> {
new Configuration.CarPreset.StorageLoot.ItemInfo {
shortname = "wood", chance = 100, amount = new Configuration.MinMax {
min = 1000, max = 10000,
}
}
, new Configuration.CarPreset.StorageLoot.ItemInfo {
shortname = "stones", chance = 100, amount = new Configuration.MinMax {
min = 5000, max = 50000
}
}
}
}
, passengers = new List<Configuration.CarPreset.Passenger> {
new Configuration.CarPreset.Passenger {
health = new Configuration.MinMax(100, 150), loot = new List<Configuration.DriverPreset.LootInfo> {
new Configuration.DriverPreset.LootInfo {
shortname = "wood", chance = 100, amount = new Configuration.MinMax {
min = 1000, max = 10000,
}
, container = "main"
}
, new Configuration.DriverPreset.LootInfo {
shortname = "stones", chance = 100, amount = new Configuration.MinMax {
min = 5000, max = 50000
}
, container = "main"
}
}
}
}
, passengerCompanions = new List<Configuration.CarPreset.PassengerCompanion> {
new Configuration.CarPreset.PassengerCompanion {
chance = 0, companionSetup = new Configuration.DriverPreset.CompanionSetup {
enableCompanion = true, health = new Configuration.MinMax(100, 150), clothes = new List<Configuration.DriverPreset.ClothInfo> {
new Configuration.DriverPreset.ClothInfo {
shortname = "attire.banditguard"
}
}
, weapons = new List<Configuration.DriverPreset.ClothInfo> {
new Configuration.DriverPreset.ClothInfo {
shortname = "rifle.ak"
}
}
}
}
}
, carHackableCrate = new Configuration.CarPreset.CarHackableCrate {
loot = new List<Configuration.DriverPreset.LootInfo> {
new Configuration.DriverPreset.LootInfo {
shortname = "rifle.ak", amount = new Configuration.MinMax(1, 1), chance = 100, container = "belt"
}
, new Configuration.DriverPreset.LootInfo {
shortname = "hatchet", amount = new Configuration.MinMax(1, 1), chance = 100, container = "main"
}
}
,
}
}
);
_config.driverPresets.Add("Yarik Driver", new Configuration.DriverPreset {
attackBehaviour = 2, health = new Configuration.MinMax(100, 150), loot = new List<Configuration.DriverPreset.LootInfo> {
new Configuration.DriverPreset.LootInfo {
shortname = "rifle.ak", amount = new Configuration.MinMax(1, 1), chance = 100, container = "belt"
}
, new Configuration.DriverPreset.LootInfo {
shortname = "hatchet", amount = new Configuration.MinMax(1, 1), chance = 100, container = "main"
}
}
, clothes = new List<Configuration.DriverPreset.ClothInfo> {
new Configuration.DriverPreset.ClothInfo {
shortname = "hazmatsuit"
}
}
, companion = new Configuration.DriverPreset.CompanionSetup {
enableCompanion = true, health = new Configuration.MinMax(100, 150), clothes = new List<Configuration.DriverPreset.ClothInfo> {
new Configuration.DriverPreset.ClothInfo {
shortname = "attire.banditguard"
}
}
, weapons = new List<Configuration.DriverPreset.ClothInfo> {
new Configuration.DriverPreset.ClothInfo {
shortname = "rifle.ak"
}
}
}
}
);
}
protected override void SaveConfig() => Config.WriteObject(_config);
protected override void LoadConfig() {
base.LoadConfig();
try {
_config = Config.ReadObject<Configuration>();
if (_config == null) throw new System.Exception();
SaveConfig();
}
catch (System.Exception ex) {
PrintError("{0}", ex);
LoadDefaultConfig();
}
}
#endregion
#region Дата
private DataFile _data;
private class DataFile {
[JsonProperty("Recorded pathes | Записанные пути")]
public Dictionary<int, List<Vector3>> pathes = new Dictionary<int, List<Vector3>>();
}
private void LoadData() => _data = Interface.Oxide.DataFileSystem.ReadObject<DataFile>("TrafficDrivers_Pathes");
private void SaveData() => Interface.Oxide.DataFileSystem.WriteObject("TrafficDrivers_Pathes", _data);
#endregion
#region Хуки
private object OnPlayerDeath(BasePlayer player, HitInfo info) {
if(player == null || player?.net == null || info == null) return null;
// if(info.Initiator == null) return null;
// if(!(info.Initiator is BradleyAPC)) return null;
var driver = GetDriver(player.net.ID.Value);
if(driver == null) return null;
driver.Destroy();
return null;
}
private void OnTrafficDestroyed() => _spawner.OnTrafficDestroyed();
private object CanNetworkTo(BaseNetworkable entity, BasePlayer target) {
foreach(var pair in _debugMarkers) {
if(pair.Value.Contains(entity)) {
if(!_debugMarkers.ContainsKey(target.userID)) return false;
else {
var marker = _debugMarkers[target.userID];
if(!marker.Contains(entity)) return false;
}
}
}
return null;
}
private void Loaded() {
Instance = this;
NextTick(() => {
if(SpawnModularCar == null) {
PrintError("SpawnModularCar plugin is not installed");
NextTick(() => Interface.Oxide.UnloadPlugin(Title));
return;
}
if(!_config.enableRecording) Unsubscribe("OnPlayerInput");
else Subscribe("OnPlayerInput");
if(_config.limits.convoy.enableConvoySupport && _config.limits.convoy.destroyCarsOnEvent) {
Subscribe("OnConvoyStart");
Subscribe("OnConvoyStop");
}
else {
Unsubscribe("OnConvoyStart");
Unsubscribe("OnConvoyStop");
}
LoadData();
}
);
}
private void OnConvoyStart() {
if(_spawner) _spawner.Pause();
foreach(var driver in _carsDrivers.Values) {
if(driver == null) continue;
var bot = driver.Driver;
if(bot == null) continue;
var mountable = bot?.GetMountedVehicle();
mountable.transform.position = new Vector3(0, -9999f, 0);
this.NextTick(() => {
if(mountable != null) mountable.Kill();
if(bot != null) bot.Kill();
}
);
}
}
private void OnConvoyStop() {
if(_spawner) _spawner.Resume(true);
}
private void Unload() {
foreach(var driver in _carsDrivers.Values) {
if(driver == null) continue;
driver.FullDestroy();
}
foreach(var recorder in _recorders.Values) {
if(recorder != null) UnityEngine.Object.Destroy(recorder);
}
if(_spawner) {
_spawner.Pause();
UnityEngine.Object.DestroyImmediate(_spawner);
}
}
private void OnPlayerInput(BasePlayer player, InputState input) {
if(!input.WasJustPressed(BUTTON.RELOAD)) return;
if(!_recorders.ContainsKey(player.userID)) return;
var recorder = _recorders[player.userID];
if(recorder == null) return;
recorder.Input();
}
private object OnCorpsePopulate(BasePlayer npcPlayer, BaseCorpse corpse) {
TrafficCompanion companion;
if(npcPlayer.TryGetComponent<TrafficCompanion>(out companion)) {
if(!companion.ShouldDeleteCorpse) return false;
var backpack = GameManager.server.CreateEntity("assets/prefabs/misc/item drop/item_drop_backpack.prefab", npcPlayer.transform.position, Quaternion.identity) as DroppedItemContainer;
List<LootSpawn> loots = new List<LootSpawn>();
foreach (LootContainer.LootSpawnSlot lootSpawnSlot in companion.NPC.LootSpawnSlots) {
for (int index = 0; index < lootSpawnSlot.numberToSpawn; ++index) {
if (UnityEngine.Random.Range(0.0f, 1f) <= lootSpawnSlot.probability) loots.Add(lootSpawnSlot.definition);
}
}
backpack.inventory = new ItemContainer();
backpack.inventory.ServerInitialize((Item) null, loots.Count);
backpack.inventory.GiveUID();
backpack.inventory.SetFlag(ItemContainer.Flag.NoItemInput, true);
foreach(var bagItem in loots) bagItem.SpawnIntoContainer(backpack.inventory);
backpack.ResetRemovalTime();
backpack.Spawn();
NextTick(() => {
corpse.ServerPosition = new Vector3(0, -1000, 0);
corpse.Kill();
}
);
return corpse;
}
return null;
}
private object OnPlayerCorpseSpawn(BasePlayer npcPlayer) {
var driver = GetDriver(npcPlayer.net.ID.Value);
if(driver != null) {
if(!driver.ShouldDropBag) return null;
var backpack = GameManager.server.CreateEntity("assets/prefabs/misc/item drop/item_drop_backpack.prefab", npcPlayer.transform.position, Quaternion.identity) as DroppedItemContainer;
backpack.TakeFrom(new ItemContainer[] {
npcPlayer.inventory.containerMain, npcPlayer.inventory.containerWear, npcPlayer.inventory.containerBelt
}
);
backpack.playerName = npcPlayer.displayName;
backpack.playerSteamID = npcPlayer.userID;
backpack.ResetRemovalTime();
backpack.Spawn();
return false;
}
TrafficPassenger passenger;
if(npcPlayer.TryGetComponent<TrafficPassenger>(out passenger)) {
var backpack = GameManager.server.CreateEntity("assets/prefabs/misc/item drop/item_drop_backpack.prefab", npcPlayer.transform.position, Quaternion.identity) as DroppedItemContainer;
backpack.TakeFrom(new ItemContainer[] {
npcPlayer.inventory.containerMain, npcPlayer.inventory.containerWear, npcPlayer.inventory.containerBelt
}
);
backpack.playerName = npcPlayer.displayName;
backpack.playerSteamID = npcPlayer.userID;
backpack.ResetRemovalTime();
backpack.Spawn();
return false;
}
return null;
}
private object OnEntityTakeDamage(BaseVehicleModule module, HitInfo info) {
if(module == null || info == null) return null;
var car = module.Vehicle;
if(car == null) return null;
var driver = car.GetDriver();
if(driver != null) {
if(driver.net == null) return null;
var traffic = GetDriver(driver.net.ID.Value);
if(traffic != null) {
if(traffic.IsCarImmortal) {
info.damageTypes = new Rust.DamageTypeList();
info.DidHit = false;
info.DoHitEffects = false;
return true;
}
}
}
return null;
}
private object CanMoveItem(Item item, PlayerInventory playerLoot, uint targetContainer, int targetSlot, int amount) {
if(item == null) return null;
if(item.parent == null) return null;
if(item.parent.IsLocked()) return false;
return null;
}
private object CanMoveItem(Item item, PlayerInventory playerLoot, ItemContainerId targetContainerId, int targetSlotIndex, int splitAmount) {
if(item == null) return null;
if(item.parent == null) return null;
if(item.parent.IsLocked()) return false;
return null;
}
private object OnEntityTakeDamage(BasePlayer player, HitInfo info) {
if(player == null || info == null) return null;
if(info.InitiatorPlayer == null) return null;
if(!player.userID.IsSteamId() && player.net != null) {
var driver = GetDriver(player.net.ID.Value);
if(driver != null) {
if(!info.InitiatorPlayer.userID.IsSteamId() && info.InitiatorPlayer.net != null) {
var companion = GetCompanion(info.InitiatorPlayer.net.ID.Value);
if(companion != null) {
return false;
}
}
}
}
return null;
}
private object OnEntityTakeDamage(BaseCombatEntity entity, HitInfo info) {
if(entity == null || info == null || info?.damageTypes == null) return null;
if(entity is BaseVehicleModule) OnEntityTakeDamage(entity as BaseVehicleModule, info);
if(entity is BasePlayer) {
var player = entity.ToPlayer();
if(player != null) {
if(!player.userID.IsSteamId() && player.net != null) {
var driver = GetDriver(player.net.ID.Value);
if(driver != null) {
if(driver.IsImmortal) return true;
info.damageTypes.ScaleAll(driver.GetDamageReceiveRate());
}
else {
var companion = GetCompanion(player.net.ID.Value);
if(companion != null) {
var companionDriver = GetDriver(companion.GetDriverID());
if(companionDriver != null) {
if(companionDriver.IsImmortal) return true;
}
info.damageTypes.ScaleAll(companion.GetDamageReceiveRate());
}
}
}
}
}
else {
if(info.Initiator != null) {
if(info.Initiator is ModularCar) {
if(_config.limits.convoy.enableConvoySupport) {
if(_config.limits.convoy.destroyCarsOnHit) {
if(Convoy != null) {
var driverMounted = ((ModularCar)info.Initiator)?.GetDriver();
if(driverMounted != null) {
if(driverMounted.net != null) {
var driver = GetDriver(driverMounted.net.ID.Value);
if(driver != null) {
var callResult = Convoy.Call("IsConvoyVehicle", entity);
if(callResult != null) {
if(callResult is bool) {
if(((bool)callResult)) {
UnityEngine.Object.Destroy(driver);
return null;
}
}
}
}
}
}
}
}
}
if(_config.limits.despawnPrefabs.Length != 0 || _config.limits.fullDespawnPrefabs.Length != 0) {
var find = Physics.OverlapSphere(entity.transform.position, 1f, -1);
if(find != null && find?.Length != 0) {
foreach(var collider in find) {
if(collider == null) continue;
var ent = collider.ToBaseEntity();
if(ent != null) {
if(_config.limits.despawnPrefabs.Contains(ent.ShortPrefabName) || _config.limits.fullDespawnPrefabs.Contains(ent.ShortPrefabName)) {
var driverMounted = ((ModularCar)info.Initiator).GetDriver();
if(driverMounted != null) {
var driver = GetDriver(driverMounted.net.ID.Value);
if(driver != null) {
if(_config.limits.destroyPrefab) ent.Kill();
if(_config.limits.despawnPrefabs.Contains(ent.ShortPrefabName)) {
if(driver.Driver != null) driver.Driver.Kill();
}
else driver.FullDestroy();
return null;
}
}
}
}
}
}
}
}
}
BaseModularVehicle vehicle = null;
if(entity is BaseVehicleModule) {
var module = (BaseVehicleModule)entity;
if(module.Vehicle != null) vehicle = module.Vehicle;
}
if(entity is BaseModularVehicle) vehicle = (BaseModularVehicle)entity;
if(vehicle != null) {
var driverMounted = vehicle.GetDriver();
if(driverMounted == null || driverMounted?.net == null) return null;
var driver = GetDriver(driverMounted.net.ID.Value);
if(driver == null) return null;
if(driver.IsImmortal) return true;
if(info.InitiatorPlayer != null) driver.OnAttacked(info.InitiatorPlayer);
else if(info.Initiator != null) {
if(info.Initiator is BaseVehicle && info.Initiator != entity) {
var attackerVehicle = (BaseVehicle)info.Initiator;
if(attackerVehicle != null) {
if(attackerVehicle.HasDriver()) {
driver.OnAttacked(attackerVehicle.GetDriver());
return null;
}
}
}
if(info.damageTypes.Total() > 2f) driver.OnPhysicAttacked();
}
}
}
if(info.InitiatorPlayer != null) {
if(info.InitiatorPlayer.net != null) {
var initiatorCompanion = GetCompanion(info.InitiatorPlayer.net.ID.Value);
if(initiatorCompanion != null) {
if(entity.net != null) {
if(initiatorCompanion.GetExcludeList().Contains(entity.net.ID.Value)) return true;
}
}
}
}
return null;
}
private void OnServerInitialized() {
if(_data == null) LoadData();
if(_data.pathes.Count == 0) {
Puts("Recorded paths not found, load standard Rust roads");
foreach(var path in TerrainMeta.Path.Roads) {
if(path.Path.Points.Length < _config.limits.minRoadLength || path.Splat == 1) continue;
_roadPathes.Add(path.Path.Points);
}
if(_roadPathes.Count == 0) {
PrintError("No suitable roads found! Decrease the minimum road length for traffic in the config.");
NextTick(() => Interface.Oxide.UnloadPlugin(Title));
return;
}
}
else {
Puts("Recorded paths found in data file, load them");
foreach(var path in _data.pathes) {
_roadPathes.Add(path.Value.ToArray());
}
}
_spawner = new GameObject("Traffic SpawnManager", typeof(SpawnManager)).GetComponent<SpawnManager>();
_spawner.Init(_config.limits, this, _roadPathes);
Puts($"Found suitable roads: {_roadPathes.Count}");
}
private object OnNpcTarget(BaseEntity npc, BaseEntity entity) {
if(npc == null || entity == null) return null;
if(npc.net == null || entity.net == null) return null;
var companion = GetCompanion(npc.net.ID.Value);
if(companion != null) {
if(!companion.CanTargetEntity(entity)) return true;
}
var driver = GetDriver(entity.net.ID.Value);
if(driver != null && _config.limits.blockTrafficTarget) return true;
var companionBlock = GetCompanion(entity.net.ID.Value);
if(companionBlock != null && _config.limits.blockTrafficTarget) return true;
return null;
}
private void OnPlayerCorpseSpawned(BasePlayer player, PlayerCorpse corpse) {
if(player.inventory.containerMain.IsLocked()) corpse.containers[0].SetLocked(true);
if(player.inventory.containerBelt.IsLocked()) corpse.containers[1].SetLocked(true);
if(player.inventory.containerWear.IsLocked()) corpse.containers[2].SetLocked(true);
}
#endregion
#region Методы
[ConsoleCommand("trafficdrivers.debug")]
private void showDebugInfo(ConsoleSystem.Arg arg) {
var drivers = _spawner.GetDrivers();
string msg = $"Traffic cars amount: {drivers.Count}";
if(arg.Player() != null) {
var player = arg.Player();
if(!player.IsAdmin) return;
foreach(var driver in drivers) {
if(driver == null) continue;
msg += $"\n{driver.CarPresetName}: {PhoneController.PositionToGridCoord(driver.Position)}";
DebugMarker marker = new GameObject("Debug Marker", typeof(DebugMarker)).GetComponent<DebugMarker>();
marker.displayName = driver.CarPresetName;
marker.radius = 0.2f;
marker.alpha = 0.5f;
marker.refreshRate = 3f;
marker.position = driver.Position;
marker.duration = 15;
marker.playerID = player.userID;
ColorUtility.TryParseHtmlString($"#00FFFF", out marker.color1);
ColorUtility.TryParseHtmlString($"#00FFFFFF", out marker.color2);
var instance = TrafficDrivers.Instance;
marker.instance = instance;
if(instance._debugMarkers.ContainsKey(player.userID)) {
var found = instance._debugMarkers[player.userID];
if(found != null) {
foreach(var mrkr in found) {
if(mrkr != null) UnityEngine.Object.Destroy(mrkr);
}
}
instance._debugMarkers.Remove(player.userID);
}
}
player.ChatMessage(msg);
return;
}
foreach(var driver in drivers) {
if(driver == null) continue;
msg += $"\n{driver.CarPresetName}: {PhoneController.PositionToGridCoord(driver.Position)}";
}
Puts(msg);
}
[ChatCommand("trafficdrivers")]
private void chatAdminCommand(BasePlayer player, string command, string[] args) {
if(!player.IsAdmin) return;
if(args?.Length == 0) return;
if(args[0] == "recorder") {
if(!_config.enableRecording) {
player.ChatMessage("Recorder disabled in config!");
return;
}
PlayerPathRecorder recorder;
if(_recorders.ContainsKey(player.userID)) {
recorder = _recorders[player.userID];
if(recorder != null) UnityEngine.Object.Destroy(recorder);
_recorders.Remove(player.userID);
}
recorder = player.gameObject.AddComponent<PlayerPathRecorder>();
recorder.Init(this);
_recorders.Add(player.userID, recorder);
switch(lang.GetLanguage(player.UserIDString)) {
case "ru" : player.ChatMessage("Рекордер добавлен.Чтобы начать/закончить запись пути, нажмите кнопку R");
break;
default : player.ChatMessage("Recorder added.To start/stop recording a path, press R button");
break;
}
return;
}
if(args[0] == "markers") {
if(player.IsAdmin) {
if(MarkerManager) {
foreach(var driver in _carsDrivers.Values) {
if(driver != null) {
MarkerManager.Call("API_CreateMarker", driver.transform.position, driver.CarPresetName, 5, 3f, 0.4f, driver.CarPresetName, "34495e", "7f8c8d");
}
}
player.ChatMessage("Car drivers now visible on the in-game map for everyone for 5 seconds");
}
else player.ChatMessage("MarkerManager plugin isn't installed");
}
}
}
private TrafficDriver SpawnTrafficCarParams(Vector3[] path, Vector3 position, TrafficDriver.DriveSide side) {
var presetsList = new List<Configuration.CarPreset>(_config.carPresets.Values);
var driversList = new List<Configuration.DriverPreset>(_config.driverPresets.Values);
var carPreset = presetsList[UnityEngine.Random.Range(0, presetsList.Count)];
var driverPreset = !string.IsNullOrEmpty(carPreset.driverPreset) ? _config.driverPresets[carPreset.driverPreset] : driversList[UnityEngine.Random.Range(0, driversList.Count)];
BasePlayer bot = GameManager.server.CreateEntity(driverPreset.spawnAsScientist ? "assets/rust.ai/agents/npcplayer/humannpc/scientist/scientistnpc_full_any.prefab" : "assets/prefabs/player/player.prefab", position) as BasePlayer;
if(!driverPreset.spawnAsScientist) {
bot.displayName = driverPreset.name;
bot.userID = driverPreset.skin == 0 ? (ulong)UnityEngine.Random.Range(1, 99999) : driverPreset.skin;
bot.UserIDString = bot.userID.ToString();
}
bot.enableSaving = false;
bot.Spawn();
if(!driverPreset.spawnAsScientist) bot.InitializeHealth(driverPreset.health.min, driverPreset.health.max);
if(driverPreset.spawnAsScientist) {
var navigator = bot.GetComponent<BaseNavigator>();
var npc = bot.GetComponent<ScientistNPC>();
navigator.CanUseNavMesh = false;
navigator.MaxRoamDistanceFromHome = navigator.BestMovementPointMaxDistance = navigator.BestRoamPointMaxDistance = 0f;
navigator.DefaultArea = "Not Walkable";
bot.displayName = driverPreset.name;
bot._health = UnityEngine.Random.Range(driverPreset.health.min, driverPreset.health.max);
bot.inventory.Strip();
npc.CancelInvoke(npc.EquipTest);
}
// ... [Code preview truncated due to length. Full source in attached file] ...