xEvilReeperx

Members
  • Content Count

    880
  • Joined

  • Last visited

Community Reputation

1,081 Excellent

5 Followers

About xEvilReeperx

  • Rank
    Junior Rocket Scientist

Recent Profile Visitors

The recent visitors block is disabled and is not being shown to other users.

  1. You don't need ref or out here. Just use isDragging directly in the lambda functions; C# will create a closure over it and you effectively have a reference to it (although secretly the compiler creates a private inner class which is how it pulls this off). By the way, you probably don't want to be inserting triggers in OnUpdate(): every time the slider value changes, you add another set of triggers
  2. Something sounds funny in your explanation. If you want everything to stay in one function, what are you outputting to? Why does the float need to be passed by reference? Changing it won't make any difference, you'll want to call a method on the slider itself to change it anyways or you might break state stuff. Assuming "which" slider is the problem (and you REALLY wanted to keep it all in one function [why?]), you could always do something like this: private enum WhichSlider // or however you want to identify it, right down to calling different functions { First, Second, Third } // embed which slider is clicked into another anon function private void Foo() { DialogGUISlider slider1; // = whatever DialogGUISlider slider2; DialogGUISlider slider3; // can make an inner func for logic... Action<float, WhichSlider> lambdaSliderChanged = (f, which) => { print("Slider " + which + " is now " + f); }; slider1.slider.onValueChanged.AddListener(val => { lambdaSliderChanged(val, WhichSlider.First); }); slider2.slider.onValueChanged.AddListener(val => { lambdaSliderChanged(val, WhichSlider.Second); }); slider3.slider.onValueChanged.AddListener(val => { lambdaSliderChanged(val, WhichSlider.Third); }); }
  3. xEvilReeperx

    How To Update Part Appearance?

    Can you be more specific about what you're trying to do? There isn't any code related to the part's appearance itself before PartModules start getting loaded. The part prefab is instantiated as is and then PartModules do the thing, one of which may be to modify the part's appearance. Why can't you modify the part inside OnLoad? I'm fairly sure that fires in the same frame as when the part itself is created, so changing part appearance there is fine and the user will never notice
  4. The structure is destroyed because you're not really saving the original contents of the file your ConfigNode comes from. ConfigNodes loaded by the game are all wrapped in a root ConfigNode that looks like this: root { KERBALCHANGELOG { ... } } This is so you can have multiple "inner nodes" in one cfg. You want to save the file itself to keep this structure, using cfgDir.parent.SaveFile()
  5. AudioClip clip = GameDatabase.Instance.GetAudioClip(gdb_path); clip.name = name; // <----- bad plan planetMap.Add(name, clip); fileNames.Add(clip, name); I haven't tried running your code but at a glance this stands out. Usually the GameDatabase names are the GameData-relative URLs, so on your first run this clip will likely be named something like SoundsOfSpace/Sounds/SoundsOfSpace/yourfile After successfully finding this clip the first time, you inexplicably rename it to yourfile.ogg. This will be a problem because GameDatabase.Instance.ExistsAudioClip is checking the clip names for a match
  6. This is precisely why I won't incorporate the work of others into my own stuff: a large number of these licenses have either been poisoned by unwritten rules or do not reflect the actual intent of the owner who has copy-pasted it from somewhere, and so they might as well be All Rights Reserved. Secret, unwritten rules are not transparency. If I look at a license that says YOU MAY DO ANYTHING WITH THIS WORK and think, gee, I'll have to make sure that's true, then the license is incomplete at best and useless at worst.
  7. xEvilReeperx

    About to pull out my hair

    You've nearly got it. Your issue is that your window rect is in screen space (0,0 = top left) while ReadPixels (and CopyTexture) expects pixel space (0,0 = bottom left) Convert to pixel space by inverting the y coordinate (Screen.height - y) and subtracting out the window height to get the bottom-left corner of the window [KSPAddon(KSPAddon.Startup.MainMenu, false)] class CaptureWindowScreenshot : MonoBehaviour { private Rect _windowRect = new Rect(Screen.width * 0.5f, Screen.height * 0.5f - 200, 200f, 50f); private readonly GUILayoutOption[] _defaultOptions = new GUILayoutOption[0]; private GUI.WindowFunction _windowFunc; private bool _capture = false; private void Awake() { _windowFunc = DrawWindow; } private void OnGUI() { _windowRect = KSPUtil.ClampRectToScreen(GUILayout.Window(GetInstanceID(), _windowRect, _windowFunc, "Test Window", _defaultOptions)); if (_capture && Event.current.type == EventType.Repaint) { _capture = false; StartCoroutine(Capture()); } } private IEnumerator Capture() { yield return new WaitForEndOfFrame(); var pixelRect = _windowRect; // copy values pixelRect.y = Mathf.Max(Screen.height - _windowRect.y - _windowRect.height, 0f); var captureTex = new Texture2D(Mathf.CeilToInt(pixelRect.width), Mathf.CeilToInt(pixelRect.height)); captureTex.ReadPixels(pixelRect, 0, 0, false); captureTex.SaveToDisk("window.png"); // your preferred method here Destroy(captureTex); } private void DrawWindow(int winid) { for (int i = 0; i < 5; ++i) GUILayout.Label("Text goes here", _defaultOptions); GUILayout.Space(5f); if (GUILayout.Button("Capture this window", _defaultOptions)) _capture = true; GUI.DragWindow(); } }
  8. xEvilReeperx

    PAW Event being disabled

    From easiest to most convoluted: Cheat by implementing a similarly-named KSPEvent (with different method name) and abusing GameObject.SendMessage Reimplement the method yourself (VesselRenameDialog looks interesting) Fix the cached reflected delegate data yourself. This will make things "just work", but it's a little hacky [KSPAddon(KSPAddon.Startup.MainMenu, true)] class FixSetVesselNamingIssue : MonoBehaviour { class SneakyWayIntoCachedReflectedData : BaseEventList { public SneakyWayIntoCachedReflectedData(Type nobodyCares) : base(nobodyCares) { EnsureDataExists<Part>(); // if ALL modules changed, might not be any cached data for Part EnsureDataExists<PartTapIn>(); // it's possible some MM failure didn't edit the parts as expected, so confirm here too // "reflectedAttributeCache" is part of BaseEventList and is why we derive from it -> to get access so // we can tweak it var partData = reflectedAttributeCache[typeof(Part)]; // <-- this has an event we want to copy var tapinData = reflectedAttributeCache[typeof(PartTapIn)]; // <-- this is where we'll copy it to // unfortunately the only way to tell the various attributes apart // is to examine their guiName, which is localized #autoLOC_8003140 var targetLocalizedName = Localizer.Format("#autoLOC_8003140"); var configureNamingAttr = partData.eventAttributes.Single(kspe => kspe.guiName.Equals(targetLocalizedName, StringComparison.Ordinal)); if (tapinData.eventAttributes.Any( kspe => kspe.guiName.Equals(targetLocalizedName, StringComparison.Ordinal))) { return; // clearly changes already made } // insert attribute into PartTapIn data tapinData.eventAttributes.Add(configureNamingAttr); // copy "SetVesselNaming" delegate from Part to PartTapIn // this'll work because it's technically part of PartTapIn as well // note: method name directly, no localization needed here var setVesselNamingFunc = partData.eventDelegates.Single(mi => "SetVesselNaming".Equals(mi.Name)); tapinData.eventDelegates.Add(setVesselNamingFunc); } private static void EnsureDataExists<T>() where T : MonoBehaviour { if (reflectedAttributeCache.ContainsKey(typeof(T))) return; // already cached // if we create an inactive GameObject, we can prevent stuff from triggering // (awake, start) var dummyGo = new GameObject("dummy"); dummyGo.SetActive(false); // suppress awake, start var target = dummyGo.AddComponent<T>(); var dummy = new BaseEventList(target); // force data to be cached UnityEngine.Object.Destroy(dummyGo.gameObject); } } private void Start() { try { new SneakyWayIntoCachedReflectedData( typeof(Part)); // we literally don't care about anything but getting this constructor to run } catch (Exception e) { Debug.LogError("Exception while trying to meddle with cached data: " + e); } finally { Destroy(gameObject); // done } } }
  9. The exception in the log was the first clue. I looked at the code and didn't see any reason why that would prevent a simple print statement made in Update from working, so I wrote another small addon that checked out KeyNode's state. There were three possibilities as to why Update wasn't running: the component had been destroyed due to the uncaught exception in Awake. I've never seen this before, but thought it could be something AddonLoader does on an unhandled exception the GameObject wasn't active the MonoBehaviour was disabled (by Unity?) Turns out #3 was your problem
  10. It throws an uncaught exception in Awake and its MonoBehaviour ends up getting disabled (MonoBehaviour.enabled = false) when initializing for the second+ time. That's why you don't see any output from Update on subsequent flight scenes ArgumentException: An element with the same key already exists in the dictionary. System.Collections.Generic.Dictionary`2[UnityEngine.KeyCode,Callback].Add (KeyCode key, .Callback value) KeyNode.KeyNode.Awake () UnityEngine.GameObject:AddComponent(Type) AddonLoader:StartAddon(LoadedAssembly, Type, KSPAddon, Startup) AddonLoader:StartAddons(Startup) AddonLoader:OnLevelLoaded(GameScenes) AddonLoader:OnSceneLoaded(Scene, LoadSceneMode) UnityEngine.SceneManagement.SceneManager:Internal_SceneLoaded(Scene, LoadSceneMode)
  11. What does the hierarchy of your part look like? Based on the stacktrace and name, I'd bet there's a bug in StrippedTaggedTransforms. Try making sure whatever element is tagged with Icon_Only is the very last child of its parent, wherever the tag appears
  12. xEvilReeperx

    KSP 1.4.1 Performance

    Follow the same instructions to get debugging working, and then use Unity's profiler with KSP
  13. xEvilReeperx

    KSP 1.4.1 Performance

    You're going to have a hard time writing code that doesn't generate unnecessary garbage if you don't understand the mechanisms that create it. Use the profiler to find problem spots. If you happen to use VS and have Resharper, the Heap Allocations Viewer extension is very useful
  14. xEvilReeperx

    KSP 1.4.1 Performance

    Don't do this, it has every drawback and no advantage. They will all be rendered anyways and any change to any element will still dirty its canvas and trigger a rebuild
  15. You've misunderstood my point: KSP's source code is not required to do any of these things, so I don't have any obligation to offer it.