Exemple #1
0
 public static int GetCapacity <AI>(VehicleInfo info, AI ai, bool noLoop = false) where AI : VehicleAI
 {
     if (info == null)
     {
         return(-1);
     }
     System.Reflection.FieldInfo fieldInfo;
     fieldInfo = GetVehicleCapacityField(ai);
     if (fieldInfo != null)
     {
         int capacity = ReflectionUtils.GetGetFieldDelegate <AI, int>(fieldInfo)(ai);
         try
         {
             if (!noLoop)
             {
                 foreach (VehicleInfo.VehicleTrailer trailer in info.m_trailers)
                 {
                     capacity += trailer.m_info == null ? 0 : GetCapacity(trailer.m_info, trailer.m_info.m_vehicleAI, true);
                 }
             }
         }
         catch (Exception e)
         {
             LogUtils.DoLog($"ERRO AO OBTER CAPACIDADE: [{info}] {e} {e.Message}\n{e.StackTrace}");
         }
         return(capacity);
     }
     else
     {
         LogUtils.DoLog($"AI \"{ai.GetType()}\" in asset {info} has no passenger Field!");
         return(0);
     }
 }
Exemple #2
0
        public static void ScanPrefabsFoldersDirectory <T>(string directoryToFind, Action <string, T> action) where T : PrefabInfo
        {
            var list = new List <string>();

            ForEachLoadedPrefab <T>((loaded) =>
            {
                Package.Asset asset = PackageManager.FindAssetByName(loaded.name);
                if (!(asset == null) && !(asset.package == null))
                {
                    string packagePath = asset.package.packagePath;
                    if (packagePath != null)
                    {
                        string filePath = Path.Combine(Path.GetDirectoryName(packagePath), directoryToFind);
                        if (!list.Contains(filePath))
                        {
                            list.Add(filePath);
                            LogUtils.DoLog("DIRECTORY TO FIND: " + filePath);
                            if (Directory.Exists(filePath))
                            {
                                action(filePath, loaded);
                            }
                        }
                    }
                }
            });
        }
Exemple #3
0
        private static void GetCapacityRelative <AI>(VehicleInfo info, AI ai, ref Dictionary <string, float> relativeParts, out int totalCapacity, bool noLoop = false) where AI : VehicleAI
        {
            if (info == null)
            {
                totalCapacity = 0;
                return;
            }

            totalCapacity            = ReflectionUtils.GetGetFieldDelegate <AI, int>(GetVehicleCapacityField(ai))(ai);
            relativeParts[info.name] = totalCapacity;
            if (!noLoop)
            {
                try
                {
                    foreach (VehicleInfo.VehicleTrailer trailer in info.m_trailers)
                    {
                        if (trailer.m_info != null)
                        {
                            GetCapacityRelative(trailer.m_info, trailer.m_info.m_vehicleAI, ref relativeParts, out int capacity, true);
                            totalCapacity += capacity;
                        }
                    }

                    for (int i = 0; i < relativeParts.Keys.Count; i++)
                    {
                        relativeParts[relativeParts.Keys.ElementAt(i)] /= totalCapacity;
                    }
                }
                catch (Exception e)
                {
                    LogUtils.DoLog($"ERRO AO OBTER CAPACIDADE REL: [{info}] {e} {e.Message}\n{e.StackTrace}");
                }
            }
        }
        public void ReadXml(System.Xml.XmlReader reader)

        {
            if (reader.IsEmptyElement)
            {
                reader.Read();
                return;
            }
            var valueSerializer = new XmlSerializer(typeof(ValueContainer <TKey, TValue>), "");

            LogUtils.DoLog($"reader = {reader}; empty = {reader.IsEmptyElement}");
            reader.ReadStartElement();
            while (reader.NodeType != System.Xml.XmlNodeType.EndElement)
            {
                if (reader.NodeType != System.Xml.XmlNodeType.Element)
                {
                    reader.Read();
                    continue;
                }

                var value = (ValueContainer <TKey, TValue>)valueSerializer.Deserialize(reader);
                if (value.Index == null)
                {
                    continue;
                }
                Add(value.Index, value.Value);
            }

            reader.ReadEndElement();
        }
Exemple #5
0
 public static Color DeserializeColor(string value, string separator)
 {
     if (!string.IsNullOrEmpty(value))
     {
         var list = value.Split(separator.ToCharArray()).ToList();
         if (list.Count == 3 && byte.TryParse(list[0], out var r) && byte.TryParse(list[1], out var g) && byte.TryParse(list[2], out var b))
         {
             return(new Color32(r, g, b, 255));
         }
         else
         {
             LogUtils.DoLog($"val = {value}; list = {string.Join(",", list.ToArray())} (Size {list.Count})");
         }
     }
     return(Color.clear);
 }
        public static string LoadResourceString(string name)
        {
            name = $"{Prefix}.{name}";

            var stream = (UnmanagedMemoryStream)Assembly.GetExecutingAssembly().GetManifestResourceStream(name);

            if (stream == null)
            {
                LogUtils.DoLog("Could not find resource: " + name);
                return(null);
            }

            var read = new StreamReader(stream);

            return(read.ReadToEnd());
        }
        private static Color[] ApplyFilter(int width, int height, FilterMethod method, float startTime, Color[] inPixels, params object[] parameters)
        {
            var outPixels = new Color[inPixels.Length];

            if (method != null)
            {
                method(width, height, inPixels, ref outPixels, parameters);
            }


            float endTime = Time.realtimeSinceStartup;

            LogUtils.DoLog($"Exec time filter apply: {endTime - startTime}s");

            return(outPixels);
        }
        public static byte[] LoadResourceData(string name)
        {
            name = $"{Prefix}.{name}";

            var stream = (UnmanagedMemoryStream)Assembly.GetExecutingAssembly().GetManifestResourceStream(name);

            if (stream == null)
            {
                LogUtils.DoLog("Could not find resource: " + name);
                return(null);
            }

            var read = new BinaryReader(stream);

            return(read.ReadBytes((int)stream.Length));
        }
        public static string GetBuildingName(ushort buildingId, out ItemClass.Service serviceFound, out ItemClass.SubService subserviceFound)
        {
            BuildingManager bm = Singleton <BuildingManager> .instance;

            while (bm.m_buildings.m_buffer[buildingId].m_parentBuilding > 0)
            {
                LogUtils.DoLog("getBuildingName(): building id {0} - parent = {1}", buildingId, bm.m_buildings.m_buffer[buildingId].m_parentBuilding);
                buildingId = bm.m_buildings.m_buffer[buildingId].m_parentBuilding;
                bm.m_buildings.m_buffer[buildingId] = bm.m_buildings.m_buffer[buildingId];
            }
            InstanceID iid = default;

            iid.Building    = buildingId;
            serviceFound    = bm.m_buildings.m_buffer[buildingId].Info?.GetService() ?? default;
            subserviceFound = bm.m_buildings.m_buffer[buildingId].Info?.GetSubService() ?? default;

            return(bm.GetBuildingName(buildingId, iid));
        }
        public static IEnumerable <string> LoadResourceStringLines(string name)
        {
            name = $"{Prefix}.{name}";

            using var stream = (UnmanagedMemoryStream)Assembly.GetExecutingAssembly().GetManifestResourceStream(name);
            if (stream == null)
            {
                LogUtils.DoLog("Could not find resource: " + name);
                yield break;
            }

            using var reader = new StreamReader(stream);
            string line;

            while ((line = reader.ReadLine()) != null)
            {
                yield return(line);
            }
        }
Exemple #11
0
        public static List <ushort> GetSegmentOrderRoad(ushort segmentID, bool requireSameDirection, bool requireSameSizeAndType, bool localAdjust, out bool startRef, out bool endRef, out ushort[] nodes)
        {
            NetSegment.Flags flags = NetManager.instance.m_segments.m_buffer[segmentID].m_flags;
            var nodeList           = new List <ushort>();

            if (segmentID != 0 && flags != NetSegment.Flags.None)
            {
                List <ushort> path = CalculatePathNet(segmentID, false, requireSameDirection, requireSameSizeAndType, out nodes);
                path.Add(segmentID);

                ushort startNode0   = NetManager.instance.m_segments.m_buffer[path[0]].m_startNode;
                ushort endNode0     = NetManager.instance.m_segments.m_buffer[path[0]].m_endNode;
                ushort startNodeRef = NetManager.instance.m_segments.m_buffer[segmentID].m_startNode;
                ushort endNodeRef   = NetManager.instance.m_segments.m_buffer[segmentID].m_endNode;

                bool circular = (path.Count > 2 && (startNode0 == endNodeRef || startNode0 == startNodeRef || endNode0 == endNodeRef || endNode0 == startNodeRef)) ||
                                (path.Count == 2 && (startNode0 == endNodeRef || startNode0 == startNodeRef) && (endNode0 == endNodeRef || endNode0 == startNodeRef));

                if (circular)
                {
                    LogUtils.DoLog("Circular!");
                    ushort refer    = path.Min();
                    int    referIdx = path.IndexOf(refer);
                    if (referIdx != 0)
                    {
                        path = path.GetRange(referIdx, path.Count - referIdx).Union(path.Take(referIdx)).ToList();
                    }
                }
                else
                {
                    path.AddRange(CalculatePathNet(segmentID, true, requireSameDirection, requireSameSizeAndType, out _));
                }
                //doLog($"[s={strict}]path = [{string.Join(",", path.Select(x => x.ToString()).ToArray())}]");
                GetEdgeNodes(ref path, out startRef, out endRef, localAdjust);
                return(path);
            }
            nodes    = new ushort[0];
            startRef = false;
            endRef   = false;
            return(null);
        }
Exemple #12
0
        public static VehicleInfo GetRandomModel(IEnumerable <string> assetList, out string selectedModel)
        {
            selectedModel = null;
            if (assetList.Count() == 0)
            {
                return(null);
            }

            var r = new Randomizer(new System.Random().Next());

            selectedModel = assetList.ElementAt(r.Int32(0, assetList.Count() - 1));

            VehicleInfo saida = PrefabCollection <VehicleInfo> .FindLoaded(selectedModel);

            if (saida == null)
            {
                LogUtils.DoLog("MODEL DOESN'T EXIST!");
                return(null);
            }
            return(saida);
        }
            public int CompareTo(ComparableRoad otherRoad)
            {
                int result = 0;

                if (otherRoad.isHighway != isHighway)
                {
                    result = isHighway ? 1 : -1;
                }
                if (otherRoad.isPassing != isPassing)
                {
                    result = isPassing ? 1 : -1;
                }
                if (otherRoad.width != width)
                {
                    result = otherRoad.width < width ? 1 : -1;
                }
                if (otherRoad.lanes != lanes)
                {
                    result = otherRoad.lanes < lanes ? 1 : -1;
                }
                LogUtils.DoLog($"cmp: {this} & {otherRoad} => {result}");
                return(result);
            }
        public static StopPointDescriptorLanes[] MapStopPoints(BuildingInfo buildingInfo, float thresold)
        {
            var result = new List <StopPointDescriptorLanes>();

            if (buildingInfo?.m_paths != null)
            {
                foreach (BuildingInfo.PathInfo path in buildingInfo.m_paths)
                {
                    if (path.m_nodes.Length < 2)
                    {
                        continue;
                    }

                    Vector3 position  = path.m_nodes[0];
                    Vector3 position2 = path.m_nodes[1];


                    position.z  *= -1;
                    position2.z *= -1;
                    Vector3 directionPath = Quaternion.AngleAxis(90, Vector3.up) * (position2 - position).normalized;

                    foreach (NetInfo.Lane refLane in path.m_netInfo.m_lanes)
                    {
                        if (refLane.m_stopType == VehicleInfo.VehicleType.None)
                        {
                            continue;
                        }
                        NetInfo.Lane lane = FindNearestVehicleStopLane(path.m_netInfo.m_lanes, refLane, out ushort laneId);
                        if (lane == null)
                        {
                            continue;
                        }


                        LogUtils.DoLog($"[{buildingInfo}] pos + dir = ({position} {position2} + {directionPath})");
                        Vector3 lanePos = position + (lane.m_position / 2 * directionPath) + new Vector3(0, lane.m_verticalOffset);
                        Vector3 lanePos2 = position2 + (lane.m_position / 2 * directionPath) + new Vector3(0, lane.m_verticalOffset);
                        Vector3 b3, c;
                        if (path.m_curveTargets == null || path.m_curveTargets.Length == 0)
                        {
                            NetSegment.CalculateMiddlePoints(lanePos, Vector3.zero, lanePos2, Vector3.zero, true, true, out b3, out c);
                        }
                        else
                        {
                            GetMiddlePointsFor(path, out b3, out c);
                            LogUtils.DoLog($"[{buildingInfo}] GetMiddlePointsFor path =  ({b3} {c})");
                            b3  += (lane.m_position * directionPath) + new Vector3(0, lane.m_verticalOffset);
                            c   += (lane.m_position * directionPath) + new Vector3(0, lane.m_verticalOffset);
                            b3.y = c.y = (lanePos.y + lanePos2.y) / 2;
                        }
                        var refBezier = new Bezier3(lanePos, b3, c, lanePos2);
                        LogUtils.DoLog($"[{buildingInfo}]refBezier = {refBezier} ({lanePos} {b3} {c} {lanePos2})");


                        Vector3 positionR = refBezier.Position(m_defaultStopOffset);
                        Vector3 direction = refBezier.Tangent(m_defaultStopOffset);
                        LogUtils.DoLog($"[{buildingInfo}]1positionR = {positionR}; direction = {direction}");

                        Vector3 normalized = Vector3.Cross(Vector3.up, direction).normalized;
                        positionR += normalized * (MathUtils.SmootherStep(0.5f, 0f, Mathf.Abs(m_defaultStopOffset - 0.5f)) * lane.m_stopOffset);
                        LogUtils.DoLog($"[{buildingInfo}]2positionR = {positionR}; direction = {direction}; {normalized}");
                        result.Add(new StopPointDescriptorLanes
                        {
                            platformLine  = refBezier,
                            width         = lane.m_width,
                            vehicleType   = refLane.m_stopType,
                            laneId        = laneId,
                            subbuildingId = -1,
                            directionPath = directionPath * (path.m_invertSegments == (refLane.m_finalDirection == NetInfo.Direction.AvoidForward || refLane.m_finalDirection == NetInfo.Direction.Backward) ? 1 : -1)
                        });
                    }
                }
            }
            for (int i = 0; i < (buildingInfo.m_subBuildings?.Length ?? 0); i++)
            {
                StopPointDescriptorLanes[] subPlats = MapStopPoints(buildingInfo.m_subBuildings[i].m_buildingInfo, thresold);
                if (subPlats != null)
                {
                    var rotationToApply = Quaternion.AngleAxis(buildingInfo.m_subBuildings[i].m_angle, Vector3.up);
                    result.AddRange(subPlats.Select(x =>
                    {
                        x.platformLine.a = (rotationToApply * x.platformLine.a) + buildingInfo.m_subBuildings[i].m_position;
                        x.platformLine.b = (rotationToApply * x.platformLine.b) + buildingInfo.m_subBuildings[i].m_position;
                        x.platformLine.c = (rotationToApply * x.platformLine.c) + buildingInfo.m_subBuildings[i].m_position;
                        x.platformLine.d = (rotationToApply * x.platformLine.d) + buildingInfo.m_subBuildings[i].m_position;
                        x.subbuildingId  = (sbyte)i;
                        x.directionPath  = (rotationToApply * x.directionPath).normalized;
                        return(x);
                    }));
                }
            }
            result.Sort((x, y) =>
            {
                int priorityX = VehicleToPriority(x.vehicleType);
                int priorityY = VehicleToPriority(y.vehicleType);
                if (priorityX != priorityY)
                {
                    return(priorityX.CompareTo(priorityY));
                }

                Vector3 centerX = (x.platformLine.Position(0.5f));
                Vector3 centerY = (y.platformLine.Position(0.5f));
                if (Mathf.Abs(centerX.y - centerY.y) >= thresold)
                {
                    return(-centerX.y.CompareTo(centerY.y));
                }

                if (Mathf.Abs(centerX.z - centerY.z) >= thresold)
                {
                    return(-centerX.z.CompareTo(centerY.z));
                }

                return(-centerX.x.CompareTo(centerY.x));
            });
            if (CommonProperties.DebugMode)
            {
                LogUtils.DoLog($"{buildingInfo.name} PLAT ORDER:\n{string.Join("\n", result.Select((x, y) => $"{y}=> {x.ToString()}").ToArray())}");
            }
            return(result.ToArray());
        }
        private void SetProperties(BindProperties propertiesToSet, Func <int, bool> callback)
        {
            m_mainPanel.autoLayout = true;
            if (propertiesToSet.help_isArticle)
            {
                if (!Directory.Exists(propertiesToSet.help_fullPathName))
                {
                    LogUtils.DoErrorLog($"Invalid tutorial path! {propertiesToSet.help_fullPathName}");
                    Close(-1);
                    return;
                }

                string fullText;
                if (File.Exists($"{propertiesToSet.help_fullPathName}{Path.DirectorySeparatorChar}texts_{KlyteLocaleManager.CurrentLanguageId}.txt"))
                {
                    fullText = File.ReadAllText($"{propertiesToSet.help_fullPathName}{Path.DirectorySeparatorChar}texts_{KlyteLocaleManager.CurrentLanguageId}.txt");
                }
                else if (File.Exists($"{propertiesToSet.help_fullPathName}{Path.DirectorySeparatorChar}texts.txt"))
                {
                    fullText = File.ReadAllText($"{propertiesToSet.help_fullPathName}{Path.DirectorySeparatorChar}texts.txt");
                }
                else
                {
                    LogUtils.DoErrorLog($"Corrupted tutorial path! File \"texts.txt\" not found at folder {propertiesToSet.help_fullPathName}.");
                    Close(-1);
                    return;
                }
                string[] tutorialEntries = Regex.Split(fullText, "<BR>", RegexOptions.Multiline | RegexOptions.ECMAScript);

                int      lastPage         = tutorialEntries.Length - 1;
                int      currentPage      = Math.Max(0, Math.Min(lastPage, propertiesToSet.help_currentPage));
                string   targetImg        = $"{propertiesToSet.help_fullPathName}{Path.DirectorySeparatorChar}{currentPage.ToString("D3")}.jpg";
                string   textureImagePath = File.Exists(targetImg) ? targetImg : null;
                string   path             = propertiesToSet.help_fullPathName;
                string   feature          = propertiesToSet.help_featureName;
                string[] formatEntries    = propertiesToSet.help_formatsEntries;
                LogUtils.DoLog($"IMG: {targetImg}");
                propertiesToSet = new BindProperties
                {
                    icon             = propertiesToSet.icon,
                    title            = string.Format(Locale.Get("K45_CMNS_HELP_FORMAT"), propertiesToSet.help_featureName, currentPage + 1, lastPage + 1),
                    message          = string.Format(tutorialEntries[currentPage], formatEntries),
                    imageTexturePath = textureImagePath,

                    showClose   = true,
                    showButton1 = currentPage != 0,
                    textButton1 = "<<<\n" + Locale.Get("K45_CMNS_PREV"),
                    showButton2 = true,
                    textButton2 = Locale.Get("EXCEPTION_OK"),
                    showButton3 = currentPage != lastPage,
                    textButton3 = ">>>\n" + Locale.Get("K45_CMNS_NEXT"),
                };
                callback = (x) =>
                {
                    if (x == 1)
                    {
                        ShowModalHelpAbsolutePath(path, feature, currentPage - 1, formatEntries);
                    }
                    if (x == 3)
                    {
                        ShowModalHelpAbsolutePath(path, feature, currentPage + 1, formatEntries);
                    }
                    return(true);
                };
            }

            m_currentCallback = callback;

            m_properties.FindBinding("title").property.value        = propertiesToSet.title;
            m_properties.FindBinding("icon").property.value         = propertiesToSet.icon ?? CommonProperties.ModIcon;
            m_properties.FindBinding("showClose").property.value    = propertiesToSet.showClose || !(propertiesToSet.showButton1 || propertiesToSet.showButton2 || propertiesToSet.showButton3 || propertiesToSet.showButton4);
            m_properties.FindBinding("message").property.value      = propertiesToSet.message;
            m_properties.FindBinding("messageAlign").property.value = propertiesToSet.messageAlign;
            m_properties.FindBinding("showButton1").property.value  = propertiesToSet.showButton1;
            m_properties.FindBinding("showButton2").property.value  = propertiesToSet.showButton2;
            m_properties.FindBinding("showButton3").property.value  = propertiesToSet.showButton3;
            m_properties.FindBinding("showButton4").property.value  = propertiesToSet.showButton4;
            m_properties.FindBinding("showButton5").property.value  = propertiesToSet.showButton5;
            m_properties.FindBinding("textButton1").property.value  = propertiesToSet.textButton1 ?? "";
            m_properties.FindBinding("textButton2").property.value  = propertiesToSet.textButton2 ?? "";
            m_properties.FindBinding("textButton3").property.value  = propertiesToSet.textButton3 ?? "";
            m_properties.FindBinding("textButton4").property.value  = propertiesToSet.textButton4 ?? "";
            m_properties.FindBinding("textButton5").property.value  = propertiesToSet.textButton5 ?? "";

            m_textField.isVisible = propertiesToSet.showTextField;
            m_textField.text      = propertiesToSet.defaultTextFieldContent ?? "";

            if (m_dropDown == null)
            {
                KlyteMonoUtils.CreateUIElement(out UIPanel DDpanel, m_mainPanel.transform);
                DDpanel.maximumSize            = new Vector2(m_boxText.minimumSize.x - 10, 40);
                DDpanel.anchor                 = UIAnchorStyle.CenterHorizontal;
                DDpanel.zOrder                 = m_textField.zOrder + 1;
                DDpanel.autoLayout             = true;
                m_dropDown                     = UIHelperExtension.CloneBasicDropDownNoLabel(new string[0], (x) => { }, DDpanel);
                m_dropDown.name                = DD_INPUT_ID;
                m_dropDown.minimumSize         = new Vector2(m_boxText.minimumSize.x - 10, 25);
                m_dropDown.size                = new Vector2(m_boxText.minimumSize.x - 10, 40);
                m_dropDown.autoSize            = false;
                m_dropDown.processMarkup       = true;
                m_dropDown.verticalAlignment   = UIVerticalAlignment.Middle;
                m_dropDown.horizontalAlignment = UIHorizontalAlignment.Left;
            }
            m_dropDown.parent.isVisible = propertiesToSet.showDropDown;
            m_dropDown.items            = propertiesToSet.dropDownOptions?.Split(BindProperties.DD_OPTIONS_SEPARATOR.ToCharArray()) ?? new string[0];
            m_dropDown.selectedIndex    = propertiesToSet.dropDownCurrentSelection;


            m_textureSprite.size = default;
            if (!propertiesToSet.imageTexturePath.IsNullOrWhiteSpace())
            {
                if (File.Exists(propertiesToSet.imageTexturePath))
                {
                    byte[] fileData = File.ReadAllBytes(propertiesToSet.imageTexturePath);
                    var    tex      = new Texture2D(2, 2);
                    if (tex.LoadImage(fileData))
                    {
                        m_textureSupContainer.isVisible = true;
                        m_textureSprite.texture         = tex;
                        m_textureSprite.size            = new Vector2(tex.width, tex.height);
                        if (m_textureSprite.height > 400)
                        {
                            float proportion = m_textureSprite.width / m_textureSprite.height;
                            m_textureSprite.height = 400;
                            m_textureSprite.width  = proportion * 400;
                        }
                        m_textureSupContainer.height = m_textureSprite.size.y;
                    }
                    else
                    {
                        LogUtils.DoWarnLog($"Failed loading image: {propertiesToSet.imageTexturePath}");
                        m_textureSupContainer.isVisible = false;
                    }
                }
            }
            else
            {
                m_textureSprite.texture         = null;
                m_textureSupContainer.isVisible = false;
            }

            float width;

            if (propertiesToSet.useFullWindowWidth || m_textureSprite.width > 800)
            {
                width = UIView.GetAView().fixedWidth - 100;
                if (width < m_textureSprite.width)
                {
                    float proportion = m_textureSprite.width / m_textureSprite.height;
                    m_textureSprite.width  = width;
                    m_textureSprite.height = width / proportion;
                }
            }
            else
            {
                width = 800;
            }
            m_mainPanel.width  = width;
            m_closeButton.area = new Vector4(width - 37, 3, 32, 32);
            width -= m_mainPanel.padding.horizontal;
            m_titleContainer.width      = width;
            m_boxText.width             = width;
            m_buttonSupContainer.width  = width;
            m_textureSupContainer.width = width;
            m_mainPanel.autoLayout      = !propertiesToSet.showDropDown;
        }
Exemple #16
0
        public static Texture2D RenderSpriteLine(UIDynamicFont font, UITextureAtlas atlas, string spriteName, Color bgColor, string text, float textScale = 1)
        {
            UITextureAtlas.SpriteInfo spriteInfo = atlas[spriteName];
            if (spriteInfo == null)
            {
                CODebugBase <InternalLogChannel> .Warn(InternalLogChannel.UI, "Missing sprite " + spriteName + " in " + atlas.name);

                return(null);
            }
            else
            {
                textScale *= 2;

                Texture2D texture        = atlas.texture;
                float     calcHeight     = font.size * textScale * 2;
                float     calcProportion = spriteInfo.region.width * texture.width / (spriteInfo.region.height * texture.height);
                float     calcWidth      = Mathf.CeilToInt(calcHeight * calcProportion);

                int height = Mathf.CeilToInt(calcHeight);
                int width  = Mathf.CeilToInt(calcWidth);

                float textureScale = height / (spriteInfo.region.height * texture.height);

                LogUtils.DoLog($"height = {height} - width = {width} -  renderer.pixelRatio = 1 - textureScale = {height} / {(spriteInfo.region.height * texture.height)}");

                var   size        = new Vector3(width, height);
                float borderWidth = textScale * 3;

                Vector2 textDimensions = MeasureTextWidth(font, text, textScale, out Vector2 yBounds);
                float   borderBottom   = Mathf.Max(0, (spriteInfo.border.bottom * textScale * 2) + Mathf.Min(0, yBounds.x));
                var     textAreaSize   = new Vector4((spriteInfo.border.left * textScale * 2) + borderWidth, borderBottom + borderWidth, width - (spriteInfo.border.horizontal * textScale * 2) - borderWidth, height - (spriteInfo.border.top * textScale * 2) - borderBottom - borderWidth);

                float multipler = Mathf.Min(Mathf.Min(3.5f, textAreaSize.z / textDimensions.x), Mathf.Min(3.5f, textAreaSize.w / textDimensions.y));
                if (multipler > 1)
                {
                    textScale     *= 1 + ((multipler - 1) / 2.1f);
                    multipler      = 1;
                    textDimensions = MeasureTextWidth(font, text, textScale, out yBounds);
                }

                var imageSize = new Vector2(Mathf.NextPowerOfTwo((int)Mathf.Max(textDimensions.x * multipler, width)), Mathf.NextPowerOfTwo((int)Mathf.Max(textDimensions.y, height)));


                var tex = new Texture2D((int)imageSize.x, (int)imageSize.y, TextureFormat.ARGB32, false);
                tex.SetPixels(new Color[(int)(imageSize.x * imageSize.y)]);


                var texText = new Texture2D((int)textDimensions.x, (int)textDimensions.y, TextureFormat.ARGB32, false);
                texText.SetPixels(new Color[(int)(textDimensions.x * textDimensions.y)]);

                Color contrastColor = KlyteMonoUtils.ContrastColor(bgColor);

                Vector2 position = RenderSprite(atlas, spriteName, contrastColor, tex, textureScale);
                RenderSprite(atlas, spriteName, bgColor, tex, null, tex.height - (int)(borderWidth * 2), null, new Vector2((textScale / 2) - 0.5f, (textScale / 2) - 0.5f), (a, b) =>
                {
                    if (b.a == 1)
                    {
                        return(b);
                    }

                    if (b.a == 0)
                    {
                        return(a);
                    }

                    float totalAlpha = a.a + b.a;
                    return((a * (1 - b.a)) + (b * b.a));
                });
                Vector2 posText = position + VectorUtils.XY(textAreaSize) + new Vector2((textAreaSize.z / 2) - (textDimensions.x * multipler / 2) + 1, (textAreaSize.w / 2) - (textDimensions.y / 2) - (yBounds.x / 2));

                RenderText(font, text, new Vector3(0, -yBounds.x), textScale, contrastColor, bgColor, texText);

                if (multipler < 1)
                {
                    TextureScaler.scale(texText, (int)(texText.width * multipler), texText.height);
                }
                MergeTextures(tex, texText.GetPixels(), (int)posText.x, (int)posText.y, texText.width, texText.height, false);
                UnityEngine.Object.Destroy(texText);
                tex.Apply();

                return(tex);
            }
        }
            public ComparableRoad(ushort segmentId, bool startNode)
            {
                NetSegment segment = NetManager.instance.m_segments.m_buffer[segmentId];

                if (startNode)
                {
                    nodeReference = segment.m_startNode;
                }
                else
                {
                    nodeReference = segment.m_endNode;
                }

                bool entering = startNode != ((NetManager.instance.m_segments.m_buffer[segmentId].m_flags & NetSegment.Flags.Invert) != 0);

                NetNode node = NetManager.instance.m_nodes.m_buffer[nodeReference];

                isPassing        = false;
                segmentReference = 0;
                for (int i = 0; i < 7; i++)
                {
                    ushort segment1 = node.GetSegment(i);
                    if (segment1 > 0 && segment1 != segmentId)
                    {
                        for (int j = i + 1; j < 8; j++)
                        {
                            ushort segment2 = node.GetSegment(j);
                            if (segment2 > 0 && segment2 != segmentId)
                            {
                                isPassing = IsSameName(segment1, segment2, true);
                                if (isPassing)
                                {
                                    segmentReference = segment1;
                                    break;
                                }
                            }
                        }
                        if (isPassing)
                        {
                            break;
                        }
                    }
                }
                if (!isPassing)
                {
                    for (int i = 0; i < 7; i++)
                    {
                        ushort segment1 = node.GetSegment(i);
                        if (segment1 > 0 && segment1 != segmentId)
                        {
                            NetSegment segment1Obj         = NetManager.instance.m_segments.m_buffer[segment1];
                            bool       isSegment1StartNode = segment1Obj.m_startNode == nodeReference;
                            bool       isSegment1Entering  = isSegment1StartNode != ((NetManager.instance.m_segments.m_buffer[segment1].m_flags & NetSegment.Flags.Invert) != 0);

                            if (!(segment1Obj.Info.GetAI() is RoadBaseAI seg1Ai))
                            {
                                continue;
                            }

                            bool isSegment1TwoWay = segment1Obj.Info.m_hasBackwardVehicleLanes && segment1Obj.Info.m_hasForwardVehicleLanes;

                            if (!isSegment1TwoWay && isSegment1Entering == entering)
                            {
                                LogUtils.DoLog($"IGNORED: {segment1} (Tw=>{isSegment1TwoWay},entering=>{entering},s1entering=>{isSegment1Entering})");
                                continue;
                            }

                            if (segmentReference == 0)
                            {
                                segmentReference = segment1;
                            }
                            else
                            {
                                NetSegment segmentRefObj = NetManager.instance.m_segments.m_buffer[segmentReference];
                                if (!(segmentRefObj.Info.GetAI() is RoadBaseAI roadAi))
                                {
                                    continue;
                                }
                                if (!roadAi.m_highwayRules && seg1Ai.m_highwayRules)
                                {
                                    segmentReference = segment1;
                                    continue;
                                }
                                if (roadAi.m_highwayRules && !seg1Ai.m_highwayRules)
                                {
                                    continue;
                                }
                                int laneCount1   = (segment1Obj.Info.m_forwardVehicleLaneCount + segment1Obj.Info.m_backwardVehicleLaneCount);
                                int laneCountRef = (segmentRefObj.Info.m_forwardVehicleLaneCount + segmentRefObj.Info.m_backwardVehicleLaneCount);
                                if (laneCount1 > laneCountRef)
                                {
                                    segmentReference = segment1;
                                    continue;
                                }
                                if (laneCount1 < laneCountRef)
                                {
                                    continue;
                                }
                                if (segment1Obj.Info.m_halfWidth > segmentRefObj.Info.m_halfWidth)
                                {
                                    segmentReference = segment1;
                                    continue;
                                }
                            }
                        }
                    }
                }
                if (segmentReference > 0)
                {
                    NetSegment segmentRefObj = NetManager.instance.m_segments.m_buffer[segmentReference];
                    NetInfo    infoRef       = segmentRefObj.Info;
                    isHighway = infoRef.GetAI() is RoadBaseAI aiRef && aiRef.m_highwayRules;
                    width     = infoRef.m_halfWidth * 2;
                    lanes     = infoRef.m_backwardVehicleLaneCount + infoRef.m_forwardVehicleLaneCount;
                }
                else
                {
                    isHighway = false;
                    width     = 0;
                    lanes     = 0;
                }
            }