예제 #1
0
        /// <summary>
        /// Adds this side screen to the side screen list, and loads the prefabs from the
        /// Assignable side screen for UI consistency.
        /// </summary>
        /// <param name="existing">The existing side screens.</param>
        /// <param name="parent">The parent where the screens need to be added.</param>
        internal static void AddSideScreen(IList <DetailsScreen.SideScreenRef> existing,
                                           GameObject parent)
        {
            bool found = false;

            // Does it in a custom way because we need to duplicate an existing UI, not make
            // a new one with PLib
            foreach (var ssRef in existing)
            {
                if (ssRef.screenPrefab is AssignableSideScreen ss)
                {
                    var newScreen = new DetailsScreen.SideScreenRef();
                    var ours      = CreateScreen(ss);
                    // Reparent to the details screen
                    found                    = true;
                    newScreen.name           = nameof(WorkshopProfileSideScreen);
                    newScreen.screenPrefab   = ours;
                    newScreen.screenInstance = ours;
                    // It somehow gets a 0.8x scale
                    var ssTransform = ours.gameObject.transform;
                    ssTransform.SetParent(parent.transform);
                    ssTransform.localScale = Vector3.one;
                    existing.Insert(0, newScreen);
                    // Must break to avoid concurrent modification exception
                    break;
                }
            }
            if (!found)
            {
                PUtil.LogWarning("Unable to find Assignable side screen!");
            }
        }
예제 #2
0
 /// <summary>
 /// Inserts the side screen at the target location.
 /// </summary>
 /// <param name="screens">The current list of side screens.</param>
 /// <param name="newScreen">The screen to insert.</param>
 /// <param name="targetClassName">The target class name for locating the screen. If this
 /// class is not found, it will be added at the end regardless of insertBefore.</param>
 /// <param name="insertBefore">true to insert before that class, or false to insert after.</param>
 private static void InsertSideScreenContent(IList <SideScreenRef> screens,
                                             SideScreenRef newScreen, string targetClassName, bool insertBefore)
 {
     if (screens == null)
     {
         throw new ArgumentNullException(nameof(screens));
     }
     if (newScreen == null)
     {
         throw new ArgumentNullException(nameof(newScreen));
     }
     if (string.IsNullOrEmpty(targetClassName))
     {
         // Add to end by default
         screens.Add(newScreen);
     }
     else
     {
         int  n     = screens.Count;
         bool found = false;
         for (int i = 0; i < n; i++)
         {
             var screen   = screens[i];
             var contents = UIDetours.SS_PREFAB.Get(screen)?.GetComponentsInChildren <
                 SideScreenContent>();
             if (contents == null || contents.Length < 1)
             {
                 // Some naughty mod added a prefab with no side screen content!
                 LogUIWarning("Could not find SideScreenContent on side screen: " +
                              screen.name);
             }
             else if (contents[0].GetType().FullName == targetClassName)
             {
                 // Once the first matching screen is found, perform insertion
                 if (insertBefore)
                 {
                     screens.Insert(i, newScreen);
                 }
                 else if (i >= n - 1)
                 {
                     screens.Add(newScreen);
                 }
                 else
                 {
                     screens.Insert(i + 1, newScreen);
                 }
                 found = true;
                 break;
             }
         }
         // Warn if no match found
         if (!found)
         {
             LogUIWarning("No side screen with class name {0} found!".F(
                              targetClassName));
             screens.Add(newScreen);
         }
     }
 }
예제 #3
0
            public static void Postfix(GameObject ___sideScreenContentBody, List <DetailsScreen.SideScreenRef> ___sideScreens)
            {
                var sideScreen = Gui.Create <ComboSensorSideScreen>(parent: ___sideScreenContentBody);

                var sideScreenRef = new DetailsScreen.SideScreenRef();

                sideScreenRef.name           = typeof(ComboSensorSideScreen).Name;
                sideScreenRef.screenPrefab   = sideScreen;
                sideScreenRef.screenInstance = sideScreen;

                ___sideScreens.Add(sideScreenRef);
            }
예제 #4
0
            public static void Postfix()
            {
                List <DetailsScreen.SideScreenRef> sideScreens = Traverse.Create(DetailsScreen.Instance).Field("sideScreens").GetValue <List <DetailsScreen.SideScreenRef> >();
                GameObject     sideScreenContentBody           = Traverse.Create(DetailsScreen.Instance).Field("sideScreenContentBody").GetValue <GameObject>();
                TestControl    controller = new TestControl();
                TestSideScreen screen     = controller.RootPanel.AddComponent <TestSideScreen>();

                screen.gameObject.transform.parent = sideScreenContentBody.transform;
                DetailsScreen.SideScreenRef myRef = new DetailsScreen.SideScreenRef {
                    name           = "TestSideScreen",
                    screenPrefab   = screen,
                    offset         = new Vector2(0f, 0f),
                    screenInstance = screen
                };
                sideScreens.Add(myRef);
            }
예제 #5
0
        /// <summary>
        /// Adds the specified side screen content to the side screen list. The side screen
        /// behavior should be defined in a class inherited from SideScreenContent.
        ///
        /// This method should be used in a postfix on DetailsScreen.OnPrefabInit.
        /// </summary>
        /// <typeparam name="T">The type of the controller that will determine how the side
        /// screen works. A new instance will be created and added as a component to the new
        /// side screen.</typeparam>
        /// <param name="targetClassName">The full name of the type of side screen to based to ordering
        /// around. An example of how this method can be used is:
        /// `AddSideScreenContentWithOrdering&lt;MySideScreen&gt;(typeof(CapacityControlSideScreen).FullName);`
        /// `typeof(TargetedSideScreen).FullName` is the suggested value of this parameter.
        /// Side screens from other mods can be used with their qualified names, even if no
        /// no reference to their type is available, but the target mod must have added their
        /// custom side screen to the list first.</param>
        /// <param name="insertBefore">Whether to insert the new screen before or after the
        /// target side screen in the list. Defaults to before (true).
        /// When inserting before the screen, if both are valid for a building then the side
        /// screen of type "T" will show below the one of type "fullName". When inserting after
        /// the screen, the reverse is true.</param>
        /// <param name="uiPrefab">The UI prefab to use. If null is passed, the UI should
        /// be created and added to the GameObject hosting the controller object in its
        /// constructor.</param>
        public static void AddSideScreenContentWithOrdering <T>(string targetClassName,
                                                                bool insertBefore = true, GameObject uiPrefab = null)
            where T : SideScreenContent
        {
            var inst = DetailsScreen.Instance;

            if (inst == null)
            {
                LogUIWarning("DetailsScreen is not yet initialized, try a postfix on " +
                             "DetailsScreen.OnPrefabInit");
            }
            else
            {
                var trInst = Traverse.Create(inst);
                // These are private fields
                var    screens = trInst.GetField <List <SideScreenRef> >("sideScreens");
                var    body    = trInst.GetField <GameObject>("sideScreenContentBody");
                string name    = typeof(T).Name;
                if (body != null && screens != null)
                {
                    // The ref normally contains a prefab which is instantiated
                    var newScreen = new SideScreenRef();
                    // Mimic the basic screens
                    var rootObject = PUIElements.CreateUI(body, name);
                    // Preserve the border by fitting the child
                    rootObject.AddComponent <BoxLayoutGroup>().Params = new BoxLayoutParams()
                    {
                        Direction = PanelDirection.Vertical, Alignment = TextAnchor.
                                                                         UpperCenter, Margin = new RectOffset(1, 1, 0, 1)
                    };
                    var controller = rootObject.AddComponent <T>();
                    if (uiPrefab != null)
                    {
                        // Add prefab if supplied
                        controller.ContentContainer = uiPrefab;
                        uiPrefab.transform.parent   = rootObject.transform;
                    }
                    newScreen.name = name;
                    // Offset is never used
                    newScreen.offset         = Vector2.zero;
                    newScreen.screenPrefab   = controller;
                    newScreen.screenInstance = controller;
                    InsertSideScreenContent(screens, newScreen, targetClassName, insertBefore);
                }
            }
        }
예제 #6
0
            public static void Postfix()
            {
                List <DetailsScreen.SideScreenRef> sideScreens = Traverse.Create(DetailsScreen.Instance).Field("sideScreens").GetValue <List <DetailsScreen.SideScreenRef> >();
                GameObject               sideScreenContentBody = Traverse.Create(DetailsScreen.Instance).Field("sideScreenContentBody").GetValue <GameObject>();
                GridFilterableControl    gridSelectControl     = new GridFilterableControl();
                GridFilterableSideScreen screen = gridSelectControl.RootPanel.AddComponent <GridFilterableSideScreen>();

                screen.gameObject.transform.parent = sideScreenContentBody.transform;
                PUIUtils.DebugObjectTree(sideScreenContentBody);
                DetailsScreen.SideScreenRef myRef = new DetailsScreen.SideScreenRef {
                    name           = "bob",
                    screenPrefab   = screen,
                    offset         = new Vector2(0f, 0f),
                    screenInstance = screen
                };
                sideScreens.Add(myRef);
                Console.WriteLine("Postfix patch was called and added in the side screen");
            }
예제 #7
0
        /// <summary>
        /// Adds the specified side screen content to the side screen list. The side screen
        /// behavior should be defined in a class inherited from SideScreenContent.
        /// </summary>
        /// <typeparam name="T">The type of the controller that will determine how the side
        /// screen works. A new instance will be created and added as a component to the new
        /// side screen.</typeparam>
        /// <param name="uiPrefab">The UI prefab to use. If null is passed, the UI should
        /// be created and added to the GameObject hosting the controller object in its
        /// OnPrefabInit function.</param>
        /// <param name="inOrder">If the insertion should be performed in some order. The default of
        /// false will simply insert at the end of the list which will make this screen appear
        /// at the top of every side screen it applies to. Set to true to perform insertion
        /// elsewhere in the list.</param>
        /// <param name="insertBefore">If the insertion should be done before "insertionName" or
        /// after "insertionName". True means before, false means after.</param>
        /// <param name="insertionName">The name of the side screen that you want to choose
        /// the ordering of this one around. Should be from this list:
        /// Telepad Side Screen
        /// Assignable Side Screen
        /// Valve Side Screen
        /// Tree Filterable Side Screen
        /// Single Entity Receptacle Screen
        /// Planter Side Screen
        /// SingleSliderScreen
        /// DualSliderScreen
        /// Timed Switch Side Screen
        /// Threshold Switch Side Screen
        /// Research Side Screen
        /// Filter Side Screen
        /// Access Control Side Screen
        /// ActivationRangeSideScreen
        /// Gene Shuffler Side Screen
        /// Sealed Door Side Screen
        /// Capacity Control Side Screen
        /// Door Toggle Side Screen
        /// Suit Locker Side Screen
        /// Lure Side Screen
        /// Role Station Side Screen
        /// Automatable Side Screen
        /// SingleButtonSideScreen
        /// IncubatorSideScreen
        /// IntSliderSideScreen
        /// SingleCheckboxSideScreen
        /// CommandModuleSideScreen
        /// CometDetectorSideScreen
        /// TelescopeSideScreen
        /// ComplexFabricatorSideScreen
        /// MinionSideScreen
        /// MonumentSideScreen
        /// Logic Filter Side Screen</param>
        public static void AddSideScreenContent <T>(GameObject uiPrefab = null, bool inOrder = false, bool insertBefore = true, string insertionName = null)
            where T : SideScreenContent
        {
            var inst = DetailsScreen.Instance;

            if (inst == null)
            {
                LogUIWarning("DetailsScreen is not yet initialized, try a postfix on " +
                             "DetailsScreen.OnPrefabInit");
                return;
            }
            if (inOrder && insertionName == null)
            {
                LogUIWarning("When specifying \"inOrder: true\" the \"insertionName\" must be non-null");
                return;
            }
            var trInst = Traverse.Create(inst);
            // These are private fields
            var    ss   = trInst.GetField <List <SideScreenRef> >("sideScreens");
            var    body = trInst.GetField <GameObject>("sideScreenContentBody");
            string name = typeof(T).Name;

            if (ss != null && body != null)
            {
                // The ref normally contains a prefab which is instantiated
                var newScreen = new SideScreenRef();
                // Mimic the basic screens
                var rootObject = new GameObject(name);
                PUIElements.SetParent(rootObject, body);
                rootObject.AddComponent <LayoutElement>();
                rootObject.AddComponent <VerticalLayoutGroup>();
                rootObject.AddComponent <CanvasRenderer>();
                var controller = rootObject.AddComponent <T>();
                if (uiPrefab != null)
                {
                    // Add prefab if supplied
                    controller.ContentContainer = uiPrefab;
                    uiPrefab.transform.parent   = rootObject.transform;
                }
                newScreen.name = name;
                // Never used
                newScreen.offset         = Vector2.zero;
                newScreen.screenPrefab   = controller;
                newScreen.screenInstance = controller;
                if (!inOrder)
                {
                    ss.Add(newScreen);
                }
                else
                {
                    for (var i = 0; i < ss.Count; i++)
                    {
                        if (ss[i].name.Equals(insertionName))
                        {
                            if (insertBefore)
                            {
                                ss.Insert(i, newScreen);
                            }
                            else
                            {
                                if (i + 1 >= ss.Count)
                                {
                                    ss.Add(newScreen);
                                }
                                else
                                {
                                    ss.Insert(i + 1, newScreen);
                                }
                            }
                            return;
                        }
                    }
                }
            }
        }