/// <summary> /// Removes an entry from the master dictionary of all-network replacements currently applied to networks. /// </summary> /// <param name="netPrefab">Network prefab</param> /// <param name="target">Target prop info</param> /// <param name="laneIndex">Lane index</param> /// <param name="propIndex">Prop index</param> internal new void RemoveEntry(NetInfo netPrefab, PrefabInfo target, int laneIndex, int propIndex) { // Check to see if we have an entry for this prefab. if (replacements.ContainsKey(target)) { // Yes - iterate through each recorded prop reference. for (int i = 0; i < replacements[target].references.Count; ++i) { // Look for a network, lane and index match. NetPropReference propReference = replacements[target].references[i]; if (propReference.netInfo == netPrefab && propReference.laneIndex == laneIndex && propReference.propIndex == propIndex) { // Got a match! Revert instance. if (target is PropInfo propTarget) { propReference.netInfo.m_lanes[propReference.laneIndex].m_laneProps.m_props[propReference.propIndex].m_finalProp = propTarget; } else { propReference.netInfo.m_lanes[propReference.laneIndex].m_laneProps.m_props[propReference.propIndex].m_finalTree = (TreeInfo)target; } netPrefab.m_lanes[laneIndex].m_laneProps.m_props[propIndex].m_angle = propReference.angle; netPrefab.m_lanes[laneIndex].m_laneProps.m_props[propIndex].m_position = propReference.position; netPrefab.m_lanes[laneIndex].m_laneProps.m_props[propIndex].m_probability = propReference.probability; // Remove this reference and return. replacements[target].references.Remove(replacements[target].references[i]); return; } } } }
/// <summary> /// Unapplies a particular replacement instance to defer to a higher-priority replacement. /// </summary> /// <param name="netInfo">Network prefab</param> /// <param name="targetInfo">Target prefab</param> /// <param name="laneIndex">Lane index</param> /// <param name="propIndex">Prop index</param> internal void RemoveEntry(NetInfo netInfo, PrefabInfo targetInfo, int laneIndex, int propIndex) { // Check to see if we have an entry for this prefab and target. List <NetPropReference> referenceList = ReferenceList(netInfo, targetInfo, laneIndex, propIndex); if (referenceList != null) { // Got an active reference list; create a variable to store any matching reference for later removal. NetPropReference thisPropReference = null; // Iterate through each recorded prop reference. foreach (NetPropReference propReference in referenceList) { // Look for a network, lane and index match. if (propReference.netInfo == netInfo && propReference.laneIndex == laneIndex && propReference.propIndex == propIndex) { // Got a match! Revert instance. RevertReference(propReference); // Record the matching reference and stop iterating - we're done here. thisPropReference = propReference; break; } } // Remove replacement if one was found. if (thisPropReference != null) { referenceList.Remove(thisPropReference); } } }
/// <summary> /// Restores a pack replacement, if any (e.g. after a network replacement has been reverted). /// </summary> /// <param name="netPrefab">Network prefab</param> /// <param name="target">Target prop info</param> /// <param name="laneIndex">Lane index</param> /// <param name="propIndex">Prop index</param> /// <returns>True if a restoration was made, false otherwise</returns> internal bool Restore(NetInfo netPrefab, PrefabInfo target, int laneIndex, int propIndex) { // Check to see if we have an entry for this prefab. if (replacements.ContainsKey(target)) { // Yes - add reference data to the list. NetPropReference newReference = new NetPropReference { network = netPrefab, laneIndex = laneIndex, propIndex = propIndex, angle = netPrefab.m_lanes[laneIndex].m_laneProps.m_props[propIndex].m_angle, postion = netPrefab.m_lanes[laneIndex].m_laneProps.m_props[propIndex].m_position }; replacements[target].references.Add(newReference); // Apply replacement and return true to indicate restoration. NetworkReplacement.instance.ReplaceProp(replacements[target], newReference); return(true); } // If we got here, no restoration was made. return(false); }
/// <summary> /// Replaces a prop, using a network replacement. /// </summary> /// <param name="replacement">Network replacement to apply</param> /// <param name="propReference">Individual prop reference to apply to</param> protected void ReplaceProp(BOBNetReplacement replacement, NetPropReference propReference) { // If this is a vanilla network, then we've probably got shared NetLaneProp references, so need to copy to a new instance. // If the name doesn't contain a period (c.f. 12345.MyNetwok_Data), then assume it's vanilla - may be a mod or not shared, but better safe than sorry. if (!propReference.netInfo.name.Contains(".")) { CloneLanePropInstance(propReference.netInfo, propReference.laneIndex); } // Convert offset to Vector3. Vector3 offset = new Vector3 { x = replacement.offsetX, y = replacement.offsetY, z = replacement.offsetZ }; NetInfo.Lane thisLane = propReference.netInfo.m_lanes[propReference.laneIndex]; // Apply replacement. if (replacement.replacementInfo is PropInfo propInfo) { thisLane.m_laneProps.m_props[propReference.propIndex].m_prop = propInfo; } else if (replacement.replacementInfo is TreeInfo treeInfo) { thisLane.m_laneProps.m_props[propReference.propIndex].m_tree = treeInfo; } else { Logging.Error("invalid replacement ", replacement.replacementInfo?.name ?? "null", " passed to NetworkReplacement.ReplaceProp"); return; } // Invert x offset to match original prop x position. if (thisLane.m_position + propReference.position.x < 0) { offset.x = 0 - offset.x; } // Angle and offset. thisLane.m_laneProps.m_props[propReference.propIndex].m_angle = propReference.angle + replacement.angle; thisLane.m_laneProps.m_props[propReference.propIndex].m_position = propReference.position + offset; // Probability. thisLane.m_laneProps.m_props[propReference.propIndex].m_probability = replacement.probability; // Update network prop references. propReference.netInfo.CheckReferences(); // Add network to dirty list. NetData.DirtyList.Add(propReference.netInfo); }
/// <summary> /// Creates a new PropReference from the provided building prefab and prop index. /// </summary> /// <param name="reference">Referene to revert</param> protected void RevertReference(NetPropReference reference) { // Local reference. NetLaneProps.Prop thisProp = reference.netInfo.m_lanes[reference.laneIndex].m_laneProps.m_props?[reference.propIndex]; if (thisProp != null) { thisProp.m_prop = reference.originalProp; thisProp.m_tree = reference.originalTree; thisProp.m_angle = reference.angle; thisProp.m_position = reference.position; thisProp.m_probability = reference.probability; // Update network. reference.netInfo.CheckReferences(); NetData.DirtyList.Add(reference.netInfo); } }
/// <summary> /// Adds the given prop reference to the record for the given replacement. /// </summary> /// <param name="replacement">Replacement reference</param> /// <param name="propReference">Pop reference to store</param> protected override void AddReference(BOBNetReplacement replacement, NetPropReference propReference) { // Check to see if we've got an entry for this target prefab in our dictionary, and if not, create one. if (!propReferences.ContainsKey(propReference.netInfo)) { propReferences.Add(propReference.netInfo, new Dictionary <PrefabInfo, List <NetPropReference> >()); } // Check to see if we've got an entry for this network prefab in our dictionary entry for this target prefab, and if not, create one. if (!propReferences[propReference.netInfo].ContainsKey(replacement.targetInfo)) { propReferences[propReference.netInfo].Add(replacement.targetInfo, new List <NetPropReference>()); } // Add this prop reference to the dictioanry. propReferences[propReference.netInfo][replacement.targetInfo].Add(propReference); }
/// <summary> /// Restores a pack replacement, if any (e.g. after a network replacement has been reverted). /// </summary> /// <param name="netPrefab">Network prefab</param> /// <param name="target">Target prop info</param> /// <param name="laneIndex">Lane index</param> /// <param name="propIndex">Prop index</param> /// <returns>True if a restoration was made, false otherwise</returns> internal new bool Restore(NetInfo netPrefab, PrefabInfo target, int laneIndex, int propIndex) { // Check to see if we have an entry for this prefab. if (replacements.ContainsKey(target)) { // Yes - add reference data to the list. NetPropReference newReference = CreateReference(netPrefab, target, laneIndex, propIndex, target is TreeInfo); replacements[target].references.Add(newReference); // Apply replacement and return true to indicate restoration. ReplaceProp(replacements[target], newReference); return(true); } // If we got here, no restoration was made. return(false); }
/// <summary> /// Restores a replacement, if any (e.g. after a higher-priority replacement has been reverted). /// </summary> /// <param name="netInfo">Network prefab</param> /// <param name="targetInfo">Target prop info</param> /// <param name="laneIndex">Lane index</param> /// <param name="propIndex">Prop index</param> /// <returns>True if a restoration was made, false otherwise</returns> internal bool Restore(NetInfo netInfo, PrefabInfo targetInfo, int laneIndex, int propIndex) { // See if we have a relevant replacement record. BOBNetReplacement thisReplacement = EligibileReplacement(netInfo, targetInfo, laneIndex, propIndex); if (thisReplacement != null) { // Yes - add reference data to the list. NetPropReference newReference = CreateReference(netInfo, targetInfo, laneIndex, propIndex, thisReplacement.isTree); AddReference(thisReplacement, newReference); // Apply replacement and return true to indicate restoration. ReplaceProp(thisReplacement, newReference); return(true); } // If we got here, no restoration was made. return(false); }
/// <summary> /// Applies a replacement. /// </summary> /// <param name="replacement">Replacement record to apply</param> protected override void ApplyReplacement(BOBNetReplacement replacement) { // Don't do anything if prefabs can't be found. if (replacement?.targetInfo == null || replacement.replacementInfo == null || replacement.NetInfo == null) { return; } // Check lane index. NetInfo.Lane thisLane = replacement.NetInfo.m_lanes[replacement.laneIndex]; if (thisLane == null) { return; } // Check prop index. NetLaneProps.Prop thisLaneProp = thisLane.m_laneProps.m_props[replacement.propIndex]; if (thisLaneProp == null) { return; } // Reset any pack, network, or all-network replacements first. NetworkReplacement.Instance.RemoveEntry(replacement.NetInfo, replacement.targetInfo, replacement.laneIndex, replacement.propIndex); AllNetworkReplacement.Instance.RemoveEntry(replacement.NetInfo, replacement.targetInfo, replacement.laneIndex, replacement.propIndex); NetworkPackReplacement.Instance.RemoveEntry(replacement.NetInfo, replacement.targetInfo, replacement.laneIndex, replacement.propIndex); // Create replacment entry. NetPropReference newPropReference = CreateReference(replacement.NetInfo, replacement.targetInfo, replacement.laneIndex, replacement.propIndex, replacement.isTree); // Reset replacement list to be only our new replacement entry. replacement.references = new List <NetPropReference> { newPropReference }; // Apply the replacement. ReplaceProp(replacement, newPropReference); }
/// <summary> /// Replaces a prop using a network replacement. /// </summary> /// <param name="netElement">Network replacement element to apply</param> /// <param name="propReference">Individual prop reference to apply to</param> internal void ReplaceProp(BOBNetReplacement netElement, NetPropReference propReference) { // Convert offset to Vector3. Vector3 offset = new Vector3 { x = netElement.offsetX, y = netElement.offsetY, z = netElement.offsetZ }; // Apply replacement. if (netElement.replacementInfo is PropInfo propInfo) { propReference.network.m_lanes[propReference.laneIndex].m_laneProps.m_props[propReference.propIndex].m_finalProp = propInfo; } else { propReference.network.m_lanes[propReference.laneIndex].m_laneProps.m_props[propReference.propIndex].m_finalTree = (TreeInfo)netElement.replacementInfo; } // Invert x offset if lane position is negative. if (propReference.network.m_lanes[propReference.laneIndex].m_position < 0) { offset.x = 0 - offset.x; } // Angle and offset. propReference.network.m_lanes[propReference.laneIndex].m_laneProps.m_props[propReference.propIndex].m_angle = propReference.angle + netElement.angle; propReference.network.m_lanes[propReference.laneIndex].m_laneProps.m_props[propReference.propIndex].m_position = propReference.postion + offset; // Probability. propReference.network.m_lanes[propReference.laneIndex].m_laneProps.m_props[propReference.propIndex].m_probability = netElement.probability; // Add network to dirty list. NetData.DirtyList.Add(propReference.network); }
/// <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 lanes. if (SelectedNet?.m_lanes == null || SelectedNet.m_lanes.Length == 0) { // No lanes - show 'no props' label and return an empty list. noPropsLabel.Show(); targetList.rowsData = new FastList <object>(); return; } // Local reference. NetInfo.Lane[] lanes = SelectedNet.m_lanes; // Iterate through each lane. for (int lane = 0; lane < lanes.Length; ++lane) { // Local reference. NetLaneProps.Prop[] laneProps = lanes[lane].m_laneProps?.m_props; // If no props in this lane, skip it and go to the next one. if (laneProps == null) { continue; } // Iterate through each prop in lane. for (int propIndex = 0; propIndex < laneProps.Length; ++propIndex) { // Create new list item. NetTargetListItem targetListItem = new NetTargetListItem(); // Try to get relevant prefab (prop/tree), using finalProp. PrefabInfo finalInfo = IsTree ? (PrefabInfo)laneProps[propIndex]?.m_finalTree : (PrefabInfo)laneProps[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; } // Get original (pre-replacement) tree/prop prefab and current probability (as default original probability). targetListItem.originalPrefab = finalInfo; targetListItem.originalProb = laneProps[propIndex].m_probability; targetListItem.originalAngle = laneProps[propIndex].m_angle; // Grouped or individual? if (CurrentMode == (int)ReplacementModes.Individual) { // Individual - set index to the current prop indexes. targetListItem.index = propIndex; targetListItem.lane = lane; } else { // Grouped - set index to -1 and add to our list of indexes. targetListItem.index = -1; targetListItem.lane = -1; targetListItem.indexes.Add(propIndex); targetListItem.lanes.Add(lane); } // 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; // Update original prop reference. targetListItem.originalPrefab = allNetReplacement.targetInfo; // See if we can find an active reference. Logging.Message("finding original probability - all-network"); NetPropReference originalReference = allNetReplacement?.references?.Find(x => x.netInfo == SelectedNet && x.laneIndex == lane && x.propIndex == propIndex); if (originalReference != null) { // Original reference found; update original probability. targetListItem.originalProb = originalReference.probability; } Logging.Message("original probability not found"); } // 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; // Update original prop reference. targetListItem.originalPrefab = netReplacement.targetInfo; Logging.Message("finding original probability - grouped"); targetListItem.originalProb = netReplacement.references.Find(x => x.laneIndex == lane && x.propIndex == propIndex).probability; Logging.Message("original probability found"); } // 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; Logging.Message("finding original probability - individual"); targetListItem.originalProb = individualReplacement.references.Find(x => x.laneIndex == lane && x.propIndex == propIndex).probability; Logging.Message("original probability found"); // Update original prop reference. targetListItem.originalPrefab = individualReplacement.targetInfo; } // Replacement pack replacement and original probability (if any). BOBNetReplacement packReplacement = NetworkPackReplacement.Instance.ActiveReplacement(SelectedNet, lane, propIndex); if (packReplacement != null) { targetListItem.packagePrefab = packReplacement.replacementInfo; // Update original prop reference. targetListItem.originalPrefab = packReplacement.targetInfo; targetListItem.originalProb = packReplacement.references.Find(x => x.laneIndex == lane && x.propIndex == propIndex).probability; } // 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 (NetTargetListItem item in itemList) { // Check to see if we already have this in the list - matching original prefab, individual replacement prefab, network replacement prefab, all-network 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); item.lanes.Add(lane); 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 network 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 }; targetList.Refresh(); // If the list is empty, show the 'no props' label; otherwise, hide it. if (itemList.Count == 0) { noPropsLabel.Show(); } else { noPropsLabel.Hide(); } }
/// <summary> /// Adds the given prop reference to the record for the given replacement. /// </summary> /// <param name="replacement">Replacement reference</param> /// <param name="propReference">Pop reference to store</param> protected virtual void AddReference(BOBNetReplacement replacement, NetPropReference propReference) => replacement.references.Add(propReference);