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

FREE SimpleSymmetry : 1.2.0 1.2.0

Нет прав для скачивания
C#:
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Game.Rust.Cui;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using UnityEngine;
using UnityEngine.Networking;
//SimpleSymmetry created with PluginMerge v(1.0.8.0) by MJSU @ https://github.com/dassjosh/Plugin.Merge
namespace Oxide.Plugins {
    [Info("SimpleSymmetry", "Shady14u", "1.2.0")]
    [Description("Effortlessly create symmetrical base designs")]
    public partial class SimpleSymmetry : RustPlugin {
#region 0.SimpleSymmetry.cs
        private static Color _color = Color.blue;
        private readonly int _constructionMask = LayerMask.GetMask("Construction");
        private readonly int _terrainMask = LayerMask.GetMask("Terrain");
        private readonly List<ulong> _waterFoundations = new();
        private void AdjustSymmetry(PlayerBuildOptions buildOptions, BasePlayer player, SymmetryType symmetryType) {
            buildOptions.SymmetryType = symmetryType;
            SendMessage(player, $"Symmetry set to {symmetryType}.");
            ShowCurrentSymmetryPoint(player);
        }
        private bool CanAfford(BasePlayer player, List<ItemAmount> cost) {
            foreach (var itemAmount in cost) {
                if (player.inventory.GetAmount(itemAmount.itemid) < itemAmount.amount) {
                    return false;
                }
            }
            foreach (var itemAmount in cost) {
                player.inventory.Take(null, itemAmount.itemid, (int) itemAmount.amount);
                player.Command("note.inv " + itemAmount.itemid + " " + (float) (itemAmount.amount * -1.0));
            }
            return true;
        }
        private bool CanPlace(BaseEntity foundation, BasePlayer player) {
            var buildOptions = GetBuildOptions(player.userID.Get());
            var dist = Vector3.Distance(buildOptions.StartPoint, foundation.transform.position);
            if (buildOptions.SymmetryEnabled && dist > _config.MaxRadiusForBuilding) {
                SendMessage(player, "You are to far from your center point to use symmetry");
                return false;
            }
            var volumes = PrefabAttribute.server.FindAll<DeployVolume>(foundation.prefabID);
            var trans = foundation.transform;
            if (DeployVolume.Check(trans.position, trans.rotation, volumes)) {
                SendMessage(player, "Not enough space");
                return false;
            }
            if (player.IsBuildingBlocked(trans.position, trans.rotation, foundation.bounds)) {
                SendMessage(player, "You don't have permission to build here");
                return false;
            }
            if (foundation.ShortPrefabName.Contains("foundation") && !CheckFoundationCollision(foundation)) {
                return false;
            }
            return !IsToCloseToRoad(foundation);
        }
        private bool CheckFoundationCollision(BaseEntity entity) {
            var ray = new Ray(entity.transform.position, Vector3.down);
            Physics.Raycast(ray, out var hitInfo, 100, LayerMask.GetMask("Terrain"));
            return hitInfo.distance <= 2.8 && !SocketMod_TerrainCheck.IsInTerrain(entity.transform.position, true);
        }
        private static string CreateButton(ref CuiElementContainer container, string anchorMin, string anchorMax, string offsetMin, string offsetMax, float padding, string buttonColor, string textColor, string buttonText, int fontSize, string buttonCommand, string parent = "Overlay", TextAnchor labelAnchor = TextAnchor.MiddleCenter) {
            var panel = container.Add(new CuiPanel {
                RectTransform = {
                    AnchorMin = anchorMin, AnchorMax = anchorMax, OffsetMin = offsetMin, OffsetMax = offsetMax
                }
                , Image = {
                    Color = "0 0 0 0"
                }
            }
            , parent);
            container.Add(new CuiButton {
                RectTransform = {
                    AnchorMin = $"{padding} {padding}", AnchorMax = $"{1 - padding} {1 - padding}"
                }
                , Button = {
                    Color = buttonColor, Command = $"{buttonCommand}"
                }
                , Text = {
                    Align = labelAnchor, Color = textColor, FontSize = fontSize, Text = buttonText
                }
            }
            , panel);
            return panel;
        }
        private static string CreateImagePanel(ref CuiElementContainer container, string anchorMin, string anchorMax, string offsetMin, string offsetMax, float padding, string imageData, string parent = "Overlay", string panelName = null) {
            var panel = container.Add(new CuiPanel {
                RectTransform = {
                    AnchorMin = anchorMin, AnchorMax = anchorMax, OffsetMin = offsetMin, OffsetMax = offsetMax
                }
                , Image = {
                    Color = "0 0 0 0"
                }
            }
            , parent, panelName);
            container.Add(new CuiElement {
                Parent = panel, Components = {
                    new CuiRectTransformComponent {
                        AnchorMin = $"{padding} {padding +.004f}", AnchorMax = $"{1 - padding -.004f} {1 - padding -.02f}"
                    }
                    , new CuiRawImageComponent {
                        Png = imageData
                    }
                }
            }
            );
            return panel;
        }
        private string CreateLabel(ref CuiElementContainer container, string anchorMin, string anchorMax, string offsetMin, string offsetMax, float padding, string backgroundColor, string textColor, string labelText, int fontSize, TextAnchor alignment, string parent = "Overlay", string labelName = null) {
            var panel = container.Add(new CuiPanel {
                RectTransform = {
                    AnchorMin = anchorMin, AnchorMax = anchorMax, OffsetMin = offsetMin, OffsetMax = offsetMax
                }
                , Image = {
                    Color = backgroundColor
                }
            }
            , parent, labelName);
            container.Add(new CuiLabel {
                Text = {
                    Color = textColor, Text = labelText, Align = alignment, FontSize = fontSize
                }
                , RectTransform = {
                    AnchorMin = $"{padding} {padding}", AnchorMax = $"{1 - padding} {1 - padding}"
                }
            }
            , panel);
            return panel;
        }
        private static string CreatePanel(ref CuiElementContainer container, string anchorMin, string anchorMax, string offsetMin, string offsetMax, string panelColor, string parent = "Overlay", string panelName = null) {
            return container.Add(new CuiPanel {
                RectTransform = {
                    AnchorMin = anchorMin, AnchorMax = anchorMax, OffsetMin = offsetMin, OffsetMax = offsetMax
                }
                , Image = {
                    Color = panelColor
                }
            }
            , parent, panelName);
        }
        private void CreateSymmetryPanel(ref CuiElementContainer container, string anchorMin, string anchorMax, string offsetMin, string offsetMax, string backgroundColor, PlayerBuildOptions buildOptions, string parent = "Overlay", string buttonName = "") {
            var btnHeight = 36;
            var top = 0;
            var symmetryPanel = CreatePanel(ref container, anchorMin, anchorMax, offsetMin, offsetMax, backgroundColor, parent);
            var labelOffset = 0f;
            if (buildOptions.SymmetryShape == SymmetryShape.Triangle) {
                labelOffset = -25;
            }
            var symImagePanel = CreateImagePanel(ref container, Anchors.TopLeft, Anchors.TopLeft, $"5 {top - 132}", $"140 {top}", .02f, GetSymmetryImage(buildOptions), symmetryPanel);
            CreateLabel(ref container, Anchors.Center, Anchors.Center, $"-100 {labelOffset - 10}", $"100 {labelOffset + 10}", .02f, "0 0 0 0", "1 1 1 1", ToSentenceCase(GetMsg(buildOptions.SymmetryEnabled ? buildOptions.SymmetryType.ToString() : "SymmetryNotSet")), 10, TextAnchor.MiddleCenter, symImagePanel);
            CreateButton(ref container, Anchors.TopRight, Anchors.TopRight, $"-95 {top - 136}", "-70 1.5", .04f, GetButtonColor(buttonName == "cycle"), "1 1 1 1", ">", 8, "symmetry cycle", "SymmetryPanel");
            CreateButton(ref container, Anchors.TopRight, Anchors.TopRight, $"-70 -25", $"-35 0", .2f, GetButtonColor(buttonName == "minimize"), "1 1 1 1", "_", 8, "symmetry minimize", "SymmetryPanel");
            CreateButton(ref container, Anchors.TopRight, Anchors.TopRight, $"-35 -25", $"0 0", .2f, GetButtonColor(buttonName == "close"), "1 1 1 1", "X", 8, "symmetry ui", "SymmetryPanel");
            top = -25;
            CreateButton(ref container, Anchors.TopRight, Anchors.TopRight, $"-70 {top - btnHeight}", $"0 -25", .1f, GetButtonColor(buttonName == "set"), "1 1 1 1", GetMsg(PluginMessages.SetSymmetry), 8, "symmetry set", "SymmetryPanel");
            top -= btnHeight;
            CreateButton(ref container, Anchors.TopRight, Anchors.TopRight, $"-70 {top - btnHeight}", $"0 {top}", .1f, GetButtonColor(buttonName == "toggle"), "1 1 1 1", GetMsg(PluginMessages.ToggleSymmetry), 8, "symmetry toggle", "SymmetryPanel");
            top -= btnHeight;
            CreateButton(ref container, Anchors.TopRight, Anchors.TopRight, $"-70 {top - btnHeight}", $"0 {top}", .1f, GetButtonColor(buttonName == "delete"), "1 1 1 1", GetMsg(PluginMessages.DeleteSymmetry), 8, "symmetry delete", "SymmetryPanel");
        }
        private void DemolishByType(SymmetryShape symmetryShape, SymmetryType symmetryType, Vector3 startPoint, BaseNetworkable entity, Quaternion buildOptionsStartRotation) {
            switch (symmetryShape) {
                case SymmetryShape.Triangle : ServerMgr.Instance.StartCoroutine(DemolishGeneric(startPoint, entity, 3));
                break;
                case SymmetryShape.Hexagon : switch (symmetryType) {
                    case SymmetryType.Normal6Sided : ServerMgr.Instance.StartCoroutine(DemolishGeneric(startPoint, entity, 6));
                    return;
                    case SymmetryType.Mirrored2Sided : ServerMgr.Instance.StartCoroutine(DemolishGeneric(startPoint, entity, 2));
                    return;
                    case SymmetryType.Normal3Sided : ServerMgr.Instance.StartCoroutine(DemolishGeneric(startPoint, entity, 3));
                    return;
                    default : ServerMgr.Instance.StartCoroutine(DemolishGeneric(startPoint, entity, 2));
                    return;
                }
                case SymmetryShape.Square : case SymmetryShape.Rectangle : case SymmetryShape.Octagon : switch (symmetryType) {
                    case SymmetryType.Normal2Sided : ServerMgr.Instance.StartCoroutine(DemolishGeneric(startPoint, entity, 2));
                    return;
                    case SymmetryType.Normal4Sided : ServerMgr.Instance.StartCoroutine(DemolishGeneric(startPoint, entity, 4));
                    return;
                    case SymmetryType.Mirrored2Sided : ServerMgr.Instance.StartCoroutine(DemolishMirroredGeneric(startPoint, entity, 2, buildOptionsStartRotation));
                    return;
                    case SymmetryType.Mirrored4Sided : ServerMgr.Instance.StartCoroutine(DemolishMirroredGeneric(startPoint, entity, 4, buildOptionsStartRotation));
                    return;
                }
                break;
            }
        }
        private IEnumerator DemolishGeneric(Vector3 startingPoint, BaseNetworkable newBlock, int total) {
            if (newBlock == null) yield break;
            var pos = newBlock.transform.position;
            var angles = 360 / total;
            for (var i = 1; i < total; i++) {
                var newPos = startingPoint + Quaternion.Euler(0, angles * i, 0) * (pos - startingPoint);
                var entityToDemolish = Physics.OverlapSphere(newPos, 2, _constructionMask).Select(x => x.ToBaseEntity()).Where(x => x.ShortPrefabName == newBlock.ShortPrefabName).OrderBy(x => Vector3.Distance(x.transform.position, newPos)).FirstOrDefault();
                if (entityToDemolish == null) continue;
                if (!entityToDemolish.IsDestroyed) entityToDemolish.Kill(BaseNetworkable.DestroyMode.Gib);
                yield return i;
            }
        }
        private IEnumerator DemolishMirroredGeneric(Vector3 startingPoint, BaseNetworkable newBlock, int sides, Quaternion startRotation) {
            var pos = newBlock.transform.position;
            var localOffset = Quaternion.Inverse(startRotation) * (pos - startingPoint);
            localOffset = Math.Abs(localOffset.x) > Math.Abs(localOffset.z) ? localOffset.WithX(-localOffset.x) : localOffset.WithZ(-localOffset.z);
            var newPoint = startingPoint + startRotation * localOffset;
            var entityToDemolish = Physics.OverlapSphere(newPoint, 2f, _constructionMask).Select(x => x.ToBaseEntity()).OrderBy(x => Vector3.Distance(x.transform.position, newPoint)).FirstOrDefault(x => x.ShortPrefabName == newBlock.ShortPrefabName);
            if (entityToDemolish == null) yield break;
            if (!entityToDemolish.IsDestroyed) entityToDemolish.Kill(BaseNetworkable.DestroyMode.Gib);
        }
        private Vector3 FindTheCenter(BaseNetworkable entity, BasePlayer player) {
            if (!entity) return new Vector3();
            // Create a new vector to store the center position
            var centerPosition = Vector3.zero;
            if (entity.ShortPrefabName is "foundation" or "floor") {
                centerPosition = entity.transform.position;
                player.SendConsoleCommand("ddraw.sphere", 10f, Color.blue, centerPosition, 0.2f);
                return centerPosition;
            }
            // Get the angle of the triangle's baseline relative to the x-axis
            var transform = entity.transform;
            var baselineAngle = transform.eulerAngles.y;
            // Set the position of the triangle's baseline
            var baselinePosition = transform.position;
            // Calculate the position of the center of the triangle
            centerPosition.x = baselinePosition.x + (0.8660254f * Mathf.Sin(baselineAngle * Mathf.Deg2Rad));
            centerPosition.z = baselinePosition.z + (0.8660254f * Mathf.Cos(baselineAngle * Mathf.Deg2Rad));
            centerPosition.y = baselinePosition.y;
            player.SendConsoleCommand("ddraw.sphere", 10f, Color.blue, centerPosition, 0.2f);
            return centerPosition;
        }
        private string GetButtonColor(bool isSelected) {
            return isSelected ? _config.SelectedButtonColor : _config.DefaultButtonColor;
        }
        public BuildingBlock GetNearbyBuildingBlock(Vector3 position) {
            var nearbyBuildingBlock = (BuildingBlock) null;
            var list = Facepunch.Pool.Get<List<BuildingBlock>>();
            Vis.Entities(position, 5f, list, LayerMask.GetMask("Construction"));
            var maxDistance = 5f;
            foreach (var buildingBlock in list) {
                var distance = Vector3.Distance(buildingBlock.transform.position, position);
                if (distance > maxDistance) continue;
                maxDistance = distance;
                nearbyBuildingBlock = buildingBlock;
            }
            Facepunch.Pool.FreeUnmanaged(ref list);
            return nearbyBuildingBlock;
        }
        private string GetSymmetryImage(PlayerBuildOptions buildOptions) {
            var name = buildOptions.SymmetryEnabled ? $"{buildOptions.SymmetryShape}_{buildOptions.SymmetryType}.png" : $"{buildOptions.SymmetryShape}.png";
            return _storedData.CommonImages.TryGetValue(name, out var image) ? image : _storedData.CommonImages["Square.png"];
        }
        private bool IsToCloseToRoad(BaseEntity baseEntity) {
            var heightMap = TerrainMeta.HeightMap;
            var topologyMap = TerrainMeta.TopologyMap;
            if (heightMap == null) {
                return false;
            }
            if (topologyMap == null) {
                return false;
            }
            var transform = baseEntity.transform;
            var obb = new OBB(transform.position, Vector3.one, transform.rotation, baseEntity.bounds);
            var num = Mathf.Abs(heightMap.GetHeight(obb.position) - obb.position.y);
            if (num > 9f) {
                return false;
            }
            var radius = Mathf.Lerp(3f, 0f, num / 9f);
            var position = obb.position;
            var point = obb.GetPoint(-1f, 0f, -1f);
            var point2 = obb.GetPoint(-1f, 0f, 1f);
            var point3 = obb.GetPoint(1f, 0f, -1f);
            var point4 = obb.GetPoint(1f, 0f, 1f);
            var topology = topologyMap.GetTopology(position, radius);
            var topology2 = topologyMap.GetTopology(point, radius);
            var topology3 = topologyMap.GetTopology(point2, radius);
            var topology4 = topologyMap.GetTopology(point3, radius);
            var topology5 = topologyMap.GetTopology(point4, radius);
            return ((topology | topology2 | topology3 | topology4 | topology5) & 526336) != 0;
        }
        private void MinimizeUi(BasePlayer player) {
            var buildOptions = GetBuildOptions(player.userID.Get());
            buildOptions.UiMinimized = true;
            var container = new CuiElementContainer {
                new CuiElement {
                    Parent = "Overlay", Name = "SymmetryPanel", Components = {
                        new CuiRectTransformComponent {
                            AnchorMin = _config.UiAnchorMax, AnchorMax = _config.UiAnchorMax, OffsetMin = "-50 -50", OffsetMax = "0 0"
                        }
                        , new CuiImageComponent {
                            Color = _config.MainBackgroundColor
                        }
                    }
                }
            }
            ;
            CreateImagePanel(ref container, "0 0", "1 1", "0 0", "0 0", 0.1f, GetSymmetryImage(buildOptions), "SymmetryPanel");
            CreateButton(ref container, "0 0", "1 1", "0 0", "0 0", 0.1f, ".2.2.2.9", "1 1 1 1", "+", 12, "symmetry ui true", "SymmetryPanel");
            CuiHelper.DestroyUi(player, "SymmetryPanel");
            CuiHelper.AddUi(player, container);
            Interface.CallHook("OnSymmetryUiChanged", player, false, true);
        }
        private void ReplicateByType(SymmetryShape symmetryShape, SymmetryType symmetryType, Vector3 startPoint, BaseNetworkable entity, Quaternion buildOptionsStartRotation, Planner plan) {
            switch (symmetryShape) {
                case SymmetryShape.Triangle : ServerMgr.Instance.StartCoroutine(ReplicateGeneric(startPoint, entity, 3, plan));
                break;
                case SymmetryShape.Hexagon : switch (symmetryType) {
                    case SymmetryType.Normal6Sided : ServerMgr.Instance.StartCoroutine(ReplicateGeneric(startPoint, entity, 6, plan));
                    return;
                    case SymmetryType.Mirrored2Sided : ServerMgr.Instance.StartCoroutine(ReplicateGeneric(startPoint, entity, 2, plan));
                    return;
                    case SymmetryType.Normal3Sided : ServerMgr.Instance.StartCoroutine(ReplicateGeneric(startPoint, entity, 3, plan));
                    return;
                    default : ServerMgr.Instance.StartCoroutine(ReplicateGeneric(startPoint, entity, 2, plan));
                    return;
                }
                case SymmetryShape.Square : case SymmetryShape.Rectangle : switch (symmetryType) {
                    case SymmetryType.Normal2Sided : ServerMgr.Instance.StartCoroutine(ReplicateGeneric(startPoint, entity, 2, plan));
                    return;
                    case SymmetryType.Normal4Sided : ServerMgr.Instance.StartCoroutine(ReplicateGeneric(startPoint, entity, 4, plan));
                    return;
                    case SymmetryType.Mirrored2Sided : ServerMgr.Instance.StartCoroutine(ReplicateMirroredGeneric(startPoint, entity, 2, buildOptionsStartRotation, plan));
                    return;
                    case SymmetryType.Mirrored4Sided : ServerMgr.Instance.StartCoroutine(ReplicateMirroredGeneric(startPoint, entity, 4, buildOptionsStartRotation, plan));
                    return;
                }
                break;
                case SymmetryShape.Octagon : switch (symmetryType) {
                    case SymmetryType.Normal2Sided : ServerMgr.Instance.StartCoroutine(ReplicateGeneric(startPoint, entity, 2, plan));
                    return;
                    case SymmetryType.Normal4Sided : ServerMgr.Instance.StartCoroutine(ReplicateGeneric(startPoint, entity, 4, plan));
                    return;
                    case SymmetryType.Mirrored2Sided : ServerMgr.Instance.StartCoroutine(ReplicateMirroredGeneric(startPoint, entity, 2, buildOptionsStartRotation, plan));
                    return;
                    case SymmetryType.Mirrored4Sided : ServerMgr.Instance.StartCoroutine(ReplicateMirroredGeneric(startPoint, entity, 4, buildOptionsStartRotation, plan));
                    return;
                }
                break;
            }
        }
        private IEnumerator ReplicateGeneric(Vector3 startingPoint, BaseNetworkable newBlock, int total, Planner plan) {
            var pos = newBlock.transform;
            var playerId = (newBlock as BaseEntity)?.OwnerID ?? 0;
            if (playerId == 0 || total < 1) yield break;
            var player = BasePlayer.Find(playerId.ToString());
            if (player == null) yield break;
            var newBuildBlock = newBlock.GetComponent<BuildingBlock>();
            if (newBuildBlock == null) yield break;
            var cost = newBuildBlock.BuildCost();
            var newDefinition = PrefabAttribute.server.Find<Construction>(newBlock.prefabID);
            var newGrade = (newBlock as BuildingBlock)?.grade ?? BuildingGrade.Enum.Twigs;
            for (var i = 1; i < total; i++) {
                if (_config.RequireMaterialsToBuild && !CanAfford(player, cost)) yield break;
                var angles = 360 / total;
                var foundation = GameManager.server.CreateEntity(newBlock.PrefabName, pos.position, pos.rotation);
                if (foundation == null) continue;
                foundation.transform.RotateAround(startingPoint, Vector3.down, angles * i);
                if (!CanPlace(foundation, player)) continue;
                foundation.OwnerID = playerId;
                var decayEntity = foundation as DecayEntity;
                var nearbyBuildingBlock = GetNearbyBuildingBlock(newBlock.transform.position);
                if (nearbyBuildingBlock != null && decayEntity != null) {
                    var buildingId = nearbyBuildingBlock.buildingID == 0 ? BuildingManager.server.NewBuildingID() : nearbyBuildingBlock.buildingID;
                    decayEntity.AttachToBuilding(buildingId);
                }
                foundation.Spawn();
                var block = foundation.GetComponent<BuildingBlock>();
                if (block != null) {
                    block.blockDefinition = newDefinition;
                    block.SetGrade(newGrade);
                    block.SetHealthToMax();
                    block.SendNetworkUpdateImmediate();
                    _waterFoundations.Add(block.net.ID.Value);
                    Interface.Call("OnEntityBuilt", plan, block.gameObject);
                }
                yield return null;
            }
        }
        private IEnumerator ReplicateMirroredGeneric(Vector3 startingPoint, BaseNetworkable newBlock, int total, Quaternion startRotation, Planner plan) {
            var pos = newBlock.transform;
            var playerId = (newBlock as BaseEntity)?.OwnerID ?? 0;
            if (playerId == 0 || total < 1) yield break;
            var player = BasePlayer.Find(playerId.ToString());
            if (player == null) yield break;
            var newBuildBlock = newBlock.GetComponent<BuildingBlock>();
            if (newBuildBlock == null) yield break;
            var cost = newBuildBlock.BuildCost();
            if (_config.RequireMaterialsToBuild && !CanAfford(player, cost)) yield break;
            var newPos = pos.position;
            var localOffset = Quaternion.Inverse(startRotation) * (newPos - startingPoint);
            localOffset = Math.Abs(localOffset.x) > Math.Abs(localOffset.z) ? localOffset.WithX(-localOffset.x) : localOffset.WithZ(-localOffset.z);
            var newPoint = startingPoint + startRotation * localOffset;
            var eulerAngles = pos.eulerAngles;
            var deltaY = startRotation.eulerAngles.y - eulerAngles.y;
            var newRot = Quaternion.Euler(eulerAngles.WithY(startRotation.eulerAngles.y + deltaY + 180));
            var entity = GameManager.server.CreateEntity(newBlock.PrefabName, newPoint, newRot);
            if (entity == null) yield break;
            entity.OwnerID = playerId;
            var decayEntity = entity as DecayEntity;
            var nearbyBuildingBlock = GetNearbyBuildingBlock(newBlock.transform.position);
            if (nearbyBuildingBlock != null && decayEntity != null) {
                var buildingId = nearbyBuildingBlock.buildingID == 0 ? BuildingManager.server.NewBuildingID() : nearbyBuildingBlock.buildingID;
                decayEntity?.AttachToBuilding(buildingId);
            }
            entity.Spawn();
            var block = entity.GetComponent<BuildingBlock>();
            if (block != null) {
                block.blockDefinition = PrefabAttribute.server.Find<Construction>(newBlock.prefabID);
                block.SetGrade((newBlock as BuildingBlock)?.grade ?? BuildingGrade.Enum.Twigs);
                block.SetHealthToMax();
                block.SendNetworkUpdateImmediate();
                _waterFoundations.Add(block.net.ID.Value);
                Interface.Call("OnEntityBuilt", plan, block.gameObject);
            }
            if (total != 4) yield break;
            localOffset = Quaternion.Inverse(startRotation) * (newPos - startingPoint);
            localOffset = Math.Abs(localOffset.x) < Math.Abs(localOffset.z) ? localOffset.WithX(-localOffset.x) : localOffset.WithZ(-localOffset.z);
            newPoint = startingPoint + startRotation * localOffset;
            eulerAngles = pos.eulerAngles;
            deltaY = startRotation.eulerAngles.y - eulerAngles.y;
            newRot = Quaternion.Euler(eulerAngles.WithY(startRotation.eulerAngles.y + deltaY + 180));
            entity = GameManager.server.CreateEntity(newBlock.PrefabName, newPoint, newRot);
            if (entity == null) yield break;
            entity.OwnerID = playerId;
            decayEntity = entity as DecayEntity;
            nearbyBuildingBlock = GetNearbyBuildingBlock(newBlock.transform.position);
            if (nearbyBuildingBlock != null && decayEntity != null) {
                var buildingId = nearbyBuildingBlock.buildingID == 0 ? BuildingManager.server.NewBuildingID() : nearbyBuildingBlock.buildingID;
                decayEntity?.AttachToBuilding(buildingId);
            }
            entity.Spawn();
            block = entity.GetComponent<BuildingBlock>();
            if (block != null) {
                block.blockDefinition = PrefabAttribute.server.Find<Construction>(newBlock.prefabID);
                block.SetGrade((newBlock as BuildingBlock)?.grade ?? BuildingGrade.Enum.Twigs);
                block.SetHealthToMax();
                block.SendNetworkUpdateImmediate();
                _waterFoundations.Add(block.net.ID.Value);
                Interface.Call("OnEntityBuilt", plan, block.gameObject);
            }
            yield return null;
        }
        private void SendMessage(BasePlayer player, string message) {
            if (!_config.ShowChatMessages) return;
            player.ChatMessage(message);
        }
        private void SetupSymmetry(BasePlayer player) {
            var buildOptions = GetBuildOptions(player.userID.Get());
            buildOptions.SymmetryEnabled = false;
            var allEntities = Physics.OverlapSphere(player.eyes.center, 1.6f, _constructionMask).Select(x => x.ToBaseEntity()).Where(x => x.ShortPrefabName.Contains("foundation") || x.ShortPrefabName.Contains("floor")).ToArray();
            _color = Color.blue;
            if (!allEntities.Any()) {
                player.ChatMessage(GetMsg(PluginMessages.NoProperFoundations, player.userID.Get()));
                return;
            }
            if (allEntities.Any(x => x.ShortPrefabName == "foundation.triangle" || x.ShortPrefabName == "floor.triangle")) {
                switch (allEntities.Length) {
                    case 6 : buildOptions.SymmetryShape = SymmetryShape.Hexagon;
                    var x1 = FindTheCenter(allEntities[0], player);
                    x1 += FindTheCenter(allEntities[1], player);
                    x1 += FindTheCenter(allEntities[2], player);
                    x1 += FindTheCenter(allEntities[3], player);
                    x1 += FindTheCenter(allEntities[4], player);
                    x1 += FindTheCenter(allEntities[5], player);
                    x1 /= 6;
                    buildOptions.StartPoint = x1;
                    buildOptions.SymmetryType = SymmetryType.Normal6Sided;
                    break;
                    default : var centerBlock = allEntities.First(x => x.ShortPrefabName == "foundation.triangle" || x.ShortPrefabName == "floor.triangle");
                    buildOptions.SymmetryShape = SymmetryShape.Triangle;
                    var initialPosition = centerBlock.transform.position;
                    // Set the angle of the triangle's baseline relative to the x-axis
                    var baselineAngle = centerBlock.transform.eulerAngles.y;
                    // Set the position of the triangle's baseline
                    var baselinePosition = initialPosition;
                    // Create a new vector to store the center position
                    var centerPosition = Vector3.zero;
                    // Calculate the position of the center of the triangle
                    centerPosition.x = baselinePosition.x + (0.8667854f * Mathf.Sin(baselineAngle * Mathf.Deg2Rad));
                    centerPosition.z = baselinePosition.z + (0.8667854f * Mathf.Cos(baselineAngle * Mathf.Deg2Rad));
                    centerPosition.y = baselinePosition.y;
                    buildOptions.StartPoint = centerPosition;
                    buildOptions.SymmetryType = SymmetryType.Normal3Sided;
                    break;
                }
            }
            else {
                switch (allEntities.Length) {
                    case 1 : buildOptions.SymmetryShape = SymmetryShape.Square;
                    buildOptions.StartPoint = allEntities[0].transform.position;
                    break;
                    case 2 : buildOptions.SymmetryShape = SymmetryShape.Rectangle;
                    var x0 = FindTheCenter(allEntities[0], player);
                    x0 += FindTheCenter(allEntities[1], player);
                    x0 /= 2;
                    buildOptions.StartPoint = x0;
                    _color = Color.magenta;
                    break;
                    case 4 : buildOptions.SymmetryShape = SymmetryShape.Octagon;
                    var x1 = FindTheCenter(allEntities[0], player);
                    x1 += FindTheCenter(allEntities[1], player);
                    x1 += FindTheCenter(allEntities[2], player);
                    x1 += FindTheCenter(allEntities[3], player);
                    x1 /= 4;
                    buildOptions.StartPoint = x1;
                    break;
                    default : player.ChatMessage(GetMsg(PluginMessages.NoProperFoundations, player.userID.Get()));
                    return;
                }
                buildOptions.SymmetryEnabled = true;
                buildOptions.StartRotation = allEntities[0].transform.rotation;
                buildOptions.SymmetryType = SymmetryType.Normal2Sided;
                player.ChatMessage(GetMsg(PluginMessages.SymmetrySet, player.userID.Get()));
            }
            player.SendConsoleCommand("ddraw.sphere", 10f, _color, buildOptions.StartPoint, 0.5f);
        }
        private void ShowCurrentSymmetryPoint(BasePlayer player) {
            var buildOptions = GetBuildOptions(player.userID.Get());
            if (buildOptions.StartPoint == Vector3.zero) {
                player.ChatMessage(GetMsg(PluginMessages.SymmetryUnSet, player.userID.Get()));
                return;
            }
            _color = Color.blue;
            switch (buildOptions.SymmetryShape) {
                case SymmetryShape.Rectangle : {
                    _color = Color.magenta;
                    if (buildOptions.SymmetryType == SymmetryType.Mirrored2Sided) {
                        _color = Color.red;
                    }
                    break;
                }
                case SymmetryShape.Octagon : {
                    switch (buildOptions.SymmetryType) {
                        case SymmetryType.Mirrored2Sided : _color = Color.red;
                        break;
                        case SymmetryType.Mirrored4Sided : _color = Color.yellow;
                        break;
                        case SymmetryType.Normal2Sided : _color = Color.cyan;
                        break;
                    }
                    break;
                }
            }
            player.SendConsoleCommand("ddraw.sphere", 10f, _color, buildOptions.StartPoint, 0.5f);
        }
        private void ShowUi(BasePlayer player, string buttonName = "") {
            var buildOptions = GetBuildOptions(player.userID.Get());
            buildOptions.UiEnabled = true;
            buildOptions.UiMinimized = false;
            var container = new CuiElementContainer {
                new CuiElement {
                    Parent = "Overlay", Name = "SymmetryPanel", Components = {
                        new CuiRectTransformComponent {
                            AnchorMin = _config.UiAnchorMin, AnchorMax = _config.UiAnchorMax, OffsetMin = _config.OffsetMin, OffsetMax = _config.OffsetMax
                        }
                        , new CuiImageComponent {
                            Color = _config.MainBackgroundColor
                        }
                    }
                }
            }
            ;
            CreateSymmetryPanel(ref container, "0 0", "1 1", "0 0", "0 0", "0 0 0 0", buildOptions, "SymmetryPanel", buttonName);
            CuiHelper.DestroyUi(player, "SymmetryPanel");
            CuiHelper.AddUi(player, container);
        }
        private void StopSymmetry(BasePlayer player) {
            var buildOptions = GetBuildOptions(player.userID.Get());
            buildOptions.SymmetryEnabled = false;
        }
        private static string ToSentenceCase(string input) {
            return Regex.Replace(input, "((^[a-z]+)|([0-9]+)|([A-Z]{1}[a-z]+)|([A-Z]+(?=([A-Z][a-z])|($)|([0-9]))))", "$1 ");
        }
        internal class Anchors {
            public static string BottomCenter = ".5 0";
            public static string BottomLeft = "0 0";
            public static string BottomRight = "1 0";
            public static string Center = ".5.5";
            public static string CenterLeft = "0.5";
            public static string CenterRight = "1.5";
            public static string TopCenter = ".5 1";
            public static string TopLeft = "0 1";
            public static string TopRight = "1 1";
        }
#endregion
#region 1.SimpleSymmetry.Config.cs
        private static Configuration _config;
        protected override void LoadConfig() {
            base.LoadConfig();
            try {
                _config = Config.ReadObject<Configuration>();
                if (_config == null) LoadDefaultConfig();
                SaveConfig();
                LoadData();
            }
            catch (Exception e) {
                Debug.LogException(e);
                PrintWarning("Creating new config file.");
                LoadDefaultConfig();
            }
        }
        protected override void LoadDefaultConfig() => _config = Configuration.DefaultConfig();
        protected override void SaveConfig() => Config.WriteObject(_config);
        public class Configuration {
            public string DefaultButtonColor = "0 0 0.7";
            public string MainBackgroundColor = "0 0 0.8";
            public string OffsetMax = "-5 -5";
            public string OffsetMin = "-245 -140";
            public string SelectedButtonColor = "0.45 1.7";
            [JsonProperty(PropertyName = "ShowUIByDefault")]
            public bool ShowUiByDefault = false;
            public string UiAnchorMax = "1 1";
            public string UiAnchorMin = "1 1";
            public bool EnableEntKill {
                get;
                set;
            }
            [JsonProperty(PropertyName = "Max Radius For Building")]
            public double MaxRadiusForBuilding {
                get;
                set;
            }
            public bool ShowChatMessages {
                get;
                set;
            }
            = false;
            public bool SupportRemoverTool {
                get;
                set;
            }
            = true;
            public bool ToggleUiWithPlanner {
                get;
                set;
            }
            = true;
            public bool RequireMaterialsToBuild {
                get;
                set;
            }
            = true;
            public static Configuration DefaultConfig() {
                return new Configuration {
                    MaxRadiusForBuilding = 40
                }
                ;
            }
        }
#endregion
#region 2.SimpleSymmetry.Localization.cs
        private string GetMsg(string key, object userId = null) {
            return lang.GetMessage(key, this, userId?.ToString());
        }
        protected override void LoadDefaultMessages() {
            lang.RegisterMessages(new Dictionary<string, string> {
                [PluginMessages.NoPermission]
                = "You do not have permission to do that", [PluginMessages.MustUse2X2] = "Your Symmetry point could not be set.\n You must start with a square or 2x2", [PluginMessages.SetSymmetry] = "Set\nSymmetry", [PluginMessages.ToggleSymmetry] = "Toggle\nSymmetry", [PluginMessages.DeleteSymmetry] = "Delete\nSymmetry", [$"{SymmetryType.Mirrored2Sided}"] = SymmetryType.Mirrored2Sided.ToString(), [$"{SymmetryType.Mirrored4Sided}"] = SymmetryType.Mirrored4Sided.ToString(), [$"{SymmetryType.Normal2Sided}"] = SymmetryType.Normal2Sided.ToString(), [$"{SymmetryType.Normal3Sided}"] = SymmetryType.Normal3Sided.ToString(), [$"{SymmetryType.Normal4Sided}"] = SymmetryType.Normal4Sided.ToString(), [$"{SymmetryType.Normal6Sided}"] = SymmetryType.Normal6Sided.ToString(), [$"SymmetryNotSet"] = "Symmetry Not Set", [PluginMessages.SymmetryChanged] = "Symmetry type changed to {0}", [PluginMessages.SymmetrySet] = "Your Symmetry point has been set.", [PluginMessages.SymmetryUnSet] = "Symmetry Point not set.", [PluginMessages.NoProperFoundations] = "Your Symmetry point could not be set.You must start with:\n1.A single triangle\n2.A single square\n3.Squares in a  2x2\n4.Triangles in a hexagon", [PluginMessages.CanNotAfford] = "Can not afford to fully upgrade.", [PluginMessages.DisablingSymmetry] = "Disabling Symmetry", [PluginMessages.SymmetryPointDeleted] = "Symmetry point deleted", [PluginMessages.SymmetryReEnabled] = "Symmetry Re-Enabled", [PluginMessages.HelpMenu] = "<color=#28B9DD>/sym ui</color> - Toggles UI on/off \n" + "<color=#28B9DD>/sym toggle</color> - Toggles Symmetry on/off \n" + "<color=#28B9DD>/sym show</color> - Show the current Symmetry Center\n" + "<color=#28B9DD>/sym set</color> - Sets the Symmetry Center\n" + "<color=#28B9DD>/sym delete</color> - Deletes the Symmetry Center\n" + "<color=#28B9DD>/sym {type}</color> - Sets the Symmetry Type (see below) \n" + "<color=#28B9DD>  N2S</color> (Normal 2 sided)\n" + "<color=#28B9DD>  N3S</color> (Normal 3 sided)\n" + "<color=#28B9DD>  N4S</color> (Normal 4 sided)\n" + "<color=#28B9DD>  N6S</color> (Normal 6 sided)\n" + "<color=#28B9DD>  M2S</color> (Mirrored 2 sided)\n" + "<color=#28B9DD>  M4S</color> (Mirrored 4 sided)\n"
            }
            , this);
            lang.RegisterMessages(new Dictionary<string, string> {
                [PluginMessages.NoPermission]
                = "No tienes permiso para hacer eso", [PluginMessages.MustUse2X2] = "No se pudo establecer tu punto de simetría.\nDebes comenzar con un cuadrado o un 2x2", [PluginMessages.SymmetrySet] = "Se ha establecido tu punto de simetría.", [PluginMessages.SetSymmetry] = "Establecer\nsimetría", [PluginMessages.ToggleSymmetry] = "Alternar\nsimetría", [PluginMessages.DeleteSymmetry] = "Eliminar\nsimetría", [PluginMessages.SymmetryUnSet] = "Punto de simetría no establecido.", [$"{SymmetryType.Mirrored2Sided}"] = "Simetría de 2 lados", [$"{SymmetryType.Mirrored4Sided}"] = "Simetría de 4 lados", [$"{SymmetryType.Normal2Sided}"] = "Normal de 2 lados", [$"{SymmetryType.Normal3Sided}"] = "Normal de 3 lados", [$"{SymmetryType.Normal4Sided}"] = "Normal de 4 lados", [$"{SymmetryType.Normal6Sided}"] = "Normal de 6 lados", [$"SymmetryNotSet"] = "Simetría no establecida", [PluginMessages.SymmetryChanged] = "El tipo de simetría cambió a {0}", [PluginMessages.NoProperFoundations] = "No se pudo establecer tu punto de simetría.Debes comenzar con:\n1.Un triángulo único\n2.Un cuadrado único\n3.Cuadrados en un 2x2\n4.Triángulos en un hexágono", [PluginMessages.CanNotAfford] = "No puedes permitirte mejorar completamente.", [PluginMessages.DisablingSymmetry] = "Desactivando simetría", [PluginMessages.SymmetryPointDeleted] = "Punto de simetría eliminado", [PluginMessages.SymmetryReEnabled] = "Simetría reactivada", [PluginMessages.HelpMenu] = "<color=#28B9DD>/sym ui</color> - Alterna la interfaz de usuario (UI) activada/desactivada \n" + "<color=#28B9DD>/sym toggle</color> - Activa/desactiva la simetría \n" + "<color=#28B9DD>/sym show</color> - Muestra el punto de simetría actual\n" + "<color=#28B9DD>/sym set</color> - Establece el punto de simetría\n" + "<color=#28B9DD>/sym delete</color> - Elimina el punto de simetría\n" + "<color=#28B9DD>/sym {tipo}</color> - Establece el tipo de simetría (ver más abajo) \n" + "<color=#28B9DD>  N2S</color> (Normal de 2 lados)\n" + "<color=#28B9DD>  N3S</color> (Normal de 3 lados)\n" + "<color=#28B9DD>  N4S</color> (Normal de 4 lados)\n" + "<color=#28B9DD>  N6S</color> (Normal de 6 lados)\n" + "<color=#28B9DD>  M2S</color> (Simetría de 2 lados)\n" + "<color=#28B9DD>  M4S</color> (Simetría de 4 lados)\n"
            }
            , this, "es");
        }
        private static class PluginMessages {
            public const string CanNotAfford = "CanNotAfford";
            public const string DeleteSymmetry = "DeleteSymmetry";
            public const string DisablingSymmetry = "DisablingSymmetry";
            public const string HelpMenu = "HelpMenu";
            public const string MustUse2X2 = "MustUse2X2";
            public const string NoPermission = "NoPermission";
            public const string NoProperFoundations = "NoProperFoundations";
            public const string SetSymmetry = "SetSymmetry";
            public const string SymmetryChanged = "SymmetryChanged";
            public const string SymmetryPointDeleted = "SymmetryPointDeleted";
            public const string SymmetryReEnabled = "SymmetryReEnabled";
            public const string SymmetrySet = "SymmetrySet";
            public const string SymmetryUnSet = "SymmetryUnset";
            public const string ToggleSymmetry = "ToggleSymmetry";
        }
#endregion
#region 3.SimpleSymmetry.Permissions.cs
        public class PluginPermissions {
            public const string SimpleSymmetryUse = "simplesymmetry.use";
        }
        private void LoadPermissions() {
            permission.RegisterPermission(PluginPermissions.SimpleSymmetryUse, this);
        }
#endregion
#region 4.SimpleSymmetry.Data.cs
        private static readonly Dictionary<ulong, PlayerBuildOptions> ActiveBuildOptions = new();
        private readonly List<AssetInfo> _assets = new() {
            new() {
                FileName = "Triangle.png"
            }
            , new() {
                FileName = "Triangle_Normal3Sided.png"
            }
            , new() {
                FileName = "Rectangle.png"
            }
            , new() {
                FileName = "Rectangle_Normal2Sided.png"
            }
            , new() {
                FileName = "Rectangle_Mirrored2Sided.png"
            }
            , new() {
                FileName = "Square.png"
            }
            , new() {
                FileName = "Square_Normal2Sided.png"
            }
            , new() {
                FileName = "Square_Normal4Sided.png"
            }
            , new() {
                FileName = "Square_Mirrored2Sided.png"
            }
            , new() {
                FileName = "Square_Mirrored4Sided.png"
            }
            , new() {
                FileName = "Octagon.png"
            }
            , new() {
                FileName = "Octagon_Normal2Sided.png"
            }
            , new() {
                FileName = "Octagon_Normal4Sided.png"
            }
            , new() {
                FileName = "Octagon_Mirrored2Sided.png"
            }
            , new() {
                FileName = "Octagon_Mirrored4Sided.png"
            }
            , new() {
                FileName = "Hexagon.png"
            }
            , new() {
                FileName = "Hexagon_Normal2Sided.png"
            }
            , new() {
                FileName = "Hexagon_Normal3Sided.png"
            }
            , new() {
                FileName = "Hexagon_Normal6Sided.png"
            }
        }
        ;
        private StoredData _storedData;
        private void DownloadAssetImages() {
            var assetInfo = _assets.FirstOrDefault(x => !_storedData.CommonImages.ContainsKey(x.FileName));
            if (assetInfo == null) return;
            ServerMgr.Instance.StartCoroutine(GetImageFromFilePath(assetInfo));
        }
        private static PlayerBuildOptions GetBuildOptions(ulong playerId) {
            if (!ActiveBuildOptions.ContainsKey(playerId)) {
                ActiveBuildOptions.Add(playerId, new PlayerBuildOptions());
            }
            return ActiveBuildOptions[playerId];
        }
        IEnumerator GetImageFromFilePath(AssetInfo assetInfo) {
            var url = $"file://{Interface.Oxide.DataDirectory}{Path.DirectorySeparatorChar}SimpleSymmetry{Path.DirectorySeparatorChar}assets{Path.DirectorySeparatorChar}{assetInfo.FileName}";
            using (var webRequest = UnityWebRequestTexture.GetTexture(url)) {
                yield return webR
// ... [Code preview truncated due to length. Full source in attached file] ...

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