using System; using KSP; using KSP.UI; using UnityEngine; using System.Collections.Generic; using System.Linq; using System.Text; namespace AlphabeticalKerbals { class KerbalSorter { static void print(string s) { MonoBehaviour.print("AlphabeticalKerbals: " + s); } /// /// Sorts the kerbals in the CrewAssignmentDialog /// Will not work on dialogs that do not use the CrewAssignmentDialog GUI element /// /// success static public bool Sort_Kerbals() { if (CrewAssignmentDialog.Instance == null) { print("OnEditorCrewOpened has no CrewAssignmentDialog yet..."); } else { UIList avail = CrewAssignmentDialog.Instance.scrollListAvail; UIList_QSort(avail, 0, avail.Count - 1); #if DEBUG for (int i = 0; i < avail.Count; i++) { UIListItem li = avail.GetUilistItemAt(i); CrewListItem crew = li.GetComponent(); print("AFTER SORT = " + crew.GetName()); } #endif return true; /* for (int i = 0; i < comps.Length; ++i) { print($"Component {i}: {comps[i].GetType()}"); } foreach (Component comp in firstdata) { print("Got a component"); print("Component name is " + comp.name); print("Component type is " + comp.GetType().Name); print("Component string is " + comp.ToString()); } */ } return false; } /// /// Sorts Kerbals, but first checks the list to make sure it's not already sorted. /// Overall, this ends up using more resources than just blind-sorting, but in cases /// where the list is almost always going to be correctly sorted, it may save some time. /// /// success static public bool Sort_Kerbals_If_Needed() { if (CrewAssignmentDialog.Instance == null) { print("OnEditorCrewOpened has no CrewAssignmentDialog yet..."); return false; } else { UIList avail = CrewAssignmentDialog.Instance.scrollListAvail; bool unsorted = false; int i = 0; for (; i < (avail.Count - 1); i++) { UIListItem li = avail.GetUilistItemAt(i); UIListItem li2 = avail.GetUilistItemAt(i + 1); CrewListItem crew = li.GetComponent(); if (UIList_Cmp(li, li2) > 0) { unsorted = true; break; } } if (unsorted) { print("Change in Kerbal List detected, re-sorting"); #if DEBUG print("Sort_If_Needed: Sort IS needed due to i = " + i.ToString()); for (i = 0; i < avail.Count; i++) { UIListItem li = avail.GetUilistItemAt(i); CrewListItem crew = li.GetComponent(); print("BEFORE SORT = " + crew.GetName()); } #endif Sort_Kerbals(); } return true; } } /// /// Return value positive means left > right, return value negative means left < right /// /// /// /// static int UIList_Cmp(UIListItem left, UIListItem right) { CrewListItem ldata = null; CrewListItem rdata = null; try { ldata = left.GetComponent(); } catch { return 1; } try { rdata = right.GetComponent(); } catch { return -1; } #if DEBUG if (ldata == null) { return 1; } if (rdata == null) { return -1; } #endif bool ltourist = ldata.GetCrewRef().type == ProtoCrewMember.KerbalType.Tourist; bool rtourist = rdata.GetCrewRef().type == ProtoCrewMember.KerbalType.Tourist; if (ltourist && !rtourist) { return 1; } // tourists are also sorted to the end if (!ltourist && rtourist) { return -1; } // tourists are also sorted to the end return ldata.GetName().CompareTo(rdata.GetName()); } static int UIList_Partition(UIList list, int li, int ri) { // Select a random pivot point int pi = UnityEngine.Random.Range(li+1, ri+1); UIListItem pivot = list.GetUilistItemAt(pi); #if DEBUG print("Selected pivot is " + pivot.GetComponent().GetName() + " at pos " + pi.ToString()); #endif if (pi < ri) { // Move the pivot to the very end list.SwapItems(pivot, list.GetUilistItemAt(ri)); pi = ri; } UIList_DebugPrint(list, li, ri, "Pivot-selection"); // Iterate over the list and sort above or below pivot as we go int i = li; UIListItem prev = list.GetUilistItemAt(i); for (int j = li; j < ri; j++) { UIListItem selected = list.GetUilistItemAt(j); if (UIList_Cmp(selected, pivot) < 1) { #if DEBUG print("Pivotname is " + pivot.GetComponent().GetName() + " selname is " + selected.GetComponent().GetName()); UIList_DebugPrint(list, i, j, "Partition-swapping (" + i.ToString() + "," + j.ToString() + "," + UIList_Cmp(selected, pivot) + ")"); #endif if (i < j) { list.SwapItems(prev, selected); } UIList_DebugPrint(list, li, ri, "Afterswap i=" + i.ToString()); i++; prev = list.GetUilistItemAt(i); } } UIListItem pivot_target = list.GetUilistItemAt(i); if (UIList_Cmp(pivot_target, pivot) >= 0) { UIList_DebugPrint(list, li, ri, "Finalswap i=" + i.ToString()); list.SwapItems(list.GetUilistItemAt(i), pivot); UIList_DebugPrint(list, li, ri, "Finalswap done i=" + i.ToString()); return i; } else { return ri; } } static void UIList_QSort(UIList list, int li, int ri) { if (list == null || list.Count <= 1) return; if (li < ri) { #if DEBUG print("Before partition from " + li.ToString() + "-" + ri.ToString()); UIList_DebugPrint(list, li, ri, "Initial"); #endif int pi = UIList_Partition(list, li, ri); #if DEBUG print("After partition to pivot " + pi.ToString()); UIList_DebugPrint(list, li, pi-1, "Left"); UIList_DebugPrint(list, pi, pi, "Pivot"); UIList_DebugPrint(list, pi+1, ri, "Right"); #endif UIList_QSort(list, li, pi - 1); UIList_QSort(list, pi + 1, ri); } } static void UIList_DebugPrint(UIList list, int li, int ri, string msg) { #if DEBUG string outmsg = msg + " -- "; for (int i = li; i < ri+1; i++) { UIListItem curitem = list.GetUilistItemAt(i); CrewListItem crew = curitem.GetComponent(); outmsg = outmsg + crew.GetName().Split(' ')[0] + "[" + i.ToString() + "], "; } print(outmsg); #endif } } }