/// <summary> /// Revert button event handler. /// <param name="control">Calling component (unused)</param> /// <param name="mouseEvent">Mouse event (unused)</param> /// </summary> protected override void Revert(UIComponent control, UIMouseEventParameter mouseEvent) { try { // Make sure we've got a valid selection. if (CurrentTargetItem == null) { return; } // Individual building prop reversion? if (CurrentTargetItem.individualPrefab != null) { // Individual reversion - use IndividualIndex to ensure valid value for current context is used. IndividualBuildingReplacement.Instance.Revert(currentBuilding, CurrentTargetItem.originalPrefab, IndividualIndex, true); // Clear current target replacement prefab. CurrentTargetItem.individualPrefab = null; } else if (CurrentTargetItem.replacementPrefab != null) { // Grouped reversion. BuildingReplacement.Instance.Revert(currentBuilding, CurrentTargetItem.originalPrefab, -1, true); // Clear current target replacement prefab. CurrentTargetItem.replacementPrefab = null; } else if (CurrentTargetItem.allPrefab != null) { // All-building reversion - make sure we've got a currently active replacement before doing anything. if (CurrentTargetItem.originalPrefab) { // Apply all-building reversion. AllBuildingReplacement.Instance.Revert(currentBuilding, CurrentTargetItem.originalPrefab, CurrentTargetItem.index, true); // Clear current target 'all' prefab. CurrentTargetItem.allPrefab = null; } } // Update current item. UpdateTargetItem(CurrentTargetItem); // Update controls. CurrentTargetItem = CurrentTargetItem; // Update target list. targetList.Refresh(); } catch (Exception e) { // Log and report any exception. Logging.LogException(e, "exception perforiming building reversion"); } }
/// <summary> /// Updates the target item record for changes in replacement status (e.g. after applying or reverting changes). /// </summary> /// <param name="propListItem">Target item</param> protected override void UpdateTargetItem(TargetListItem targetListItem) { // Determine index to test - if no individual index, just grab first one from list. int propIndex = targetListItem.index; if (propIndex < 0) { propIndex = targetListItem.indexes[0]; } // All-building replacement and original probability (if any). BOBBuildingReplacement allBuildingReplacement = AllBuildingReplacement.Instance.ActiveReplacement(currentBuilding, propIndex); if (allBuildingReplacement != null) { targetListItem.allPrefab = allBuildingReplacement.replacementInfo; targetListItem.allProb = allBuildingReplacement.probability; } else { // If no active current record, ensure that it's reset to null. targetListItem.allPrefab = null; } // Building replacement and original probability (if any). BOBBuildingReplacement buildingReplacement = BuildingReplacement.Instance.ActiveReplacement(currentBuilding, propIndex); if (buildingReplacement != null) { targetListItem.replacementPrefab = buildingReplacement.replacementInfo; targetListItem.replacementProb = buildingReplacement.probability; } else { // If no active current record, ensure that it's reset to null. targetListItem.replacementPrefab = null; } // Individual replacement and original probability (if any). BOBBuildingReplacement individualReplacement = IndividualBuildingReplacement.Instance.ActiveReplacement(currentBuilding, propIndex); if (individualReplacement != null) { targetListItem.individualPrefab = individualReplacement.replacementInfo; targetListItem.individualProb = individualReplacement.probability; } else { // If no active current record, ensure that it's reset to null. targetListItem.individualPrefab = null; } }
/// <summary> /// Revert button event handler. /// <param name="control">Calling component (unused)</param> /// <param name="mouseEvent">Mouse event (unused)</param> /// </summary> protected override void Revert(UIComponent control, UIMouseEventParameter mouseEvent) { try { // Make sure we've got a valid selection. if (currentNetItem == null) { return; } // Individual prop reversion? if (currentNetItem.individualPrefab != null) { // Individual reversion - use IndividualLane and IndividualIndex to ensure valid values for current context are used. IndividualNetworkReplacement.Instance.Revert(SelectedNet, currentNetItem.originalPrefab, IndividualLane, IndividualIndex, true); // Clear current target replacement prefab. CurrentTargetItem.individualPrefab = null; } else if (currentNetItem.replacementPrefab != null) { // Network reversion. NetworkReplacement.Instance.Revert(SelectedNet, currentNetItem.originalPrefab, -1, -1, true); } else if (currentNetItem.allPrefab != null) { // All-network reversion. AllNetworkReplacement.Instance.Revert(SelectedNet, currentNetItem.originalPrefab, -1, -1, true); } // Update current item. UpdateTargetItem(currentNetItem); // Update controls. CurrentTargetItem = currentNetItem; // Update target list. targetList.Refresh(); } catch (Exception e) { // Log and report any exception. Logging.LogException(e, "exception perforiming network reversion"); } }
/// <summary> /// Populates the target list with a list of map trees or props. /// </summary> protected override void TargetList() { Logging.Message("starting TargetList"); // List of prefabs that have passed filtering. List <TargetListItem> itemList = new List <TargetListItem>(); // Local references. TreeInstance[] trees = Singleton <TreeManager> .instance.m_trees.m_buffer; // Iterate through each prop or tree instance on map. for (uint i = 0; i < (IsTree ? trees.Length : PropAPI.PropBufferLen); ++i) { // Create new list item, hiding probabilities. TargetListItem propListItem = new TargetListItem { showProbs = false }; if (IsTree) { // Local reference. TreeInstance tree = trees[i]; // Skip non-existent trees (those with no flags). if (tree.m_flags == (ushort)TreeInstance.Flags.None) { continue; } // Try to get any tree replacement. propListItem.originalPrefab = MapTreeReplacement.instance.GetOriginal(tree.Info); // Did we find a current replacment? if (propListItem.originalPrefab == null) { // No - set current item as the original tree. propListItem.originalPrefab = tree.Info; } else { // Yes - record current item as replacement. propListItem.replacementPrefab = tree.Info; } } else { // Props - skip non-existent props (those with no flags). if (PropAPI.Wrapper.GetFlags(i) == (ushort)PropInstance.Flags.None) { continue; } // Get prop info. PropInfo prop = PropAPI.Wrapper.GetInfo(i); if (prop == null) { continue; } // Try to get any prop replacement. propListItem.originalPrefab = MapPropReplacement.instance.GetOriginal(prop); // Did we find a current replacment? if (propListItem.originalPrefab == null) { // No - set current item as the original prop. propListItem.originalPrefab = prop; } else { // Yes - record current item as replacement. propListItem.replacementPrefab = prop; } } // Check to see if we were succesful - if not (e.g. we only want trees and this is a prop), continue on to next instance. if (propListItem.originalPrefab?.name == null) { continue; } // Map instances are always grouped, and we don't have lists of indexes - too many trees! propListItem.index = -1; // Are we grouping? if (propListItem.index == -1) { // Yes, grouping - initialise a flag to show if we've matched. bool matched = false; // Iterate through each item in our existing list of props. foreach (TargetListItem item in itemList) { // Check to see if we already have this in the list - matching original prefab. if (item.originalPrefab == propListItem.originalPrefab) { // We've already got an identical grouped instance of this item - set the flag to indicate that we've match it. matched = true; // No point going any further through the list, since we've already found our match. break; } } // Did we get a match? if (matched) { // Yes - continue on to next tree (without adding this item separately to the list). continue; } } // Add this item to our list. itemList.Add(propListItem); } // Create return fastlist from our filtered list, ordering by name. targetList.rowsData = new FastList <object> { m_buffer = targetSearchStatus == (int)OrderBy.NameDescending ? itemList.OrderByDescending(item => item.DisplayName).ToArray() : itemList.OrderBy(item => item.DisplayName).ToArray(), m_size = itemList.Count }; // If the list is empty, show the 'no props' label; otherwise, hide it. if (itemList.Count == 0) { noPropsLabel.Show(); } else { noPropsLabel.Hide(); } }
/// <summary> /// Updates the target item record for changes in replacement status (e.g. after applying or reverting changes). /// </summary> /// <param name="propListItem">Target item</param> protected override void UpdateTargetItem(TargetListItem targetListItem) { if (targetListItem is NetTargetListItem netItem) { // Determine index to test - if no individual index, just grab first one from list. int propIndex = netItem.index; if (propIndex < 0) { propIndex = netItem.indexes[0]; } // Determine lane to test - if no individual lane, just grab first one from list. int lane = netItem.lane; if (lane < 0) { lane = netItem.lanes[0]; } // Replacement pack replacement and original probability (if any). BOBNetReplacement packReplacement = NetworkPackReplacement.Instance.ActiveReplacement(SelectedNet, lane, propIndex); if (packReplacement != null) { targetListItem.packagePrefab = packReplacement.replacementInfo; } else { // If no active current record, ensure that it's reset to null. targetListItem.packagePrefab = null; } // All-network replacement and original probability (if any). BOBNetReplacement allNetReplacement = AllNetworkReplacement.Instance.ActiveReplacement(SelectedNet, lane, propIndex); if (allNetReplacement != null) { targetListItem.allPrefab = allNetReplacement.replacementInfo; targetListItem.allProb = allNetReplacement.probability; } else { // If no active current record, ensure that it's reset to null. targetListItem.allPrefab = null; } // Network replacement and original probability (if any). BOBNetReplacement netReplacement = NetworkReplacement.Instance.ActiveReplacement(SelectedNet, lane, propIndex); if (netReplacement != null) { targetListItem.replacementPrefab = netReplacement.replacementInfo; targetListItem.replacementProb = netReplacement.probability; } else { // If no active current record, ensure that it's reset to null. targetListItem.replacementPrefab = null; } // Individual replacement and original probability (if any). BOBNetReplacement individualReplacement = IndividualNetworkReplacement.Instance.ActiveReplacement(SelectedNet, lane, propIndex); if (individualReplacement != null) { targetListItem.individualPrefab = individualReplacement.replacementInfo; targetListItem.individualProb = individualReplacement.probability; } else { // If no active current record, ensure that it's reset to null. targetListItem.individualPrefab = null; } } }
/// <summary> /// Generates and displays a list row. /// </summary> /// <param name="data">Object to list</param> /// <param name="isRowOdd">If the row is an odd-numbered row (for background banding)</param> public virtual void Display(object data, bool isRowOdd) { // Perform initial setup for new rows. if (nameLabel == null) { isVisible = true; canFocus = true; isInteractive = true; width = parent.width; height = RowHeight; // Add object name label. nameLabel = AddUIComponent <UILabel>(); nameLabel.width = this.width - 10f; nameLabel.textScale = TextScale; // Add index text label. indexLabel = AddUIComponent <UILabel>(); indexLabel.width = IndexWidth; indexLabel.textScale = TextScale; indexLabel.relativePosition = new Vector2(IndexLabelX, PaddingY); } // Add line sprite if we need to (initially hidden). if (lineSprite == null) { lineSprite = AddUIComponent <UISprite>(); lineSprite.size = new Vector2(17f, 17f); lineSprite.relativePosition = new Vector2(3f, 3f); lineSprite.Hide(); } // Set initial label position. labelX = LeftMargin; // See if our attached data is a PropListItem replacement record). if (data is TargetListItem targetListItem) { // Hide any existing line sprites; it will be re-shown as necessary. if (lineSprite != null) { lineSprite.Hide(); // Adjust name label position to accomodate. labelX += PackageMargin; } // Text to display - StringBuilder due to the amount of manipulation we're doing. StringBuilder displayText = new StringBuilder(); // Set local references. thisItem = targetListItem; index = thisItem.index; // See if this is a network prop. NetTargetListItem thisNetItem = data as NetTargetListItem; // Clear label text. indexLabel.text = ""; // Display index number if this is an individual reference. if (thisItem.index >= 0) { // Display lane marker if this is a network prop. if (thisNetItem != null) { indexLabel.text += thisNetItem.lane.ToString() + " "; // Adjust name label position to accomodate lane number. labelX += IndexWidth; } indexLabel.text += thisItem.index.ToString(); // Adjust name label position to accomodate index number. labelX += IndexWidth; } bool hasReplacement = false; // Check to see if there's a currently active individual replacement. if (thisItem.individualPrefab != null) { // A replacement is currently active - include it in the text. displayText.Append(PrefabLists.GetDisplayName(thisItem.individualPrefab)); // Append probability to the label, if we're showing it. if (thisItem.showProbs) { displayText.Append(" "); displayText.Append(thisItem.individualProb); displayText.Append("%"); } // Set flag. hasReplacement = true; // Show building replacement sprite. lineSprite.atlas = TextureUtils.LoadSpriteAtlas(thisNetItem == null ? "BOB-BuildingSmall" : "BOB-RoadSmall"); lineSprite.spriteName = "normal"; lineSprite.tooltip = Translations.Translate(thisNetItem == null ? "BOB_SPR_SBL" : "BOB_SPR_SNT"); lineSprite.Show(); } // If no current individual replacement, check to see if there's a currently active building/network replacement. else if (thisItem.replacementPrefab != null) { // A replacement is currently active - include it in the text. displayText.Append(PrefabLists.GetDisplayName(thisItem.replacementPrefab)); // Append probability to the label, if we're showing it. if (thisItem.showProbs) { displayText.Append(" "); displayText.Append(thisItem.replacementProb); displayText.Append("%"); } // Set flag. hasReplacement = true; // Show building replacement sprite. lineSprite.atlas = TextureUtils.LoadSpriteAtlas(thisNetItem == null ? "BOB-BuildingSmall" : "BOB-RoadSmall"); lineSprite.spriteName = "normal"; lineSprite.tooltip = Translations.Translate(thisNetItem == null ? "BOB_SPR_SBL" : "BOB_SPR_SNT"); lineSprite.Show(); } // If no current building/network replacement, check to see if any all- replacement is currently active. else if (thisItem.allPrefab != null) { // An all- replacement is currently active; append name to the label. displayText.Append(PrefabLists.GetDisplayName(thisItem.allPrefab)); // Append probability if this is not a network item and we're showing probs. if (thisNetItem == null && thisItem.showProbs) { displayText.Append(" "); displayText.Append(thisItem.allProb); displayText.Append("%"); } // Set flag. hasReplacement = true; // Show all- replacement sprite. lineSprite.atlas = TextureUtils.LoadSpriteAtlas(thisNetItem == null ? "BOB-BuildingsSmall" : "BOB-RoadsSmall"); lineSprite.spriteName = "normal"; lineSprite.tooltip = Translations.Translate(thisNetItem == null ? "BOB_SPR_ABL" : "BOB_SPR_ANT"); lineSprite.Show(); } // If no other replacements, chek to see if any pack replacement is currently active else if (thisItem.packagePrefab != null) { // Yes; append name to the label. displayText.Append(PrefabLists.GetDisplayName(thisItem.packagePrefab)); // Set flag. hasReplacement = true; // Show package replacement sprite. lineSprite.atlas = TextureUtils.LoadSpriteAtlas("BOB-PropPackSmall"); lineSprite.spriteName = "normal"; lineSprite.tooltip = Translations.Translate("BOB_SPR_PCK"); lineSprite.Show(); } // Do we have a replacement? if (hasReplacement) { // Yes; append "was" to the display name. displayText.Append("; "); displayText.Append(Translations.Translate("BOB_ROW_WAS")); displayText.Append(" "); } // Original prefab display name. displayText.Append(PrefabLists.GetDisplayName(thisItem.originalPrefab)); // Show original probability in brackets immediately afterwards. if (thisItem.showProbs) { displayText.Append(" ("); displayText.Append(thisItem.originalProb); displayText.Append("%)"); } // Set display text. nameLabel.text = displayText.ToString(); } // Set label position nameLabel.relativePosition = new Vector2(labelX, PaddingY); // Set initial background as deselected state. Deselect(isRowOdd); }
/// <summary> /// Populates the target fastlist with a list of target-specific trees or props. /// </summary> protected override void TargetList() { // Clear current selection. targetList.selectedIndex = -1; // List of prefabs that have passed filtering. List <TargetListItem> itemList = new List <TargetListItem>(); // Check to see if this building contains any props. if (currentBuilding.m_props == null || currentBuilding.m_props.Length == 0) { // No props - show 'no props' label and return an empty list. noPropsLabel.Show(); targetList.rowsData = new FastList <object>(); return; } // Iterate through each prop in building. for (int propIndex = 0; propIndex < currentBuilding.m_props.Length; ++propIndex) { // Create new list item. TargetListItem targetListItem = new TargetListItem(); // Try to get relevant prefab (prop/tree), using finalProp. PrefabInfo finalInfo = IsTree ? (PrefabInfo)currentBuilding.m_props[propIndex]?.m_finalTree : (PrefabInfo)currentBuilding.m_props[propIndex]?.m_finalProp; // Check to see if we were succesful - if not (e.g. we only want trees and this is a prop), continue on to next building prop. if (finalInfo?.name == null) { continue; } // Grouped or individual? if (CurrentMode == ReplacementModes.Individual) { // Individual - set index to the current building prop indexes. targetListItem.index = propIndex; } else { // Grouped - set index to -1 and add to our list of indexes. targetListItem.index = -1; targetListItem.indexes.Add(propIndex); } // Get original (pre-replacement) tree/prop prefab and current probability (as default original probability). targetListItem.originalPrefab = finalInfo; targetListItem.originalProb = currentBuilding.m_props[propIndex].m_probability; targetListItem.originalAngle = (currentBuilding.m_props[propIndex].m_radAngle * 180f) / Mathf.PI; // All-building replacement and original probability (if any). BOBBuildingReplacement allBuildingReplacement = AllBuildingReplacement.Instance.ActiveReplacement(currentBuilding, propIndex); if (allBuildingReplacement != null) { targetListItem.allPrefab = allBuildingReplacement.replacementInfo; targetListItem.allProb = allBuildingReplacement.probability; // Update original prop reference. targetListItem.originalPrefab = allBuildingReplacement.targetInfo; } // Building replacement and original probability (if any). BOBBuildingReplacement buildingReplacement = BuildingReplacement.Instance.ActiveReplacement(currentBuilding, propIndex); if (buildingReplacement != null) { targetListItem.replacementPrefab = buildingReplacement.replacementInfo; targetListItem.replacementProb = buildingReplacement.probability; // Update original prop reference. targetListItem.originalPrefab = buildingReplacement.targetInfo; } // Individual replacement and original probability (if any). BOBBuildingReplacement individualReplacement = IndividualBuildingReplacement.Instance.ActiveReplacement(currentBuilding, propIndex); if (individualReplacement != null) { targetListItem.individualPrefab = individualReplacement.replacementInfo; targetListItem.individualProb = individualReplacement.probability; // Update original prop reference. targetListItem.originalPrefab = individualReplacement.targetInfo; } // Are we grouping? if (targetListItem.index == -1) { // Yes, grouping - initialise a flag to show if we've matched. bool matched = false; // Iterate through each item in our existing list of props. foreach (TargetListItem item in itemList) { // Check to see if we already have this in the list - matching original prefab, individual replacement prefab, building replacement prefab, all-building replacement prefab, and probability. if (item.originalPrefab == targetListItem.originalPrefab && item.individualPrefab == targetListItem.individualPrefab && item.replacementPrefab == targetListItem.replacementPrefab && targetListItem.allPrefab == item.allPrefab) { // We've already got an identical grouped instance of this item - add this index and lane to the lists of indexes and lanes under that item and set the flag to indicate that we've done so. item.indexes.Add(propIndex); matched = true; // No point going any further through the list, since we've already found our match. break; } } // Did we get a match? if (matched) { // Yes - continue on to next building prop (without adding this item separately to the list). continue; } } // Add this item to our list. itemList.Add(targetListItem); } // Create return fastlist from our filtered list, ordering by name. targetList.rowsData = new FastList <object> { m_buffer = targetSearchStatus == (int)OrderBy.NameDescending ? itemList.OrderByDescending(item => item.DisplayName).ToArray() : itemList.OrderBy(item => item.DisplayName).ToArray(), m_size = itemList.Count }; // If the list is empty, show the 'no props' label; otherwise, hide it. if (targetList.rowsData.m_size == 0) { noPropsLabel.Show(); } else { noPropsLabel.Hide(); } }