-
Posts
627 -
Joined
-
Last visited
Content Type
Profiles
Forums
Developer Articles
KSP2 Release Notes
Everything posted by TaxiService
-
[1.11] RemoteTech v1.9.9 [2020-12-19]
TaxiService replied to tomek.piotrowski's topic in KSP1 Mod Releases
The spreadsheet with the responses is public. cynerpunkdreams posted this public link and I checked with netisa on this too. -
[1.11] RemoteTech v1.9.9 [2020-12-19]
TaxiService replied to tomek.piotrowski's topic in KSP1 Mod Releases
Is this picture what you are looking for? I looked up the RT codebase and found that it was trivial to slip in additional connection rules and a new icon button but I need more tests to be sure. No, the current RT 1.8.x does not have any notification system on connection events (I looked over the codebase and could not find any relevant) and I estimate it is not easy to implement this (edit multiple code places to broadcast upon reconnection). However, I think the stock CommNet has the infrastructure that should allow the easy broadcasting. I could look into this in the RT 2 redevelopment later. -
[1.11] RemoteTech v1.9.9 [2020-12-19]
TaxiService replied to tomek.piotrowski's topic in KSP1 Mod Releases
The RemoteTech codebase indicates that: 1) At the beginning of a scene (flight or tracking station), the base range of an omni antenna, Ab, is multiplied by the range modifier of 0.5 so this antenna's final range A is Ab*0.5. 2) RemoteTech computes the bonus omni range on one sat (2 '16s and 2 DP-10s): (A+B+B)*0.2. Similarly, the bonus range on the other sat (4 '16s) is (A+A+A)*0.2. Then, when checking the possible connection between each antenna combination of these two sats, r1 = Ai + ((A+B+B)*0.2) and r2 = Aj + ((A+A+A)*0.2), where Ai is an omni antenna of one sat and Aj is an omni antenna of the other sat. I say combination because the codebase (link) compares every antenna of one sat against every antenna of the other sat, rather than picking the longest-range antenna of each vessel. -
[1.11] RemoteTech v1.9.9 [2020-12-19]
TaxiService replied to tomek.piotrowski's topic in KSP1 Mod Releases
Wow, I am an idiot. Here're the code snapshots: /// <summary>Returns the bonus from having multiple antennas</summary> /// <returns>The boost to all omni antenna ranges, if MultipleAntennaMultiplier is enabled; /// otherwise zero.</returns> private static double GetMultipleAntennaBonus(IEnumerable<IAntenna> omniList, double maxOmni) { if (RTSettings.Instance.MultipleAntennaMultiplier > 0.0) { double total = omniList.Sum(a => a.Omni); return (total - maxOmni) * RTSettings.Instance.MultipleAntennaMultiplier; } else { return 0.0; } } On given list of omni antennas and the max omni range of one vessel, this GetMultipleAntennaBonus function returns the double value (sum of every omni range but the max range and multiple it) to add to the given value of an omni antenna. Does this answer your query? -
[1.11] RemoteTech v1.9.9 [2020-12-19]
TaxiService replied to tomek.piotrowski's topic in KSP1 Mod Releases
Sorry for reading your post incorrectly. I believe that each (dish-type) antenna on the vessel is still acting independently so the formula still applies when checking each antenna of two vessels. As far as I can see in the codebase, RemoteTech doesn't stack up the ranges of multiple antennas on a vessel into a single range. -
[1.11] RemoteTech v1.9.9 [2020-12-19]
TaxiService replied to tomek.piotrowski's topic in KSP1 Mod Releases
According to the online RT manual, this formula is min(r1, r2) + sqrt(r1 * r2). -
[1.11] RemoteTech v1.9.9 [2020-12-19]
TaxiService replied to tomek.piotrowski's topic in KSP1 Mod Releases
Thanks for reporting the flight computer issues. Unfortunately, most of the issues seem to be tied to the astrophysics maths buried inside the flight computer, that we (RT team) are yet to get familiar with. But don't worry as the rebuilt flight computer of RT 2.x under development is to piggyback the stock's autopilot functions (combined SAS and autopilot in KSP 1.1) instead of depending on the hard-written maths. Not sure how old is the bug but it is not present in the latest RT 1.8.4. I tested the flight computer thoroughly (apart from the minor glitches due to the sub-optimized maths inside the computer) -
[1.11] RemoteTech v1.9.9 [2020-12-19]
TaxiService replied to tomek.piotrowski's topic in KSP1 Mod Releases
RemoteTech 1.8.4 for KSP 1.2.2 released This release 1.8.4 is minor, containing two bug fixes. What are fixed: The retracted/extended state of an antenna in VAB/SPH works properly The flight computer now aims to a target-designated celestial body Complete changelog is below: If you find any bug, please report them on our github (as it is hard to keep track of bugs here). Feedback is also welcome for the next release, here or on this github post. We are continuing the 2.x development. We, however, will fix any nasty issue found in RT 1.x branch. (P.S. Our Github's latest release page should show the RT 1.8.4 (KSP 1.2.2) instead of the RT 1.7.2 (KSP 1.1.3) now) -
[1.11] RemoteTech v1.9.9 [2020-12-19]
TaxiService replied to tomek.piotrowski's topic in KSP1 Mod Releases
Thanks for the report on this behaviour, which I can reproduce in KSP 1.2.2 with latest RT develop branch. However, this behaviour (relevant codes) is intended in this way because a vessel uses the patched conic solver (trajectories) to get the node information. When your kerbal goes EVA, the active vessel flag moves to this kerbal from the vessel. Therefore, the previous vessel loses the patched conic solver and falls back to the prograde target until the vessel becomes active again. It doesn't seem to be possible to get the patched conic info outside the active vessel. Yes, I believe you installed the mod incorrectly. Your whole RemoteTech folder (contained Parts, Plugins, Textures etc) and ModuleManager.xxxxx should be inside the GameData. By the way, you are using the old RemoteTech version, 1.7.2, which is for KSP 1.1.3. Our latest version is 1.8.3 for KSP 1.2.2 at this moment. The latest release page in the first post will be automatically updated when we push a next release of RemoteTech for minor fix. Edit: Oops. Neitsa posted his at same time -
[1.2.2] CommNet Constellation [v1.0] [7 April 2017]
TaxiService replied to TaxiService's topic in KSP1 Mod Development
Working on this matter since your last post as it is also part of my RemoteTech research on KSP's science-data transmission (eg how much power for full rate of transmission? How much data to transmit at an extreme range?) -
[1.11] RemoteTech v1.9.9 [2020-12-19]
TaxiService replied to tomek.piotrowski's topic in KSP1 Mod Releases
For RT 2.x or RT 1.8.x? For RT 1.8.x, I don't think the flight computer was designed for such scenario as it is too deeply wired to everything. For RT 2.x, it could be accomplished once the flight computer is remade into independent and isolated component. -
[1.11] RemoteTech v1.9.9 [2020-12-19]
TaxiService replied to tomek.piotrowski's topic in KSP1 Mod Releases
Psst. You can edit the extra stations into your existing save's RemoteTech_Settings.cfg. -
[1.11] RemoteTech v1.9.9 [2020-12-19]
TaxiService replied to tomek.piotrowski's topic in KSP1 Mod Releases
What do you mean by "full signal integration"? RemoteTech 1.8's signal was fully integrated into CommNet? Edit: I need to go now. RT 1.8.3 (current version) remains isolated like in KSP 1.1 and earlier. No integration into CommNet in any way (except for the stock antennas being usable for RT). -
Color picker (codes available)
TaxiService replied to TaxiService's topic in KSP1 C# Plugin Development Help and Support
For anyone asking if it is possible to build a similar color picker using KSP's DialogGUI components (KSP 1.1 and later), the answer is undoubtedly yes. The catch is, however, learn how to draw a texture (like this hue slider, main image) to pass to DialogGUIImage (and DialogGUISprite if possible) There is no repeat button in DialogGUI components to choose a color so use the positions of mouse cursor and dialog's center to detect when a player presses his cursor within the color picker image using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using UnityEngine.EventSystems; using System; namespace CommNetConstellation.UI { public class ColorPickerDialog : AbstractDialog { private Callback<Color> callbackForChosenColor; private int displayTextureWidth = 250; private int displayTextureHeight = 250; private DialogGUIImage colorPickerImage; private Texture2D colorPickerTexture; private static int dialogWidth = 250 + 10; private static int dialogHeight = 300; private Color chosenColor; private Texture2D chosenColorTexture; private DialogGUIImage newColorImage; private Color currentColor; private Texture2D currentColorTexture; private float hueValue = 0f; private int sliderHeight = 5; private bool buttonPressing = false; public ColorPickerDialog(Color userColor, Callback<Color> callbackForChosenColor) : base("Color Picker", 0.5f, //x 0.5f, //y dialogWidth, //width dialogHeight, //height new string[] { "hideclosebutton", "nodragging" }) //arguments { this.currentColor = userColor; this.chosenColor = userColor; this.callbackForChosenColor = callbackForChosenColor; this.chosenColorTexture = UIUtils.createAndColorize(30, 24, chosenColor); this.currentColorTexture = UIUtils.createAndColorize(30, 24, currentColor); this.colorPickerTexture = new Texture2D(displayTextureWidth, displayTextureHeight, TextureFormat.ARGB32, false); renderColorPicker(this.colorPickerTexture, hueValue); } protected override void OnUpdate() // MultiOptionDialog.OnUpdate = this method { Vector2 cursor = Input.mousePosition; Vector3 pickerCenter = Camera.current.WorldToScreenPoint(colorPickerImage.uiItem.transform.position); if (!EventSystem.current.IsPointerOverGameObject()) buttonPressing = false; if (pickerCenter.x- displayTextureWidth/2 <= cursor.x && cursor.x <= pickerCenter.x+displayTextureWidth/2 && pickerCenter.y - displayTextureHeight / 2 <= cursor.y && cursor.y <= pickerCenter.y + displayTextureHeight / 2) { if(!buttonPressing && Input.GetMouseButtonDown(0)) // user pressing button { buttonPressing = true; } else if(buttonPressing && Input.GetMouseButtonUp(0)) // user releasing button { buttonPressing = false; } if (buttonPressing) { int localX = (int)(cursor.x - (pickerCenter.x - displayTextureWidth/2)); int localY = (int)(cursor.y - (pickerCenter.y - displayTextureHeight/2)); renderColorPicker(colorPickerTexture, hueValue); // wipe out cursor data chosenColor = colorPickerTexture.GetPixel(localX, localY); UIUtils.colorizeFull(chosenColorTexture, chosenColor); newColorImage.uiItem.GetComponent<RawImage>().texture = chosenColorTexture; colorPickerImage.uiItem.GetComponent<RawImage>().texture = drawCursorOn(colorPickerTexture, localX, localY); } } } protected override List<DialogGUIBase> drawContentComponents() { List<DialogGUIBase> listComponments = new List<DialogGUIBase>(); DialogGUILabel newColorLabel = new DialogGUILabel("<b> New</b>", 40, 12); newColorImage = new DialogGUIImage(new Vector2(30, 24), Vector2.zero, Color.white, chosenColorTexture); DialogGUILabel currentColorLabel = new DialogGUILabel("<b>Current </b>", 45, 12); DialogGUIImage currentColorImage = new DialogGUIImage(new Vector2(30, 24), Vector2.zero, Color.white, currentColorTexture); listComponments.Add(new DialogGUIHorizontalLayout(true, false, 0, new RectOffset(), TextAnchor.MiddleCenter, new DialogGUIBase[] { new DialogGUISpace(40), newColorImage, newColorLabel, new DialogGUISpace(dialogWidth - 80 - 145), currentColorLabel, currentColorImage, new DialogGUISpace(40) })); colorPickerImage = new DialogGUIImage(new Vector2(displayTextureWidth, displayTextureHeight), Vector2.zero, Color.white, colorPickerTexture); DialogGUIImage hueSliderImage = new DialogGUIImage(new Vector2(displayTextureWidth, sliderHeight * 2), Vector2.zero, Color.white, renderHueSliderTexture()); DialogGUISlider hueSlider = new DialogGUISlider(() => hueValue, 0f, 1f, false, displayTextureWidth, sliderHeight, setHueValue); listComponments.Add(new DialogGUIVerticalLayout(true, false, 0, new RectOffset(), TextAnchor.UpperCenter, new DialogGUIBase[] { colorPickerImage, new DialogGUISpace(5f), hueSliderImage, hueSlider })); DialogGUIButton applyButton = new DialogGUIButton("Apply", applyClick); listComponments.Add(new DialogGUIHorizontalLayout(true, false, 0, new RectOffset(), TextAnchor.MiddleCenter, new DialogGUIBase[] { new DialogGUIFlexibleSpace(), applyButton, new DialogGUIFlexibleSpace() })); return listComponments; } protected override bool DialogAwake(object[] args) { return true; } private void renderColorPicker(Texture2D thisTexture, float hueValue) { for (int x = 0; x < displayTextureWidth; x++) { for (int y = 0; y < displayTextureHeight; y++) { float h = hueValue; float v = (y / (displayTextureHeight * 1.0f)) * 1f; float s = (x / (displayTextureWidth * 1.0f)) * 1f; thisTexture.SetPixel(x, y, new ColorHSV(h, s, v).ToColor()); } } thisTexture.Apply(); } private Texture2D renderHueSliderTexture() { Texture2D hueTexture = new Texture2D(displayTextureWidth, sliderHeight * 2, TextureFormat.ARGB32, false); for (int x = 0; x < hueTexture.width; x++) { for (int y = 0; y < hueTexture.height; y++) { float h = (x / (hueTexture.width* 1.0f)) * 1f; hueTexture.SetPixel(x, y, new ColorHSV(h, 1f, 1f).ToColor()); } } hueTexture.Apply(); return hueTexture; } private void setHueValue(float newValue) { this.hueValue = newValue; renderColorPicker(colorPickerTexture, newValue); colorPickerImage.uiItem.GetComponent<RawImage>().texture = colorPickerTexture; } private Texture2D drawCursorOn(Texture2D thisTexture, int x, int y) { Color cursorColor = Color.white; if (x - 2 >= 0) // left arm thisTexture.SetPixel(x-2, y, cursorColor); if (x - 3 >= 0) thisTexture.SetPixel(x-3, y, cursorColor); if (x +2 <= thisTexture.width) // right arm thisTexture.SetPixel(x + 2, y, cursorColor); if (x + 3 <= thisTexture.width) thisTexture.SetPixel(x + 3, y, cursorColor); if (y - 2 >= 0) // legs thisTexture.SetPixel(x, y - 2, cursorColor); if (y - 3 >= 0) thisTexture.SetPixel(x, y - 3, cursorColor); if (y + 2 <= thisTexture.height) // head thisTexture.SetPixel(x, y + 2, cursorColor); if (y + 3 <= thisTexture.height) thisTexture.SetPixel(x, y + 3, cursorColor); thisTexture.Apply(); return thisTexture; } private void applyClick() // TODO: to be replaced by abstract dialog's close button's callback & text { UnityEngine.GameObject.DestroyImmediate(colorPickerTexture, true); UnityEngine.GameObject.DestroyImmediate(chosenColorTexture, true); UnityEngine.GameObject.DestroyImmediate(currentColorTexture, true); callbackForChosenColor(chosenColor); this.dismiss(); } } } -
[1.2.2] CommNet Constellation [v1.0] [7 April 2017]
TaxiService replied to TaxiService's topic in KSP1 Mod Development
Latest iteration of the Constellation interfaces (though mostly non-functional) :3 The next step is the implementation of the functions in the interfaces -
[1.2.2] CommNet Constellation [v1.0] [7 April 2017]
TaxiService replied to TaxiService's topic in KSP1 Mod Development
No, RemoteTech is not required. This Constellation has its own layer hooking CommNet. -
[1.11] RemoteTech v1.9.9 [2020-12-19]
TaxiService replied to tomek.piotrowski's topic in KSP1 Mod Releases
DOH! The new editor in KSP 1.1 and later reveals the soft-deprecated antennas by searching for RT modules though they are not found in the stock tech tree. They are going to be gone in RT 2.0. RT 1.8 codebase was already broken up into the separate modules of RT 2.0. At this point, we are writing "updated" codes over some old codes dated to very early KSP versions, and throwing out the classes/codes that are made redundant by CommNet. Some of us are investigating the new toys in KSP 1.1/1.2 such as DialogGUI components and ScenarioModule -
[1.11] RemoteTech v1.9.9 [2020-12-19]
TaxiService replied to tomek.piotrowski's topic in KSP1 Mod Releases
Yup, RemoteTech 1.x codebase is over 6,000 in code lines and 130 classes (according to VS's Code Metric Results), contributed by 82 members since its birth in early 2013. This mod is easily large enough to classify as a moderate software project on own. It isn't something a simple mod can be cleaned up in a few weeks. -
[1.11] RemoteTech v1.9.9 [2020-12-19]
TaxiService replied to tomek.piotrowski's topic in KSP1 Mod Releases
No, it is missing many major features and there are still large gaps to fill up. Come back in a few months and poke again. -
[Solved] Texture issues
TaxiService replied to TaxiService's topic in KSP1 C# Plugin Development Help and Support
I found the answer to the first problem. A UIStyle is necessary to point to a number of sprites if you want to override the DialogGUIButton's default skin (UISkinDef class) when creating an image button. UIStyle focusButtonStyle = new UIStyle(); // necessary for multiple button states focusButtonStyle.normal = new UIStyleState(); // ? (not same as DialogGUIButton.image) focusButtonStyle.normal.background = Sprite.Create(focusTexture, new Rect(0, 0, 32, 32), Vector2.zero); focusButtonStyle.normal.textColor = Color.black; focusButtonStyle.highlight = focusButtonStyle.normal; // when hovering your cursor over it focusButtonStyle.active = focusButtonStyle.normal; // when pressing focusButtonStyle.disabled = focusButtonStyle.normal; // when button is disabled (no reaction when clicking) DialogGUIButton focusButton = new DialogGUIButton("", magicFunction, a, 32, 32, false, focusButtonStyle); // pass focusButtonStyle to this image button focusButton.image = Sprite.Create(focusTexture, new Rect(0, 0, 32, 32), Vector2.zero); // when your cursor is not near it anywhere i.e. what you see The downside is you cannot use the default button skin for your image button i.e. you better draw different images for different button states. -
"Use a picture. It's worth a thousand words." - Tess Flanders, 1911 I searched for codes of a free color picker in this forum and found nothing. So I wrote a new one. I spent way too much time and effort of rewriting a Unity color picker for KSP not to share this little gem to you. Enjoy! The license of the original picker is not specified so I think it is released to the public domain. using UnityEngine; // credit to Brian Jones (https://github.com/boj) // obtained from https://gist.github.com/boj/1181465 (warning: the original author's codes were written hurriedly, resulting in obvious bugs) // license - not found; I think it is released to public domain namespace CommNetConstellation { [KSPAddon(KSPAddon.Startup.TrackingStation, false)] public class ColorPicker : MonoBehaviour { public bool showPicker = true; private Texture2D displayPicker; public int displayTextureWidth = 360; public int displayTextureHeight = 360; public int positionLeft; public int positionTop; public Color chosenColor; private Texture2D chosenColorTexture; private float hueSlider = 0f; private float prevHueSlider = 0f; private Texture2D hueTexture; protected void Awake() { positionLeft = (Screen.width / 2) - (displayTextureWidth / 2); positionTop = (Screen.height / 2) - (displayTextureHeight / 2); renderColorPicker(); hueTexture = new Texture2D(10, displayTextureHeight, TextureFormat.ARGB32, false); for (int x = 0; x < hueTexture.width; x++) { for (int y = 0; y < hueTexture.height; y++) { float h = (y / (hueTexture.height*1.0f)) * 1f; hueTexture.SetPixel(x, y, new ColorHSV(h, 1f, 1f).ToColor()); } } hueTexture.Apply(); // small color picker box texture chosenColorTexture = new Texture2D(1, 1); chosenColorTexture.SetPixel(0, 0, chosenColor); } private void renderColorPicker() { Texture2D colorPicker = new Texture2D(displayTextureWidth, displayTextureHeight, TextureFormat.ARGB32, false); for (int x = 0; x < displayTextureWidth; x++) { for (int y = 0; y < displayTextureHeight; y++) { float h = hueSlider; float v = (y / (displayTextureHeight * 1.0f)) * 1f; float s = (x / (displayTextureWidth * 1.0f)) * 1f; colorPicker.SetPixel(x, y, new ColorHSV(h, s, v).ToColor()); } } colorPicker.Apply(); displayPicker = colorPicker; } protected void OnGUI() { if (!showPicker) return; GUI.Box(new Rect(positionLeft - 3, positionTop - 3, displayTextureWidth + 60, displayTextureHeight + 60), ""); if (hueSlider != prevHueSlider) // new Hue value { prevHueSlider = hueSlider; renderColorPicker(); } if (GUI.RepeatButton(new Rect(positionLeft, positionTop, displayTextureWidth, displayTextureHeight), displayPicker)) { int a = (int)Input.mousePosition.x; int b = Screen.height - (int)Input.mousePosition.y; chosenColor = displayPicker.GetPixel(a - positionLeft, -(b - positionTop)); } hueSlider = GUI.VerticalSlider(new Rect(positionLeft + displayTextureWidth + 3, positionTop, 10, displayTextureHeight), hueSlider, 1, 0); GUI.Box(new Rect(positionLeft + displayTextureWidth + 20, positionTop, 20, displayTextureHeight), hueTexture); if (GUI.Button(new Rect(positionLeft + displayTextureWidth - 60, positionTop + displayTextureHeight + 10, 60, 25), "Apply")) { chosenColor = chosenColorTexture.GetPixel(0, 0); showPicker = false; } // box for chosen color GUIStyle style = new GUIStyle(); chosenColorTexture.SetPixel(0, 0, chosenColor); chosenColorTexture.Apply(); style.normal.background = chosenColorTexture; GUI.Box(new Rect(positionLeft + displayTextureWidth + 10, positionTop + displayTextureHeight + 10, 30, 30), new GUIContent(""), style); } } }
-
Hi, we (RemoteTech team) are perplexed by a coordination-space issue (link). Our problem is basically that satellite connection lines in Map View (aka planetarium) sometimes invert in axis for no apparent reason. We tracked down to the offending codes in our RT codebase (link). var start = camera.WorldToScreenPoint(ScaledSpace.LocalToScaledSpace(edge.A.Position)); var end = camera.WorldToScreenPoint(ScaledSpace.LocalToScaledSpace(edge.B.Position)); //the edge (A, B) is a connection between two satellites/ground stations //Position is in the world space We observed that the start and end vectors sometimes are suddenly shifted when a player's camera satisfies the conditions for shifting KSP's scaled space factor/offset, resulting in providing completely different vectors to RemoteTech codes. Given that we, the fresh blood for RT, are relatively new to the KSP mod scene, we seek the assistance of expert modders regarding KSP's world, screen and scaled spaces. Our question is: How should we solve the problem, that may be linked to KSP's inner codes in LocalToScaledSpace()? //Decompiled ScaledSpace class of KSP public static Vector3d LocalToScaledSpace(Vector3d localSpacePoint) { return localSpacePoint * (double)ScaledSpace.InverseScaleFactor - ScaledSpace.totalOffset; }
-
[1.11] RemoteTech v1.9.9 [2020-12-19]
TaxiService replied to tomek.piotrowski's topic in KSP1 Mod Releases
By any chance, can you tell me what antennas you used in your tests? I notice some of third-party antennas don't set up a connection with your probe (CommNet's red satellite icon, despite RT's connected status). This prevents the R pressing. (No problem, it didn't damage my computer in any way) -
[1.11] RemoteTech v1.9.9 [2020-12-19]
TaxiService replied to tomek.piotrowski's topic in KSP1 Mod Releases
According to Unity documentation (1) (2), there is the OnApplicationQuit handler but it is not consistent across multiple platforms (like Xbox, PS). Moreover, the official KSP API documentation does not have any kind handler for the application quit and the closest thing is GameEvents.onGameStateSave. For these reasons, the save handler on the exit/quit button (the brown button/menu button) inside KSP is preferred by Squad and mod developers. P.S. you can still kill your KSP quickly by clicking the "Quit to menu" button of menu from the flight scene and then the red x button. KSP will do its usual closing action on this "Quit to menu". (Correct me if I am wrong on some details) -
[1.11] RemoteTech v1.9.9 [2020-12-19]
TaxiService replied to tomek.piotrowski's topic in KSP1 Mod Releases
Thanks for the uploading your GameData of 130+ mods (!). I gave it a go and found some results on different configurations of parts As you can see from the screenshots (pardon the null-exception spam), I can toggle and command RCS on stock parts. However, not every third-party part can be work with RemoteTech (RSC parts do nothing or a probe ignores the RCS press) because they are either not patched or using different ways other than RemoteTech. I think the workaround for you is to use the stock parts as much as possible while enjoying your rich library of mods. Let me think more about this implication of such many third-party mods, in which some mods are so old or not patched for RT. (For those who are curious on the effect of the 130+ mods on my middle-end computer, see below)