Иконка ресурса

FREE TrafficDrivers : 1.1.0 1.1.0

Нет прав для скачивания
C#:
using Oxide.Core.Plugins;
using Oxide.Core;
using Newtonsoft.Json;
using UnityEngine;
using System.Collections.Generic;
namespace Oxide.Plugins {
    [Info("Traffic Drivers", "walkinrey", "1.1.0")]
    public class TrafficDrivers : RustPlugin {
        [PluginReference]
        private Plugin SpawnModularCar, Convoy;
        private SpawnManager _spawner;
        private List<Vector3[]> _roadPathes = new List<Vector3[]>();
        private Dictionary<uint, TrafficCompanion> _driverCompanions = new Dictionary<uint, TrafficCompanion>();
        private Dictionary<uint, TrafficDriver> _carsDrivers = new Dictionary<uint, TrafficDriver>();
        private Dictionary<ulong, PlayerPathRecorder> _recorders = new Dictionary<ulong, PlayerPathRecorder>();
        private TrafficCompanion GetCompanion(uint playerNetID) {
            if(_driverCompanions.ContainsKey(playerNetID)) {
                var value = _driverCompanions[playerNetID];
                if(value == null) return null;
                return value;
            }
            return null;
        }
        private TrafficDriver GetDriver(uint 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("Включить запись пути?")]
            public bool enableRecording = false;
            [JsonProperty("Пресеты автомобилей")]
            public Dictionary<string, CarPreset> carPresets = new Dictionary<string, CarPreset>();
            [JsonProperty("Пресеты водителей")]
            public Dictionary<string, DriverPreset> driverPresets = new Dictionary<string, DriverPreset>();
            [JsonProperty("Настройка лимитов, спавна и взаимодействий")]
            public Limits limits = new Limits();
            public class ConvoySupport {
                [JsonProperty("Включить поддержку плагина Convoy?")]
                public bool enableConvoySupport = false;
                [JsonProperty("Уничтожать машины трафика при начале ивента плагина Convoy?")]
                public bool destroyCarsOnEvent = false;
                [JsonProperty("Уничтожать машины трафика при столкновении с машинами ивента плагина Convoy?")]
                public bool destroyCarsOnHit = false;
            }
            public class Limits {
                [JsonProperty("Максимальное количество автомобилей")]
                public MinMax maxCars = new MinMax();
                [JsonProperty("Минимальная длина дороги для использования трафиком")]
                public int minRoadWidth = 100;
                [JsonProperty("Через сколько секунд удалять застрявшую машину?")]
                public float stuckDespawnTime = 60f;
                [JsonProperty("Задержка между спавном следующего автомобиля")]
                public int spawnCooldown = 5;
                [JsonProperty("Запретить ботам атаковать водителей и компаньонов?")]
                public bool blockTrafficTarget = true;
                [JsonProperty("Поддержка плагина Convoy")]
                public ConvoySupport convoy = new ConvoySupport();
            }
            public class DriverPreset {
                [JsonProperty("Отображаемое имя водителя")]
                public string name = "Водитель Ярик";
                [JsonProperty("Скин бота (0 - рандом)")]
                public ulong skin = 0;
                [JsonProperty("Здоровье бота")]
                public MinMax health = new MinMax();
                [JsonProperty("Лут в боте")]
                public List<LootInfo> loot = new List<LootInfo>();
                [JsonProperty("Водитель будет продолжать движение (1) или продолжать движение ускорившись (2) при атаке?")]
                public int attackBehaviour = 1;
                [JsonProperty("Рейт получаемого урона")]
                public float damageReceiveRate = 0.5f;
                [JsonProperty("Одежда")]
                public List<ClothInfo> clothes = new List<ClothInfo>();
                [JsonProperty("Компаньон")]
                public CompanionSetup companion = new CompanionSetup();
                public class CompanionSetup {
                    [JsonProperty("Спавнить компаньона для водителя? (садится пассажиром, стреляет и защищает водителя)")]
                    public bool enableCompanion = false;
                    [JsonProperty("Отображаемое имя компаньона")]
                    public string name = "Компаньон-защитник";
                    [JsonProperty("Здоровье компаньона")]
                    public MinMax health = new MinMax();
                    [JsonProperty("Одежда")]
                    public List<ClothInfo> clothes = new List<ClothInfo>();
                    [JsonProperty("Оружие")]
                    public List<ClothInfo> weapons = new List<ClothInfo>();
                    [JsonProperty("Рейт получаемого урона")]
                    public float damageReceiveRate = 0.5f;
                    [JsonProperty("Рейт наносимого урона")]
                    public float damageHurtRate = 2f;
                }
                public class LootInfo : ClothInfo {
                    [JsonProperty("Название предмета", Order = -1)]
                    public string name;
                    [JsonProperty("Шанс спавна", Order = 3)]
                    public float chance;
                    [JsonProperty("Количество предмета", Order = 4)]
                    public MinMax amount;
                    [JsonProperty("Контейнер куда поместить предмет (main, belt, wear)", Order = 5)]
                    public string container;
                }
                public class ClothInfo {
                    [JsonProperty("Шортнейм предмета")]
                    public string shortname;
                    [JsonProperty("Скин предмета")]
                    public ulong skin;
                }
            }
            public class CarPreset {
                [JsonProperty("Модули")]
                public string[] modules = new string[] {
                }
                ;
                [JsonProperty("Добавить кодовый замок?")]
                public bool addCodeLock = false;
                [JsonProperty("Добавить дверной замок?")]
                public bool addDoorLock = false;
                [JsonProperty("Уровень запчастей (0-3, 0 чтобы заспавнить без запчастей)")]
                public int enginePartsTier = 3;
                [JsonProperty("Количество топлива (-1 для максимального кол-ва)")]
                public int fuelAmount = -1;
                [JsonProperty("Количество воды в цистерне (если она есть, -1 для максимального кол-ва)")]
                public int waterAmount = 0;
                [JsonProperty("Максимальная скорость")]
                public float maxSpeed = 15;
                [JsonProperty("Включить бесконечное топливо")]
                public bool infiniteFuel = true;
                [JsonProperty("Название пресета водителя (оставьте пустым, чтобы спавнить рандомного водителя)")]
                public string driverPreset = "";
                [JsonProperty("Удалять машину после смерти водителя?")]
                public bool destroyCarAfterDeath = false;
                [JsonProperty("Блокировать доступ к запчастям автомобиля?")]
                public bool blockEngineLooting = true;
                [JsonProperty("Удалять запчасти автомобиля после смерти бота?")]
                public bool destroyEngineParts = true;
                [JsonProperty("Добавлять мигающие синие огни к водительскому модулю автомобиля?")]
                public bool enableBlueLights = false;
                [JsonProperty("Время неуязвимости автомобиля и пассажиров после спавна")]
                public float immortalTime = 5f;
                [JsonProperty("Сделать машину неуязвимой?")]
                public bool enableImmortal = false;
                [JsonProperty("Детонатор для деспавна авто")]
                public Detonator detonator = new Detonator();
                [JsonProperty("Настройка лута в модуле хранения")]
                public StorageLoot storage = new StorageLoot();
                public class Detonator {
                    [JsonProperty("Добавлять детонатор к автомобилю после смерти водителя (используется для деспавна авто)")]
                    public bool enableDetonator = true;
                    [JsonProperty("Через сколько секунд детонатор взорвет весь автомобиль?")]
                    public float timer = 300f;
                }
                public class StorageLoot {
                    [JsonProperty("Добавлять лут в модуль хранения лута?")]
                    public bool enableLoot = true;
                    [JsonProperty("Лут в контейнере")]
                    public List<ItemInfo> lootInfo = new List<ItemInfo>();
                    public struct ItemInfo {
                        [JsonProperty("Шортнейм предмета")]
                        public string shortname;
                        [JsonProperty("Скин предмета")]
                        public ulong skin;
                        [JsonProperty("Название предмета (если не нужно оставьте пустым)")]
                        public string name;
                        [JsonProperty("Шанс спавна")]
                        public float chance;
                        [JsonProperty("Количество предмета")]
                        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("Минимум")]
                public float min = 1;
                [JsonProperty("Максимум")]
                public float max = 5;
                [JsonIgnore]
                public float randomized;
                public MinMax(float minimum = 1, float maximum = 5) {
                    min = minimum;
                    max = maximum;
                }
                public float Randomize() {
                    if(randomized != 0) return randomized;
                    else {
                        randomized = UnityEngine.Random.Range(min, max);
                        return randomized;
                    }
                }
            }
        }
        protected override void LoadDefaultConfig() {
            _config = new Configuration();
            _config.carPresets.Add("3-х модульный транспорт", 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
                            }
                        }
                    }
                }
            }
            );
            _config.driverPresets.Add("Водитель Ярик", 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 void OnTrafficDestroyed() => _spawner.OnTrafficDestroyed();
        private void Loaded() {
            NextTick(() => {
                if(SpawnModularCar == null) {
                    PrintError("Плагин SpawnModularCar не установлен / SpawnModularCar plugin is not installed");
                    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.GetComponent<BasePlayer>();
                var mountable = bot?.GetMountedVehicle();
                if(mountable != null) mountable.Kill();
                if(bot != null) bot.Kill();
            }
        }
        private void OnConvoyStop() {
            if(_spawner) _spawner.Resume(true);
        }
        private void Unload() {
            UnityEngine.Object.Destroy(_spawner);
            foreach(var driver in _carsDrivers.Values) {
                if(driver == null) continue;
                var bot = driver.GetComponent<BasePlayer>();
                var mountable = bot?.GetMountedVehicle();
                if(mountable != null) mountable.Kill();
                if(bot != null) bot.Kill();
            }
            foreach(var recorder in _recorders.Values) {
                if(recorder == null) return;
                UnityEngine.Object.Destroy(recorder);
            }
        }
        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 OnEntityTakeDamage(BaseVehicleModule module, HitInfo info) {
            if(module == null) return null;
            var car = module.Vehicle;
            if(car == null) return null;
            var driver = car.GetDriver();
            if(driver) {
                var traffic = GetDriver(driver.net.ID);
                if(traffic) {
                    if(traffic.IsCarImmortal) {
                        info.damageTypes = new Rust.DamageTypeList();
                        info.DidHit = false;
                        info.DoHitEffects = false;
                        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);
                        if(driver) {
                            if(driver.IsImmortal) return false;
                            info.damageTypes.ScaleAll(driver.GetDamageReceiveRate());
                        }
                        else {
                            var companion = GetCompanion(player.net.ID);
                            if(companion) {
                                var companionDriver = GetDriver(companion.GetDriverID());
                                if(companionDriver) {
                                    if(companionDriver.IsImmortal) return false;
                                }
                                info.damageTypes.ScaleAll(companion.GetDamageReceiveRate());
                            }
                        }
                    }
                }
            }
            else {
                if(_config.limits.convoy.enableConvoySupport) {
                    if(_config.limits.convoy.destroyCarsOnHit) {
                        if(Convoy) {
                            if(info.Initiator is ModularCar) {
                                var driverMounted = ((ModularCar)info.Initiator).GetDriver();
                                if(driverMounted != null) {
                                    var driver = GetDriver(driverMounted.net.ID);
                                    if(driver != null) {
                                        if(Convoy.Call<bool>("IsConvoyVehicle", entity)) {
                                            UnityEngine.Object.Destroy(driver);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                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);
                    if(driver == null) return null;
                    if(driver.IsImmortal) return false;
                    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) {
                var initiatorCompanion = GetCompanion(info.InitiatorPlayer.net.ID);
                if(initiatorCompanion) {
                    if(_carsDrivers.ContainsKey(entity.net.ID)) return false;
                }
            }
            return null;
        }
        private void OnServerInitialized() {
            if(_data == null) LoadData();
            if(_data.pathes.Count == 0) {
                Puts("Записанные пути не найдены, загружаем стандартные дороги Rust / Recorded paths not found, load standard Rust roads");
                foreach(var path in TerrainMeta.Path.Roads) {
                    if(path.Path.Points.Length < _config.limits.minRoadWidth || 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.");
                    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($"Найдено подходящих дорог: {_roadPathes.Count} / Finded suitable roads: {_roadPathes.Count}");
        }
        private object OnNpcTarget(BaseEntity npc, BaseEntity entity) {
            if(npc == null || entity == null) return null;
            if(_config.limits.blockTrafficTarget) {
                var driver = GetDriver(entity.net.ID);
                if(driver != null) return true;
                var companionBlock = GetCompanion(entity.net.ID);
                if(companionBlock != null) return true;
            }
            var companion = GetCompanion(npc.net.ID);
            if(companion != null) {
                if(!companion.CanTargetEntity(entity)) return true;
            }
            return null;
        }
#endregion
#region Методы
        [ConsoleCommand("trafficdrivers.debug")]
        private void showDebugInfo(ConsoleSystem.Arg arg) {
            if(arg.Player() != null) return;
            var drivers = _spawner.GetDrivers();
            string msg = $"Всего машин трафика: {drivers.Count} / Traffic cars amount: {drivers.Count}";
            foreach(var driver in drivers) {
                if(driver == null) continue;
                msg += $"\n{driver.CarPresetName}: {PhoneController.PositionToGridCoord(driver.transform.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;
            }
        }
        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("assets/prefabs/player/player.prefab", position, Quaternion.identity) as BasePlayer;
            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();
            bot.InitializeHealth(driverPreset.health.min, driverPreset.health.max);
            foreach(var cloth in driverPreset.clothes) bot.inventory.containerWear.Insert(ItemManager.CreateByName(cloth.shortname, 1, cloth.skin));
            foreach(var loot in driverPreset.loot) {
                if(UnityEngine.Random.Range(0, 100) < loot.chance) {
                    Item item = ItemManager.CreateByName(loot.shortname, (int)loot.amount.Randomize(), loot.skin);
                    if(item == null) continue;
                    if(!string.IsNullOrEmpty(loot.name)) item.name = loot.name;
                    if(loot.container == "main") bot.inventory.containerMain.Insert(item);
                    if(loot.container == "belt") bot.inventory.containerBelt.Insert(item);
                    if(loot.container == "wear") bot.inventory.containerWear.Insert(item);
                }
            }
            ModularCar car = SpawnModularCar.Call<ModularCar>("API_SpawnPresetCar", bot, carPreset.ConvertForAPI());
            car.enableSaving = false;
            if(carPreset.infiniteFuel) {
                var container = car.GetFuelSystem().fuelStorageInstance.Get(true);
                if (container != null) {
                    var item = ItemManager.CreateByName("lowgradefuel", 200, 12345);
                    item.OnDirty += delegate(Item item1) {
                        item1.amount = 200;
                    }
                    ;
                    container.inventory.Insert(item);
                    item.SetFlag(global : : Item.Flag.IsLocked, true);
                    container.dropsLoot = false;
                    container.inventory.SetFlag(ItemContainer.Flag.IsLocked, true);
                    container.SetFlag(BaseEntity.Flags.Locked, true);
                }
            }
            VehicleModuleStorage storage = null;
            BaseMountable driverPlace = null, companionPlace = null;
            foreach(var module in car.AttachedModuleEntities) {
                if(carPreset.storage.enableLoot && storage == null) {
                    if(module is VehicleModuleStorage && module.ShortPrefabName == "1module_storage") {
                        storage = module as VehicleModuleStorage;
                        var container = storage.GetContainer();
                        if(container.inventory.entityOwner is StorageContainer) {
                            ((StorageContainer)container.inventory.entityOwner).dropsLoot = false;
                        }
                        foreach(var item in carPreset.storage.lootInfo) {
                            if(UnityEngine.Random.Range(0, 100) > item.chance) continue;
                            Item loot = ItemManager.CreateByName(item.shortname, (int)item.amount.Randomize(), item.skin);
                            if(!string.IsNullOrEmpty(item.name)) loot.name = item.name;
                            container.inventory.Insert(loot);
                        }
                    }
                }
                if(carPreset.blockEngineLooting) {
                    if(module is VehicleModuleEngine) {
                        var container = ((VehicleModuleEngine)module).GetContainer();
                        container.inventory.SetLocked(true);
                        if(container.inventory.entityOwner is StorageContainer) ((StorageContainer)container.inventory.entityOwner).dropsLoot = false;
                    }
                }
                if(module is VehicleModuleSeating) {
                    var seating = module as VehicleModuleSeating;
                    foreach(var info in seating.mountPoints) {
                        if(driverPlace != null) {
                            if(companionPlace == null && !driverPreset.companion.enableCompanion) break;
                            if(companionPlace != null) break;
                        }
                        if(info.isDriver && driverPlace == null) {
                            driverPlace = info.mountable;
                            if(carPreset.enableBlueLights) AddFlashingLights(seating);
                        }
                        else if(!info.isDriver && companionPlace == null && driverPreset.companion.enableCompanion) {
                            companionPlace = info.mountable;
                        }
                    }
                }
            }
            driverPlace.MountPlayer(bot);
            ScientistNPC companion = null;
            if(driverPreset.companion.enableCompanion) {
                companion = GameManager.server.CreateEntity("assets/rust.ai/agents/npcplayer/humannpc/scientist/scientistnpc_full_any.prefab", position, Quaternion.identity) as ScientistNPC;
                companion.Spawn();
                companion.enableSaving = false;
                var trafficCompanion = companion.gameObject.AddComponent<TrafficCompanion>();
                trafficCompanion.Init(driverPreset.companion, bot.net.ID);
                companionPlace.MountPlayer(companion);
                _driverCompanions.Add(companion.net.ID, trafficCompanion);
            }
            var driver = bot.gameObject.AddComponent<TrafficDriver>();
            driver.AssignCar(car, path, side, driverPreset, carPreset, GetKeyFromValue(_config.carPresets, carPreset), _config.limits.stuckDespawnTime, companion != null ? companion.GetComponent<TrafficCompanion>() : null);
            _carsDrivers.Add(bot.net.ID, driver);
            Puts($"Машина для трафика была успешно заспавнена! | Traffic car was sucessfully spawned!");
            return driver;
        }
        private void AddFlashingLights(VehicleModuleSeating module) {
            BaseEntity light1 = GameManager.server.CreateEntity("assets/prefabs/deployable/playerioents/lights/flasherlight/electric.flasherlight.deployed.prefab", module.transform.position), light2 = GameManager.server.CreateEntity("assets/prefabs/deployable/playerioents/lights/flasherlight/electric.flasherlight.deployed.prefab", module.transform.position);
            DestroyOnGroundMissing groundMissing;
            if(light1.TryGetComponent<DestroyOnGroundMissing>(out groundMissing)) UnityEngine.Object.Destroy(groundMissing);
            if(light2.TryGetComponent<DestroyOnGroundMissing>(out groundMissing)) UnityEngine.Object.Destroy(groundMissing);
            GroundWatch groundWatch;
            if(light1.TryGetComponent<GroundWatch>(out groundWatch)) UnityEngine.Object.Destroy(groundWatch);
            if(light2.TryGetComponent<GroundWatch>(out groundWatch)) UnityEngine.Object.Destroy(groundWatch);
            StabilityEntity stabilityEntity;
            if(light1.TryGetComponent<StabilityEntity>(out stabilityEntity)) UnityEngine.Object.Destroy(stabilityEntity);
            if(light2.TryGetComponent<StabilityEntity>(out stabilityEntity)) UnityEngine.Object.Destroy(stabilityEntity);
            light1.Spawn();
            light2.Spawn();
            light1.SetParent(module, true);
            light2.SetParent(module, true);
            module.AddChild(light1);
            module.AddChild(light2);
            light1.transform.localPosition += new Vector3(-0.5f, 1.35f, -0.4f);
            light2.transform.localPosition += new Vector3(0.5f, 1.35f, -0.4f);
            light1.SetFlag(BaseEntity.Flags.Reserved8, true);
            light2.SetFlag(BaseEntity.Flags.Reserved8, true);
            light1.SendNetworkUpdateImmediate(true);
            light2.SendNetworkUpdateImmediate(true);
            module.SendNetworkUpdateImmediate(true);
        }
        private TrafficDriver SpawnTrafficCar() {
            var road = _roadPathes[UnityEngine.Random.Range(0, _roadPathes.Count)];
            var side = UnityEngine.Random.Range(-5, 5) > 0 ? TrafficDriver.DriveSide.Right : TrafficDriver.DriveSide.Left;
            var position = road[side == TrafficDriver.DriveSide.Right ? 0 : road.Length - 1];
            return SpawnTrafficCarParams(road, position, side);
        }
        public static string GetKeyFromValue(Dictionary<string, Configuration.CarPreset> dictionary, Configuration.CarPreset value) {
            foreach (string keyVar in dictionary.Keys) {
                if (dictionary[keyVar] == value) return keyVar;
            }
            return null;
        }
#endregion
#region Запись пути
        private class PlayerPathRecorder : FacepunchBehaviour {
            private TrafficDrivers _pluginInstance;
            private BasePlayer _player;
            private List<Vector3> _path = new List<Vector3>();
            private bool _isRecording = false;
            private void Start() => _player = GetComponent<BasePlayer>();
            public virtual void Init(TrafficDrivers plugin) => _pluginInstance = plugin;
            public void Input() {
                if(_isRecording) {
                    StopRecording();
                    _path.Add(_player.transform.position);
                    _pluginInstance._data.pathes.Add(_pluginInstance._data.pathes.Keys.Count, _path);
                    switch(_pluginInstance.lang.GetLanguage(_player.UserIDString)) {
                        case "ru" : _player.ChatMessage($"Путь записан и сохранен в дата-файл.Индекс: {_pluginInstance._data.pathes.Keys.Count - 1}");
                        break;
                        default : _player.ChatMessage($"Path recorded and saved to data.Index: {_pluginInstance._data.pathes.Keys.Count - 1}");
                        break;
                    }
                    _pluginInstance.SaveData();
                    Destroy(this);
                }
                else {
                    StartRecording();
                    switch(_pluginInstance.lang.GetLanguage(_player.UserIDString)) {
                        case "ru" : _player.ChatMessage("Запись пути начата! Нажмите R чтобы остановить запись.");
                        break;
                        default : _player.ChatMessage("Path recording started! Press R to stop recording.");
                        break;
                    }
                }
            }
            public void StartRecording() {
                _isRecording = true;
                InvokeRepeating(() => Record(), 0.1f, 1f);
            }
            public void StopRecording() => _isRecording = false;
            public virtual void Record() {
                if(!_isRecording) return;
                _path.Add(_player.transform.position);
                switch(_pluginInstance.lang.GetLanguage(_player.UserIDString)) {
                    case "ru" : _player.ChatMessage($"Добавлена точка {_player.transform.position}, индекс {_path.Count - 1}");
                    break;
                    default : _player.ChatMessage($"Added point {_player.transform.position}, index {_path.Count - 1}");
                    break;
                }
            }
        }
#endregion
#region Поведение
        public class TrafficCompanion : FacepunchBehaviour {
            private ScientistNPC _npc;
            private Configuration.DriverPreset.CompanionSetup _setup;
            private uint _driverNetID;
            private List<uint> _attackers = new List<uint>();
            public virtual bool CanTargetEntity(BaseEntity ent) => _driverNetID != ent.net.ID && _attackers.Contains(ent.net.ID);
            public virtual float GetDamageReceiveRate() => _setup.damageReceiveRate;
            public virtual uint GetDriverID() => _driverNetID;
            public virtual void Kill() => _npc.Kill();
            public virtual void AddAttacker(uint id) {
                if(_attackers.Contains(id)) return;
                _attackers.Add(id);
            }
            public virtual void Init(Configuration.DriverPreset.CompanionSetup companionSetup, uint driverNet) {
                _driverNetID = driverNet;
                _setup = companionSetup;
                _npc = GetComponent<ScientistNPC>();
                var navigator = GetComponent<BaseNavigator>();
                navigator.CanUseNavMesh = false;
                navigator.MaxRoamDistanceFromHome = navigator.BestMovementPointMaxDistance = navigator.BestRoamPointMaxDistance = 0f;
                navigator.DefaultArea = "Not Walkable";
                _npc.displayName = _setup.name;
                _npc._health = companionSetup.health.Randomize();
                _npc.inventory.containerWear.Clear();
                _npc.Brain = _npc.GetComponent<ScientistBrain>();
                _npc.CancelInvoke(_npc.EquipTest);
                foreach(var item in _npc.inventory.containerBelt.itemList) item.Remove();
                foreach(var weapon in _setup.weapons) ItemManager.CreateByName(weapon.shortname, 1, weapon.skin).MoveToContainer(_npc.inventory.containerBelt);
                foreach(var item in _npc.inventory.containerBelt.itemList) {
                    if(item.info.category == ItemCategory.Weapon) {
                        var held = item.GetHeldEntity();
                        if(held != null) {
                            if(held is BaseProjectile) {
                                var projectile = held as BaseProjectile;
                                projectile.damageScale += _setup.damageHurtRate;
                            }
                        }
                    }
                }
                foreach(var cloth in _setup.clothes) ItemManager.CreateByName(cloth.shortname, 1, cloth.skin).MoveToContainer(_npc.inventory.containerWear);
                _npc.EquipWeapon();
            }
        }
        public class TrafficDriver : FacepunchBehaviour {
            public enum Movement {
                Idle = 0, Forward = 2, Backward = 4, Left = 8, Right = 16
            }
            public enum DriveSide {
                Left = -1, Right = 1
            }
            private ModularCar _car;
            private BasePlayer _driver;
            private TrafficCompanion _companion;
            private DriveSide _side;
            private Vector3[] _path;
            private Configuration.DriverPreset _driverPreset;
            private Configuration.CarPreset _carPreset;
            private float _lastObstacleTime;
            private int _currentPathIndex = 0;
            private float _lastIncreaseSpeedTime, _stuckTime, _lastDestinationTime, _spawnTime, _lastTimeBackwards;
            public bool IsImmortal => _spawnTime + _carPreset.immortalTime > Time.realtimeSinceStartup;
            public bool IsCarImmortal => _carPreset.enableImmortal;
            public string CarPresetName;
            public virtual float GetDamageReceiveRate() => _driverPreset.damageReceiveRate;
            public virtual void Start() {
                _driver = GetComponent<BasePlayer>();
                _spawnTime = Time.realtimeSinceStartup;
                _lastDestinationTime = Time.realtimeSinceStartup;
                InvokeRepeating(() => {
                    var instance = TOD_Sky.Instance;
                    if(instance) {
                        if(_car) {
                            _car.SetFlag(BaseEntity.Flags.Reserved5, (instance.Cycle.Hour < 8 && instance.Cycle.Hour > 0));
                        }
                    }
                }
                , 5f, 5f);
            }
            public virtual void AssignCar(ModularCar car, Vector3[] path, DriveSide side, Configuration.DriverPreset driverPreset, Configuration.CarPreset carPreset, string carPresetName, float stuckTime, TrafficCompanion companion) {
                CarPresetName = carPresetName;
                _companion = companion;
                _stuckTime = stuckTime;
                _car = car;
                _side = side;
                _path = path;
                _carPreset = carPreset;
                _driverPreset = driverPreset;
                _currentPathIndex = ((int)_side) > 0 ? 0 : _path.Length - 1;
            }
            public virtual void OnAttacked(BaseEntity attacker) {
                if(_companion) _companion.AddAttacker(attacker.net.ID);
                if(_driverPreset.attackBehaviour == 3) _lastIncreaseSpeedTime = UnityEngine.Time.realtimeSinceStartup + 10;
            }
            public virtual void OnPhysicAttacked() => _lastObstacleTime = UnityEngine.Time.realtimeSinceStartup + 3;
            public virtual void Update() {
                if(_car == null) {
                    if(_companion) _companion.Kill();
                    _driver.Kill();
                    return;
                }
                if(_lastDestinationTime + _stuckTime < Time.realtimeSinceStartup) {
                    if(_companion) _companion.Kill();
                    foreach(var module in _car.AttachedModuleEntities) {
                        if(module is VehicleModuleStorage) {
                            var storage = module as VehicleModuleStorage;
                            var container = storage.GetContainer();
                            for (int i = container.inventory.itemList.Count - 1; i >= 0; i--) {
                                var item = container.inventory.itemList[i];
                                container.inventory.Remove(item);
                            }
                        }
                    }
                    _car.Kill();
                    return;
                }
                else if(_lastDestinationTime + (_stuckTime / 3) < Time.realtimeSinceStartup && _lastObstacleTime < Time.realtimeSinceStartup && _lastTimeBackwards < Time.realtimeSinceStartup) {
                    _lastTimeBackwards = Time.realtimeSinceStartup + 10;
                    OnPhysicAttacked();
                }
                Vector3 destination = Vector3.zero;
                if(_side == DriveSide.Left) destination = _path[_currentPathIndex] + new Vector3(2, 1, -4.5f * (int)TrafficDriver.DriveSide.Left - 2);
                else destination = _path[_currentPathIndex] + new Vector3(-2, 1, -3 * (int)TrafficDriver.DriveSide.Right + 2);
                if(Vector3.Distance(_car.transform.position, destination) < 10f) {
                    _lastDestinationTime = Time.realtimeSinceStartup;
                    _currentPathIndex += (int)_side;
                    if(_side == DriveSide.Left) {
                        if(_currentPathIndex < 0) {
                            _currentPathIndex = 0;
                            _side = DriveSide.Right;
                        }
                    }
                    else {
                        if(_currentPathIndex > _path.Length - 1) {
                            _currentPathIndex = _path.Length - 1;
                            _side = DriveSide.Left;
                        }
                    }
                }
                Movement verticalMovement = Movement.Idle, horizontalMovement = Movement.Idle;
                Vector3 lhs = BradleyAPC.Direction2D(destination, _car.transform.position);
                float dotRight = Vector3.Dot(lhs, _car.transform.right);
                var turning = Vector3.Dot(lhs, -_car.transform.forward) <= dotRight ? Mathf.Clamp(dotRight * 3f, -1f, 1f) : (dotRight < Vector3.Dot(lhs, -_car.transform.right) ? -1f : 1f);
                var throttle = (0.1f + Mathf.InverseLerp(0f, 20f, Vector3.Distance(_car.transform.position, destination)) * 1) * (1f - Mathf.InverseLerp(0f, 0.3f, Mathf.Abs(turning))) + Mathf.InverseLerp(0.1f, 0.4f, Vector3.Dot(_car.transform.forward, Vector3.up));
                if(_lastObstacleTime > UnityEngine.Time.realtimeSinceStartup) verticalMovement = Movement.Backward;
                else if(GetSpeed() < _carPreset.maxSpeed) verticalMovement = Movement.Forward;
                if(verticalMovement != Movement.Backward) {
                    if(turning < -0.6f) horizontalMovement = Movement.Left;
                    else if(turning > 0.6f) horizontalMovement = Movement.Right;
                }
                _car.PlayerServerInput(new InputState {
                    current = new InputMessage {
                        buttons = (int)(verticalMovement | horizontalMovement)
                    }
                }
                , _driver);
            }
            private float GetSpeed() => _car.GetSpeed() - ((_lastIncreaseSpeedTime > UnityEngine.Time.realtimeSinceStartup) ? 5 : 0);
            private void OnDestroy() {
                Interface.CallHoo
// ... [Code preview truncated due to length. Full source in attached file] ...

Автор
15FPS
Скачиваний
0
Просмотры
1
Первый выпуск
Обновление
Оценка
0.00 звёзд 0 оценок

Другие ресурсы пользователя 15FPS

Сверху