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

FREE CustomEntitiesExample : 1.0.1 1.0.1

Нет прав для скачивания
C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
 // Requires: CustomEntities
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEngine;
namespace Oxide.Plugins {
    [Info("Custom Entities Example", "Nikedemos", "1.0.1")]
    [Description("Sample dependency for Custom Entities that registers a bundle with some test entities")]
    public class CustomEntitiesExample : RustPlugin {
        private static CustomEntitiesExample Instance;
        public static bool Unloading = false;
#region CONST
        public const string PREFAB_LIGHT_POINT_GREEN = "assets/bundled/prefabs/modding/cinematic/cinelights/cinelight_point_green.prefab";
        public const string PREFAB_LIGHT_POINT_WARM = "assets/bundled/prefabs/modding/cinematic/cinelights/cinelight_point_warm.prefab";
        public const string PREFAB_LIGHT_POINT_RED = "assets/bundled/prefabs/modding/cinematic/cinelights/cinelight_point_red.prefab";
        public const string PREFAB_LIGHT_POINT_COOL = "assets/bundled/prefabs/modding/cinematic/cinelights/cinelight_point_cool.prefab";
        public const string PREFAB_FX_SELECT = "assets/bundled/prefabs/fx/notice/item.select.fx.prefab";
        public const string PREFAB_FX_DROP_SUCCESS = "assets/bundled/prefabs/fx/notice/loot.drag.dropsuccess.fx.prefab";
        public const string PREFAB_FX_LOCK_CODE_DENIED = "assets/prefabs/locks/keypad/effects/lock.code.denied.prefab";
        public const byte LAYER_DEFAULT = 0;
        public const byte LAYER_IGNORE_RAYCAST = 2;
        public const byte LAYER_WAYPOINTS = 3;
        public const byte LAYER_PLAYER = 17;
        public const byte LAYER_VEHICLE_DETAILED = 13;
        public const byte LAYER_VEHICLE_LARGE = 27;
        public const byte LAYER_VEHICLE_WORLD = 15;
        public const byte LAYER_CONSTRUCTION = 21;
        public const byte LAYER_DEPLOYED = 8;
        public const byte LAYER_AI = 11;
        public const byte LAYER_TREE = 30;
        public const byte LAYER_TERRAIN = 23;
        public const byte LAYER_WORLD = 16;
        public const int LAYERMASK_PLAYER = 1 << LAYER_PLAYER;
        public const int LAYERMASK_OBSTACLES = 1 << LAYER_VEHICLE_DETAILED | 1 << LAYER_VEHICLE_LARGE | 1 << LAYER_VEHICLE_WORLD | 1 << LAYER_CONSTRUCTION | 1 << LAYER_DEFAULT | 1 << LAYER_DEPLOYED | 1 << LAYER_AI | 1 << LAYER_TREE | 1 << LAYER_TERRAIN | 1 << LAYER_WORLD;
        public const int LAYERMASK_WAYPOINTS = 1 << LAYER_WAYPOINTS;
        public const int LAYERMASK_OBSTACLES_AND_WAYPOINTS = LAYERMASK_OBSTACLES | LAYERMASK_WAYPOINTS;
        public const float WAYPOINT_PERSONAL_SPACE_SPHERE_RADIUS = 0.5F;
        public const float WAYPOINT_NEIGHBOUR_AUTO_CONNECT_RADIUS = 30F;
#endregion
#region HOOK SUBSCRIPTIONS
        void OnServerInitialized() {
            Instance = this;
            RegisterAndLoadTestBundle();
        }
        void Unload() {
            Unloading = true;
            SaveAndUnregisterTestBundle();
            Unloading = false;
            Instance = null;
        }
        void OnActiveItemChanged(BasePlayer player, Item oldItem, Item newItem) {
            if (Instance == null) {
                return;
            }
            WaypointBrushEntity.OnActiveItemChanged(player, oldItem, newItem);
        }
#endregion
#region TEST ENTITY BUNDLE
        public static CustomEntities.CustomPrefabRecipe WaypointEntityRecipe;
        public static CustomEntities.CustomPrefabRecipe WaypointBrushRecipe;
        public static CustomEntities.CustomPrefabBundle TestBundle;
        public static void RegisterAndLoadTestBundle() {
            WaypointEntityRecipe = new CustomEntities.CustomPrefabRecipe("waypoint", typeof(VisualWaypointEntity), (Rust.Layer)LAYER_DEFAULT);
            WaypointBrushRecipe = new CustomEntities.CustomPrefabRecipe("waypoint_brush", typeof(WaypointBrushEntity), (Rust.Layer)LAYER_IGNORE_RAYCAST, null, false);
            VisualWaypointEntity.Graphs = new Dictionary<ulong, List<VisualWaypointEntity>>();
            VisualWaypointEntity.AllWaypoints = new List<VisualWaypointEntity>();
            TestBundle = new CustomEntities.CustomPrefabBundle(Instance, WaypointEntityRecipe, WaypointBrushRecipe);
            if (!CustomEntities.CustomPrefabs.RegisterAndLoadBundle(TestBundle)) {
                Instance.PrintError($"Something went wrong while trying to register the custom prefab bundle from the plugin {Instance.Name}");
            }
        }
        public static void SaveAndUnregisterTestBundle() {
            if (!CustomEntities.CustomPrefabs.SaveAndUnregisterBundle(TestBundle)) {
                Instance.PrintError("Something went wrong while trying to unregister the custom prefab bundle.");
            }
            VisualWaypointEntity.Graphs = null;
            VisualWaypointEntity.AllWaypoints = null;
            WaypointEntityRecipe = null;
            WaypointBrushRecipe = null;
            TestBundle.Recipes = null;
            TestBundle = null;
        }
#endregion
#region WAYPOINT BRUSH ENTITY
        public class WaypointBrushEntity : CustomEntities.CustomBaseEntity {
            public const string BRUSH_ITEM_SHORTNAME = "map";
            public const ulong BRUSH_ITEM_SKIN = 0;
            public override string DefaultClientsideFullPrefabName() => PREFAB_LIGHT_POINT_COOL;
            public override bool EnableSavingToDiskByDefault => false;
            public static Dictionary<ulong, WaypointBrushEntity> PlayerToBrush;
            private BasePlayer _ownerPlayer = null;
            private InputState _ownerPlayerInput;
            private bool _ready = false;
            private Vector3 _posPrevious;
            private Vector3 _posCurrent;
            private bool _posChanged = true;
            private float _beenStayingStillFor = 0F;
            private bool _isStablePrevious = true;
            private bool _isStableCurrent = true;
            public const float MUST_BE_STILL_FOR_N_SECS_TO_STABILISE = 0.125F;
            private ListHashSet<VisualWaypointEntity> _lastWaypointsNearby = new ListHashSet<VisualWaypointEntity>();
            private VisualWaypointEntity _firstScannedWaypoint = null;
            private VisualWaypointEntity.CinematicLightColour _colour = VisualWaypointEntity.CinematicLightColour.Cool;
            public VisualWaypointEntity.CinematicLightColour Colour {
                get {
                    return _colour;
                }
                set {
                    if (_colour == value) {
                        return;
                    }
                    _colour = value;
                    //update to new colour...Handler.ClientsideFullPrefabName = VisualWaypointEntity.ColourToPrefabName[value];
                }
            }
            public override void ServerInit() {
                base.ServerInit();
                if (_ownerPlayer == null) {
                    Instance.PrintError("Error: you can't spawn the Waypoint Brush directly without an associated player or item, killing...");
                    Invoke(() => {
                        Kill();
                    }
                    , 0.1F);
                    return;
                }
                _ownerPlayerInput = _ownerPlayer.serverInput;
                _ready = true;
            }
            public override void PostInitShared() {
                base.PostInitShared();
                if (!_ready) {
                    return;
                }
            }
            public void LateUpdate() {
                if (!_ready) {
                    return;
                }
                if (_ownerPlayer == null) {
                    Kill(DestroyMode.None);
                    return;
                }
                if (IsDestroyed) {
                    return;
                }
                _posPrevious = _posCurrent;
                _posCurrent = GetPositionInFrontOfPlayerEyes(_ownerPlayer);
                _posChanged = false;
                if (_posPrevious != _posCurrent) {
                    transform.position = _posCurrent;
                    transform.hasChanged = true;
                    _posChanged = true;
                }
                if (!_isStableCurrent) {
                    if (!_posChanged) {
                        //you're not stable but you're still, start stabilising
                        _beenStayingStillFor += Time.deltaTime;
                        if (_beenStayingStillFor > MUST_BE_STILL_FOR_N_SECS_TO_STABILISE) {
                            _isStablePrevious = false;
                            _isStableCurrent = true;
                            _beenStayingStillFor = 0F;
                        }
                    }
                    else {
                        _beenStayingStillFor = 0F;
                    }
                }
                else {
                    if (_posChanged) {
                        //you're stable but your position changed, no more stable
                        _isStablePrevious = true;
                        _isStableCurrent = false;
                    }
                    else {
                        //you're stable and your position hasn't changed, do nothing
                    }
                }
                if (_isStablePrevious != _isStableCurrent) {
                    if (_isStableCurrent) {
                        //you were not stable before but you are now
                        OnStoppedMoving();
                        _isStablePrevious = true;
                        //so we don't trigger this again until next time
                    }
                    else {
                        //you were stable before but you aren't now
                        OnStartedMoving();
                        _isStablePrevious = false;
                        //so we don't trigger this again until next time
                    }
                }
                if (Colour == VisualWaypointEntity.CinematicLightColour.Cool) {
                    //we're not stable.return;
                }
                bool leftJustPressed = _ownerPlayerInput.WasJustPressed(BUTTON.FIRE_PRIMARY);
                bool rightJustPressed = _ownerPlayerInput.WasJustPressed(BUTTON.FIRE_SECONDARY);
                switch (Colour) {
                    case VisualWaypointEntity.CinematicLightColour.Black : {
                        if (rightJustPressed) {
                            CustomEntities.PlayEffect(PREFAB_FX_DROP_SUCCESS, _firstScannedWaypoint.transform.position, Vector3.up, _ownerPlayer);
                            _firstScannedWaypoint.Kill(DestroyMode.None);
                            //opposite day it, we need to trigger OnStoppedMoving
                            _isStableCurrent = false;
                            _ownerPlayerInput.SwallowButton(BUTTON.FIRE_PRIMARY);
                        }
                    }
                    break;
                    case VisualWaypointEntity.CinematicLightColour.Red : {
                        if (leftJustPressed) {
                            CustomEntities.PlayEffect(PREFAB_FX_LOCK_CODE_DENIED, _posCurrent, Vector3.up, _ownerPlayer);
                            _isStableCurrent = false;
                        }
                    }
                    break;
                    case VisualWaypointEntity.CinematicLightColour.Yellow : case VisualWaypointEntity.CinematicLightColour.Green : {
                        if (leftJustPressed) {
                            CustomEntities.PlayEffect(PREFAB_FX_SELECT, _posCurrent, Vector3.up, _ownerPlayer);
                            var newWaypoint = GameManager.server.CreateEntity("assets/custom/waypoint.prefab", _posCurrent);
                            newWaypoint.Spawn();
                            //to trigger OnStoppedMoving the very next frame again
                            _isStableCurrent = false;
                        }
                    }
                    break;
                }
            }
            private void OnStartedMoving() {
                _firstScannedWaypoint = null;
                Colour = VisualWaypointEntity.CinematicLightColour.Cool;
            }
            private void OnStoppedMoving() {
                _lastWaypointsNearby.Clear();
                _firstScannedWaypoint = null;
                CustomEntities.CastingNonAlloc.GetCollidersWithinRadius(_posCurrent, WAYPOINT_PERSONAL_SPACE_SPHERE_RADIUS, LAYERMASK_OBSTACLES_AND_WAYPOINTS, QueryTriggerInteraction.Ignore);
                if (CustomEntities.CastingNonAlloc.ReusableColCount > 0) {
                    //unless we can get some waypoints
                    //stop after first found
                    CustomEntities.CastingNonAlloc.ProcessColliderBufferInto(_lastWaypointsNearby, null, null, null, true);
                    int found = _lastWaypointsNearby.Count;
                    if (found == 1) {
                        //found the first one closeby, go Black
                        Colour = VisualWaypointEntity.CinematicLightColour.Black;
                        _firstScannedWaypoint = _lastWaypointsNearby.First();
                    }
                    else {
                        //just an obstacle.Colour = VisualWaypointEntity.CinematicLightColour.Red;
                    }
                }
                else {
                    //free of obstacles or closeby stuff.CustomEntities.CastingNonAlloc.VisEntitiesUniqueWithinRadius(_posCurrent, WAYPOINT_NEIGHBOUR_AUTO_CONNECT_RADIUS, _lastWaypointsNearby, LAYERMASK_WAYPOINTS, QueryTriggerInteraction.Ignore);
                    int found = _lastWaypointsNearby.Count;
                    if (found > 0) {
                        Colour = VisualWaypointEntity.CinematicLightColour.Green;
                    }
                    else {
                        Colour = VisualWaypointEntity.CinematicLightColour.Yellow;
                    }
                }
            }
            public override void OnCustomPrefabPrototypeEntityRegistered() {
                base.OnCustomPrefabPrototypeEntityRegistered();
                syncPosition = true;
                PlayerToBrush = new Dictionary<ulong, WaypointBrushEntity>();
            }
            public override void OnCustomPrefabPrototypeEntityUnregistered() {
                base.OnCustomPrefabPrototypeEntityUnregistered();
                PlayerToBrush = null;
            }
            public static void OnActiveItemChanged(BasePlayer player, Item oldItem, Item newItem) {
                bool oldItemIsNull = oldItem == null;
                bool newItemIsNull = newItem == null;
                bool oldItemIsBrush = oldItemIsNull ? false : IsBrushItem(oldItem);
                bool newItemIsBrush = newItemIsNull ? false : IsBrushItem(newItem);
                if (!oldItemIsBrush && !newItemIsBrush) {
                    //no brushes involved, just return
                    return;
                }
                if (oldItem == newItem) {
                    //don't think that's possible...but just in case
                    return;
                }
                if (oldItemIsBrush && newItemIsBrush) {
                    return;
                }
                if (oldItemIsBrush) {
                    PlayerStoppedUsingBrush(player);
                }
                if (newItemIsBrush) {
                    PlayerStartedUsingBrush(player);
                }
            }
            public static void PlayerStartedUsingBrush(BasePlayer player) {
                player.ChatMessage("STARTED USING BRUSH");
                var newBrush = GameManager.server.CreateEntity("assets/custom/waypoint_brush.prefab", GetPositionInFrontOfPlayerEyes(player)) as WaypointBrushEntity;
                newBrush._ownerPlayer = player;
                newBrush.OwnerID = player.OwnerID;
                newBrush.Spawn();
                PlayerToBrush.Add(player.userID, newBrush);
            }
            public static void PlayerStoppedUsingBrush(BasePlayer player) {
                player.ChatMessage("STOPPED USING BRUSH");
                WaypointBrushEntity maybePlayerBrush;
                if (!PlayerToBrush.TryGetValue(player.userID, out maybePlayerBrush)) {
                    return;
                }
                PlayerToBrush.Remove(player.userID);
                maybePlayerBrush.Kill();
            }
            public static Vector3 GetPositionInFrontOfPlayerEyes(BasePlayer player) {
                return player.eyes.position + 2 * player.eyes.HeadForward();
            }
            public static bool IsBrushItem(Item item) {
                if (item == null) {
                    return false;
                }
                if (item.info.shortname != BRUSH_ITEM_SHORTNAME) {
                    return false;
                }
                if (item.skin != BRUSH_ITEM_SKIN) {
                    return false;
                }
                return true;
            }
        }
#endregion
#region WAYPOINT ENTITY
        public class VisualWaypointEntity : CustomEntities.CustomBaseEntity {
            public override string DefaultClientsideFullPrefabName() => PREFAB_LIGHT_POINT_RED;
            public static Dictionary<ulong, List<VisualWaypointEntity>> Graphs;
            public static List<VisualWaypointEntity> AllWaypoints;
            [SerializeField]
            private SphereCollider _myTinyCollider;
            public ListHashSet<VisualWaypointEntity> WaypointLinks;
            private ListHashSet<VisualWaypointEntity> _waypointsWithinRadius;
            public static void EnsureAllWaypointsHaveCorrectColours() {
                for (var i = 0; i < AllWaypoints.Count; i++) {
                    var waypoint = AllWaypoints[i];
                    waypoint.Invoke(() => {
                        if (waypoint.IsDestroyed) {
                            return;
                        }
                        waypoint.EnsureCorrectColour();
                    }
                    , UnityEngine.Random.Range(0.01F, 0.1F));
                }
            }
            //public static ListHashSet<BasePlayer> EditingPlayers;
            /*
             * RED: is a part of a graph with only one element in it
             * YELLOW: is part of the largest graph
             * GREEN: is part of the only graph (so either all are green, or none - this indicates anything can reach anything)
             * COOL: is part of any other graph
             */
            public static readonly Dictionary<string, CinematicLightColour> PrefabNameToColour = new Dictionary<string, CinematicLightColour> {
                [CustomEntities.PREFAB_SPHERE]
                = CinematicLightColour.Black, [PREFAB_LIGHT_POINT_RED] = CinematicLightColour.Red, [PREFAB_LIGHT_POINT_WARM] = CinematicLightColour.Yellow, [PREFAB_LIGHT_POINT_GREEN] = CinematicLightColour.Green, [PREFAB_LIGHT_POINT_COOL] = CinematicLightColour.Cool
            }
            ;
            public static readonly Dictionary<CinematicLightColour, string> ColourToPrefabName = new Dictionary<CinematicLightColour, string> {
                [CinematicLightColour.Black]
                = CustomEntities.PREFAB_SPHERE, [CinematicLightColour.Red] = PREFAB_LIGHT_POINT_RED, [CinematicLightColour.Yellow] = PREFAB_LIGHT_POINT_WARM, [CinematicLightColour.Green] = PREFAB_LIGHT_POINT_GREEN, [CinematicLightColour.Cool] = PREFAB_LIGHT_POINT_COOL
            }
            ;
            public static readonly Dictionary<CinematicLightColour, Color> ColourToUnityColour = new Dictionary<CinematicLightColour, Color> {
                [CinematicLightColour.Black]
                = Color.black, [CinematicLightColour.Red] = Color.red, [CinematicLightColour.Yellow] = Color.yellow, [CinematicLightColour.Green] = Color.green, [CinematicLightColour.Cool] = Color.white
            }
            ;
            public enum CinematicLightColour {
                Black = -1, Red = 0, Yellow = 1, Green = 2, Cool = 3,
            }
            private CinematicLightColour _colour = CinematicLightColour.Red;
            public CinematicLightColour Colour {
                get {
                    return _colour;
                }
                set {
                    if (_colour == value) {
                        return;
                    }
                    _colour = value;
                    //update to new colour...Handler.ClientsideFullPrefabName = ColourToPrefabName[value];
                }
            }
            public ulong GraphID = 0;
            public static List<VisualWaypointEntity> TryGetGraphByGraphID(ulong graphID) {
                List<VisualWaypointEntity> graph;
                if (!Graphs.TryGetValue(graphID, out graph)) {
                    return null;
                }
                return graph;
            }
            public override void ServerInit() {
                base.ServerInit();
                OnAdded();
                InvokeRandomized(DrawSelf, 0.1F, 0.75F, 0.5F);
            }
            public override void DestroyShared() {
                base.DestroyShared();
                CancelInvoke(DrawSelf);
                if (Unloading) {
                    return;
                }
                if (Instance == null) {
                    return;
                }
                OnRemoved();
            }
            public override void LoadExtra(Stream stream, BinaryReader reader) {
                base.LoadExtra(stream, reader);
                GraphID = reader.ReadUInt64();
            }
            public override void SaveExtra(Stream stream, BinaryWriter writer) {
                base.SaveExtra(stream, writer);
                writer.Write(GraphID);
            }
            public override void OnCustomPrefabPrototypeEntityRegistered() {
                base.OnCustomPrefabPrototypeEntityRegistered();
                //run this only once, otherwise you're gonna have trouble
                _myTinyCollider = gameObject.AddComponent<SphereCollider>();
                _myTinyCollider.isTrigger = false;
                _myTinyCollider.radius = 0.2F;
            }
            public void EstablishLinkBetweenWaypointAndYou(VisualWaypointEntity otherLinkedWaypoint, bool invokeThisInTheOtherWaypoint) {
                if (!WaypointLinks.Contains(otherLinkedWaypoint)) {
                    WaypointLinks.Add(otherLinkedWaypoint);
                }
                if (!invokeThisInTheOtherWaypoint) {
                    return;
                }
                otherLinkedWaypoint.EstablishLinkBetweenWaypointAndYou(this, false);
                //false to prevent infinite loops
            }
            public void ClearLinkBetweenWaypointAndYou(VisualWaypointEntity otherLinkedWaypoint, bool invokeThisInTheOtherWaypoint) {
                if (WaypointLinks.Contains(otherLinkedWaypoint)) {
                    WaypointLinks.Remove(otherLinkedWaypoint);
                }
                if (!invokeThisInTheOtherWaypoint) {
                    return;
                }
                otherLinkedWaypoint.ClearLinkBetweenWaypointAndYou(this, false);
                //false to prevent infinite loops
            }
            public void EnsureRemovedFromGraph(ulong graphID) {
                var maybeCurrentGraph = TryGetGraphByGraphID(GraphID);
                if (maybeCurrentGraph != null) {
                    maybeCurrentGraph.Remove(this);
                    if (maybeCurrentGraph.Count == 0) {
                        //if it was the last element, remove the entire graph
                        Graphs.Remove(graphID);
                    }
                }
                GraphID = 0;
            }
            public void EnsureMovedToGraph(ulong newGraphID) {
                //remove from old graph first...EnsureRemovedFromGraph(GraphID);
                //and now GraphID is 0....var maybeNewGraph = TryGetGraphByGraphID(newGraphID);
                if (maybeNewGraph == null) {
                    //no such graph, create a new graph with yourself in it
                    maybeNewGraph = new List<VisualWaypointEntity> {
                        this
                    }
                    ;
                    Graphs.Add(newGraphID, maybeNewGraph);
                }
                else {
                    if (!maybeNewGraph.Contains(this)) {
                        //graph found, add yourself
                        maybeNewGraph.Add(this);
                    }
                }
                GraphID = newGraphID;
            }
            public void OnAdded() {
                _waypointsWithinRadius = new ListHashSet<VisualWaypointEntity>();
                WaypointLinks = new ListHashSet<VisualWaypointEntity>();
                AllWaypoints.Add(this);
                //first, attach to a self graph based on your NET id
                EnsureMovedToGraph(net.ID.Value);
                CustomEntities.CastingNonAlloc.VisEntitiesUniqueWithinRadius(transform.position, WAYPOINT_NEIGHBOUR_AUTO_CONNECT_RADIUS, _waypointsWithinRadius, LAYERMASK_WAYPOINTS, QueryTriggerInteraction.Ignore, OtherWaypointIsNotYou);
                for (var v = 0; v < _waypointsWithinRadius.Count; v++) {
                    var otherWaypoint = _waypointsWithinRadius[v];
                    //can you fully "see" each other? and nothing else in between or overlapping in the "capsule" encompassing personal space from your position to the other position?
                    Vector3 dir = otherWaypoint.transform.position - transform.position;
                    float length = dir.magnitude;
                    dir /= length;
                    var colliderResults = Physics.SphereCastNonAlloc(transform.position, WAYPOINT_PERSONAL_SPACE_SPHERE_RADIUS, dir, CustomEntities.CastingNonAlloc.ReusableRaycastBuffer, length, LAYERMASK_OBSTACLES, QueryTriggerInteraction.Ignore);
                    if (colliderResults > 0) {
                        continue;
                    }
                    //good, nothing in between you and the other waypoint - pair up
                    EstablishLinkBetweenWaypointAndYou(otherWaypoint, true);
                    //true, becuase we want it to be mutual
                }
                if (_waypointsWithinRadius.Count == 0) {
                    //nothing to do as you won't have any neighbours
                    EnsureAllWaypointsHaveCorrectColours();
                    return;
                }
                //now it's time to iterate over links.ulong lowestNetIDfoundSoFar = ulong.MaxValue;
                //we should make it into a reusable
                var buildListOfAll = new ListHashSet<VisualWaypointEntity>();
                FloodFillRecursively(this, buildListOfAll, ref lowestNetIDfoundSoFar);
                //now iterate over buildListOfAll and ensure they are all in the graph with the id of lowestNetIDfoundSoFar.//this will also include yourself.for (var i = 0; i < buildListOfAll.Count; i++)
                {
                    var fromBuildList = buildListOfAll[i];
                    fromBuildList.EnsureMovedToGraph(lowestNetIDfoundSoFar);
                }
                //no need to execute this if you had no waypoints to begin with!
                EnsureAllWaypointsHaveCorrectColours();
            }
            public void OnRemoved() {
                //okay something is still wrong.We're getting a NRE.//it looks like as if the connections are NOT properly severed.AllWaypoints.Remove(this);
                var currentGraphID = GraphID;
                EnsureRemovedFromGraph(currentGraphID);
                if (WaypointLinks.Count == 0) {
                    //nothing to do, you had no links
                    EnsureAllWaypointsHaveCorrectColours();
                    return;
                }
                var linksCopy = WaypointLinks.ToArray();
                //sever all your connections
                var buildListOfAll = new ListHashSet<VisualWaypointEntity>();
                //do them branches
                //clear links first, maybe?
                for (var l = 0; l < linksCopy.Length; l++) {
                    var branchWaypoint = linksCopy[l];
                    //sever your link mutually so it doesn't take you in the flood fill
                    ClearLinkBetweenWaypointAndYou(branchWaypoint, true);
                }
                for (var l = 0; l < linksCopy.Length; l++) {
                    var branchWaypoint = linksCopy[l];
                    ulong lowestNetIDfoundSoFarForThisBranch = ulong.MaxValue;
                    ListHashSet<VisualWaypointEntity> branchSpecificList = new ListHashSet<VisualWaypointEntity>();
                    FloodFillRecursively(branchWaypoint, branchSpecificList, ref lowestNetIDfoundSoFarForThisBranch, buildListOfAll);
                    //we have the branch, now make sure they all assume the lowest net ID as their Graph ID...//and we can also ensure their colours
                    for (var i = 0; i < branchSpecificList.Count; i++) {
                        var fromBranchSpecificList = branchSpecificList[i];
                        fromBranchSpecificList.EnsureMovedToGraph(lowestNetIDfoundSoFarForThisBranch);
                    }
                }
                EnsureAllWaypointsHaveCorrectColours();
            }
            public static void FloodFillRecursively(VisualWaypointEntity doingNow, ListHashSet<VisualWaypointEntity> branchList, ref ulong lowestNetIDFoundSoFar, ListHashSet<VisualWaypointEntity> globalList = null) {
                if (globalList != null) {
                    if (globalList.Contains(doingNow)) {
                        //terminate
                        return;
                    }
                }
                if (branchList.Contains(doingNow)) {
                    //terminate the recursion branch
                    return;
                }
                //now add so you never do yourself again
                var doingNowNetID = doingNow.net.ID.Value;
                if (doingNowNetID < lowestNetIDFoundSoFar) {
                    lowestNetIDFoundSoFar = doingNowNetID;
                }
                branchList.Add(doingNow);
                if (globalList != null) {
                    globalList.Add(doingNow);
                }
                //and now your neighbours
                for (var i = 0; i < doingNow.WaypointLinks.Count; i++) {
                    var linked = doingNow.WaypointLinks[i];
                    FloodFillRecursively(linked, branchList, ref lowestNetIDFoundSoFar, globalList);
                }
            }
            public bool OtherWaypointIsNotYou(VisualWaypointEntity otherWaypoint) {
                return !EqualNetID(otherWaypoint);
            }
            public void EnsureCorrectColour() {
                //by default you're "other"
                var useCinematicColour = CinematicLightColour.Cool;
                var ourGraph = TryGetGraphByGraphID(GraphID);
                if (ourGraph != null) {
                    if (Graphs.Count == 1) {
                        //the only graph - become green like everyone else
                        useCinematicColour = CinematicLightColour.Green;
                    }
                    else {
                        int ourGraphCount = ourGraph.Count;
                        //are you the only memeber of your graph?
                        if (ourGraphCount == 1) {
                            useCinematicColour = CinematicLightColour.Red;
                        }
                        else {
                            //are you a member of the largest graph?
                            bool someoneBeatOurGraph = false;
                            foreach (var graph in Graphs) {
                                if (graph.Value == ourGraph) {
                                    continue;
                                }
                                if (graph.Value.Count > ourGraphCount) {
                                    someoneBeatOurGraph = true;
                                    break;
                                }
                            }
                            if (!someoneBeatOurGraph) {
                                useCinematicColour = CinematicLightColour.Yellow;
                            }
                        }
                    }
                }
                //set it...Colour = useCinematicColour;
            }
            public void DrawSelf() {
                if (IsDestroyed) {
                    return;
                }
                var unityColour = ColourToUnityColour[Colour];
                for (var p = 0; p < BasePlayer.activePlayerList.Count; p++) {
                    var player = BasePlayer.activePlayerList[p];
                    if (!player.IsAdmin) {
                        continue;
                    }
                    //uncomment to only draw when close enough
                    /*
                    if (Vector3.Distance(player.transform.position, transform.position) > WAYPOINT_NEIGHBOUR_AUTO_CONNECT_RADIUS)
                    {
                        continue;
                    }*/
                    //draw yourself...CustomEntities.DrawTextCommon(player, 1F, unityColour, transform.position, $"{net.ID}\n{GraphID}");
                    if (WaypointLinks.Count == 0) {
                        continue;
                    }
                    var myDistanceToPlayer = Vector3.Distance(player.transform.position, transform.position);
                    for (var i = 0; i < WaypointLinks.Count; i++) {
                        var linkedWaypoint = WaypointLinks[i];
                        if (linkedWaypoint.IsDestroyed) {
                            continue;
                        }
                        var otherDistanceToPlayer = Vector3.Distance(player.transform.position, linkedWaypoint.transform.position);
                        if (myDistanceToPlayer > otherDistanceToPlayer) {
                            //the other one is closer, only draw the other one
                            continue;
                        }
                        CustomEntities.DrawLineCommon(player, 1F, unityColour, transform.position, linkedWaypoint.transform.position);
                    }
                }
            }
        }
#endregion
    }
}

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