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

FREE RaceTrack : 1.0.0 1.0.0

Нет прав для скачивания
C#:
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 Rust;
namespace Oxide.Plugins {
    [Info("RaceTrack", "k1lly0u", "1.0.0")]
    [Description("A standalone racing event for cars, boats, mincopters and horses")]
    class RaceTrack : RustPlugin {
#region Fields
        private Hash<string, TrackData> trackData;
        private Hash<string, ModularCarData> carData;
        private RestoreData restoreData;
        private List<uint> spawnedEntities;
        private DynamicConfigFile entitydata, trackdata, cardata, restorationData;
        [PluginReference]
        Plugin CarCommander, BoatCommander, HeliCommander, Economics, ServerRewards;
        private static RaceTrack ins;
        private static bool disableSpectate;
        private RaceManager manager;
        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 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 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
        }
#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()
            }
            ;
        }
        private void OnServerInitialized() {
            ins = this;
            disableSpectate = configData.DisableSpectate;
            if (disableSpectate) {
                //Unsubscribe(nameof(OnPlayerInput));
                //Unsubscribe(nameof(OnPlayerTick));
                Unsubscribe(nameof(CanSpectateTarget));
            }
            if (!configData.Racers.DisableMetabolism) Unsubscribe(nameof(OnRunPlayerMetabolism));
            lightType = ParseType<LightType>(configData.Checkpoints.LightType);
            LoadData();
            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 (manager != null) manager.PlayerDisconnected(player);
            else {
                RaceDriver raceDriver = player.GetComponent<RaceDriver>();
                if (raceDriver != null) {
                    raceDriver.DismountPlayer();
                    NextTick(() => {
                        if (raceDriver != null) UnityEngine.Object.Destroy(raceDriver);
                    }
                    );
                }
            }
        }
        private void OnPlayerSleepEnded(BasePlayer player) {
            RaceDriver raceDriver = player.GetComponent<RaceDriver>();
            if (raceDriver != null) {
                if (!player.isMounted && raceDriver.Vehicle != null && raceDriver.Vehicle.entity != null) raceDriver.MountPlayer(raceDriver.Vehicle);
            }
        }
        private void OnEntityTakeDamage(BaseCombatEntity entity, HitInfo info) {
            if (entity == null || info == null) return;
            if (entity.GetComponent<RaceDriver>() != null) NullifyDamage(ref info);
            if (entity.GetComponent<RaceVehicle>() != null) NullifyDamage(ref info);
            BaseVehicleModule module = entity as BaseVehicleModule;
            if (module != null && module.Vehicle?.GetComponent<RaceVehicle>()) NullifyDamage(ref info);
            CheckPoint.Marker marker = entity.GetComponent<CheckPoint.Marker>();
            if (marker != null && manager != null && manager.Status != EventStatus.Finished) NullifyDamage(ref info);
        }
        private object OnRunPlayerMetabolism(PlayerMetabolism metabolism, BasePlayer owner, float delta) {
            if (owner.GetComponent<RaceDriver>()) return true;
            return null;
        }
        private object CanMountEntity(BasePlayer player, BaseMountable mountable) {
            if (mountable.GetComponent<RaceCar>()) return false;
            return null;
        }
        private object CanDismountEntity(BasePlayer player, BaseMountable mountable) {
            RaceDriver raceDriver = player.GetComponent<RaceDriver>();
            if (raceDriver != null && !raceDriver.HasFinished) return false;
            return null;
        }
        private object OnPlayerCommand(BasePlayer player, string command, string[] args) {
            if (player != null && player.GetComponent<RaceDriver>()) {
                if (configData.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 != null && player.GetComponent<RaceDriver>()) {
                if (configData.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 != null && raceDriver.Player.IsSpectating()) {
                raceDriver.UpdateSpectateTarget(1);
                return false;
            }
            return null;
        }
        private void Unload() {
            SaveRestoreData();
            if (autoTimer != null) autoTimer.Destroy();
            RaceDriver[] raceDrivers = UnityEngine.Object.FindObjectsOfType<RaceDriver>();
            if (raceDrivers != null) {
                foreach(RaceDriver raceDriver in raceDrivers) UnityEngine.Object.Destroy(raceDriver);
            }
            RaceVehicle[] raceVehicles = UnityEngine.Object.FindObjectsOfType<RaceVehicle>();
            if (raceVehicles != null) {
                foreach(RaceVehicle raceVehicle in raceVehicles) UnityEngine.Object.Destroy(raceVehicle);
            }
            CheckPoint[] checkPoints = UnityEngine.Object.FindObjectsOfType<CheckPoint>();
            if (checkPoints != null) {
                foreach(CheckPoint checkPoint in checkPoints) UnityEngine.Object.Destroy(checkPoint);
            }
            CheckPoint.Marker[] markers = UnityEngine.Object.FindObjectsOfType<CheckPoint.Marker>();
            if (markers != null) {
                foreach (CheckPoint.Marker marker in markers) UnityEngine.Object.Destroy(marker);
            }
            UnityEngine.Object.Destroy(manager);
            ins = null;
        }
#endregion
#region Functions
        private void CleanupEntities() {
            if (spawnedEntities.Count > 0) {
                PrintWarning("Finding and destroying left over entities");
                BaseNetworkable[] objects = BaseNetworkable.serverEntities.ToArray();
                if (objects != null) {
                    foreach(BaseNetworkable obj in BaseNetworkable.serverEntities) {
                        if (obj != null && !obj.IsDestroyed) {
                            if (spawnedEntities.Contains(obj.net.ID)) obj.Kill(BaseNetworkable.DestroyMode.None);
                        }
                    }
                }
                spawnedEntities.Clear();
                SaveEntityData();
                PrintWarning("Cleanup completed");
            }
        }
        private string FormatTime(double time) {
            TimeSpan dateDifference = TimeSpan.FromSeconds((float)time);
            int days = dateDifference.Days;
            int hours = dateDifference.Hours;
            hours += (days * 24);
            int mins = dateDifference.Minutes;
            int secs = dateDifference.Seconds;
            if (hours > 0) return string.Format("{0:00}:{1:00}:{2:00}", hours, mins, secs);
            else return string.Format("{0:00}:{1:00}", mins, secs);
        }
        private T ParseType<T>(string type) {
            try {
                return (T)Enum.Parse(typeof(T), type, true);
            }
            catch {
                return default(T);
            }
        }
        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;
                default : return string.Empty;
            }
        }
        private static Type VehicleComponentFromRaceType(RaceType raceType) {
            switch (raceType) {
                case RaceType.Car : return typeof(RaceCar);
                case RaceType.Boat : case RaceType.RHIB : case RaceType.Kayak : case RaceType.BoogieBoard : case RaceType.InnerTube : return typeof(RaceBoat);
                case RaceType.Minicopter : return typeof(RaceHelicopter);
                case RaceType.Horse : return typeof(RaceHorse);
                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 (configData.Automation.Enabled) {
                if (trackData.Count == 0) {
                    PrintError("You have no race tracks set up.Unable to automate events");
                    return;
                }
                autoTimer = timer.In(configData.Timers.Interval, () => {
                    if (manager == null) manager = new GameObject().AddComponent<RaceManager>();
                    if (manager.Status != EventStatus.Finished) return;
                    if (configData.Automation.Random) {
                        var data = trackData.ElementAt(UnityEngine.Random.Range(0, trackData.Count - 1));
                        manager.SetTrackData(data.Key, data.Value);
                        manager.OpenEvent();
                    }
                    else {
                        if (configData.Automation.Order.Count < 1) {
                            PrintError("You have no race tracks set in your config.Unable to automate events by order");
                            return;
                        }
                        if (!trackData.ContainsKey(configData.Automation.Order[lastEventIndex])) {
                            PrintError($"Unable to find a race track with the name : {configData.Automation.Order[lastEventIndex]}");
                            return;
                        }
                        var data = trackData[configData.Automation.Order[lastEventIndex]];
                        manager.SetTrackData(configData.Automation.Order[lastEventIndex], data);
                        lastEventIndex++;
                        if (lastEventIndex >= configData.Automation.Order.Count) lastEventIndex = 0;
                        manager.OpenEvent();
                    }
                }
                );
            }
        }
        private void BroadcastEvent() {
            if (!configData.Entrance.Enabled) BroadcastToChat(string.Format(msg("eventopen1"), manager.RaceType));
            else {
                if (configData.Entrance.ServerRewards) BroadcastToChat(string.Format(msg("eventopenfee1"), configData.Entrance.Amount, msg("serverrewards"), manager.RaceType));
                if (configData.Entrance.Economics) BroadcastToChat(string.Format(msg("eventopenfee1"), configData.Entrance.Amount, msg("economics"), manager.RaceType));
                if (configData.Entrance.Scrap) if (configData.Entrance.Scrap) BroadcastToChat(string.Format(msg("eventopenfee1"), configData.Entrance.Amount, msg("scrap"), manager.RaceType));
            }
            if (configData.Rewards.Enabled) {
                string rewards = configData.Rewards.ServerRewards ? msg("serverrewards") : configData.Rewards.Scrap ? msg("scrap") : msg("economics");
                if (configData.Rewards.Podium) BroadcastToChat(string.Format(msg("eventprizepodium"), configData.Rewards.Prize1, rewards, configData.Rewards.Prize2, configData.Rewards.Prize3));
                else BroadcastToChat(string.Format(msg("eventprize"), configData.Rewards.Prize1, rewards));
            }
        }
        private void OnVehicleUnderwater(BasicCar car) {
            RaceCar raceCar = car.GetComponent<RaceCar>();
            if (raceCar != null) {
                raceCar.ResetVehicle();
                ins.CarCommander.Call("ToggleController", car, true);
            }
        }
        private static void BroadcastToChat(string message) {
            foreach (BasePlayer player in BasePlayer.activePlayerList) player.SendConsoleCommand("chat.add", new object[] {
                0, 0, message
            }
            );
        }
#endregion
#region Component
        enum EventStatus {
            Open, Loading, Started, Finishing, Finished
        }
        private class RaceManager : MonoBehaviour {
            private List<BasePlayer> joiners;
            private List<RaceDriver> raceDrivers;
            private List<RaceVehicle> raceVehicles;
            private List<CheckPoint> checkPoints;
            internal List<RaceDriver> spectateTargets;
            private RaceScores[] winners;
            private int playersFinished;
            private int totalRacers;
            private string trackName;
            private TrackData trackData;
            private EventStatus status;
            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 isRacing;
            private bool hasLaunchedFirework;
#region Properties
            public EventStatus Status {
                get {
                    return status;
                }
            }
            public bool HasTrackSet {
                get {
                    return trackData != null;
                }
            }
            public int RacerCount {
                get {
                    return raceDrivers.Count;
                }
            }
            public int CheckpointCount {
                get {
                    return trackData.checkPoints.Count;
                }
            }
            public int JoinerCount {
                get {
                    return joiners.Count;
                }
            }
            public string TrackName {
                get {
                    return trackName;
                }
            }
            public RaceMode RaceMode {
                get {
                    return trackData.raceMode;
                }
            }
            public RaceType RaceType {
                get {
                    return trackData.raceType;
                }
            }
            public TrackData TrackData {
                get {
                    return trackData;
                }
            }
            public int Laps {
                get {
                    return trackData.laps;
                }
            }
            public double StartTime {
                get {
                    return startTime;
                }
            }
            public double CurrentTime {
                get {
                    return DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds;
                }
            }
            public bool CanReset {
                get {
                    return isRacing;
                }
            }
#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>();
                countdown = ins.configData.Timers.Countdown;
                status = EventStatus.Finished;
                enabled = false;
            }
            private void OnDestroy() {
                DestroyEvent();
                ins.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 (ins.autoTimer != null) ins.autoTimer.Destroy();
                isStarting = false;
                isEnding = false;
                hasStarted = false;
                isRacing = false;
                status = EventStatus.Loading;
                ins.scoreContainer = null;
                ServerMgr.Instance.StartCoroutine(CreateCheckPoints());
            }
            public void StartEvent() {
                isStarting = false;
                hasStarted = true;
                status = EventStatus.Started;
                InvokeHandler.CancelInvoke(this, StartEvent);
                InvokeHandler.CancelInvoke(this, EndEvent);
                foreach (BasePlayer player in joiners) SpawnPlayer(player);
                joiners.Clear();
                ins.DisplayInformation(raceDrivers, trackName, trackData);
                Countdown();
                winners = new RaceScores[raceDrivers.Count];
                playersFinished = 0;
                totalRacers = raceDrivers.Count;
            }
            public void EndEvent() {
                InvokeHandler.CancelInvoke(this, Countdown);
                InvokeHandler.CancelInvoke(this, CalculateScores);
                raceDrivers.ForEach((RaceDriver driver) => CuiHelper.DestroyUi(driver.Player, UITime));
                if (status == EventStatus.Open) {
                    status = EventStatus.Finished;
                    ins.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"), ins.configData.Timers.StartTime));
                    InvokeHandler.Invoke(this, StartEvent, ins.configData.Timers.StartTime);
                }
            }
            public void LeaveEvent(BasePlayer player, bool hasFinished) {
                if (status == EventStatus.Open) {
                    if (joiners.Contains(player)) {
                        ins.IssueRefund(player);
                        joiners.Remove(player);
                        if (joiners.Count < trackData.minPlayers) {
                            isStarting = false;
                            InvokeHandler.CancelInvoke(this, EndEvent);
                            InvokeHandler.CancelInvoke(this, StartEvent);
                            InvokeHandler.Invoke(this, EndEvent, ins.configData.Timers.CloseTime);
                            BroadcastToChat(string.Format(msg("leftevent.wait"), player.displayName));
                        }
                        else BroadcastToChat(string.Format(msg("leftevent"), player.displayName));
                    }
                }
                else if (status == EventStatus.Started) {
                    RaceDriver raceDriver = player.GetComponent<RaceDriver>();
                    if (raceDriver != null) {
                        raceDrivers.Remove(raceDriver);
                        spectateTargets.Remove(raceDriver);
                        if (!disableSpectate) {
                            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.GetDistanceTravelled());
                        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;
                isRacing = false;
                joiners.Clear();
                for (int i = raceDrivers.Count - 1; i >= 0; i--) {
                    RaceDriver raceDriver = raceDrivers[i];
                    Destroy(raceDriver);
                }
                raceDrivers.Clear();
                for (int i = raceVehicles.Count - 1; i >= 0; i--) {
                    RaceVehicle raceVehicle = raceVehicles[i];
                    BaseMountable baseMountable = raceVehicle.entity;
                    Destroy(raceVehicle);
                }
                raceVehicles.Clear();
                for (int i = checkPoints.Count - 1; i >= 0; i--) {
                    CheckPoint checkPoint = checkPoints[i];
                    Destroy(checkPoint);
                }
                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);
                CancelInvoke();
                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--) {
                    CheckPoint checkPoint = checkPoints[i];
                    Destroy(checkPoint);
                    yield return new WaitForSeconds(0.5f);
                }
                checkPoints.Clear();
                Destroy(this, 15f);
            }
#endregion
#region Player Management
            private void SpawnPlayer(BasePlayer player) {
                if (player == null) return;
                if (player.isMounted) {
                    player.GetMounted().DismountPlayer(player, true);
                    player.DismountObject();
                }
                ins.restoreData.AddData(player);
                player.inventory.Strip();
                ins.NextTick(() => {
                    player.inventory.containerWear.SetFlag(ItemContainer.Flag.IsLocked, true);
                    string[] clothing = ins.configData.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;
                RaceDriver raceDriver = player.gameObject.AddComponent<RaceDriver>();
                raceDrivers.Add(raceDriver);
                spectateTargets.Add(raceDriver);
                int gridId = raceDrivers.Count - 1;
                TrackData.PointInfo gridPoint = trackData.gridPoints.ElementAt(gridId);
                BaseEntity baseEntity = CreateEntity(RaceType, gridPoint.position, gridPoint.rotation, trackData.useCommander, trackData.UseModularCars);
                RaceVehicle raceVehicle = baseEntity.gameObject.AddComponent(VehicleComponentFromRaceType(RaceType)) as RaceVehicle;
                ins.spawnedEntities.Add(baseEntity.net.ID);
                raceVehicles.Add(raceVehicle);
                if (RaceType == RaceType.BoogieBoard || RaceType == RaceType.InnerTube || RaceType == RaceType.Kayak) baseEntity.GetComponent<Rigidbody>().isKinematic = true;
                if (RaceType == RaceType.Horse) (baseEntity as RidableHorse).SetBreed(trackData.horseBreed);
                raceVehicle.Driver = raceDriver;
                raceVehicle.Manager = this;
                raceVehicle.gridId = gridId;
                raceDriver.Vehicle = raceVehicle;
                raceDriver.Manager = this;
                if (player.isMounted) {
                    player.GetMounted()?.DismountPlayer(player);
                    ins.NextTick(() => ins.MovePosition(player, raceVehicle.transform.position + raceVehicle.transform.up, true));
                    return;
                }
                else ins.MovePosition(player, raceVehicle.transform.position + raceVehicle.transform.up, true);
            }
            private BaseEntity CreateEntity(RaceType raceType, Vector3 position, float rotation, bool useCommander, bool useModularCars) {
                if (useModularCars) return SpawnModularCar(position, rotation);
                if (raceType == RaceType.Car && ins.CarCommander && useCommander) return SpawnCarCommander(position, rotation);
                if (raceType == RaceType.Boat && ins.BoatCommander && useCommander) return SpawnBoatCommander(position, rotation);
                if (raceType == RaceType.Minicopter && ins.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 = ins.CarCommander.Call("SpawnAtLocation", position + (Vector3.up * 0.2f), Quaternion.Euler(0, rotation, 0), false, true) as BasicCar;
                ins.CarCommander.Call("ToggleController", baseEntity as BasicCar, false);
                return baseEntity;
            }
            private BaseEntity SpawnBoatCommander(Vector3 position, float rotation) {
                BaseEntity baseEntity = ins.BoatCommander.Call("SpawnAtLocation", position + (Vector3.up * 0.2f), Quaternion.Euler(0, rotation, 0), false, true, true, false, false, false, RaceType == RaceType.RHIB) as MotorRowboat;
                ins.BoatCommander.Call("ToggleController", baseEntity as MotorRowboat, false);
                return baseEntity;
            }
            private BaseEntity SpawnHeliCommander(Vector3 position, float rotation) {
                BaseEntity baseEntity = ins.HeliCommander.Call("SpawnAtLocation", position + (Vector3.up * 0.2f), Quaternion.Euler(0, rotation, 0), "Mini", false, 0UL, true) as MiniCopter;
                ins.HeliCommander.Call("ToggleController", baseEntity, false);
                return baseEntity;
            }
            private BaseEntity SpawnModularCar(Vector3 position, float rotation) {
                ModularCarData modularCarData = ins.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.rigidBody.isKinematic = true;
                modularCar.enabled = false;
                return modularCar;
            }
            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, ins.configData.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 != null) {
                    raceDrivers.Remove(raceDriver);
                    spectateTargets.Remove(raceDriver);
                    if (!disableSpectate) {
                        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.GetDistanceTravelled());
                    winners[raceDrivers.Count].hasFinished = false;
                    raceDriver.DismountPlayer();
                    Destroy(raceDriver);
                    totalRacers -= 1;
                    if (raceDrivers.Count == 0) EndEvent();
                }
            }
            public TrackData.PointInfo GetLastCheckpoint(int number) {
                if (number < 0) number = 0;
                if (number > trackData.checkPoints.Count - 1) number = trackData.checkPoints.Count - 1;
                return trackData.checkPoints[number];
            }
#endregion
#region Checkpoints
            private IEnumerator CreateCheckPoints() {
                print("[RaceTrack] Creating race checkpoints, please wait!");
                enabled = true;
                for (int i = 0; i < trackData.checkPoints.Count; i++) {
                    print($"[RaceTrack] Building Checkpoint {i + 1}/{trackData.checkPoints.Count}");
                    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);
                    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!");
                ins.SaveEntityData();
                countdown = Mathf.Max(11, ins.configData.Timers.Countdown);
                status = EventStatus.Open;
                ins.BroadcastEvent();
                InvokeHandler.Invoke(this, EndEvent, ins.configData.Timers.CloseTime);
                enabled = false;
            }
#endregion
#region Pre-race Setup
            private void Countdown() {
                --countdown;
                ins.UpdateCountdown(raceDrivers, countdown > 0 ? string.Format(msg("countdown.count"), countdown) : msg("countdown.go"));
                if (countdown > 0) InvokeHandler.Invoke(this, Countdown, 1f);
                else {
                    startTime = CurrentTime;
                    EnableAllVehicles();
                    InvokeHandler.Invoke(this, DestroyCountdown, 1f);
                    if (trackData.maxTime > 0) {
                        foreach(RaceDriver raceDriver in raceDrivers) {
                            raceDriver.Player.ChatMessage(string.Format(msg("eventtimer", raceDriver.Player.UserIDString), ins.FormatTime(trackData.maxTime)));
                        }
                        endTime = UnityEngine.Time.realtimeSinceStartup + trackData.maxTime;
                        InvokeHandler.Invoke(this, FinishRace, trackData.maxTime);
                    }
                }
            }
            private void EnableAllVehicles() {
                foreach(RaceDriver raceDriver in raceDrivers) {
                    RaceVehicle raceVehicle = raceDriver.Vehicle;
                    if (RaceType == RaceType.Car) {
                        if (TrackData.UseModularCars) {
                            raceVehicle.entity.SetFlag(BaseEntity.Flags.Reserved1, false);
                            raceVehicle.entity.SetFlag(BaseEntity.Flags.On, true);
                            (raceVehicle.entity as ModularCar).rigidBody.isKinematic = false;
                            raceVehicle.entity.enabled = true;
                        }
                        else {
                            if (ins.CarCommander && TrackData.useCommander) ins.CarCommander.Call("ToggleController", raceVehicle.entity as BasicCar, true);
                            else raceVehicle.entity.GetComponent<BasicCar>().enabled = true;
                        }
                    }
                    else if (RaceType == RaceType.Boat || RaceType == RaceType.RHIB) {
                        if (ins.BoatCommander && TrackData.useCommander) ins.BoatCommander.Call("ToggleController", raceVehicle.entity as MotorRowboat, true);
                        else raceVehicle.entity.GetComponent<MotorRowboat>().enabled = true;
                        raceVehicle.entity.GetComponent<MotorRowboat>().EngineToggle(true);
                    }
                    else if (RaceType == RaceType.Kayak || RaceType == RaceType.BoogieBoard || RaceType == RaceType.InnerTube) {
                        raceVehicle.entity.GetComponent<Rigidbody>().isKinematic = false;
                    }
                    else if (RaceType == RaceType.Horse) {
                        raceVehicle.entity.GetComponent<BaseRidableAnimal>().enabled = true;
                    }
                    else {
                        if (ins.HeliCommander && TrackData.useCommander) ins.HeliCommander.Call("ToggleController", raceVehicle.entity as MiniCopter, true);
                        else raceVehicle.entity.GetComponent<MiniCopter>().enabled = true;
                        (raceVehicle as RaceHelicopter).OnRaceStarted();
                    }
                    raceDriver.StartLap();
                }
                isRacing = true;
            }
            private void DestroyCountdown() {
                foreach (var raceDriver in raceDrivers) {
                    raceDriver.DestroyUI(UIInfo);
                    raceDriver.DestroyUI(UITime);
                    if (trackData.raceMode == RaceMode.Laps) ins.UpdateLapCounter(raceDriver, true, null);
                    else ins.UpdateLapCounter(raceDriver, false, null);
                }
            }
#endregion
#region Finished Racers
            public void FinishedRace(RaceDriver raceDriver) {
                spectateTargets.Remove(raceDriver);
                if (!hasLaunchedFirework && ins.configData.Checkpoints.LaunchFirework) {
                    MortarFirework firework = GameManager.server.CreateEntity(ins.configData.Checkpoints.FireworkPrefab, raceDriver.transform.position + (Vector3.up * 3f)) as MortarFirework;
                    if (firework != null) {
                        firework.enableSaving = false;
                        firework.Spawn();
                        firework.Ignite();
                    }
                    hasLaunchedFirework = true;
                }
                winners[playersFinished] = new RaceScores(raceDriver, trackData);
                playersFinished++;
                if (!disableSpectate) {
                    raceDrivers.ForEach((RaceDriver spectatorDriver) => {
                        if (spectatorDriver.Player.IsSpectating()) {
                            if (playersFinished >= totalRacers) spectatorDriver.FinishSpectating();
                            else {
                                if (spectatorDriver.SpectateTarget == raceDriver) spectatorDriver.UpdateSpectateTarget();
                            }
                        }
                    }
                    );
                }
                raceDriver.DismountPlayer();
                if (!isEnding) {
                    isEnding = true;
                    int finishTime = ins.configData.Timers.EndTime;
                    if (trackData.maxTime > 0) {
                        double forcedFinishTime = endTime - UnityEngine.Time.realtimeSinceStartup;
                        if (forcedFinishTime < finishTime) finishTime = (int)forcedFinishTime;
                    }
                    foreach(RaceDriver driver in raceDrivers) driver.Player.ChatMessage(string.Format(msg("win.end", driver.Player.UserIDString), raceDriver.Player.displayName, finishTime));
                    timerTick = ins.configData.Timers.EndTime;
                    TimerTick();
                }
                if (playersFinished >= totalRacers) {
                    InvokeHandler.CancelInvoke(this, FinishRace);
                    FinishRace();
                }
                else {
                    if (disableSpectate) LeaveEvent(raceDriver.Player, true);
                    else ins.NextTick(raceDriver.BeginSpectating);
                }
                ins.NextTick(() => Destroy(raceDriver.Vehicle));
            }
            private void TimerTick() {
                timerTick -= 1;
                if (timerTick == 30 || timerTick == 10) {
                    int finishTime = timerTick;
                    if (trackData.maxTime > 0) {
                        double forcedFinishTime = endTime - UnityEngine.Time.realtimeSinceStartup;
                        if (forcedFinishTime < finishTime) finishTime = (int)forcedFinishTime;
                    }
                    foreach (RaceDriver driver in raceDrivers) driver.Player.ChatMessage(string.Format(msg("win.countdown", driver.Player.UserIDString), finishTime));
                }
                if (timerTick > 0) InvokeHandler.Invoke(this, TimerTick, 1f);
                if (timerTick == 0) FinishRace();
            }
            public void FinishRace() {
                InvokeHandler.CancelInvoke(this, TimerTick);
                status = EventStatus.Finishing;
                foreach(RaceDriver raceDriver in raceDrivers) {
                    if (raceDriver.Player.IsSpectating()) raceDriver.FinishSpectating();
                    raceDriver.DestroyAllUI();
                }
                ins.NextTick(DismountDrivers);
            }
            private void DismountDrivers() {
                foreach (RaceDriver raceDriver in raceDrivers) raceDriver.DismountPlayer();
                ins.NextTick(CalculateScores);
            }
            public void UpdateLapCounter(RaceDriver raceDriver) {
                ins.UpdateLapCounter(raceDriver, RaceMode == RaceMode.Laps, null);
                foreach (RaceDriver spectator in raceDrivers) {
                    if (spectator.SpectateTarget == raceDriver) ins.UpdateLapCounter(raceDriver, RaceMode == RaceMode.Laps, spectator);
                }
            }
            public void UpdateLapTime(RaceDriver raceDriver) {
                ins.UpdateLapTime(raceDriver, raceDriver.LastLapTime, null);
                foreach (RaceDriver spectator in raceDrivers) {
                    if (spectator.SpectateTarget == raceDriver) ins.UpdateLapTime(raceDriver, raceDriver.LastLapTime, spectator);
                }
            }
#endregion
#region Scores
            public void CalculateScores() {
                foreach (RaceDriver raceDriver in raceDrivers.Where(x => !x.HasFinished).OrderByDescending(x => x.GetDistanceTravelled())) {
                    winners[playersFinished] = new RaceScores(raceDriver, CurrentTime - StartTime, raceDriver.LapNumber - 1, raceDriver.GetDistanceTravelled());
                    playersFinished++;
                }
                string podiumStr = string.Empty;
                for (int i = 0; i < 3; i++) {
                    if (winners.Length >= i + 1 && winners[i] != null) podiumStr += string.Format(msg("win.podium"), i == 0 ? "\n1st" : i == 1 ? "\n2nd" : "\n3rd", ins.StripTags(winners[i].displayName));
                }
                BroadcastToChat(string.Format(msg("win.winners"), podiumStr));
                BroadcastToChat(msg("win.viewscores"));
                ins.CreateScoreboard(TrackName, winners);
                foreach (RaceDriver raceDriver in raceDrivers) raceDriver.AddUI(ins.scoreContainer, UIScoreboard);
                IssueRewards(winners);
                ServerMgr.Instance.StartCoroutine(DestroyCheckpoints());
            }
            private void IssueRewards(RaceScores[] raceScores) {
                int amount = raceScores.Length < 3 ? raceScores.Length : 3;
                for (int i = 0; i < amount; i++) {
                    if (raceScores[i] == null) continue;
                    if (raceScores[i].hasFinished) ins.IssueReward(raceScores[i].playerId, i + 1);
                }
            }
            public class RaceScores {
                public ulong playerId;
                public string displayName;
                public double raceTime;
                public float laps;
                public float distance;
                public bool hasFinished;
    
// ... [Code preview truncated due to length. Full source in attached file] ...

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

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

Сверху