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

FREE RaceTrack : 0.2.24 0.2.24

Нет прав для скачивания
C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using System;
using System.Collections;
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Oxide.Core;
using Oxide.Core.Configuration;
using Oxide.Game.Rust.Cui;
using Oxide.Core.Plugins;
using UnityEngine;
using System.Linq;
using System.Globalization;
using System.Reflection;
using Rust;
namespace Oxide.Plugins {
    using Extensions;
    [Info("RaceTrack", "k1lly0u", "0.2.24")]
    [Description("A standalone racing event for cars, boats, mincopters and horses")]
    class RaceTrack : RustPlugin {
#region Fields
        [PluginReference]
        Plugin CarCommander, BoatCommander, HeliCommander, Economics, ServerRewards;
        private Hash<string, TrackData> trackData;
        private Hash<string, ModularCarData> carData;
        private RestoreData restoreData;
        private List<ulong> spawnedEntities;
        private DynamicConfigFile entitydata, trackdata, cardata, restorationData;
        private Timer autoTimer;
        private int lastEventIndex = 0;
        private Hash<string, TrackData> raceTracks = new Hash<string, TrackData>();
        private Hash<ulong, TrackData> trackCreator = new Hash<ulong, TrackData>();
        private CuiElementContainer scoreContainer;
        private LightType lightType;
        private static RaceTrack Instance;
        private static RaceManager Current;
        private const string SEDAN_PREFAB = "assets/content/vehicles/sedan_a/sedantest.entity.prefab";
        private const string ROWBOAT_PREFAB = "assets/content/vehicles/boats/rowboat/rowboat.prefab";
        private const string RHIB_PREFAB = "assets/content/vehicles/boats/rhib/rhib.prefab";
        private const string MINICOPTER_PREFAB = "assets/content/vehicles/minicopter/minicopter.entity.prefab";
        private const string HORSE_PREFAB = "assets/rust.ai/nextai/testridablehorse.prefab";
        private const string BOOGIEBOARD_PREFAB = "assets/prefabs/misc/summer_dlc/boogie_board/boogieboard.deployed.prefab";
        private const string INNER_TUBE_PREFAB = "assets/prefabs/misc/summer_dlc/inner_tube/innertube.deployed.prefab";
        private const string SUBMARINE_PREFAB = "assets/content/vehicles/submarine/submarinesolo.entity.prefab";
        private const string SNOWMOBILE_PREFAB = "assets/content/vehicles/snowmobiles/snowmobile.prefab";
        private const string KAYAK_PREFAB = "assets/content/vehicles/boats/kayak/kayak.prefab";
        private const string KAYAK_PADDLE_ITEM = "paddle";
        private const string LANTERN_PREFAB = "assets/prefabs/deployable/lantern/lantern.deployed.prefab";
        private const string FLASHER_PREFAB = "assets/prefabs/deployable/playerioents/lights/flasherlight/electric.flasherlight.deployed.prefab";
        private const string SIREN_PREFAB = "assets/prefabs/deployable/playerioents/lights/sirenlight/electric.sirenlight.deployed.prefab";
        private const string WALL_PREFAB = "assets/prefabs/building core/wall.low/wall.low.prefab";
        private enum RaceMode {
            Laps, Sprint
        }
        private enum RaceType {
            Car, Boat, RHIB, Minicopter, Horse, Kayak, BoogieBoard, InnerTube, Submarine, Snowmobile, Foot
        }
        private enum EventStatus {
            Open, Loading, Prestart, Started, Finishing, Finished
        }
        private enum LightType {
            Lantern, Flasher, Siren
        }
#endregion
#region Oxide Hooks
        private void Loaded() {
            permission.RegisterPermission("racetrack.admin", this);
            permission.RegisterPermission("racetrack.play", this);
            lang.RegisterMessages(Messages, this);
            entitydata = Interface.Oxide.DataFileSystem.GetFile("RaceTrack/entity_data");
            trackdata = Interface.Oxide.DataFileSystem.GetFile("RaceTrack/track_data");
            cardata = Interface.Oxide.DataFileSystem.GetFile("RaceTrack/car_data");
            restorationData = Interface.Oxide.DataFileSystem.GetFile("RaceTrack/restoration_data");
            trackdata.Settings.Converters = new JsonConverter[] {
                new UnityVector3Converter()
            }
            ;
            restorationData.Settings.Converters = new JsonConverter[] {
                new UnityVector3Converter()
            }
            ;
            LoadData();
        }
        private void OnServerInitialized() {
            Instance = this;
            if (Configuration.DisableSpectate) Unsubscribe(nameof(CanSpectateTarget));
            if (!Configuration.Racers.DisableMetabolism) Unsubscribe(nameof(OnRunPlayerMetabolism));
            Instance.Unsubscribe(nameof(OnEngineStart));
            lightType = ParseType<LightType>(Configuration.Checkpoints.LightType);
            CleanupEntities();
            StartEventTimer();
        }
        private void OnPlayerConnected(BasePlayer player) {
            if (player.IsSleeping() || player.HasPlayerFlag(BasePlayer.PlayerFlags.ReceivingSnapshot)) {
                timer.Once(1, () => OnPlayerConnected(player));
                return;
            }
            if (restoreData.HasRestoreData(player.userID)) restoreData.RestorePlayer(player);
        }
        private void OnPlayerRespawned(BasePlayer player) => OnPlayerConnected(player);
        private void OnPlayerDisconnected(BasePlayer player) {
            if (Current) Current.PlayerDisconnected(player);
            else {
                RaceDriver raceDriver = player.GetComponent<RaceDriver>();
                if (raceDriver) {
                    raceDriver.DismountPlayer();
                    NextTick(() => {
                        if (raceDriver) UnityEngine.Object.Destroy(raceDriver);
                    }
                    );
                }
            }
        }
        private void OnPlayerSleepEnded(BasePlayer player) {
            RaceDriver raceDriver = player.GetComponent<RaceDriver>();
            if (raceDriver) {
                if (!player.isMounted) {
                    if (raceDriver.Vehicle && raceDriver.Vehicle.GetEntity()) raceDriver.MountPlayer(raceDriver.Vehicle);
                    UpdatePosition(raceDriver);
                }
            }
        }
        private void OnEntityTakeDamage(BaseCombatEntity entity, HitInfo info) {
            if (!entity || info == null) return;
            if (entity.GetComponent<RaceDriver>()) {
                NullifyDamage(ref info);
                return;
            }
            if (entity.GetComponent<RaceVehicle>()) {
                if (Current.AllowDamage && entity is ModularCar) {
                    HandleModularVehicleDamage(entity, info);
                    return;
                }
                NullifyDamage(ref info);
                return;
            }
            BaseVehicleModule module = entity as BaseVehicleModule;
            if (module && module.Vehicle?.GetComponent<RaceVehicle>()) {
                if (Current.AllowDamage) {
                    HandleModularVehicleDamage(entity, info);
                    return;
                }
                NullifyDamage(ref info);
                return;
            }
            CheckPoint.Marker marker = entity.GetComponent<CheckPoint.Marker>();
            if (marker && Current && Current.Status != EventStatus.Finished) NullifyDamage(ref info);
        }
        private void HandleModularVehicleDamage(BaseCombatEntity entity, HitInfo info) {
            BaseModularVehicle baseModularVehicle = entity as BaseModularVehicle ?? (entity as BaseVehicleModule)?.Vehicle;
            if (baseModularVehicle) {
                RaceDriver raceDriver = entity.GetComponent<RaceVehicle>()?.Driver;
                if (raceDriver) {
                    if (info.damageTypes.GetMajorityDamageType() != DamageType.Collision) {
                        NullifyDamage(ref info);
                        return;
                    }
                    info.damageTypes.Scale(DamageType.Collision, Current.TrackData.modularDamageMulti);
                    if (info.damageTypes.Total() >= baseModularVehicle.health) {
                        Current.FailedRace(raceDriver);
                    }
                }
            }
        }
        private object OnRunPlayerMetabolism(PlayerMetabolism metabolism, BasePlayer owner, float delta) => owner.GetComponent<RaceDriver>() ? (object)true : null;
        private object CanMountEntity(BasePlayer player, BaseMountable mountable) => mountable.GetComponent<RaceModularCar>() ? (object)true : null;
        private object CanDismountEntity(BasePlayer player, BaseMountable mountable) {
            RaceDriver raceDriver = player.GetComponent<RaceDriver>();
            if (raceDriver && !raceDriver.HasFinished) return false;
            return null;
        }
        private object OnEngineStart(MiniCopter miniCopter, BasePlayer player) {
            if (!Current || Current.Status != EventStatus.Prestart) return null;
            RaceHelicopter raceHelicopter = miniCopter.GetComponent<RaceHelicopter>();
            if (raceHelicopter) return false;
            return null;
        }
        private object OnPlayerCommand(BasePlayer player, string command, string[] args) {
            if (player && player.GetComponent<RaceDriver>()) {
                if (Configuration.CommandBlacklist.Any(x => x.StartsWith("/") ? x.Substring(1).ToLower() == command : x.ToLower() == command)) {
                    SendReply(player, msg("blacklistcmd", player.UserIDString));
                    return false;
                }
            }
            return null;
        }
        private object OnServerCommand(ConsoleSystem.Arg arg) {
            BasePlayer player = arg.Player();
            if (player && player.GetComponent<RaceDriver>()) {
                if (Configuration.CommandBlacklist.Any(x => arg.cmd.FullName.Contains(x.ToLower())) || arg.cmd.FullName == "vehicle.swapseats") {
                    SendReply(player, msg("blacklistcmd", player.UserIDString));
                    return false;
                }
            }
            return null;
        }
        private object CanSpectateTarget(BasePlayer player, string name) {
            RaceDriver raceDriver = player.GetComponent<RaceDriver>();
            if (raceDriver && raceDriver.Player.IsSpectating()) {
                raceDriver.UpdateSpectateTarget(1);
                return false;
            }
            return null;
        }
        private object OnSamSiteTarget(SamSite samSite, BaseCombatEntity baseCombatEntity) => baseCombatEntity.GetComponent<RaceVehicle>() ? (object)true : null;
        private void Unload() {
            SaveRestoreData();
            if (autoTimer != null) autoTimer.Destroy();
            RaceDriver[] raceDrivers = UnityEngine.Object.FindObjectsOfType<RaceDriver>();
            if (raceDrivers != null) {
                for (int i = 0; i < raceDrivers.Length; i++) {
                    UnityEngine.Object.Destroy(raceDrivers[i]);
                }
            }
            RaceVehicle[] raceVehicles = UnityEngine.Object.FindObjectsOfType<RaceVehicle>();
            if (raceVehicles != null) {
                for (int i = 0; i < raceVehicles.Length; i++) {
                    UnityEngine.Object.Destroy(raceVehicles[i]);
                }
            }
            CheckPoint[] checkPoints = UnityEngine.Object.FindObjectsOfType<CheckPoint>();
            if (checkPoints != null) {
                for (int i = 0; i < checkPoints.Length; i++) {
                    UnityEngine.Object.Destroy(checkPoints[i]);
                }
            }
            CheckPoint.Marker[] markers = UnityEngine.Object.FindObjectsOfType<CheckPoint.Marker>();
            if (markers != null) {
                for (int i = 0; i < markers.Length; i++) {
                    UnityEngine.Object.Destroy(markers[i]);
                }
            }
            UnityEngine.Object.Destroy(Current);
            Current = null;
            Instance = null;
            Configuration = null;
        }
#endregion
#region Functions
        private void CleanupEntities() {
            if (spawnedEntities.Count > 0) {
                PrintWarning("Finding and destroying left over entities");
                foreach (BaseNetworkable obj in BaseNetworkable.serverEntities) {
                    if (obj && !obj.IsDestroyed) {
                        if (spawnedEntities.Contains(obj.net.ID.Value)) obj.Kill(BaseNetworkable.DestroyMode.None);
                    }
                }
                spawnedEntities.Clear();
                SaveEntityData();
                PrintWarning("Cleanup completed");
            }
        }
        private T ParseType<T>(string type) {
            try {
                return (T)Enum.Parse(typeof(T), type, true);
            }
            catch {
                return default(T);
            }
        }
        private static string FormatTime(double time) {
            TimeSpan dateDifference = TimeSpan.FromSeconds((float)time);
            int hours = dateDifference.Hours + (dateDifference.Days * 24);
            if (hours > 0) return string.Format("{0:00}:{1:00}:{2:00}", hours, dateDifference.Minutes, dateDifference.Seconds);
            else return string.Format("{0:00}:{1:00}", dateDifference.Minutes, dateDifference.Seconds);
        }
        private static bool IsWaterSurfaceBasedRace(RaceType raceType) => raceType == RaceType.Boat || raceType == RaceType.BoogieBoard || raceType == RaceType.InnerTube || raceType == RaceType.Kayak || raceType == RaceType.RHIB;
        private static string EntityFromRaceType(RaceType raceType) {
            switch (raceType) {
                case RaceType.Car : return SEDAN_PREFAB;
                case RaceType.Boat : return ROWBOAT_PREFAB;
                case RaceType.RHIB : return RHIB_PREFAB;
                case RaceType.Minicopter : return MINICOPTER_PREFAB;
                case RaceType.Horse : return HORSE_PREFAB;
                case RaceType.Kayak : return KAYAK_PREFAB;
                case RaceType.BoogieBoard : return BOOGIEBOARD_PREFAB;
                case RaceType.InnerTube : return INNER_TUBE_PREFAB;
                case RaceType.Submarine : return SUBMARINE_PREFAB;
                case RaceType.Snowmobile : return SNOWMOBILE_PREFAB;
                default : return string.Empty;
            }
        }
        private static Type VehicleComponentFromRaceType(RaceType raceType) {
            switch (raceType) {
                case RaceType.Car : return typeof(RaceModularCar);
                case RaceType.Boat : case RaceType.RHIB : return typeof(RaceBoat);
                case RaceType.Kayak : return typeof(RaceKayak);
                case RaceType.BoogieBoard : case RaceType.InnerTube : return typeof(RaceInflatable);
                case RaceType.Minicopter : return typeof(RaceHelicopter);
                case RaceType.Horse : return typeof(RaceHorse);
                case RaceType.Submarine : return typeof(RaceSubmarine);
                case RaceType.Snowmobile : return typeof(RaceSnowmobile);
                default : return null;
            }
        }
        private void NullifyDamage(ref HitInfo info) {
            info.damageTypes = new DamageTypeList();
            info.HitEntity = null;
            info.HitMaterial = 0;
            info.PointStart = Vector3.zero;
        }
        private void StartEventTimer() {
            if (Configuration.Automation.Enabled) {
                if (trackData.Count == 0) {
                    PrintError("You have no race tracks set up.Unable to automate events");
                    return;
                }
                autoTimer = timer.In(Configuration.Timers.Interval, () => {
                    if (Configuration.Automation.MinimumPlayers > 0 && BasePlayer.activePlayerList.Count < Configuration.Automation.MinimumPlayers) {
                        StartEventTimer();
                        return;
                    }
                    if (Configuration.Automation.Time.Enabled) {
                        float currentTime = TOD_Sky.Instance.Cycle.Hour;
                        if (Configuration.Automation.Time.Start > Configuration.Automation.Time.End) {
                            if (currentTime > Configuration.Automation.Time.Start || currentTime < Configuration.Automation.Time.End) {
                                StartEventTimer();
                                return;
                            }
                        }
                        else {
                            if (currentTime > Configuration.Automation.Time.Start && currentTime < Configuration.Automation.Time.End) {
                                StartEventTimer();
                                return;
                            }
                        }
                    }
                    if (!Current) Current = new GameObject().AddComponent<RaceManager>();
                    if (Current.Status != EventStatus.Finished) return;
                    if (Configuration.Automation.Random) {
                        KeyValuePair<string, TrackData> data = trackData.ElementAt(UnityEngine.Random.Range(0, trackData.Count));
                        Current.SetTrackData(data.Key, data.Value);
                        Current.OpenEvent();
                    }
                    else {
                        if (Configuration.Automation.Order.Count < 1) {
                            PrintError("You have no race tracks set in your config.Unable to automate events by order");
                            return;
                        }
                        if (!trackData.ContainsKey(Configuration.Automation.Order[lastEventIndex])) {
                            PrintError($"Unable to find a race track with the name : {Configuration.Automation.Order[lastEventIndex]}");
                            return;
                        }
                        TrackData data = trackData[Configuration.Automation.Order[lastEventIndex]];
                        Current.SetTrackData(Configuration.Automation.Order[lastEventIndex], data);
                        lastEventIndex++;
                        if (lastEventIndex >= Configuration.Automation.Order.Count) lastEventIndex = 0;
                        Current.OpenEvent();
                    }
                }
                );
            }
        }
        private void BroadcastEvent() {
            if (!Configuration.Entrance.Enabled) BroadcastToChat(string.Format(msg("eventopen1"), Current.RaceType));
            else {
                if (Configuration.Entrance.ServerRewards) BroadcastToChat(string.Format(msg("eventopenfee1"), Configuration.Entrance.Amount, msg("serverrewards"), Current.RaceType));
                if (Configuration.Entrance.Economics) BroadcastToChat(string.Format(msg("eventopenfee1"), Configuration.Entrance.Amount, msg("economics"), Current.RaceType));
                if (Configuration.Entrance.Scrap) BroadcastToChat(string.Format(msg("eventopenfee1"), Configuration.Entrance.Amount, msg("scrap"), Current.RaceType));
            }
            if (Configuration.Rewards.Enabled) {
                string rewards = Configuration.Rewards.ServerRewards ? msg("serverrewards") : Configuration.Rewards.Scrap ? msg("scrap") : msg("economics");
                if (Configuration.Rewards.Podium) BroadcastToChat(string.Format(msg("eventprizepodium"), Configuration.Rewards.Prize1, rewards, Configuration.Rewards.Prize2, Configuration.Rewards.Prize3));
                else BroadcastToChat(string.Format(msg("eventprize"), Configuration.Rewards.Prize1, rewards));
            }
        }
        private void OnVehicleUnderwater(BasicCar car) {
            RaceModularCar raceCar = car.GetComponent<RaceModularCar>();
            if (raceCar) {
                raceCar.ResetVehicle();
                Instance.CarCommander.Call("ToggleController", car, true);
            }
        }
        private static void DisableTerrainAntiHack() {
            int protection = ConVar.AntiHack.terrain_protection;
            ConVar.AntiHack.terrain_protection = 0;
            Instance.timer.In(3f, () => ConVar.AntiHack.terrain_protection = protection);
        }
        private static void BroadcastToChat(string message) {
            foreach (BasePlayer player in BasePlayer.activePlayerList) player.SendConsoleCommand("chat.add", new object[] {
                0, 0, message
            }
            );
        }
        private static string ToOrdinal(int i) => (i + "th").Replace("1th", "1st").Replace("2th", "2nd").Replace("3th", "3rd");
        private object IsEventPlayer(BasePlayer player) => player.GetComponent<RaceDriver>() ? (object)true : null;
        private object isEventPlayer(BasePlayer player) => player.GetComponent<RaceDriver>() ? (object)true : null;
#endregion
#region Component
        private class RaceManager : MonoBehaviour {
            private List<BasePlayer> joiners;
            private List<RaceDriver> raceDrivers;
            private List<RaceVehicle> raceVehicles;
            private List<CheckPoint> checkPoints;
            private List<RaceDriver> positions;
            internal List<RaceDriver> spectateTargets;
            private RaceScores[] winners;
            private int playersFinished;
            private int playersFailed;
            private int totalRacers;
            private int maxRacers;
            private int countdown = 10;
            private int timerTick;
            private double startTime;
            private double endTime;
            private bool hasStarted;
            private bool isEnding;
            private bool isStarting;
            private bool hasLaunchedFirework;
#region Properties
            public EventStatus Status {
                get;
                private set;
            }
            public bool HasTrackSet => TrackData != null;
            public int RacerCount => raceDrivers.Count;
            public int CheckpointCount => TrackData.checkPoints.Count;
            public int JoinerCount => joiners.Count;
            public string TrackName {
                get;
                private set;
            }
            public RaceMode RaceMode => TrackData.raceMode;
            public RaceType RaceType => TrackData.raceType;
            public bool AllowDamage => TrackData.allowVehicleDamage && TrackData.UseModularCars;
            public TrackData TrackData {
                get;
                private set;
            }
            public List<CheckPoint> Checkpoints => checkPoints;
            public int Laps => TrackData.laps;
            public double StartTime => startTime;
            public double CurrentTime => DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds;
            public bool CanReset {
                get;
                private set;
            }
#endregion
            private void Awake() {
                joiners = Facepunch.Pool.GetList<BasePlayer>();
                raceDrivers = Facepunch.Pool.GetList<RaceDriver>();
                raceVehicles = Facepunch.Pool.GetList<RaceVehicle>();
                checkPoints = Facepunch.Pool.GetList<CheckPoint>();
                spectateTargets = Facepunch.Pool.GetList<RaceDriver>();
                positions = Facepunch.Pool.GetList<RaceDriver>();
                countdown = Configuration.Timers.Countdown;
                Status = EventStatus.Finished;
                enabled = false;
            }
            private void OnDestroy() {
                DestroyEvent();
                Instance?.StartEventTimer();
            }
#region Event Management
            public void SetTrackData(string trackName, TrackData trackData) {
                this.TrackName = trackName;
                this.TrackData = trackData;
                maxRacers = trackData.gridPoints.Count;
            }
            public void OpenEvent() {
                if (Instance.autoTimer != null) Instance.autoTimer.Destroy();
                isStarting = false;
                isEnding = false;
                hasStarted = false;
                CanReset = false;
                Status = EventStatus.Loading;
                Instance.scoreContainer = null;
                ServerMgr.Instance.StartCoroutine(CreateCheckPoints());
            }
            public void StartEvent() {
                if (TrackData.raceType == RaceType.Minicopter) Instance.Subscribe("OnEngineStart");
                isStarting = false;
                hasStarted = true;
                Status = EventStatus.Prestart;
                InvokeHandler.CancelInvoke(this, StartEvent);
                InvokeHandler.CancelInvoke(this, EndEvent);
                for (int i = 0; i < joiners.Count; i++) {
                    BasePlayer joiner = joiners[i];
                    if (!joiner || joiner.IsDead()) continue;
                    SpawnPlayer(joiner);
                }
                joiners.Clear();
                DisplayInformation(raceDrivers, TrackName, TrackData);
                Countdown();
                winners = new RaceScores[raceDrivers.Count];
                playersFinished = 0;
                totalRacers = raceDrivers.Count;
            }
            public void EndEvent() {
                Instance.Unsubscribe("OnEngineStart");
                InvokeHandler.CancelInvoke(this, Countdown);
                InvokeHandler.CancelInvoke(this, CalculateScores);
                raceDrivers.ForEach((RaceDriver driver) => {
                    driver.UpdateTravelDistance();
                    CuiHelper.DestroyUi(driver.Player, UITime);
                }
                );
                if (Status == EventStatus.Open) {
                    Status = EventStatus.Finished;
                    Instance.IssueRefunds(joiners);
                    joiners.Clear();
                    BroadcastToChat(msg("cancelled"));
                    Destroy(this);
                }
                else FinishRace();
            }
            public void JoinEvent(BasePlayer player) {
                if (Status != EventStatus.Open) {
                    player.ChatMessage(Status == EventStatus.Finished ? msg("noevent", player.UserIDString) : msg("nojoin", player.UserIDString));
                    return;
                }
                if (joiners.Contains(player)) {
                    player.ChatMessage(msg("inevent", player.UserIDString));
                    return;
                }
                if (joiners.Count >= maxRacers) {
                    player.ChatMessage(msg("eventfull", player.UserIDString));
                    return;
                }
                joiners.Add(player);
                player.ChatMessage(msg("joinevent", player.UserIDString));
                BroadcastToChat(string.Format(msg("joinevent.player"), player.displayName));
                if (joiners.Count >= TrackData.minPlayers && !isStarting) {
                    isStarting = true;
                    InvokeHandler.CancelInvoke(this, EndEvent);
                    BroadcastToChat(string.Format(msg("minplayers.reached"), Configuration.Timers.StartTime));
                    InvokeHandler.Invoke(this, StartEvent, Configuration.Timers.StartTime);
                }
            }
            public void LeaveEvent(BasePlayer player, bool hasFinished) {
                if (Status == EventStatus.Open) {
                    if (joiners.Contains(player)) {
                        Instance.IssueRefund(player);
                        joiners.Remove(player);
                        if (joiners.Count < TrackData.minPlayers) {
                            isStarting = false;
                            InvokeHandler.CancelInvoke(this, EndEvent);
                            InvokeHandler.CancelInvoke(this, StartEvent);
                            InvokeHandler.Invoke(this, EndEvent, Configuration.Timers.CloseTime);
                            BroadcastToChat(string.Format(msg("leftevent.wait"), player.displayName));
                        }
                        else BroadcastToChat(string.Format(msg("leftevent"), player.displayName));
                    }
                }
                else if (Status == EventStatus.Prestart || Status == EventStatus.Started) {
                    RaceDriver raceDriver = player.GetComponent<RaceDriver>();
                    if (raceDriver) {
                        raceDrivers.Remove(raceDriver);
                        spectateTargets.Remove(raceDriver);
                        positions.Remove(raceDriver);
                        raceDriver.UpdateTravelDistance();
                        if (!Configuration.DisableSpectate) {
                            DisableTerrainAntiHack();
                            raceDrivers.ForEach((RaceDriver spectatorDriver) => {
                                if (spectatorDriver.Player.IsSpectating()) {
                                    if (raceDrivers.Count == 0) spectatorDriver.FinishSpectating();
                                    else {
                                        if (raceDriver.SpectateTarget == raceDriver) raceDriver.UpdateSpectateTarget();
                                    }
                                }
                            }
                            );
                        }
                        winners[raceDrivers.Count] = new RaceScores(raceDriver, CurrentTime - StartTime, raceDriver.LapNumber - 1, raceDriver.TotalDistanceTravelled);
                        winners[raceDrivers.Count].hasFinished = false;
                        Destroy(raceDriver);
                        if (!hasFinished) BroadcastToChat(string.Format(msg("leftevent"), player.displayName));
                        totalRacers -= 1;
                        if (raceDrivers.Count == 0) EndEvent();
                    }
                }
                else player.ChatMessage(msg("noevent", player.UserIDString));
            }
            private void DestroyEvent() {
                isStarting = false;
                isEnding = false;
                CanReset = false;
                joiners.Clear();
                for (int i = raceDrivers.Count - 1; i >= 0; i--) Destroy(raceDrivers[i]);
                raceDrivers.Clear();
                for (int i = raceVehicles.Count - 1; i >= 0; i--) Destroy(raceVehicles[i]);
                raceVehicles.Clear();
                for (int i = checkPoints.Count - 1; i >= 0; i--) Destroy(checkPoints[i]);
                checkPoints.Clear();
                Facepunch.Pool.FreeList(ref joiners);
                Facepunch.Pool.FreeList(ref raceDrivers);
                Facepunch.Pool.FreeList(ref spectateTargets);
                Facepunch.Pool.FreeList(ref raceVehicles);
                Facepunch.Pool.FreeList(ref checkPoints);
                Facepunch.Pool.FreeList(ref positions);
                InvokeHandler.CancelInvoke(this, OpenEvent);
                InvokeHandler.CancelInvoke(this, StartEvent);
                InvokeHandler.CancelInvoke(this, EndEvent);
                InvokeHandler.CancelInvoke(this, CalculateScores);
                InvokeHandler.CancelInvoke(this, Countdown);
                InvokeHandler.CancelInvoke(this, DestroyCountdown);
                InvokeHandler.CancelInvoke(this, FinishRace);
            }
            private IEnumerator DestroyCheckpoints() {
                for (int i = checkPoints.Count - 1; i >= 0; i--) {
                    Destroy(checkPoints[i]);
                    yield return new WaitForSeconds(0.5f);
                }
                checkPoints.Clear();
                Destroy(this, 15f);
            }
#endregion
#region Player Management
            private void SpawnPlayer(BasePlayer player) {
                if (!player) return;
                if (player.isMounted) {
                    player.GetMounted().DismountPlayer(player, true);
                    player.DismountObject();
                }
                if (player.IsSleeping()) player.EndSleeping();
                player.inventory.crafting.CancelAll(true);
                Instance.restoreData.AddData(player);
                player.inventory.Strip();
                Instance.NextTick(() => {
                    player.inventory.containerWear.SetFlag(ItemContainer.Flag.IsLocked, true);
                    string[] clothing = Configuration.Racers.Clothing.GetRandom();
                    for (int i = 0; i < clothing.Length; i++) {
                        Item item = ItemManager.CreateByName(clothing[i]);
                        if (item != null) {
                            if (!item.MoveToContainer(player.inventory.containerWear)) item.Remove(0f);
                        }
                    }
                }
                );
                player.metabolism.Reset();
                player.health = 100f;
                int gridId = raceDrivers.Count;
                RaceDriver raceDriver = player.gameObject.AddComponent<RaceDriver>();
                raceDrivers.Add(raceDriver);
                spectateTargets.Add(raceDriver);
                positions.Add(raceDriver);
                TrackData.PointInfo gridPoint = TrackData.gridPoints[gridId];
                if (TrackData.raceType == RaceType.Foot) {
                    raceDriver.gridId = gridId;
                    raceDriver.Manager = this;
                    raceDriver.Position = gridId + 1;
                    if (player.isMounted) {
                        player.GetMounted()?.DismountPlayer(player);
                        Instance.NextTick(() => {
                            MovePosition(player, gridPoint.position, true);
                            player.OverrideViewAngles(Quaternion.Euler(0, gridPoint.rotation, 0) * Vector3.forward);
                        }
                        );
                        return;
                    }
                    MovePosition(player, gridPoint.position, true);
                    player.OverrideViewAngles(Quaternion.Euler(0, gridPoint.rotation, 0) * Vector3.forward);
                    raceDriver.freezePosition = gridPoint.position;
                }
                else {
                    BaseEntity baseEntity = CreateEntity(RaceType, gridPoint.position, gridPoint.rotation, TrackData.useCommander, TrackData.UseModularCars);
                    RaceVehicle raceVehicle = RaceType == RaceType.Car && !TrackData.UseModularCars ? baseEntity.gameObject.AddComponent<RaceSedan>() : baseEntity.gameObject.AddComponent(VehicleComponentFromRaceType(RaceType)) as RaceVehicle;
                    Instance.spawnedEntities.Add(baseEntity.net.ID.Value);
                    raceVehicles.Add(raceVehicle);
                    raceVehicle.ToggleKinematic(true);
                    if (RaceType == RaceType.Horse) (baseEntity as RidableHorse).SetBreed(TrackData.horseBreed);
                    raceVehicle.Driver = raceDriver;
                    raceVehicle.Manager = this;
                    raceDriver.gridId = gridId;
                    raceDriver.Vehicle = raceVehicle;
                    raceDriver.Manager = this;
                    raceDriver.Position = gridId + 1;
                    raceDriver.enabled = false;
                    if (player.isMounted) {
                        player.GetMounted()?.DismountPlayer(player);
                        Instance.NextTick(() => MovePosition(player, raceVehicle.transform.position + raceVehicle.transform.up, true));
                        return;
                    }
                    MovePosition(player, raceVehicle.transform.position + raceVehicle.transform.up, true);
                }
            }
            public void PlayerDisconnected(BasePlayer player) {
                if (joiners.Contains(player)) {
                    joiners.Remove(player);
                    if (joiners.Count < TrackData.minPlayers) {
                        isStarting = false;
                        InvokeHandler.CancelInvoke(this, EndEvent);
                        InvokeHandler.CancelInvoke(this, StartEvent);
                        InvokeHandler.Invoke(this, EndEvent, Configuration.Timers.CloseTime);
                        BroadcastToChat(string.Format(msg("leftevent.wait"), player.displayName));
                    }
                    else BroadcastToChat(string.Format(msg("leftevent"), player.displayName));
                }
                RaceDriver raceDriver = player.GetComponent<RaceDriver>();
                if (raceDriver) {
                    raceDrivers.Remove(raceDriver);
                    spectateTargets.Remove(raceDriver);
                    positions.Remove(raceDriver);
                    if (!Configuration.DisableSpectate) {
                        DisableTerrainAntiHack();
                        raceDrivers.ForEach((RaceDriver spectatorDriver) => {
                            if (spectatorDriver.Player.IsSpectating()) {
                                if (raceDrivers.Count == 0) spectatorDriver.FinishSpectating();
                                else {
                                    if (raceDriver.SpectateTarget == raceDriver) raceDriver.UpdateSpectateTarget();
                                }
                            }
                        }
                        );
                    }
                    winners[raceDrivers.Count] = new RaceScores(raceDriver, CurrentTime - StartTime, raceDriver.LapNumber - 1, raceDriver.TotalDistanceTravelled);
                    winners[raceDrivers.Count].hasFinished = false;
                    raceDriver.DismountPlayer();
                    Destroy(raceDriver);
                    totalRacers -= 1;
                    if (raceDrivers.Count == 0) EndEvent();
                }
            }
            private BaseEntity CreateEntity(RaceType raceType, Vector3 position, float rotation, bool useCommander, bool useModularCars) {
                if (IsWaterSurfaceBasedRace(raceType)) position.y = TerrainMeta.WaterMap.GetHeight(position);
                if (useModularCars) return SpawnModularCar(position, rotation);
                if (raceType == RaceType.Car && Instance.CarCommander && useCommander) return SpawnCarCommander(position, rotation);
                if (raceType == RaceType.Boat && Instance.BoatCommander && useCommander) return SpawnBoatCommander(position, rotation);
                if (raceType == RaceType.Minicopter && Instance.HeliCommander && useCommander) return SpawnHeliCommander(position, rotation);
                string prefab = EntityFromRaceType(raceType);
                BaseEntity baseEntity = GameManager.server.CreateEntity(prefab, position + (Vector3.up * 0.2f), Quaternion.Euler(0, rotation, 0));
                baseEntity.enableSaving = false;
                baseEntity.Spawn();
                baseEntity.enabled = false;
                return baseEntity;
            }
            private BaseEntity SpawnCarCommander(Vector3 position, float rotation) {
                BaseEntity baseEntity = Instance.CarCommander.Call("SpawnAtLocation", position + (Vector3.up * 0.2f), Quaternion.Euler(0, rotation, 0), false, true) as BasicCar;
                Instance.CarCommander.Call("ToggleController", baseEntity as BasicCar, false);
                return baseEntity;
            }
            private BaseEntity SpawnBoatCommander(Vector3 position, float rotation) {
                BaseEntity baseEntity = Instance.BoatCommander.Call("SpawnAtLocation", position + (Vector3.up * 0.2f), Quaternion.Euler(0, rotation, 0), false, true, true, false, false, false, RaceType == RaceType.RHIB) as MotorRowboat;
                Instance.BoatCommander.Call("ToggleController", baseEntity as MotorRowboat, false);
                return baseEntity;
            }
            private BaseEntity SpawnHeliCommander(Vector3 position, float rotation) {
                BaseEntity baseEntity = Instance.HeliCommander.Call("SpawnAtLocation", position + (Vector3.up * 0.2f), Quaternion.Euler(0, rotation, 0), "Mini", false, 0UL, true) as MiniCopter;
                Instance.HeliCommander.Call("ToggleController", baseEntity, false);
                return baseEntity;
            }
            private BaseEntity SpawnModularCar(Vector3 position, float rotation) {
                ModularCarData modularCarData = Instance.carData[TrackData.modularCarProfiles.GetRandom()];
                ModularCar modularCar = modularCarData.LoadVehicle(position + (Vector3.up * 0.2f), Quaternion.Euler(0, rotation, 0));
                modularCar.SetFlag(BaseEntity.Flags.Reserved1, true);
                modularCar.SetFlag(BaseEntity.Flags.On, false);
                modularCar.SetHealth(200);
                modularCar.SetMaxHealth(200);
                return modularCar;
            }
#endregion
#region Checkpoints
            private IEnumerator CreateCheckPoints() {
                print("[RaceTrack] Creating race checkpoints, please wait!");
                enabled = true;
                for (int i = 0; i < CheckpointCount; i++) {
                    print($"[RaceTrack] Building Checkpoint {i + 1}/{CheckpointCount}");
                    TrackData.PointInfo pointInfo = TrackData.checkPoints[i];
                    CheckPoint checkPoint = new GameObject().AddComponent<CheckPoint>();
                    checkPoint.transform.position = pointInfo.position;
                    checkPoint.transform.rotation = Quaternion.Euler(0, pointInfo.rotation, 0);
                    if (pointInfo.SegmentDistance < 0f) {
                        if (i == CheckpointCount - 1) {
                            if (TrackData.raceMode == RaceMode.Laps) pointInfo.SegmentDistance = Vector3.Distance(pointInfo.position, TrackData.checkPoints[0].position);
                            else pointInfo.SegmentDistance = 0f;
                        }
                        else pointInfo.SegmentDistance = Vector3.Distance(pointInfo.position, TrackData.checkPoints[i + 1].position);
                    }
                    checkPoint.SetCheckpointData(i, pointInfo.size);
                    checkPoints.Add(checkPoint);
                    yield return new WaitWhile(()=> checkPoint.IsBuilding);
                    yield return new WaitForSeconds(0.5f);
                }
                print("[RaceTrack] All checkpoints have been loaded.Race is now open!");
                Instance.SaveEntityData();
                countdown = Mathf.Max(11, Configuration.Timers.Countdown);
                Status = EventStatus.Open;
                Instance.BroadcastEvent();
                InvokeHandler.Invoke(this, EndEvent, Configuration.Timers.CloseTime);
                enabled = false;
            }
            public TrackData.PointInfo GetCheckpoint(int index) {
                if (index < 0) index += CheckpointCount;
                if (index >= CheckpointCount) index -= CheckpointCount;
                return TrackData.checkPoints[Mathf.Clamp(index, 0, CheckpointCount - 1)];
            }
#endregion
#region Pre-race Setup
            private void Countdown() {
                --countdown;
                UpdateCountdown(raceDrivers, countdown > 0 ? string.Format(msg("countdown.count"), countdown) : msg("countdown.go"));
                if (countdown > 0) InvokeHandler.Invoke(this, Countdown, 1f);
                else {
                    if (TrackData.raceType == RaceType.Minicopter) Instance.Unsubscribe("OnEngineStart");
                    Status = EventStatus.Started;
                    startTime = CurrentTime;
                    EnableAllVehicles();
                    InvokeHandler.Invoke(this, DestroyCountdown, 1f);
                    if (TrackData.maxTime > 0) {
                        for (int i = 0; i < raceDrivers.Count; i++) {
                            RaceDriver raceDriver = raceDrivers[i];
                            raceDriver.Player.ChatMessage(string.Format(msg("eventtimer", raceDriver.Player.UserIDString), FormatTime(TrackData.maxTime)));
                        }
                        endTime = UnityEngine.Time.realtimeSinceStartup + TrackData.maxTime;
                        InvokeHandler.Invoke(this, FinishRace, TrackData.maxTime);
                    }
                    InvokeHandler.InvokeRepeating(this, UpdateDriverPositions, 1f, 1f);
                }
            }
            private void EnableAllVehicles() {
                if (TrackData.raceType == RaceType.Foot) {
                    for (int i = 0; i < raceDrivers.Count; i++) {
                        RaceDriver raceDriver = raceDrivers[i];
                        if (raceDriver) raceDriver.enabled = false;
                    }
                    return;
                }
                for (int i = 0; i < raceDrivers.Count; i++) {
                    RaceDriver raceDriver = raceDrivers[i];
                    RaceVehicle raceVehicle = raceDriver.Vehicle;
                    BaseMountable vehicle = raceVehicle.GetEntity();
                    if (RaceType == RaceType.Car) {
                        if (TrackData.UseModularCars) {
                            vehicle.SetFlag(BaseEntity.Flags.Reserved1, false);
                            vehicle.SetFlag(BaseEntity.Flags.On, true);
                        }
                        else {
                            if (Instance.CarCommander && TrackData.useCommander) Instance.CarCommander.Call("ToggleController", vehicle as BasicCar, true);
                        }
                    }
                    else if (RaceType == RaceType.Boat || RaceType == RaceType.RHIB) {
                        if (Instance.BoatCommander && TrackData.useCommander) Instance.BoatCommander.Call("ToggleController", vehicle as MotorRowboat, true);
                        vehicle.GetComponent<MotorRowboat>().EngineToggle(true);
                    }
                    else if (RaceType == RaceType.Minicopter) {
                        MiniCopter miniCopter = vehicle as MiniCopter;
                        if (Instance.HeliCommander && TrackData.useCommander) Instance.HeliCommander.Call("ToggleController", miniCopter, true);
                        (raceVehicle as RaceHelicopter).OnRaceStarted();
                        miniCopter.SetFlag(miniCopter.engineController.engineStartingFlag, true, false, true);
                        miniCopter.SetFlag(BaseEntity.Flags.On, false, false, true);
                        miniCopter.Invoke(miniCopter.engineController.FinishStartingEngine, miniCopter.engineController.engineStartupTime);
                    }
                    vehicle.enabled = true;
                    raceVehicle.ToggleKinematic(false);
                    raceVehicle.WakeUp();
                    raceDriver.StartRace();
                }
                CanReset = true;
            }
            private void DestroyCountdown() {
                for (int i = 0; i < raceDrivers.Count; i++) {
                    RaceDriver raceDriver = raceDrivers[i];
                    raceDriver.DestroyUI(UIInfo);
                    raceDriver.DestroyUI(UITime);
                    if (TrackData.raceMode == RaceMode.Laps) RaceTrack.UpdateLapCounter(raceDriver, true, null);
                    el
// ... [Code preview truncated due to length. Full source in attached file] ...

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