示例#1
0
        /// <summary>
        /// Creates the preview for a given light.
        ///
        /// RadiationGridManager.CreatePreview has no references so no sense in patching that
        /// yet.
        /// </summary>
        /// <param name="origin">The starting cell.</param>
        /// <param name="radius">The light radius.</param>
        /// <param name="shape">The light shape.</param>
        /// <param name="lux">The base brightness in lux.</param>
        /// <returns>true if the lighting was handled, or false otherwise.</returns>
        internal bool PreviewLight(int origin, float radius, LightShape shape, int lux)
        {
            bool handled = false;

            if (shape != LightShape.Circle && shape != LightShape.Cone)
            {
                var cells = DictionaryPool <int, float, PLightManager> .Allocate();

                // Replicate the logic of the original one...
                int index = shape - LightShape.Cone - 1;
                if (index < shapes.Count)
                {
                    // Found handler!
                    shapes[index].FillLight(CallingObject, origin, (int)radius, cells);
                    foreach (var pair in cells)
                    {
                        int cell = pair.Key;
                        if (Grid.IsValidCell(cell))
                        {
                            // Allow any fraction, not just linear falloff
                            int lightValue = (int)Math.Round(lux * pair.Value);
                            LightGridManager.previewLightCells.Add(new Tuple <int, int>(cell,
                                                                                        lightValue));
                            LightGridManager.previewLux[cell] = lightValue;
                        }
                    }
                    CallingObject = null;
                    handled       = true;
                }
                cells.Recycle();
            }
            return(handled);
        }
示例#2
0
        /// <summary>
        /// Handles a lighting system call. Not intended to be used - exists as a fallback.
        /// </summary>
        /// <param name="cell">The origin cell.</param>
        /// <param name="visiblePoints">The location where lit points will be stored.</param>
        /// <param name="range">The light radius.</param>
        /// <param name="shape">The light shape.</param>
        /// <returns>true if the lighting was handled, or false otherwise.</returns>
        internal bool GetVisibleCells(int cell, IList <int> visiblePoints, int range,
                                      LightShape shape)
        {
            int  index   = shape - LightShape.Cone - 1;
            bool handled = false;

            if (index >= 0 && index < shapes.Count)
            {
                var ps = shapes[index];
                // Do what we can, this only is reachable through methods we have patched
                var lux = DictionaryPool <int, float, PLightManager> .Allocate();

#if DEBUG
                PUtil.LogWarning("Unpatched call to GetVisibleCells; use LightGridEmitter." +
                                 "UpdateLitCells instead.");
#endif
                ps.FillLight(CallingObject, cell, range, lux);
                // Intensity does not matter
                foreach (var point in lux)
                {
                    visiblePoints.Add(point.Key);
                }
                lux.Recycle();
                handled = true;
            }
            return(handled);
        }
示例#3
0
        /// <summary>
        /// Updates the critter counts of visible pinned rows.
        /// </summary>
        internal void UpdateContents()
        {
            var ci = ClusterManager.Instance.activeWorld.GetComponent <CritterInventory>();

            if (ci != null)
            {
                var allCounts = DictionaryPool <Tag, CritterTotals, PinnedCritterManager> .
                                Allocate();

                foreach (var pair in pinnedObjects)
                {
                    allCounts.Clear();
                    ci.PopulateTotals(pair.Key, allCounts);
                    foreach (var speciesPair in pair.Value)
                    {
                        // Only refresh active rows
                        var entry = speciesPair.Value;
                        if (entry.gameObject.activeSelf)
                        {
                            int available = 0;
                            if (allCounts.TryGetValue(speciesPair.Key, out CritterTotals totals))
                            {
                                available = totals.Available;
                            }
                            RefreshLine(entry, available);
                        }
                    }
                }
                allCounts.Recycle();
            }
        }
示例#4
0
		/// <summary>
		/// Sorts the table's rows.
		/// </summary>
		/// <param name="instance">The table screen to sort.</param>
		private static void SortRows(TableScreen instance) {
			var rows = instance.all_sortable_rows;
			bool reversed = instance.sort_is_reversed;
			var comparison = new TableSortComparison(instance.active_sort_method, reversed);
			var dividerIndices = DictionaryPool<int, int, TableScreen>.Allocate();
			var dupesByWorld = DictionaryPool<int, TableRowList.PooledList, TableScreen>.
				Allocate();
			int index = 0;
			var entryList = instance.scroll_content_transform;
			UpdateHeaders(instance, reversed);
			GroupDupesByWorld(rows, dupesByWorld);
			rows.Clear();
			foreach (var pair in dupesByWorld) {
				var list = pair.Value;
				// 1 offset for the item added plus the number of items in this list
				dividerIndices.Add(pair.Key, index);
				index++;
				if (comparison.IsSortable)
					list.Sort(comparison);
				index += list.Count;
				rows.AddRange(list);
				list.Recycle();
			}
			dupesByWorld.Recycle();
			MoveRows(instance, rows, dividerIndices);
			dividerIndices.Recycle();
			// Schedule a freeze
			if (entryList != null && instance.isActiveAndEnabled)
				instance.StartCoroutine(FreezeLayouts(rows));
		}
示例#5
0
		/// <summary>
		/// Adds dividers for each planetoid in the Spaced Out DLC.
		/// </summary>
		/// <param name="instance">The table screen to update.</param>
		private static void AddDividers(TableScreen instance) {
			GameObject target;
			int id;
			var occupiedWorlds = DictionaryPool<int, WorldContainer, TableScreen>.Allocate();
			foreach (int worldId in ClusterManager.Instance.GetWorldIDsSorted())
				instance.AddWorldDivider(worldId);
			// List occupied planets
			foreach (object obj in Components.MinionAssignablesProxy)
				if (obj is MinionAssignablesProxy proxy && proxy != null && (target = proxy.
						GetTargetGameObject()) != null) {
					var world = target.GetMyWorld();
					if (world != null && !occupiedWorlds.ContainsKey(id = world.id))
						occupiedWorlds.Add(id, world);
				}
			foreach (var pair in instance.worldDividers)
				if (pair.Value.TryGetComponent(out HierarchyReferences hr)) {
					var dividerRow = hr.GetReference("NobodyRow");
					id = pair.Key;
					if (occupiedWorlds.TryGetValue(id, out WorldContainer world)) {
						dividerRow.gameObject.SetActive(false);
						pair.Value.SetActive(world.IsDiscovered);
					} else {
						dividerRow.gameObject.SetActive(true);
						pair.Value.SetActive(ClusterManager.Instance.GetWorld(id).IsDiscovered);
					}
				}
			occupiedWorlds.Recycle();
		}
示例#6
0
        /// <summary>
        /// Adds the correct descriptors to a critter info screen.
        /// </summary>
        /// <param name="critter">The critter to query.</param>
        /// <param name="descriptors">The location where the descriptors should be placed.</param>
        internal static void AddCritterDescriptors(GameObject critter,
                                                   IList <Descriptor> descriptors)
        {
            var drops = critter.GetComponentSafe <Butcherable>()?.Drops;

            // Check the meat it drops
            if (critter != null && drops != null && drops.Length > 0)
            {
                var dict = DictionaryPool <string, int, FoodRecipeCache> .Allocate();

                GetEggsPerCycle(critter, out float replacement, out float noReplacement);
                // Find out what it drops when it dies - critters always die so the
                // no-replacement rate must be positive
                CollectDrops(drops, dict);
                foreach (var pair in dict)
                {
                    CreateDescriptors(TagManager.Create(pair.Key), descriptors,
                                      pair.Value * noReplacement, FoodDescriptorTexts.CRITTERS);
                }
                dict.Recycle();
                // How much omelette can the egg be made into? Babies are excluded here
                var fertDef = critter.GetDef <FertilityMonitor.Def>();
                if (fertDef != null)
                {
                    CreateDescriptors(fertDef.eggPrefab, descriptors, replacement,
                                      FoodDescriptorTexts.CRITTERS);
                }
            }
        }
        /// <summary>
        /// Initializes the available mass by element display.
        /// </summary>
        /// <param name="panel">The parent info panel.</param>
        /// <param name="harvestable">The POI to be harvested.</param>
        /// <param name="details">The panel to refresh.</param>
        private void InitElements(SpacePOISimpleInfoPanel panel, HarvestablePOIStates.
                                  Instance harvestable, CollapsibleDetailContentPanel details)
        {
            var elementRows  = panel.elementRows;
            var existingRows = DictionaryPool <Tag, GameObject, SpacePOISimpleInfoPanel> .
                               Allocate();

            foreach (var pair in panel.elementRows)
            {
                existingRows[pair.Key] = pair.Value;
            }
            if (harvestable != null)
            {
                // Shared dictionary, does not allocate
                var sortedElements = ListPool <ElementWeight, SpacePOISimpleInfoPanel> .
                                     Allocate();

                sortedElements.AddRange(harvestable.configuration.GetElementsWithWeights());
                sortedElements.Sort(SortElementsByMassComparer.Instance);
                int n = sortedElements.Count;
                for (int i = 0; i < n; i++)
                {
                    var       pair       = sortedElements[i];
                    SimHashes element    = pair.Key;
                    Tag       elementTag = new Tag(element.ToString());
                    if (!elementRows.TryGetValue(elementTag, out GameObject row))
                    {
                        row = Util.KInstantiateUI(panel.simpleInfoRoot.iconLabelRow, details.
                                                  Content.gameObject, true);
                        elementRows[elementTag] = row;
                    }
                    else
                    {
                        row.SetActive(true);
                    }
                    if (row.TryGetComponent(out HierarchyReferences hr))
                    {
                        var uiSprite = Def.GetUISprite(elementTag, "ui", false);
                        var icon     = hr.GetReference <Image>("Icon");
                        if (uiSprite != null)
                        {
                            icon.sprite = uiSprite.first;
                            icon.color  = uiSprite.second;
                        }
                        hr.GetReference <LocText>("NameLabel").SetText(ElementLoader.
                                                                       FindElementByHash(element).name);
                        hr.GetReference <LocText>("ValueLabel").alignment = TMPro.
                                                                            TextAlignmentOptions.MidlineRight;
                    }
                    existingRows.Remove(elementTag);
                }
                sortedElements.Recycle();
            }
            // Turn off all rows that were not turned on
            foreach (var pair in existingRows)
            {
                pair.Value.SetActive(false);
            }
            existingRows.Recycle();
        }
        /// <summary>
        /// Updates a critter resource category header.
        /// </summary>
        /// <param name="header">The category header to update.</param>
        /// <param name="type">The critter type it contains (can be pulled from the CritterResourceInfo component).</param>
        public static void Update(this ResourceCategoryHeader header, CritterType type)
        {
            var totals = DictionaryPool <Tag, CritterTotals, ResourceCategoryHeader> .Allocate();

            var all        = CritterInventoryUtils.FindCreatures(totals, type);
            var discovered = header.ResourcesDiscovered;
            var trCategory = Traverse.Create(header);

            // Previously discovered but now extinct critters need an empty entry
            foreach (var pair in discovered)
            {
                var species = pair.Key;
                if (!totals.ContainsKey(species))
                {
                    totals.Add(species, new CritterTotals());
                }
            }
            // Go through resource entries for each species and update them
            foreach (var pair in totals)
            {
                var quantity = pair.Value;
                var species  = pair.Key;
                // Look up the species to see if we have found it already
                if (!discovered.TryGetValue(species, out ResourceEntry entry))
                {
                    entry = trCategory.CallMethod <ResourceEntry>("NewResourceEntry",
                                                                  species, GameUtil.MeasureUnit.quantity);
                    entry.SetName(species.ProperName());
                    // Add component to tag it as wild/tame
                    entry.gameObject.AddComponent <CritterResourceInfo>().CritterType = type;
                    discovered.Add(species, entry);
                }
                UpdateEntry(entry, quantity);
            }
            bool anyDiscovered = discovered.Count > 0;

            // Enable display and open/close based on critter presence
            header.elements.QuantityText.SetText(all.Available.ToString());
            trCategory.CallMethod("SetActiveColor", all.HasAny);
            trCategory.CallMethod("SetInteractable", anyDiscovered);
            // Still need to set this for expand/contract to work
            trCategory.SetField("anyDiscovered", anyDiscovered);
            // Update category tooltip
            var tooltip = trCategory.GetField <ToolTip>("tooltip");

            if (tooltip != null)
            {
                tooltip.OnToolTip = null;
                tooltip.toolTip   = CritterInventoryUtils.FormatTooltip(header.elements.
                                                                        LabelText.text, all);
            }
            // Disabled until coolazura's tags are up to date
#if false
            FavoritesCategoryCompat(totals, type);
#endif
            totals.Recycle();
        }
示例#9
0
        /// <summary>
        /// Initializes and computes horizontal sizes for the components in this relative
        /// layout.
        /// </summary>
        /// <param name="children">The location to store information about these components.</param>
        /// <param name="all">The components to lay out.</param>
        /// <param name="constraints">The constraints defined for these components.</param>
        internal static void CalcX(this ICollection <RelativeLayoutResults> children,
                                   RectTransform all, IDictionary <GameObject, RelativeLayoutParams> constraints)
        {
            var comps = ListPool <Component, RelativeLayoutGroup> .Allocate();

            var paramMap = DictionaryPool <GameObject, RelativeLayoutResults,
                                           RelativeLayoutGroup> .Allocate();

            int n = all.childCount;

            children.Clear();
            for (int i = 0; i < n; i++)
            {
                var child = all.GetChild(i)?.gameObject;
                if (child != null)
                {
                    comps.Clear();
                    // Calculate the preferred size using all layout components
                    child.GetComponents(comps);
                    var horiz = PUIUtils.CalcSizes(child, PanelDirection.Horizontal, comps);
                    if (!horiz.ignore)
                    {
                        RelativeLayoutResults ip;
                        float w = horiz.preferred;
                        if (constraints.TryGetValue(child, out RelativeLayoutParams cons))
                        {
                            ip = new RelativeLayoutResults(child.rectTransform(), cons);
                            // Set override size by axis if necessary
                            var overrideSize = ip.OverrideSize;
                            if (overrideSize.x > 0.0f)
                            {
                                w = overrideSize.x;
                            }
                            paramMap[child] = ip;
                        }
                        else
                        {
                            // Default its layout to fill all
                            ip = new RelativeLayoutResults(child.rectTransform(), null);
                        }
                        ip.PreferredWidth = w;
                        children.Add(ip);
                    }
                }
            }
            // Resolve object references to other children
            foreach (var ip in children)
            {
                ip.TopParams    = InitResolve(ip.TopEdge, paramMap);
                ip.BottomParams = InitResolve(ip.BottomEdge, paramMap);
                ip.LeftParams   = InitResolve(ip.LeftEdge, paramMap);
                ip.RightParams  = InitResolve(ip.RightEdge, paramMap);
                // All of these will die simultaneously when the list is recycled
            }
            paramMap.Recycle();
            comps.Recycle();
        }
示例#10
0
        /// <summary>
        /// Finds selectable objects for creating info cards.
        /// </summary>
        /// <param name="cell">The cell to search.</param>
        /// <param name="coords">The raw mouse coordinates.</param>
        /// <param name="hits">The location where all hits will be stored.</param>
        /// <param name="compareSet">The set of objects to compare.</param>
        private static void FindSelectables(int cell, Vector3 coords, List <KSelectable> hits,
                                            ISet <Component> compareSet)
        {
            var gsp  = GameScenePartitioner.Instance;
            var seen = DictionaryPool <KSelectable, float, SelectTool> .Allocate();

            var xy = new Vector2(coords.x, coords.y);

            // The override might already be there
            foreach (var obj in hits)
            {
                seen[obj] = -100.0f;
            }
            AddStatusIntersections(seen, xy);
            var entries = ListPool <ScenePartitionerEntry, SelectTool> .Allocate();

            Grid.CellToXY(cell, out int x, out int y);
            gsp.GatherEntries(x, y, 1, 1, gsp.collisionLayer, entries);
            foreach (var entry in entries)
            {
                if (entry.obj is KCollider2D collider && collider.Intersects(xy))
                {
                    if (!collider.TryGetComponent(out KSelectable selectable))
                    {
                        selectable = collider.GetComponentInParent <KSelectable>();
                    }
                    if (selectable != null && selectable.IsSelectable)
                    {
                        float distance = selectable.transform.GetPosition().z - coords.z;
                        if (seen.TryGetValue(selectable, out float oldDistance))
                        {
                            seen[selectable] = Mathf.Min(oldDistance, distance);
                        }
                        else
                        {
                            seen.Add(selectable, distance);
                        }
                    }
                }
            }
            entries.Recycle();
            hits.Clear();
            foreach (var pair in seen)
            {
                var selectable = pair.Key;
                compareSet.Add(selectable);
                hits.Add(selectable);
            }
            seen.Recycle();
            // Sort the hits; compares fewer objects at the expense of comparing a slightly
            // different behaviour (the original compares the collider)
            hits.Sort(COMPARE_SELECTABLES);
        }
示例#11
0
        /// <summary>
        /// Updates the critter resource category header.
        /// </summary>
        /// <param name="anyDiscovered">A reference to the anyDiscovered field in header.</param>
        internal void UpdateHeader(ref bool anyDiscovered)
        {
            var ci = ClusterManager.Instance.activeWorld.GetComponent <CritterInventory>();

            if (ci != null)
            {
                var totals = DictionaryPool <Tag, CritterTotals, ResourceCategoryHeader> .
                             Allocate();

                var all        = ci.PopulateTotals(CritterType, totals);
                var discovered = header.ResourcesDiscovered;
                // Previously discovered but now extinct critters need an empty entry
                foreach (var pair in discovered)
                {
                    var species = pair.Key;
                    if (!totals.ContainsKey(species))
                    {
                        totals.Add(species, new CritterTotals());
                    }
                }
                // Go through resource entries for each species and update them
                foreach (var pair in totals)
                {
                    var quantity = pair.Value;
                    var species  = pair.Key;
                    // Look up the species to see if we have found it already
                    if (!discovered.TryGetValue(species, out ResourceEntry entry))
                    {
                        discovered.Add(species, entry = NewResourceEntry(header, species,
                                                                         CritterType));
                    }
                    var cre = entry.GetComponent <CritterResourceEntry>();
                    if (cre != null)
                    {
                        cre.UpdateEntry(quantity);
                    }
                }
                // Still need to set this for expand/contract to work
                anyDiscovered = discovered.Count > 0;
                // Enable display and open/close based on critter presence
                header.elements.QuantityText.SetText(all.Available.ToString());
                SET_ACTIVE_COLOR.Invoke(header, all.HasAny);
                SET_INTERACTABLE.Invoke(header, anyDiscovered);
                // Update category tooltip
                var tooltip = header.GetComponent <ToolTip>();
                if (tooltip != null)
                {
                    tooltip.OnToolTip = OnAllTooltip;
                }
                totals.Recycle();
            }
        }
示例#12
0
        /// <summary>
        /// Adds ElementConsumer range previews to the specified building def.
        /// </summary>
        /// <param name="def">The preview to add.</param>
        private static void AddConsumerPreview(BuildingDef def)
        {
            GameObject complete = def.BuildingComplete, preview = def.BuildingPreview,
                       inBuild = def.BuildingUnderConstruction;
            var consumers      = complete.GetComponents <ElementConsumer>();
            int n        = consumers.Length;
            var existing = DictionaryPool <CellOffset, int, ElementConsumer> .Allocate();

            foreach (var consumer in consumers)
            {
                // Avoid stomping the range preview of Wall Vents and Pumps
                if (consumer.GetType().FullName != IGNORE_WALLPUMPS)
                {
                    int radius = consumer.consumptionRadius & 0xFF;
                    var sco    = consumer.sampleCellOffset;
                    var color  = Color.white;
                    var offset = new CellOffset(Mathf.RoundToInt(sco.x), Mathf.RoundToInt(
                                                    sco.y));
                    // Make secondary consumers a color related to their element
                    if (n > 1 && consumer.configuration == ElementConsumer.Configuration.
                        Element)
                    {
                        var target = ElementLoader.FindElementByHash(consumer.
                                                                     elementToConsume);
                        if (target != null)
                        {
                            color = target.substance.conduitColour;
                        }
                    }
                    if (!existing.TryGetValue(offset, out int oldRad) || radius != oldRad)
                    {
                        PUtil.LogDebug("Visualizer added to {0}, range {1:D}".F(def.PrefabID,
                                                                                radius));
                        ElementConsumerVisualizer.Create(complete, offset, radius, color);
                        // Consumer found, update the preview and under construction versions
                        if (preview != null)
                        {
                            // Previews should always be white as other colors are hard to see
                            // on overlays
                            ElementConsumerVisualizer.Create(preview, offset, radius);
                        }
                        if (inBuild != null)
                        {
                            ElementConsumerVisualizer.Create(inBuild, offset, radius, color);
                        }
                        existing[offset] = radius;
                    }
                }
            }
            existing.Recycle();
        }
示例#13
0
            /// <summary>
            /// Applied before AddTechToQueue runs.
            /// </summary>
            internal static bool Prefix(List <TechInstance> ___queuedTech,
                                        Tech tech)
            {
                var dict = DictionaryPool <string, TechInstance, Research> .Allocate();

                var techList = ListPool <TechInstance, Research> .Allocate();

                AddTechToQueue(___queuedTech, dict, tech);
                // Sort by tech level and add at end
                techList.AddRange(dict.Values);
                techList.Sort(TechTierSorter.Instance);
                ___queuedTech.AddRange(techList);
                // Update display
                UpdateResearchOrder(___queuedTech);
                dict.Recycle();
                techList.Recycle();
                return(false);
            }
示例#14
0
        public override GameObject Build()
        {
            var panel   = PUIElements.CreateUI(null, Name);
            var mapping = DictionaryPool <IUIComponent, GameObject, PRelativePanel> .Allocate();

            SetImage(panel);
            // Realize each component and add them to the panel
            foreach (var pair in constraints)
            {
                var component = pair.Key;
                var realized  = component.Build();
                realized.SetParent(panel);
                // We were already guaranteed that there were no duplicate keys
                mapping[component] = realized;
            }
            // Add layout component
            var layout = panel.AddComponent <RelativeLayoutGroup>();

            layout.Margin = Margin;
            foreach (var pair in constraints)
            {
                var realized  = mapping[pair.Key];
                var rawParams = pair.Value;
                var newParams = new RelativeLayoutParams();
                // Copy all of the settings
                Resolve(newParams.TopEdge, rawParams.TopEdge, mapping);
                Resolve(newParams.BottomEdge, rawParams.BottomEdge, mapping);
                Resolve(newParams.LeftEdge, rawParams.LeftEdge, mapping);
                Resolve(newParams.RightEdge, rawParams.RightEdge, mapping);
                newParams.OverrideSize = rawParams.OverrideSize;
                newParams.Insets       = rawParams.Insets;
                layout.SetRaw(realized, newParams);
            }
            if (!DynamicSize)
            {
                layout.LockLayout();
            }
            mapping.Recycle();
            // Set flex size
            layout.flexibleWidth  = FlexSize.x;
            layout.flexibleHeight = FlexSize.y;
            InvokeRealize(panel);
            return(panel);
        }
示例#15
0
        /// <summary>
        /// Goes through the research screen and updates titles for techs in the queue.
        /// </summary>
        /// <param name="queuedTech">The current research queue.</param>
        private static void UpdateResearchOrder(IList <TechInstance> queuedTech)
        {
            var inst   = ManagementMenu.Instance;
            var screen = (inst == null) ? null : RESEARCH_SCREEN.Get(inst);

            if (queuedTech == null)
            {
                throw new ArgumentNullException("queuedTech");
            }
            int n = queuedTech.Count;

            if (screen != null && RESEARCH_NAME != null)
            {
                // O(N^2) sucks
                var techIndex = DictionaryPool <string, int, ResearchScreen> .Allocate();

                for (int i = 0; i < n; i++)
                {
                    techIndex.Add(queuedTech[i].tech.Id, i + 1);
                }
                LocText lt;
                foreach (var tech in Db.Get().Techs.resources)
                {
                    var entry = screen.GetEntry(tech);
                    // Update all techs with the order count
                    if (entry != null && (lt = RESEARCH_NAME.Get(entry)) != null)
                    {
                        if (techIndex.TryGetValue(tech.Id, out int order))
                        {
                            lt.SetText(string.Format(ResearchQueueStrings.QueueFormat, tech.
                                                     Name, order));
                        }
                        else
                        {
                            lt.SetText(tech.Name);
                        }
                    }
                }
                techIndex.Recycle();
            }
        }
示例#16
0
        /// <summary>
        /// Goes through the research screen and updates titles for techs in the queue.
        /// </summary>
        /// <param name="queuedTech">The current research queue.</param>
        private static void UpdateResearchOrder(IList <TechInstance> queuedTech)
        {
            var screen = ManagementMenu.Instance?.researchScreen as ResearchScreen;

            if (queuedTech == null)
            {
                throw new ArgumentNullException("queuedTech");
            }
            int n = queuedTech.Count;

            if (screen != null)
            {
                // O(N^2) sucks
                var techIndex = DictionaryPool <string, int, ResearchScreen> .Allocate();

                for (int i = 0; i < n; i++)
                {
                    techIndex.Add(queuedTech[i].tech.Id, i + 1);
                }
                foreach (var tech in Db.Get().Techs.resources)
                {
                    var entry = screen.GetEntry(tech);
                    // Update all techs with the order count
                    if (entry != null)
                    {
                        var lt = Traverse.Create(entry).GetField <LocText>("researchName");
                        if (techIndex.TryGetValue(tech.Id, out int order))
                        {
                            lt?.SetText(string.Format(ResearchQueueStrings.QueueFormat, tech.
                                                      Name, order));
                        }
                        else
                        {
                            lt?.SetText(tech.Name);
                        }
                    }
                }
                techIndex.Recycle();
            }
        }
示例#17
0
        /// <summary>
        /// Updates the headings for the entire category.
        /// </summary>
        internal void UpdateContents()
        {
            var ci = ClusterManager.Instance.activeWorld.GetComponent <CritterInventory>();

            if (ci != null)
            {
                var allTotals = DictionaryPool <Tag, CritterTotals, CritterResourceRowGroup> .
                                Allocate();

                var totals = ci.PopulateTotals(CritterType, allTotals);
                refs.GetReference <LocText>("AvailableLabel").SetText(GameUtil.
                                                                      GetFormattedSimple(totals.Available));
                refs.GetReference <LocText>("TotalLabel").SetText(GameUtil.
                                                                  GetFormattedSimple(totals.Total));
                refs.GetReference <LocText>("ReservedLabel").SetText(GameUtil.
                                                                     GetFormattedSimple(totals.Reserved));
                foreach (var resource in resources)
                {
                    resource.Value.UpdateContents(allTotals, ci);
                }
                allTotals.Recycle();
            }
        }
示例#18
0
        /// <summary>
        /// Creates a ZIP file of the old mod contents merged with the saved configs at
        /// tempFilePath.
        /// </summary>
        /// <param name="copied">The number of configuration files backed up.</param>
        /// <returns>true if successful, or false if an I/O error occurred.</returns>
        public bool CreateMergedPackage(out int copied)
        {
            bool ok     = false;
            var  toCopy = HashSetPool <string, ConfigBackupUtility> .Allocate();

            var toAdd = DictionaryPool <string, string, ConfigBackupUtility> .Allocate();

            // Open old ZIP file
            copied = 0;
            try {
                using (var src = new ZipFile(oldFilePath)) {
                    foreach (var entry in src)
                    {
                        // Klei normalizes the file names to forward slashes
                        toCopy.Add(FileSystem.Normalize(entry.FileName));
                    }
                    FindFilesToCopy(toCopy, toAdd);
                    using (var dst = new ZipFile(tempFilePath)) {
                        CopyFiles(src, dst, toCopy, toAdd);
                        dst.Save();
                        copied = toAdd.Count;
                        PUtil.LogDebug("Config backup for {0} copied {1:D} files".F(modFolder,
                                                                                    copied));
                    }
                }
                ok = true;
            } catch (IOException e) {
                PUtil.LogWarning("Unable to backup mod configs:");
                PUtil.LogExcWarn(e);
            } catch (UnauthorizedAccessException e) {
                PUtil.LogWarning("Unable to backup mod configs:");
                PUtil.LogExcWarn(e);
            }
            toAdd.Recycle();
            toCopy.Recycle();
            return(ok);
        }
示例#19
0
        /// <summary>
        /// Creates new rows if necessary for each critter species, and sorts them by name.
        /// </summary>
        /// <param name="allResources">The parent window for the rows.</param>
        internal void SpawnRows(AllResourcesScreen allResources)
        {
            var ci = ClusterManager.Instance.activeWorld.GetComponent <CritterInventory>();

            if (ci != null)
            {
                var allCritters = DictionaryPool <Tag, CritterTotals, CritterResourceRowGroup> .
                                  Allocate();

                ci.PopulateTotals(CritterType, allCritters);
                bool dirty = false;
                // Insert new rows where necessary
                foreach (var pair in allCritters)
                {
                    var species = pair.Key;
                    if (!resources.ContainsKey(species))
                    {
                        resources.Add(species, Create(allResources, species));
                        dirty = true;
                    }
                }
                // Iterate and place in SORTED order in the UI
                if (dirty)
                {
                    foreach (var resource in resources)
                    {
                        resource.Value.gameObject.transform.SetAsLastSibling();
                    }
                }
                allCritters.Recycle();
                if (dirty)
                {
                    UpdateContents();
                }
            }
        }
示例#20
0
    private void UpdateOpenOrders()
    {
        ComplexRecipe[] recipes = GetRecipes();
        if (recipes.Length != openOrderCounts.Count)
        {
            Debug.LogErrorFormat(base.gameObject, "Recipe count {0} doesn't match open order count {1}", recipes.Length, openOrderCounts.Count);
        }
        bool flag = false;

        hasOpenOrders = false;
        for (int i = 0; i < recipes.Length; i++)
        {
            ComplexRecipe recipe = recipes[i];
            int           recipePrefetchCount = GetRecipePrefetchCount(recipe);
            if (recipePrefetchCount > 0)
            {
                hasOpenOrders = true;
            }
            int num = openOrderCounts[i];
            if (num != recipePrefetchCount)
            {
                if (recipePrefetchCount < num)
                {
                    flag = true;
                }
                openOrderCounts[i] = recipePrefetchCount;
            }
        }
        DictionaryPool <Tag, float, ComplexFabricator> .PooledDictionary pooledDictionary = DictionaryPool <Tag, float, ComplexFabricator> .Allocate();

        DictionaryPool <Tag, float, ComplexFabricator> .PooledDictionary pooledDictionary2 = DictionaryPool <Tag, float, ComplexFabricator> .Allocate();

        for (int j = 0; j < openOrderCounts.Count; j++)
        {
            int num2 = openOrderCounts[j];
            if (num2 > 0)
            {
                ComplexRecipe complexRecipe = recipe_list[j];
                ComplexRecipe.RecipeElement[] ingredients = complexRecipe.ingredients;
                ComplexRecipe.RecipeElement[] array       = ingredients;
                foreach (ComplexRecipe.RecipeElement recipeElement in array)
                {
                    pooledDictionary[recipeElement.material] = inStorage.GetAmountAvailable(recipeElement.material);
                }
            }
        }
        for (int l = 0; l < recipe_list.Length; l++)
        {
            int num3 = openOrderCounts[l];
            if (num3 > 0)
            {
                ComplexRecipe complexRecipe2 = recipe_list[l];
                ComplexRecipe.RecipeElement[] ingredients2 = complexRecipe2.ingredients;
                ComplexRecipe.RecipeElement[] array2       = ingredients2;
                foreach (ComplexRecipe.RecipeElement recipeElement2 in array2)
                {
                    float num4 = recipeElement2.amount * (float)num3;
                    float num5 = num4 - pooledDictionary[recipeElement2.material];
                    if (num5 > 0f)
                    {
                        pooledDictionary2.TryGetValue(recipeElement2.material, out float value);
                        pooledDictionary2[recipeElement2.material] = value + num5;
                        pooledDictionary[recipeElement2.material]  = 0f;
                    }
                    else
                    {
                        DictionaryPool <Tag, float, ComplexFabricator> .PooledDictionary pooledDictionary3;
                        Tag material;
                        (pooledDictionary3 = pooledDictionary)[material = recipeElement2.material] = pooledDictionary3[material] - num4;
                    }
                }
            }
        }
        if (flag)
        {
            CancelFetches();
        }
        if (pooledDictionary2.Count > 0)
        {
            UpdateFetches(pooledDictionary2);
        }
        UpdateMaterialNeeds(pooledDictionary2);
        pooledDictionary2.Recycle();
        pooledDictionary.Recycle();
    }
        /// <summary>
        /// The better and more optimized UpdatePickups. Aggregate runtime on a test world
        /// dropped from ~60 ms/1000 ms to ~45 ms/1000 ms.
        /// </summary>
        private static void UpdatePickups(FetchManager.FetchablesByPrefabId targets,
                                          Navigator navigator, GameObject worker)
        {
            var canBePickedUp = DictionaryPool <PickupTagKey, FetchManager.Pickup,
                                                FetchManager> .Allocate();

            var pathCosts = DictionaryPool <int, int, FetchManager> .Allocate();

            var finalPickups = targets.finalPickups;
            // Will reflect the changes from Waste Not, Want Not and No Manual Delivery
            var comparer = PICKUP_COMPARER.Get(null);

            foreach (var fetchable in targets.fetchables.GetDataList())
            {
                var target = fetchable.pickupable;
                int cell   = target.cachedCell;
                if (target.CouldBePickedUpByMinion(worker))
                {
                    // Look for cell cost, share costs across multiple queries to a cell
                    if (!pathCosts.TryGetValue(cell, out int cost))
                    {
                        pathCosts.Add(cell, cost = target.GetNavigationCost(navigator, cell));
                    }
                    // Exclude unreachable items
                    if (cost >= 0)
                    {
                        int hash      = fetchable.tagBitsHash;
                        var key       = new PickupTagKey(hash, target.KPrefabID);
                        var candidate = new FetchManager.Pickup {
                            pickupable     = target, tagBitsHash = hash, PathCost = (ushort)cost,
                            masterPriority = fetchable.masterPriority, freshness = fetchable.
                                                                                   freshness, foodQuality = fetchable.foodQuality
                        };
                        if (canBePickedUp.TryGetValue(key, out FetchManager.Pickup current))
                        {
                            // Is the new one better?
                            int result = comparer.Compare(current, candidate);
                            if (result > 0 || (result == 0 && candidate.pickupable.
                                               UnreservedAmount > current.pickupable.UnreservedAmount))
                            {
                                canBePickedUp[key] = candidate;
                            }
                        }
                        else
                        {
                            canBePickedUp.Add(key, candidate);
                        }
                    }
                }
            }
            // Copy the remaining pickups to the list, there are now way fewer because only
            // one was kept per possible tag bits (with the highest priority, best path cost,
            // etc)
            finalPickups.Clear();
            foreach (var pair in canBePickedUp)
            {
                finalPickups.Add(pair.Value);
            }
            pathCosts.Recycle();
            canBePickedUp.Recycle();
        }
示例#22
0
        public void SendMetricsEvent()
        {
            ListPool <string, Manager> .PooledList pooledList = ListPool <string, Manager> .Allocate();

            foreach (Mod mod in mods)
            {
                if (mod.enabled)
                {
                    pooledList.Add(mod.title);
                }
            }
            DictionaryPool <string, object, Manager> .PooledDictionary pooledDictionary = DictionaryPool <string, object, Manager> .Allocate();

            pooledDictionary["ModCount"] = pooledList.Count;
            pooledDictionary["Mods"]     = pooledList;
            ThreadedHttps <KleiMetrics> .Instance.SendEvent(pooledDictionary);

            pooledDictionary.Recycle();
            pooledList.Recycle();
            KCrashReporter.haveActiveMods = (pooledList.Count > 0);
        }
示例#23
0
    public void Render1000ms(float dt)
    {
        DictionaryPool <int, ListPool <FetchList2, FetchListStatusItemUpdater> .PooledList, FetchListStatusItemUpdater> .PooledDictionary pooledDictionary = DictionaryPool <int, ListPool <FetchList2, FetchListStatusItemUpdater> .PooledList, FetchListStatusItemUpdater> .Allocate();

        foreach (FetchList2 fetchList in fetchLists)
        {
            if (!((Object)fetchList.Destination == (Object)null))
            {
                ListPool <FetchList2, FetchListStatusItemUpdater> .PooledList value = null;
                int instanceID = fetchList.Destination.GetInstanceID();
                if (!pooledDictionary.TryGetValue(instanceID, out value))
                {
                    value = (pooledDictionary[instanceID] = ListPool <FetchList2, FetchListStatusItemUpdater> .Allocate());
                }
                value.Add(fetchList);
            }
        }
        DictionaryPool <Tag, float, FetchListStatusItemUpdater> .PooledDictionary pooledDictionary2 = DictionaryPool <Tag, float, FetchListStatusItemUpdater> .Allocate();

        DictionaryPool <Tag, float, FetchListStatusItemUpdater> .PooledDictionary pooledDictionary3 = DictionaryPool <Tag, float, FetchListStatusItemUpdater> .Allocate();

        foreach (KeyValuePair <int, ListPool <FetchList2, FetchListStatusItemUpdater> .PooledList> item in pooledDictionary)
        {
            ListPool <Tag, FetchListStatusItemUpdater> .PooledList pooledList2 = ListPool <Tag, FetchListStatusItemUpdater> .Allocate();

            Storage destination = item.Value[0].Destination;
            foreach (FetchList2 item2 in item.Value)
            {
                item2.UpdateRemaining();
                Dictionary <Tag, float> remaining = item2.GetRemaining();
                foreach (KeyValuePair <Tag, float> item3 in remaining)
                {
                    if (!pooledList2.Contains(item3.Key))
                    {
                        pooledList2.Add(item3.Key);
                    }
                }
            }
            ListPool <Pickupable, FetchListStatusItemUpdater> .PooledList pooledList3 = ListPool <Pickupable, FetchListStatusItemUpdater> .Allocate();

            foreach (GameObject item4 in destination.items)
            {
                if (!((Object)item4 == (Object)null))
                {
                    Pickupable component = item4.GetComponent <Pickupable>();
                    if (!((Object)component == (Object)null))
                    {
                        pooledList3.Add(component);
                    }
                }
            }
            DictionaryPool <Tag, float, FetchListStatusItemUpdater> .PooledDictionary pooledDictionary4 = DictionaryPool <Tag, float, FetchListStatusItemUpdater> .Allocate();

            foreach (Tag item5 in pooledList2)
            {
                float num = 0f;
                foreach (Pickupable item6 in pooledList3)
                {
                    if (item6.KPrefabID.HasTag(item5))
                    {
                        num += item6.TotalAmount;
                    }
                }
                pooledDictionary4[item5] = num;
            }
            foreach (Tag item7 in pooledList2)
            {
                if (!pooledDictionary2.ContainsKey(item7))
                {
                    pooledDictionary2[item7] = WorldInventory.Instance.GetTotalAmount(item7);
                }
                if (!pooledDictionary3.ContainsKey(item7))
                {
                    pooledDictionary3[item7] = WorldInventory.Instance.GetAmount(item7);
                }
            }
            foreach (FetchList2 item8 in item.Value)
            {
                bool should_add  = false;
                bool should_add2 = true;
                bool should_add3 = false;
                Dictionary <Tag, float> remaining2 = item8.GetRemaining();
                foreach (KeyValuePair <Tag, float> item9 in remaining2)
                {
                    Tag   key           = item9.Key;
                    float value2        = item9.Value;
                    float num2          = pooledDictionary4[key];
                    float b             = pooledDictionary2[key];
                    float num3          = pooledDictionary3[key];
                    float num4          = Mathf.Min(value2, b);
                    float num5          = num3 + num4;
                    float minimumAmount = item8.GetMinimumAmount(key);
                    if (num2 + num5 < minimumAmount)
                    {
                        should_add = true;
                    }
                    if (num5 < value2)
                    {
                        should_add2 = false;
                    }
                    if (num2 + num5 > value2 && value2 > num5)
                    {
                        should_add3 = true;
                    }
                }
                item8.UpdateStatusItem(Db.Get().BuildingStatusItems.WaitingForMaterials, ref item8.waitingForMaterialsHandle, should_add2);
                item8.UpdateStatusItem(Db.Get().BuildingStatusItems.MaterialsUnavailable, ref item8.materialsUnavailableHandle, should_add);
                item8.UpdateStatusItem(Db.Get().BuildingStatusItems.MaterialsUnavailableForRefill, ref item8.materialsUnavailableForRefillHandle, should_add3);
            }
            pooledDictionary4.Recycle();
            pooledList3.Recycle();
            pooledList2.Recycle();
            item.Value.Recycle();
        }
        pooledDictionary3.Recycle();
        pooledDictionary2.Recycle();
        pooledDictionary.Recycle();
    }
示例#24
0
        /// <summary>
        /// Applies decor values from the database.
        /// </summary>
        internal static void ApplyDatabase(DecorReimaginedOptions options)
        {
            DecorDbEntry[] entries = null;
            try {
                // Read in database from the embedded config json
                using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(
                           "PeterHan.DecorRework.buildings.json")) {
                    var jr = new JsonTextReader(new StreamReader(stream));
                    entries = new JsonSerializer {
                        MaxDepth = 2
                    }.Deserialize <DecorDbEntry[]>(jr);
                    jr.Close();
                }
            } catch (JsonException e) {
                // Error when loading decor
                PUtil.LogExcWarn(e);
            } catch (IOException e) {
                // Error when loading decor
                PUtil.LogExcWarn(e);
            }
            if (entries != null)
            {
                var editDecor = DictionaryPool <string, DecorDbEntry, DecorDbEntry> .Allocate();

                string id;
                // Add to dictionary, way faster
                foreach (var entry in entries)
                {
                    if (!string.IsNullOrEmpty(id = entry.id) && !editDecor.ContainsKey(id))
                    {
                        editDecor.Add(id, entry);
                    }
                }
                foreach (var def in Assets.BuildingDefs)
                {
                    if (editDecor.TryGetValue(id = def.PrefabID, out DecorDbEntry entry))
                    {
                        float decor    = entry.decor;
                        int   radius   = entry.radius;
                        var   provider = def.BuildingComplete.GetComponent <DecorProvider>();
                        // For reference, these do not alter the BuildingComplete
                        def.BaseDecor       = decor;
                        def.BaseDecorRadius = radius;
                        // Actual decor provider
                        if (provider != null)
                        {
                            PUtil.LogDebug("Patched: {0} Decor: {1:F1} Radius: {2:D}".F(id,
                                                                                        decor, radius));
                            provider.baseDecor  = decor;
                            provider.baseRadius = radius;
                        }
                    }
                }
                editDecor.Recycle();
            }
            // Patch in the debris decor
            var baseOreTemplate = Traverse.Create(typeof(EntityTemplates)).GetField <
                GameObject>("baseOreTemplate");
            DecorProvider component;

            if (baseOreTemplate != null && (component = baseOreTemplate.
                                                        GetComponent <DecorProvider>()) != null)
            {
                component.baseDecor  = options.DebrisDecor;
                component.baseRadius = Math.Max(1, options.DebrisRadius);
            }
            // Patch the suits
            PUtil.LogDebug("Snazzy Suit: {0:D} Warm/Cool Vest: {1:D}".F(options.
                                                                        SnazzySuitDecor, options.VestDecor));
            ClothingWearer.ClothingInfo.FANCY_CLOTHING.decorMod = options.SnazzySuitDecor;
            ClothingWearer.ClothingInfo.COOL_CLOTHING.decorMod  = options.VestDecor;
            ClothingWearer.ClothingInfo.WARM_CLOTHING.decorMod  = options.VestDecor;
        }
        /// <summary>
        /// Applied before UpdatePickups runs. A more optimized UpdatePickups whose aggregate
        /// runtime on a test world dropped from ~60 ms/1000 ms to ~45 ms/1000 ms.
        /// </summary>
        internal static bool BeforeUpdatePickups(FetchManager.FetchablesByPrefabId __instance,
                                                 Navigator worker_navigator, GameObject worker_go)
        {
            var canBePickedUp = Allocate();
            var pathCosts     = DictionaryPool <int, int, FetchManager> .Allocate();

            var finalPickups = __instance.finalPickups;
            // Will reflect the changes from Waste Not, Want Not and No Manual Delivery
            var  comparer       = FetchManager.ComparerIncludingPriority;
            bool needThreadSafe = FastTrackOptions.Instance.PickupOpts;
            var  fetchables     = __instance.fetchables.GetDataList();
            int  n = fetchables.Count;

            for (int i = 0; i < n; i++)
            {
                var fetchable = fetchables[i];
                var target    = fetchable.pickupable;
                int cell      = target.cachedCell;
                if (target.CouldBePickedUpByMinion(worker_go))
                {
                    // Look for cell cost, share costs across multiple queries to a cell
                    // If this is being run synchronous, no issue, otherwise the GSP patch will
                    // avoid races on the scene partitioner
                    if (!pathCosts.TryGetValue(cell, out int cost))
                    {
                        if (needThreadSafe)
                        {
                            worker_navigator.GetNavigationCostNU(target, cell, out cost);
                        }
                        else
                        {
                            cost = worker_navigator.GetNavigationCost(target);
                        }
                        pathCosts.Add(cell, cost);
                    }
                    // Exclude unreachable items
                    if (cost >= 0)
                    {
                        int hash      = fetchable.tagBitsHash;
                        var key       = new PickupTagKey(hash, target.KPrefabID);
                        var candidate = new FetchManager.Pickup {
                            pickupable     = target, tagBitsHash = hash, PathCost = (ushort)cost,
                            masterPriority = fetchable.masterPriority, freshness = fetchable.
                                                                                   freshness, foodQuality = fetchable.foodQuality
                        };
                        if (canBePickedUp.TryGetValue(key, out FetchManager.Pickup current))
                        {
                            // Is the new one better?
                            int result = comparer.Compare(candidate, current);
                            if (result < 0 || (result == 0 && candidate.pickupable.
                                               UnreservedAmount > current.pickupable.UnreservedAmount))
                            {
                                canBePickedUp[key] = candidate;
                            }
                        }
                        else
                        {
                            canBePickedUp.Add(key, candidate);
                        }
                    }
                }
            }
            // Copy the remaining pickups to the list, there are now way fewer because only
            // one was kept per possible tag bits (with the highest priority, best path cost,
            // etc)
            finalPickups.Clear();
            foreach (var pickup in canBePickedUp.Values)
            {
                finalPickups.Add(pickup);
            }
            pathCosts.Recycle();
            Recycle(canBePickedUp);
            // Prevent the original method from running
            return(false);
        }