

xEvilReeperx
Members-
Posts
894 -
Joined
-
Last visited
Everything posted by xEvilReeperx
-
Need your own thread moved or locked? Post here.
xEvilReeperx replied to Rich's topic in Kerbal Network
Close if you would please, @linuxgurugamer is continuing this for me with a new thread -
KSP 1.2.2 GameEvents Extension
xEvilReeperx replied to JPLRepo's topic in KSP1 C# Plugin Development Help and Support
If all requesters are sharing the same reference, why provide a unique identifier at all? If you want AGX to call a method and pass a list/dictionary/whatever reference, why not do that directly instead of dealing with two separate GameEvents? Here's how I'd envision that version: -
KSP 1.2.2 GameEvents Extension
xEvilReeperx replied to JPLRepo's topic in KSP1 C# Plugin Development Help and Support
You shouldn't try to link the life cycle of a GameEvent-type class with anything but static because it won't be cleaned up anyway. They register themselves in a static, private dictionary by name. The only time a previously created EventData will be GC is if a new, identically-named one is created and no other references to the previous one exist. For example, this event will exist for the lifetime of KSP, long beyond its creator, because EventData<T> registers itself in a static dictionary inside BaseGameEvent: [KSPAddon(KSPAddon.Startup.MainMenu, true)] class HelloWorld : MonoBehaviour { private void Awake() { var testTheEvent = new EventData<string>("helloworld"); } } Now, subscribers could be prevented from GC cleanup of course but since the only subscriber to my example event is the event's owner, controlling its lifetime is much simpler -
KSP 1.2.2 GameEvents Extension
xEvilReeperx replied to JPLRepo's topic in KSP1 C# Plugin Development Help and Support
Well, if you go with the one GameEvent, life cycle and all that shouldn't be a concern because the only thing that listens for the event is the event's owner anyway. Maybe it'll make more sense with a code example. Keep in mind that whatever parameter you decide to pass will need to be a reference type like @hvacengisaid [KSPAddon(KSPAddon.Startup.MainMenu, false)] class ModB : MonoBehaviour { private EventData<Dictionary<int, bool>> _actionGroupStateQuery; private void Awake() { _actionGroupStateQuery = GameEvents.FindEvent<EventData<Dictionary<int, bool>>>("AGX_QueryActionGroupStates"); var currentStates = new Dictionary<int, bool>(); _actionGroupStateQuery.Fire(currentStates); foreach (var state in currentStates) Debug.Log("Action group: " + state.Key + ": " + state.Value); } } class AGX { // note how AGX is the only thing that listens to this event. Mods who want to know stuff will fire it instead of listening public static readonly EventData<Dictionary<int, bool>> QueryActionGroupStates = new EventData<Dictionary<int, bool>>("AGX_QueryActionGroupStates"); // get around static method limitation of GameEvents private class Forwarder { private readonly EventData<Dictionary<int, bool>>.OnEvent _del; public Forwarder(EventData<Dictionary<int, bool>>.OnEvent del) { _del = del; } public void OnEvent(Dictionary<int, bool> data) { _del(data); } } // make sure initialization happens early [KSPAddon(KSPAddon.Startup.Instantly, true)] private class Initialize : MonoBehaviour { private void Awake() { Init(); Destroy(gameObject); } } private static void Init() { var forwarder = new Forwarder(OnQueryReceived); QueryActionGroupStates.Add(forwarder.OnEvent); } // somebody wants to know some stuff private static void OnQueryReceived(Dictionary<int, bool> data) { for (int i = 0; i < 32; ++i) data[i] = i % 2 == 0; } } -
KSP 1.2.2 GameEvents Extension
xEvilReeperx replied to JPLRepo's topic in KSP1 C# Plugin Development Help and Support
Why not spin it around and make AGX the thing that listens for the event? Have the requester fire the event instead, AGX can fill in the desired info. You'd only need one event this way as well -
Reversing the new GameEvents extention.
xEvilReeperx replied to Diazo's topic in KSP1 C# Plugin Development Help and Support
As long as both assemblies can fully resolve the type(s) of the arguments, it works as you'd expect -
Grab ladder programmatically
xEvilReeperx replied to Dizor's topic in KSP1 C# Plugin Development Help and Support
There's probably an equivalent FSM state event for it. Get a hold of all StateEvents looking for a likely one and run it. Here's a previous answer that does the exact opposite of what you want to give you an idea -
Well, something like this does stand out: susJoint.anchor = ITP + -wheel.transform.up * (length + radius); // using transform's world up to calculate local anchor position? susJoint.axis = new Vector3(1, 0, 0); // local space axis susJoint.autoConfigureConnectedAnchor = false; susJoint.secondaryAxis = new Vector3(0, 1, 0); // also local space
-
Move your test rig onto the north pole and test it there. If it suddenly seems to work, your issue is just a confusion of coordinate spaces. On Kerbin at the launchpad, you're actually positioned on the equator of a sphere with the camera rotated to make it look like you're on a flat surface Visualization: The game uses the planet as a reference frame here so your up direction isn't constantly changing like you might expect (as the planet spins) but what direction in worldspace "up" is will vary based on your position on the planet. You can probably figure out just from this image why I suggest testing at the north pole
-
Hi, I updated it for KSP 1.2. Didn't need any fixes besides removing the KSPUtil reference which is no longer needed Edit: whoopsie, uploaded my debug version by mistake. Fixed
-
Hi, I was going to send you a PM but I might as well post this here. The source isn't dead, it was just renamed to something that rolled off the tongue a bit better when I was last working on it. It probably won't be much help because it predates the migration to the new Unity GUI. That's actually a good thing in this case though because the new Unity UI is much more modder friendly than the old EzGUI stuff was
-
Assuming the kerbal is on the ladder (to be sure you'll find the let go event), you can run the right event directly: var fsm = FlightGlobals.ActiveVessel.gameObject.GetComponent<KerbalEVA>().fsm; var letGoEvent = fsm.CurrentState.StateEvents.SingleOrDefault(e => e.name == "Ladder Let Go"); if (letGoEvent == null) Debug.LogError("Did not find let go event"); else fsm.RunEvent(letGoEvent);
-
When 5.2 came out, we finally got access to Unity's profiler. If you've followed the plugin debugging guide (at least insofar as creating the PlayerConnectionConfigFile and using a dev version of the player) then you're already set up, just start up Unity, open the profiler window, make sure it's connected to the right thing and it'll work. This is very handy for both locating GC problems as well as performance bottlenecks. My only addition to that process is a little tool that inserts Profiler.BeginSample/EndSample into every method on a target assembly to find GC issues more easily. With 5.4, there's an actual memory profiler + API available. I've been working on getting it to work but no luck so far There's also a low-level API available in mono. I tried to make this work but all the timing and GC-watching code would have to exist in a native plugin, and with 5.2 being right around the corner at the time I ultimately abandoned that project
-
[1.10.1+] Contract Configurator [v1.30.5] [2020-10-05]
xEvilReeperx replied to nightingale's topic in KSP1 Mod Releases
Looks like it should be really easy to fix. More than 90% of the garbage being produced is coming from one method and one closure in particular based on very quick lookover New game, no mods excluding MM + CC, no active flights Contract Packs: additional progression contracts, anomaly surveyor, BaseConstruction, CleverSat, FieldResearch (a decent scattering for profiling purposes). Snapshot of profiler while on the pad with a couple contracts accepted:- 5,225 replies
-
- 4
-
-
Well there isn't much to it. All you need to know is how to find the items you're interested. Dump their contents, see if there's anything potentially useful and try it out. _UIMaster has components: ...c: UnityEngine.Transform ...c: KSP.UI.UIMasterController ...c: DoNotDestroy ->MainCanvas has components: ....c: UnityEngine.RectTransform ....c: UnityEngine.Canvas ....c: UnityEngine.UI.CanvasScaler ....c: UnityEngine.UI.GraphicRaycaster ....c: UnityEngine.CanvasGroup ....c: KSP.UI.CanvasGroupInputLock -->Editor has components: .....c: UnityEngine.RectTransform .....c: UnityEngine.Canvas .....c: UnityEngine.UI.GraphicRaycaster --->Panel Parts List has components: ......c: UnityEngine.RectTransform ......c: KSP.UI.UIPanelTransition ......c: KSP.UI.Screens.EditorPartList ......c: UnityEngine.CanvasGroup ---->Mode Transition has components: .......c: UnityEngine.RectTransform .......c: KSP.UI.UIPanelTransition .......c: UnityEngine.CanvasGroup ----->PartList Area has components: ........c: UnityEngine.RectTransform ........c: UnityEngine.UI.VerticalLayoutGroup ------>PartList and sorting has components: .........c: UnityEngine.RectTransform .........c: UnityEngine.UI.LayoutElement ------->ListAndScrollbar has components: ..........c: UnityEngine.RectTransform ..........c: UnityEngine.CanvasRenderer ..........c: UnityEngine.EventSystems.EventTrigger -------->bg has components: ...........c: UnityEngine.RectTransform ...........c: UnityEngine.CanvasRenderer ...........c: UnityEngine.UI.Image --------->ScrollRect has components: ............c: UnityEngine.RectTransform ............c: UnityEngine.UI.ScrollRect ............c: UnityEngine.CanvasRenderer ............c: UnityEngine.UI.Image ............c: UnityEngine.UI.Mask ............c: KSP.UI.Screens.UIScrollRectState ---------->PartGrid has components: .............c: UnityEngine.RectTransform .............c: UnityEngine.UI.GridLayoutGroup .............c: UnityEngine.UI.ContentSizeFitter ----------->PartItemPrefab(Clone) has components: ..............c: UnityEngine.RectTransform ..............c: UnityEngine.CanvasRenderer ..............c: UnityEngine.UI.Image ..............c: UnityEngine.UI.Button ..............c: KSP.UI.Screens.EditorPartIcon ..............c: KSP.UI.PointerEnterExitHandler ..............c: UnityEngine.UI.LayoutElement ..............c: KSP.UI.PointerClickHandler ..............c: KSP.UI.Screens.Editor.PartListTooltipController The icon has two interesting bits in there, a UnityEngine.UI.Button and KSP.UI.PointerClickHandler. Now find all part icons, add a listener to their button and see if it does what you expect: [KSPAddon(KSPAddon.Startup.EditorAny, false)] class EditorIconButtonClickTester : MonoBehaviour { private IEnumerator Start() { while (EditorPartList.Instance == null) yield return null; foreach ( var icon in EditorPartList.Instance.partListScrollRect.gameObject.GetComponentsInChildren<EditorPartIcon>( true)) { var whichIcon = icon; icon.gameObject.GetComponent<Button>().onClick.AddListener(() => IconClicked(whichIcon)); } } private static void IconClicked(EditorPartIcon icon) { if (!Input.GetKey(KeyCode.LeftAlt) && !Input.GetKey(KeyCode.RightAlt)) return; Debug.LogWarning("You clicked on " + icon.partInfo.name); } } As for prefabs: if the game clones them when it creates something, any changes you make will be automatically applied to the new object as well. Sometimes this is useful when you don't actually know how the game manages stuff ... for example, does the editor create all of the part icons straight off the bat or are they destroyed and a new set created on every category change? If it's the latter, the code above is going to break. If I tweak the prefab instead, my changes (specifically: the component I added in the first post which tweaks the icon behaviour) will just automatically be copied into the new ones and I don't have to be concerned about it at all
-
You can add a listener to the button itself (or add a MonoBehaviour that implements IPointerClickHandler to the button's GameObject). My preference is to edit the prefab wherever possible as it tends to make catching any edge cases a lot simpler. I kind of get the impression that you might want to prevent a part from spawning when clicking with alt held down so here's some code that goes a step further and lets you veto the click by using a small replacement click handler: public static class EditorIconEvents { public static readonly EventData<EditorPartIcon, EditorIconClickEvent> OnEditorPartIconClicked = new EventData<EditorPartIcon, EditorIconClickEvent>("EditorPartIconClicked"); public class EditorIconClickEvent { public void Veto() { Vetoed = true; } public bool Vetoed { get; private set; } } [KSPAddon(KSPAddon.Startup.EditorAny, true)] private class InstallEditorIconEvents : MonoBehaviour { private IEnumerator Start() { while (EditorPartList.Instance == null) yield return null; var prefab = EditorPartList.Instance.partPrefab; InstallReplacementHandler(prefab); // some icons have already been instantiated, need to fix those too. Only needed this first time; // after that, the prefab will already contain the changes we want to make foreach (var icon in EditorPartList.Instance.gameObject.GetComponentsInChildren<EditorPartIcon>(true)) InstallReplacementHandler(icon); Destroy(gameObject); } private static void InstallReplacementHandler(EditorPartIcon icon) { icon.gameObject.AddComponent<ReplacementClickHandler>(); } } private class ReplacementClickHandler : MonoBehaviour, IPointerClickHandler, IPointerDownHandler, IPointerUpHandler { private EditorPartIcon _icon; private PointerClickHandler _originalClickHandler; private Button _button; private void Start() { _button = GetComponent<Button>(); _originalClickHandler = GetComponent<PointerClickHandler>(); _icon = GetComponent<EditorPartIcon>(); if (_button == null || _originalClickHandler == null || _icon == null) { Debug.LogError("Couldn't find an expected component"); Destroy(this); return; } _originalClickHandler.enabled = false; // we'll be managing these events instead // unhook EditorPartIcon's listener from the button // this will allow us to veto any clicks _button.onClick.RemoveListener(_icon.MouseInput_SpawnPart); } public void OnPointerClick(PointerEventData eventData) { var evt = new EditorIconClickEvent(); OnEditorPartIconClicked.Fire(_icon, evt); if (evt.Vetoed) return; _originalClickHandler.OnPointerClick(eventData); if (_button.interactable) _icon.MouseInput_SpawnPart(); } public void OnPointerDown(PointerEventData eventData) { _originalClickHandler.OnPointerDown(eventData); } public void OnPointerUp(PointerEventData eventData) { _originalClickHandler.OnPointerUp(eventData); } } } And example usage: [KSPAddon(KSPAddon.Startup.EditorAny, false)] class TestTheEvent : MonoBehaviour { private void Start() { EditorIconEvents.OnEditorPartIconClicked.Add(IconClicked); } private void OnDestroy() { EditorIconEvents.OnEditorPartIconClicked.Remove(IconClicked); } private void IconClicked(EditorPartIcon icon, EditorIconEvents.EditorIconClickEvent evt) { if (!Input.GetKey(KeyCode.LeftAlt) && !Input.GetKey(KeyCode.RightAlt)) return; Debug.LogWarning("Icon was clicked for " + icon.partInfo.name + " (" + icon.partInfo.title + ")"); evt.Veto(); // prevent part from being spawned } }
-
No prefabs in .ksp assetbundle
xEvilReeperx replied to Crzyrndm's topic in KSP1 C# Plugin Development Help and Support
No, I understand what's going on now. The code is working as expected and is loading the cached version which was probably made before the bundle had any prefabs in it. I think you'll find that anything you add from this point on will appear not to work unless you Caching.CleanCache() or increment the asset bundle version number in LoadFromCacheOrDownload. Why cache it at all? The bundle is already stored locally so this will just double disk usage -
No prefabs in .ksp assetbundle
xEvilReeperx replied to Crzyrndm's topic in KSP1 C# Plugin Development Help and Support
There are a couple potential problems The URL should be escaped The bundle might have failed to load (check WWW.error, might have failed due to 1) The docs don't mention it for WWW.LoadFromCacheOrDownload method so this might not apply, but in the constructor for WWW, filenames under windows should be prefixed with file:/// rather than file:// -
Stop click-through in KSP 1.1?
xEvilReeperx replied to Angelo Kerman's topic in KSP1 C# Plugin Development Help and Support
The window prefab is exposed so you can just add a tracking component that keeps them in a list to avoid FindObjectsOfType or any iterating. I agree that just making the list public would be handy though