public void OnLevelLoaded(LoadMode mode) { for (uint index = 0; index < PrefabCollection <BuildingInfo> .LoadedCount(); index++) { BuildingInfo prefab = PrefabCollection <BuildingInfo> .GetLoaded(index); if (prefab == null || prefab.m_props == null) { continue; } for (int propIndex = 0; propIndex < prefab.m_props.Length; propIndex++) { BuildingInfo.Prop propItem = prefab.m_props[propIndex]; if (propItem.m_prop == null) { continue; } string propName = propItem.m_prop.name; if (propName == "Billboard_big_variation" || propName == "Billboard_big_variation_01" || propName == "Billboard_big_variation_02" || propName == "Billboard_big_variation_04" || propName == "neon-yakisoba-noodles" || propName == "neon-burned-bean-coffee" || propName == "neon-morellos") { propItem.m_probability = 0; } } } }
/// <summary> /// Creates a new PropReference from the provided building prefab and prop index. /// </summary> /// <param name="buildingInfo">Building prefab</param> /// <param name="originalPrefab">Original prop/tree prefab (for later restoration if needed)</param> /// <param name="propIndex">Prop index</param> /// <param name="isTree">True if this is a tree reference, false if this is a prop reference</param> /// <returns>Newly-created reference (null if creation failed)</returns> protected BuildingPropReference CreateReference(BuildingInfo buildingInfo, PrefabInfo originalPrefab, int propIndex, bool isTree) { // Safety checks. if (buildingInfo?.m_props != null && propIndex >= 0) { // Local reference. BuildingInfo.Prop thisProp = buildingInfo.m_props[propIndex]; // Create and return new reference. return(new BuildingPropReference { buildingInfo = buildingInfo, propIndex = propIndex, isTree = isTree, originalProp = isTree ? thisProp.m_finalProp : originalPrefab as PropInfo, originalTree = isTree ? originalPrefab as TreeInfo : thisProp.m_finalTree, radAngle = thisProp.m_radAngle, fixedHeight = thisProp.m_fixedHeight, position = thisProp.m_position, probability = thisProp.m_probability }); } // If we got here, something went wrong; return null. Logging.Error("invalid argument passed to BuildingReplacementBase.CreateReference"); return(null); }
/// <summary> /// Applies a replacement. /// </summary> /// <param name="replacement">Replacement record to apply</param> protected override void ApplyReplacement(BOBBuildingReplacement replacement) { // Don't do anything if prefabs can't be found, or if building prefab has no prop array. if (replacement?.targetInfo == null || replacement.replacementInfo == null || replacement.BuildingInfo?.m_props == null) { return; } // (Re)set replacement list. replacement.references = new List <BuildingPropReference>(); // Iterate through each prop in building. for (int propIndex = 0; propIndex < replacement.BuildingInfo.m_props.Length; ++propIndex) { // Check for any currently active individual building prop replacement. if (IndividualBuildingReplacement.Instance.ActiveReplacement(replacement.BuildingInfo, propIndex) != null) { // Active individual building prop replacement; skip this one. continue; } // Local reference. BuildingInfo.Prop thisBuildingProp = replacement.BuildingInfo.m_props[propIndex]; // Check for any existing all-building replacement. PrefabInfo thisProp = AllBuildingReplacement.Instance.ActiveReplacement(replacement.BuildingInfo, propIndex)?.targetInfo; if (thisProp == null) { // No active replacement; use current PropInfo. if (replacement.targetInfo is PropInfo) { thisProp = thisBuildingProp.m_finalProp; } else { thisProp = thisBuildingProp.m_finalTree; } } // See if this prop matches our replacement. if (thisProp != null && thisProp == replacement.targetInfo) { // Match! Add reference data to the list. replacement.references.Add(CreateReference(replacement.BuildingInfo, thisProp, propIndex, replacement.isTree)); } } // Now, iterate through each entry found. foreach (BuildingPropReference propReference in replacement.references) { // Reset any all-building replacements first. AllBuildingReplacement.Instance.RemoveEntry(propReference.buildingInfo, replacement.targetInfo, propReference.propIndex); // Apply the replacement. ReplaceProp(replacement, propReference); } }
/// <summary> /// Creates a new PropReference from the provided building prefab and prop index. /// </summary> /// <param name="reference">Referene to revert</param> protected void RevertReference(BuildingPropReference reference) { // Local reference. BuildingInfo.Prop thisProp = reference.buildingInfo.m_props[reference.propIndex]; if (thisProp != null) { thisProp.m_prop = reference.originalProp; thisProp.m_tree = reference.originalTree; thisProp.m_radAngle = reference.radAngle; thisProp.m_fixedHeight = reference.fixedHeight; thisProp.m_position = reference.position; thisProp.m_probability = reference.probability; // Update building. reference.buildingInfo.CheckReferences(); BuildingData.DirtyList.Add(reference.buildingInfo); } }
private static void SaveProps(BuildingInfo info, ushort buildingID, ref Building data) { FastList <BuildingInfo.Prop> fastList = new FastList <BuildingInfo.Prop>(); Vector3 mPosition = data.m_position; Quaternion quaternion = Quaternion.AngleAxis(data.m_angle * 57.29578f, Vector3.down); Matrix4x4 matrix4x4 = new Matrix4x4(); matrix4x4.SetTRS(mPosition, quaternion, Vector3.one); matrix4x4 = matrix4x4.inverse; PropManager propManager = Singleton <PropManager> .instance; for (int i = 0; i < 65536; i++) { if ((propManager.m_props.m_buffer[i].m_flags & 67) == 1) { BuildingInfo.Prop prop = new BuildingInfo.Prop(); prop.m_prop = propManager.m_props.m_buffer[i].Info; prop.m_finalProp = prop.m_prop; prop.m_position = matrix4x4.MultiplyPoint(propManager.m_props.m_buffer[i].Position); prop.m_radAngle = propManager.m_props.m_buffer[i].Angle - data.m_angle; prop.m_angle = 57.29578f * prop.m_radAngle; prop.m_fixedHeight = propManager.m_props.m_buffer[i].FixedHeight; prop.m_probability = 100; fastList.Add(prop); } } TreeManager treeManager = Singleton <TreeManager> .instance; for (int j = 0; j < LimitTreeManager.Helper.TreeLimit; j++) { if ((treeManager.m_trees.m_buffer[j].m_flags & 3) == 1 && treeManager.m_trees.m_buffer[j].GrowState != 0) { BuildingInfo.Prop prop1 = new BuildingInfo.Prop(); prop1.m_tree = treeManager.m_trees.m_buffer[j].Info; prop1.m_finalTree = prop1.m_tree; prop1.m_position = matrix4x4.MultiplyPoint(treeManager.m_trees.m_buffer[j].Position); prop1.m_fixedHeight = treeManager.m_trees.m_buffer[j].FixedHeight; prop1.m_probability = 100; fastList.Add(prop1); } } info.m_props = fastList.ToArray(); }
/// <summary> /// Applies a replacement. /// </summary> /// <param name="replacement">Replacement record to apply</param> protected override void ApplyReplacement(BOBBuildingReplacement replacement) { // Don't do anything if prefabs can't be found. if (replacement?.targetInfo == null || replacement.replacementInfo == null || replacement.BuildingInfo == null) { return; } // Check index bounds. if (replacement.BuildingInfo.m_props == null || replacement.propIndex >= replacement.BuildingInfo.m_props.Length) { Logging.Message("ignoring invalid individual building replacement index ", replacement.propIndex, " for building ", replacement.BuildingInfo.name); return; } // Check prop index. BuildingInfo.Prop thisProp = replacement.BuildingInfo.m_props[replacement.propIndex]; if (thisProp == null) { return; } // Reset any building or all-building replacements first. BuildingReplacement.Instance.RemoveEntry(replacement.BuildingInfo, replacement.targetInfo, replacement.propIndex); AllBuildingReplacement.Instance.RemoveEntry(replacement.BuildingInfo, replacement.targetInfo, replacement.propIndex); // Create replacment entry. BuildingPropReference newPropReference = CreateReference(replacement.BuildingInfo, replacement.targetInfo, replacement.propIndex, replacement.isTree); // Reset replacement list to be only our new replacement entry. replacement.references = new List <BuildingPropReference> { newPropReference }; // Apply the replacement. ReplaceProp(replacement, newPropReference); }
public override void CalculateUnspawnPosition(ushort buildingID, ref Building data, ref Randomizer randomizer, CitizenInfo info, ushort ignoreInstance, out Vector3 position, out Vector3 target, out Vector2 direction, out CitizenInstance.Flags specialFlags) { float localMeshOffset = Building.CalculateLocalMeshOffset(this.m_info, data.Length); bool flag1 = this.m_info.m_specialPlaces != null && this.m_info.m_specialPlaces.Length != 0; bool flag2 = this.m_info.m_enterDoors != null && this.m_info.m_enterDoors.Length != 0; if (flag1 && (!flag2 || randomizer.Int32(4U) == 0)) { BuildingInfo.Prop prop = this.m_info.m_specialPlaces[randomizer.Int32((uint)this.m_info.m_specialPlaces.Length)]; if (new Randomizer((int)buildingID << 6 | prop.m_index).Int32(100U) < prop.m_probability && data.Length >= prop.m_requiredLength) { Vector3 offset = prop.m_position; offset.z = localMeshOffset - offset.z; position = data.CalculatePosition(offset); int index = randomizer.Int32((uint)prop.m_finalProp.m_specialPlaces.Length); PropInfo.SpecialPlace specialPlace = prop.m_finalProp.m_specialPlaces[index]; float f = data.m_angle + prop.m_radAngle; float num1 = Mathf.Cos(f); float num2 = Mathf.Sin(f); if (!prop.m_fixedHeight) { position.y = Singleton <TerrainManager> .instance.SampleDetailHeight(position); } else if (this.m_info.m_requireHeightMap) { position.y = Singleton <TerrainManager> .instance.SampleDetailHeight(position) + offset.y; } position.x += (float)((double)specialPlace.m_position.x * (double)num1 + (double)specialPlace.m_position.z * (double)num2); position.y += specialPlace.m_position.y; position.z += (float)((double)specialPlace.m_position.x * (double)num2 - (double)specialPlace.m_position.z * (double)num1); if (!this.IsSomeBodyThere(position, ignoreInstance)) { direction.x = (float)((double)specialPlace.m_direction.x * (double)num1 + (double)specialPlace.m_direction.z * (double)num2); direction.y = (float)((double)specialPlace.m_direction.x * (double)num2 - (double)specialPlace.m_direction.z * (double)num1); //specialFlags = hangaround _ specialPlace.specialFlags specialFlags = CitizenInstance.Flags.HangAround | specialPlace.m_specialFlags; Debug.Log("SF: " + specialFlags.ToString().PadRight(25, ' ') + "; SP: " + specialPlace.m_specialFlags.ToString().PadRight(25, ' ') + "; Layer: " + data.Info.m_class.m_layer.ToString().PadRight(15, ' ') + "; Level: " + data.Info.m_class.m_level.ToString().PadRight(5, ' ') + "; Service: " + data.Info.m_class.m_service.ToString().PadRight(20, ' ') + "; Subservice: " + data.Info.m_class.m_subService.ToString().PadRight(25, ' ') + ";"); if (this.m_info.m_hasPedestrianPaths) { target = position; return; } target = data.CalculateSidewalkPosition(offset.x, 0.0f); return; } } } if (flag2) { BuildingInfo.Prop prop = this.m_info.m_enterDoors[randomizer.Int32((uint)this.m_info.m_enterDoors.Length)]; if (new Randomizer((int)buildingID << 6 | prop.m_index).Int32(100U) < prop.m_probability && data.Length >= prop.m_requiredLength) { Vector3 offset = prop.m_position; offset.z = localMeshOffset - offset.z; float num1 = prop.m_finalProp.m_generatedInfo.m_size.x * 0.5f - info.m_radius; if ((double)num1 >= 0.100000001490116) { float num2 = num1 * Mathf.Sqrt((float)randomizer.Int32(1000U) * (1f / 1000f)); float f = (float)randomizer.Int32(1000U) * ((float)System.Math.PI / 500f); offset.x += Mathf.Cos(f) * num2; offset.z += Mathf.Sin(f) * num2; } position = data.CalculatePosition(offset); if (!prop.m_fixedHeight) { position.y = Singleton <TerrainManager> .instance.SampleDetailHeight(position); } else if (this.m_info.m_requireHeightMap) { position.y = Singleton <TerrainManager> .instance.SampleDetailHeight(position) + offset.y; } direction = Vector2.zero; specialFlags = (prop.m_finalProp.m_doorType & PropInfo.DoorType.HangAround) != PropInfo.DoorType.HangAround ? CitizenInstance.Flags.None : CitizenInstance.Flags.HangAround; if (this.m_info.m_hasPedestrianPaths) { target = position; return; } target = data.CalculateSidewalkPosition(offset.x, 0.0f); return; } } Vector3 offset1 = new Vector3(0.0f, 0.0f, localMeshOffset); position = data.CalculatePosition(offset1); position.y = Singleton <TerrainManager> .instance.SampleDetailHeight(position); direction = Vector2.zero; specialFlags = CitizenInstance.Flags.None; if (this.m_info.m_hasPedestrianPaths) { target = position; } else { target = data.CalculateSidewalkPosition(offset1.x, 0.0f); } }
/// <summary> /// Add building prop to the list to be highlighted. /// </summary> /// <param name="camera">Current camera</param> /// <param name="index">Prop index</param> /// <param name="prop">Prop info</param> /// <param name="building">Building data</param> public static void HighlightBuildingProp(RenderManager.CameraInfo camera, int index, BuildingInfo.Prop prop, ref Building building) { // Check for match - prop, index (if applicable) and building (if applicable). if (prop.m_finalProp == CurrentProp && (CurrentBuilding == null || CurrentBuilding == building.Info) && (CurrentIndex < 0 || CurrentIndex == index)) { // Get transform matrix for building and use to convert prop location to worldspace. Matrix4x4 m = Matrix4x4.TRS(building.m_position, Quaternion.Euler(0, -Mathf.Rad2Deg * building.m_angle, 0), Vector3.one); // Offset building position to account for extensible yards. Vector3 propPosition = prop.m_position; propPosition.z += (building.m_length - building.Info.m_cellLength) * 4f; Vector3 propLocation = m.MultiplyPoint(propPosition); // Don't render overlay is prop is beyond rendering distance. if (camera.CheckRenderDistance(propLocation, MaxBuildingPropDistance)) { // Within rendering distance size (for effect radius). Vector3 size = prop.m_finalProp.m_mesh.bounds.size; // Add to list of overlays to be rendered. overlays.Add(new OverlayData { position = propLocation, radius = Mathf.Max(1f, size.x, size.z) }); } } }
public static bool RenderPropsPrefix(BuildingAI __instance, RenderManager.CameraInfo cameraInfo, ushort buildingID, ref Building data, int layerMask, ref RenderManager.Instance instance, bool renderFixed, bool renderNonfixed, bool isActive) { if (__instance.m_info.m_props == null || ((layerMask & __instance.m_info.m_treeLayers) == 0 && !cameraInfo.CheckRenderDistance(instance.m_position, __instance.m_info.m_maxPropDistance + 72f))) { return(false); } int length = data.Length; Texture _HeightMap = null; Vector4 _HeightMapping = Vector4.zero; Vector4 _SurfaceMapping = Vector4.zero; Matrix4x4 lhs = Matrix4x4.zero; bool flag = false; DistrictManager instance2 = Singleton <DistrictManager> .instance; byte district = instance2.GetDistrict(data.m_position); Vector3 position = data.m_position; ushort num = Building.FindParentBuilding(buildingID); if (num != 0) { position = Singleton <BuildingManager> .instance.m_buildings.m_buffer[num].m_position; } byte park = instance2.GetPark(position); for (int i = 0; i < __instance.m_info.m_props.Length; i++) { BuildingInfo.Prop prop = __instance.m_info.m_props[i]; Randomizer r = new Randomizer((buildingID << 6) | prop.m_index); if (r.Int32(100u) >= prop.m_probability || length < prop.m_requiredLength) { continue; } PropInfo finalProp = prop.m_finalProp; TreeInfo finalTree = prop.m_finalTree; if (finalProp != null) { finalProp = finalProp.GetVariation(ref r, ref instance2.m_districts.m_buffer[district], park); float num2 = finalProp.m_minScale + (float)r.Int32(10000u) * (finalProp.m_maxScale - finalProp.m_minScale) * 0.0001f; Color color = finalProp.GetColor(ref r); if ((layerMask & (1 << finalProp.m_prefabDataLayer)) == 0 && !finalProp.m_hasEffects) { continue; } Vector4 dataVector = instance.m_dataVector3; Vector3 vector; if (prop.m_fixedHeight) { if (!renderFixed) { continue; } if (__instance.m_info.m_isFloating) { if (!flag) { Singleton <TerrainManager> .instance.HeightMap_sampleWaterHeightAndNormal(instance.m_position, 0.15f, out float h, out Vector3 normal); Vector3 position2 = instance.m_position; position2.y = h; Quaternion q = Quaternion.FromToRotation(Vector3.up, normal) * instance.m_rotation; lhs = Matrix4x4.TRS(position2, q, Vector3.one); flag = true; } Matrix4x4 rhs = default(Matrix4x4); rhs.SetTRS(prop.m_position, Quaternion.AngleAxis(prop.m_radAngle * 57.29578f, Vector3.down), new Vector3(num2, num2, num2)); rhs = lhs * rhs; vector = rhs.MultiplyPoint(Vector3.zero); if (cameraInfo.CheckRenderDistance(vector, finalProp.m_maxRenderDistance)) { InstanceID propRenderID = GetPropRenderIDReverse(__instance, buildingID, i, ref data); PropInstance.RenderInstance(cameraInfo, finalProp, propRenderID, rhs, vector, num2, data.m_angle + prop.m_radAngle, color, dataVector, isActive); continue; } } else { vector = instance.m_dataMatrix1.MultiplyPoint(prop.m_position); if (__instance.m_info.m_requireHeightMap) { vector.y = (float)(int)instance.m_extraData.GetUShort(i) * 0.015625f; } } } else { if (!renderNonfixed) { continue; } vector = instance.m_dataMatrix1.MultiplyPoint(prop.m_position); if (!__instance.m_info.m_isFloating) { vector.y = (float)(int)instance.m_extraData.GetUShort(i) * 0.015625f; } if (!__instance.m_info.m_colorizeEverything || finalProp.m_isDecal) { dataVector.z = 0f; } } if (!cameraInfo.CheckRenderDistance(vector, finalProp.m_maxRenderDistance)) { continue; } InstanceID propRenderID2 = GetPropRenderIDReverse(__instance, buildingID, i, ref data); if (finalProp.m_requireWaterMap) { if (_HeightMap == null) { Singleton <TerrainManager> .instance.GetWaterMapping(data.m_position, out _HeightMap, out _HeightMapping, out _SurfaceMapping); } #if UseTask var localData = data; var localInstance = instance; Patcher.Dispatcher.Add(() => PropInstance.RenderInstance(cameraInfo, finalProp, propRenderID2, vector, num2, localData.m_angle + prop.m_radAngle, color, dataVector, isActive, localInstance.m_dataTexture0, localInstance.m_dataVector1, localInstance.m_dataVector2, _HeightMap, _HeightMapping, _SurfaceMapping)); #else PropInstance.RenderInstance(cameraInfo, finalProp, propRenderID2, vector, num2, data.m_angle + prop.m_radAngle, color, dataVector, isActive, instance.m_dataTexture0, instance.m_dataVector1, instance.m_dataVector2, _HeightMap, _HeightMapping, _SurfaceMapping); #endif } else if (finalProp.m_requireHeightMap) { #if UseTask var localData = data; var localInstance = instance; Patcher.Dispatcher.Add(() => PropInstance.RenderInstance(cameraInfo, finalProp, propRenderID2, vector, num2, localData.m_angle + prop.m_radAngle, color, dataVector, isActive, localInstance.m_dataTexture0, localInstance.m_dataVector1, localInstance.m_dataVector2)); #else PropInstance.RenderInstance(cameraInfo, finalProp, propRenderID2, vector, num2, data.m_angle + prop.m_radAngle, color, dataVector, isActive, instance.m_dataTexture0, instance.m_dataVector1, instance.m_dataVector2); #endif } else { #if UseTask var localData = data; var localInstance = instance; Patcher.Dispatcher.Add(() => PropInstance.RenderInstance(cameraInfo, finalProp, propRenderID2, vector, num2, localData.m_angle + prop.m_radAngle, color, dataVector, isActive)); #else PropInstance.RenderInstance(cameraInfo, finalProp, propRenderID2, vector, num2, data.m_angle + prop.m_radAngle, color, dataVector, isActive); #endif } } else { if (!(finalTree != null)) { continue; } finalTree = finalTree.GetVariation(ref r); float scale = finalTree.m_minScale + (float)r.Int32(10000u) * (finalTree.m_maxScale - finalTree.m_minScale) * 0.0001f; float brightness = finalTree.m_minBrightness + (float)r.Int32(10000u) * (finalTree.m_maxBrightness - finalTree.m_minBrightness) * 0.0001f; if ((layerMask & (1 << finalTree.m_prefabDataLayer)) != 0 && ((!prop.m_fixedHeight) ? renderNonfixed : renderFixed)) { Vector3 position3 = instance.m_dataMatrix1.MultiplyPoint(prop.m_position); if (!prop.m_fixedHeight || __instance.m_info.m_requireHeightMap) { position3.y = (float)(int)instance.m_extraData.GetUShort(i) * 0.015625f; } Vector4 dataVector2 = instance.m_dataVector3; if (!__instance.m_info.m_colorizeEverything) { dataVector2.z = 0f; } #if UseTask var localData = data; var localInstance = instance; Patcher.Dispatcher.Add(() => TreeInstance.RenderInstance(cameraInfo, finalTree, position3, scale, brightness, dataVector2)); #else TreeInstance.RenderInstance(cameraInfo, finalTree, position3, scale, brightness, dataVector2); #endif } } } return(false); }
public static bool RenderDestroyedPropsPrefix(BuildingAI __instance, RenderManager.CameraInfo cameraInfo, ushort buildingID, ref Building data, int layerMask, ref RenderManager.Instance instance, bool renderFixed, bool renderNonfixed) { if (__instance.m_info.m_props == null || !cameraInfo.CheckRenderDistance(instance.m_position, __instance.m_info.m_maxPropDistance + 72f)) { return(false); } int length = data.Length; Texture _HeightMap = null; Vector4 _HeightMapping = Vector4.zero; Vector4 _SurfaceMapping = Vector4.zero; BuildingProperties properties = Singleton <BuildingManager> .instance.m_properties; Building.Frame lastFrameData = data.GetLastFrameData(); float num = (float)Mathf.Max(0, lastFrameData.m_fireDamage - 127) * 0.0078125f; for (int i = 0; i < __instance.m_info.m_props.Length; i++) { BuildingInfo.Prop prop = __instance.m_info.m_props[i]; Randomizer r = new Randomizer((buildingID << 6) | prop.m_index); Randomizer r2 = new Randomizer((buildingID << 6) | prop.m_index); if (r.Int32(100u) >= prop.m_probability || length < prop.m_requiredLength) { continue; } PropInfo finalProp = prop.m_finalProp; if (!(finalProp != null)) { continue; } finalProp = finalProp.GetVariation(ref r); float scale = finalProp.m_minScale + (float)r.Int32(10000u) * (finalProp.m_maxScale - finalProp.m_minScale) * 0.0001f; Color color = finalProp.GetColor(ref r); if (!finalProp.m_isDecal) { finalProp = Singleton <PropManager> .instance.GetRandomPropInfo(ref r2, ItemClass.Service.Disaster); finalProp = finalProp.GetVariation(ref r2); scale = finalProp.m_minScale + (float)r2.Int32(10000u) * (finalProp.m_maxScale - finalProp.m_minScale) * 0.0001f; color = finalProp.GetColor(ref r2); if (properties != null && num != 0f) { color = Color.Lerp(color, properties.m_burnedColor, num); } } if ((layerMask & (1 << finalProp.m_prefabDataLayer)) == 0 && !finalProp.m_hasEffects) { continue; } Vector3 vector = instance.m_dataMatrix1.MultiplyPoint(prop.m_position); if (!prop.m_fixedHeight || __instance.m_info.m_requireHeightMap) { vector.y = (float)(int)instance.m_extraData.GetUShort(i) * 0.015625f; } if (!cameraInfo.CheckRenderDistance(vector, finalProp.m_maxRenderDistance) || !((!prop.m_fixedHeight) ? renderNonfixed : renderFixed)) { continue; } InstanceID propRenderID = GetPropRenderIDReverse(__instance, buildingID, 0, ref data); Vector4 dataVector = instance.m_dataVector3; if (!prop.m_fixedHeight && (!__instance.m_info.m_colorizeEverything || finalProp.m_isDecal)) { dataVector.z = 0f; } if (finalProp.m_requireWaterMap) { if (_HeightMap == null) { Singleton <TerrainManager> .instance.GetWaterMapping(data.m_position, out _HeightMap, out _HeightMapping, out _SurfaceMapping); } #if UseTask var localData = data; var localInstance = instance; Patcher.Dispatcher.Add(() => PropInstance.RenderInstance(cameraInfo, finalProp, propRenderID, vector, scale, localData.m_angle + prop.m_radAngle, color, dataVector, (localData.m_flags & Building.Flags.Active) != 0, localInstance.m_dataTexture0, localInstance.m_dataVector1, localInstance.m_dataVector2, _HeightMap, _HeightMapping, _SurfaceMapping)); #else PropInstance.RenderInstance(cameraInfo, finalProp, propRenderID, vector, scale, data.m_angle + prop.m_radAngle, color, dataVector, (data.m_flags & Building.Flags.Active) != 0, instance.m_dataTexture0, instance.m_dataVector1, instance.m_dataVector2, _HeightMap, _HeightMapping, _SurfaceMapping); #endif } else if (finalProp.m_requireHeightMap) { #if UseTask var localData = data; var localInstance = instance; Patcher.Dispatcher.Add(() => PropInstance.RenderInstance(cameraInfo, finalProp, propRenderID, vector, scale, localData.m_angle + prop.m_radAngle, color, dataVector, (localData.m_flags & Building.Flags.Active) != 0, localInstance.m_dataTexture0, localInstance.m_dataVector1, localInstance.m_dataVector2)); #else PropInstance.RenderInstance(cameraInfo, finalProp, propRenderID, vector, scale, data.m_angle + prop.m_radAngle, color, dataVector, (data.m_flags & Building.Flags.Active) != 0, instance.m_dataTexture0, instance.m_dataVector1, instance.m_dataVector2); #endif } else { #if UseTask var localData = data; Patcher.Dispatcher.Add(() => PropInstance.RenderInstance(cameraInfo, finalProp, propRenderID, vector, scale, localData.m_angle + prop.m_radAngle, color, dataVector, (localData.m_flags & Building.Flags.Active) != 0)); #else PropInstance.RenderInstance(cameraInfo, finalProp, propRenderID, vector, scale, data.m_angle + prop.m_radAngle, color, dataVector, (data.m_flags & Building.Flags.Active) != 0); #endif } } return(false); }
/// <summary> /// Applies a new (or updated) individual building prop replacement. /// </summary> /// <param name="building">Targeted building</param> /// <param name="target">Targeted (original) prop prefab</param> /// <param name="replacement">Replacment prop prefab</param> /// <param name="angle">Replacment prop angle adjustment</param> /// <param name="offsetX">Replacment X position offset</param> /// <param name="offsetY">Replacment Y position offset</param> /// <param name="offsetZ">Replacment Z position offset</param> /// <param name="probability">Replacement probability</param> internal void Apply(BuildingInfo building, PrefabInfo target, int targetIndex, PrefabInfo replacement, float angle, float offsetX, float offsetY, float offsetZ, int probability) { // Local reference. BuildingInfo.Prop targetProp = building?.m_props?[targetIndex]; // Bail out if no building prop. if (targetProp == null) { Logging.Error("no target prop reference found when applying individual replacement"); return; } // Check to see if we already have a replacement entry for this prop - if so, revert the replacement first. if (replacements.ContainsKey(building) && replacements[building].ContainsKey(targetIndex)) { Revert(building, targetIndex, true); } // Create new dictionary entry for building if none already exists. if (!replacements.ContainsKey(building)) { replacements.Add(building, new Dictionary <int, BOBBuildingReplacement>()); } // Create new dictionary entry for prop if none already exists. if (!replacements[building].ContainsKey(targetIndex)) { replacements[building].Add(targetIndex, new BOBBuildingReplacement()); } // Add/replace dictionary replacement data. replacements[building][targetIndex].index = targetIndex; replacements[building][targetIndex].references = new List <BuildingPropReference>(); replacements[building][targetIndex].tree = target is TreeInfo; replacements[building][targetIndex].targetInfo = target; replacements[building][targetIndex].target = target.name; replacements[building][targetIndex].angle = angle; replacements[building][targetIndex].offsetX = offsetX; replacements[building][targetIndex].offsetY = offsetY; replacements[building][targetIndex].offsetZ = offsetZ; replacements[building][targetIndex].probability = probability; // Record replacement prop. replacements[building][targetIndex].replacementInfo = replacement; replacements[building][targetIndex].Replacement = replacement.name; // Create replacement record. BuildingPropReference propReference = new BuildingPropReference { building = building, propIndex = targetIndex, radAngle = building.m_props[targetIndex].m_radAngle, postion = building.m_props[targetIndex].m_position, probability = building.m_props[targetIndex].m_probability }; // Add reference data to the list (only entry....) replacements[building][targetIndex].references.Add(propReference); // Reset any building or all-building replacements first. BuildingReplacement.instance.RemoveEntry(building, target, targetIndex); AllBuildingReplacement.instance.RemoveEntry(building, target, targetIndex); // Apply the replacement. BuildingReplacement.instance.ReplaceProp(replacements[building][targetIndex], propReference); }
public static void SaveProps(BuildingInfo info, ushort buildingID, ref Building data) { FastList <BuildingInfo.Prop> fastList = new FastList <BuildingInfo.Prop>(); Vector3 pos = data.m_position; Quaternion q = Quaternion.AngleAxis(data.m_angle * 57.29578f, Vector3.down); Matrix4x4 matrix4x4 = new Matrix4x4(); matrix4x4.SetTRS(pos, q, Vector3.one); matrix4x4 = matrix4x4.inverse; //begin mod Quaternion q_1 = Quaternion.AngleAxis(data.m_angle * 57.29578f, Vector3.down); Matrix4x4 matrix4x4_1 = new Matrix4x4(); matrix4x4_1.SetTRS(pos, q_1, Vector3.one); matrix4x4_1 = matrix4x4_1.inverse; PropManager instance1 = Singleton <PropManager> .instance; var specialPoints = CollectSpecialPoints(); var depotAI = info.m_buildingAI as DepotAI; var cargoStationAI = info.m_buildingAI as CargoStationAI; var fishingHarborAI = info.m_buildingAI as FishingHarborAI; List <DepotAI.SpawnPoint> spawnPoints = new List <DepotAI.SpawnPoint>(); List <DepotAI.SpawnPoint> spawnPoints2 = new List <DepotAI.SpawnPoint>(); Vector3 unspawnPosition = Vector3.zero; Vector3 unspawnTarget = Vector3.zero; Vector3 truckSpawnPosition = Vector3.zero; Vector3 truckUnspawnPosition = Vector3.zero; for (ushort index = 0; index < ushort.MaxValue; ++index) { if (((int)instance1.m_props.m_buffer[index].m_flags & 67) == 1) { if (specialPoints.ContainsKey(index)) { if (depotAI != null || cargoStationAI != null || fishingHarborAI != null) { var position = instance1.m_props.m_buffer[index].Position; var globalPosition = matrix4x4_1.MultiplyPoint(position); switch (specialPoints[index]) { case SpecialPointType.SpawnPointPosition: { var calculatedPositionGlobalPosition = FindClosestPositionPoint(specialPoints, SpecialPointType.SpawnPointTarget, instance1, position, globalPosition, matrix4x4_1); spawnPoints.Add(new DepotAI.SpawnPoint() { m_position = globalPosition.MirrorZ(), m_target = calculatedPositionGlobalPosition.MirrorZ(), }); break; } case SpecialPointType.SpawnPoint2Position: { if (depotAI != null || cargoStationAI != null) { var calculatedPositionGlobalPosition = FindClosestPositionPoint(specialPoints, SpecialPointType.SpawnPoint2Target, instance1, position, globalPosition, matrix4x4_1); spawnPoints2.Add(new DepotAI.SpawnPoint() { m_position = globalPosition.MirrorZ(), m_target = calculatedPositionGlobalPosition.MirrorZ(), }); } break; } case SpecialPointType.DespawnPointPosition: { if (fishingHarborAI != null) { unspawnPosition = globalPosition.MirrorZ(); } break; } case SpecialPointType.DespawnPointTarget: { if (fishingHarborAI != null) { unspawnTarget = globalPosition.MirrorZ(); } break; } case SpecialPointType.TruckSpawnPosition: { if (cargoStationAI != null) { truckSpawnPosition = globalPosition.MirrorZ(); } break; } case SpecialPointType.TruckDespawnPosition: { if (cargoStationAI != null) { truckUnspawnPosition = globalPosition.MirrorZ(); } break; } default: continue; //ignored } } continue; } //end mod BuildingInfo.Prop prop = new BuildingInfo.Prop(); prop.m_prop = instance1.m_props.m_buffer[index].Info; prop.m_finalProp = prop.m_prop; prop.m_position = matrix4x4.MultiplyPoint(instance1.m_props.m_buffer[index].Position); prop.m_radAngle = instance1.m_props.m_buffer[index].Angle - data.m_angle; prop.m_angle = 57.29578f * prop.m_radAngle; prop.m_fixedHeight = instance1.m_props.m_buffer[index].FixedHeight; //begin mod var flag = false; foreach (var mProp in info.m_props ?? new BuildingInfo.Prop[] {}) { if (mProp.m_prop != prop.m_prop || Vector3.Distance(mProp.m_position, prop.m_position) > 0.01) { continue; } prop.m_probability = mProp.m_probability; flag = true; Debug.Log($"Setting probability of {prop.m_prop.name} to {prop.m_probability}"); break; } if (!flag) { prop.m_probability = 100; } //end mod fastList.Add(prop); } } //begin mod if (depotAI != null) { if (OptionsWrapper <Options> .Options.PreciseSpecialPointsPostions) { var ai = (DepotAI)((BuildingInfo)ToolsModifierControl.toolController.m_editPrefabInfo).m_buildingAI; depotAI.m_spawnPoints = ai.m_spawnPoints; depotAI.m_spawnPosition = ai.m_spawnPosition; depotAI.m_spawnTarget = ai.m_spawnTarget; depotAI.m_spawnPoints2 = ai.m_spawnPoints2; depotAI.m_spawnPosition2 = ai.m_spawnPosition2; depotAI.m_spawnTarget2 = ai.m_spawnTarget2; } else { if (depotAI.m_transportInfo != null) { if (spawnPoints.Count == 1) { depotAI.m_spawnPosition = spawnPoints[0].m_position; depotAI.m_spawnTarget = spawnPoints[0].m_target; depotAI.m_spawnPoints = new DepotAI.SpawnPoint[] { }; } else if (spawnPoints.Count > 1) { depotAI.m_spawnPosition = Vector3.zero; depotAI.m_spawnTarget = Vector3.zero; depotAI.m_spawnPoints = spawnPoints.ToArray(); } else { depotAI.m_spawnPosition = Vector3.zero; depotAI.m_spawnTarget = Vector3.zero; depotAI.m_spawnPoints = new DepotAI.SpawnPoint[] { }; } } else { depotAI.m_spawnPosition = Vector3.zero; depotAI.m_spawnTarget = Vector3.zero; depotAI.m_spawnPoints = new DepotAI.SpawnPoint[] { }; } if (depotAI.m_secondaryTransportInfo != null) { if (spawnPoints2.Count == 1) { depotAI.m_spawnPosition2 = spawnPoints2[0].m_position; depotAI.m_spawnTarget2 = spawnPoints2[0].m_target; depotAI.m_spawnPoints2 = new DepotAI.SpawnPoint[] { }; } else if (spawnPoints2.Count > 1) { depotAI.m_spawnPosition2 = Vector3.zero; depotAI.m_spawnTarget2 = Vector3.zero; depotAI.m_spawnPoints2 = spawnPoints2.ToArray(); } else { depotAI.m_spawnPosition2 = Vector3.zero; depotAI.m_spawnTarget2 = Vector3.zero; depotAI.m_spawnPoints2 = new DepotAI.SpawnPoint[] { }; } } else { depotAI.m_spawnPosition2 = Vector3.zero; depotAI.m_spawnTarget2 = Vector3.zero; depotAI.m_spawnPoints2 = new DepotAI.SpawnPoint[] { }; } } } if (cargoStationAI != null) { if (OptionsWrapper <Options> .Options.PreciseSpecialPointsPostions) { var ai = (CargoStationAI)((BuildingInfo)ToolsModifierControl.toolController.m_editPrefabInfo).m_buildingAI; cargoStationAI.m_spawnPosition = ai.m_spawnPosition; cargoStationAI.m_spawnTarget = ai.m_spawnTarget; cargoStationAI.m_spawnPosition2 = ai.m_spawnPosition2; cargoStationAI.m_spawnTarget2 = ai.m_spawnTarget2; cargoStationAI.m_truckSpawnPosition = ai.m_truckSpawnPosition; cargoStationAI.m_truckUnspawnPosition = ai.m_truckUnspawnPosition; } else { if (cargoStationAI.m_transportInfo != null) { if (spawnPoints.Count == 1) { cargoStationAI.m_spawnPosition = spawnPoints[0].m_position; cargoStationAI.m_spawnTarget = spawnPoints[0].m_target; } else if (spawnPoints.Count == 0) { cargoStationAI.m_spawnPosition = Vector3.zero; cargoStationAI.m_spawnTarget = Vector3.zero; } else { UnityEngine.Debug.LogError("Too many spawn points 1!"); } } else { cargoStationAI.m_spawnPosition = Vector3.zero; cargoStationAI.m_spawnTarget = Vector3.zero; } if (cargoStationAI.m_transportInfo2 != null) { if (spawnPoints2.Count == 1) { cargoStationAI.m_spawnPosition2 = spawnPoints2[0].m_position; cargoStationAI.m_spawnTarget2 = spawnPoints2[0].m_target; } else if (spawnPoints2.Count == 0) { cargoStationAI.m_spawnPosition2 = Vector3.zero; cargoStationAI.m_spawnTarget2 = Vector3.zero; } else { UnityEngine.Debug.LogError("Too many spawn points 2!"); } } else { cargoStationAI.m_spawnPosition2 = Vector3.zero; cargoStationAI.m_spawnTarget2 = Vector3.zero; } cargoStationAI.m_truckSpawnPosition = truckSpawnPosition; cargoStationAI.m_truckUnspawnPosition = truckUnspawnPosition; } } if (fishingHarborAI != null) { if (OptionsWrapper <Options> .Options.PreciseSpecialPointsPostions) { var ai = (FishingHarborAI)((BuildingInfo)ToolsModifierControl.toolController.m_editPrefabInfo).m_buildingAI; fishingHarborAI.m_boatSpawnPosition = ai.m_boatSpawnPosition; fishingHarborAI.m_boatSpawnTarget = ai.m_boatSpawnTarget; fishingHarborAI.m_boatUnspawnPosition = ai.m_boatUnspawnPosition; fishingHarborAI.m_boatUnspawnTarget = ai.m_boatUnspawnTarget; } else { if (spawnPoints.Count == 1) { fishingHarborAI.m_boatSpawnPosition = spawnPoints[0].m_position; fishingHarborAI.m_boatSpawnTarget = spawnPoints[0].m_target; } else if (spawnPoints.Count == 0) { fishingHarborAI.m_boatSpawnPosition = Vector3.zero; fishingHarborAI.m_boatUnspawnPosition = Vector3.zero; } else { UnityEngine.Debug.LogError("Can be only 1 spawn point!"); } fishingHarborAI.m_boatUnspawnPosition = unspawnPosition; fishingHarborAI.m_boatUnspawnTarget = unspawnTarget; } } //end mod TreeManager instance2 = Singleton <TreeManager> .instance; for (int index = 0; index < instance2.m_trees.m_buffer.Length; ++index) { if (((int)instance2.m_trees.m_buffer[index].m_flags & 3) == 1 && instance2.m_trees.m_buffer[index].GrowState != 0) { BuildingInfo.Prop prop = new BuildingInfo.Prop(); prop.m_tree = instance2.m_trees.m_buffer[index].Info; prop.m_finalTree = prop.m_tree; prop.m_position = matrix4x4.MultiplyPoint(instance2.m_trees.m_buffer[index].Position); prop.m_fixedHeight = instance2.m_trees.m_buffer[index].FixedHeight; //begin mod var flag = false; foreach (var mProp in info.m_props ?? new BuildingInfo.Prop[] {}) { if (mProp.m_tree != prop.m_tree || Vector3.Distance(mProp.m_position, prop.m_position) > 0.01) { continue; } prop.m_probability = mProp.m_probability; flag = true; Debug.Log($"Setting probability of {prop.m_tree.name} to {prop.m_probability}"); break; } if (!flag) { prop.m_probability = 100; } //end mod fastList.Add(prop); } } info.m_props = fastList.ToArray(); }
protected void CheckCollisions(ushort instanceID, ref CitizenInstance citizenData, Vector3 sourcePos, Vector3 targetPos, ushort buildingID, ref Vector3 pushAmount, ref float pushDivider) { Segment3 segment = new Segment3(sourcePos, targetPos); Vector3 min = segment.Min(); min.x -= this.m_info.m_radius; min.z -= this.m_info.m_radius; Vector3 max = segment.Max(); max.x += this.m_info.m_radius; max.y += this.m_info.m_height; max.z += this.m_info.m_radius; CitizenManager instance = Singleton <CitizenManager> .instance; int num = Mathf.Max((int)((min.x - 3f) / 8f + 1080f), 0); int num2 = Mathf.Max((int)((min.z - 3f) / 8f + 1080f), 0); int num3 = Mathf.Min((int)((max.x + 3f) / 8f + 1080f), 2159); int num4 = Mathf.Min((int)((max.z + 3f) / 8f + 1080f), 2159); for (int i = num2; i <= num4; i++) { for (int j = num; j <= num3; j++) { ushort num5 = instance.m_citizenGrid [i * 2160 + j]; int num6 = 0; while (num5 != 0) { num5 = this.CheckCollisions(instanceID, ref citizenData, segment, min, max, num5, ref instance.m_instances.m_buffer [(int)num5], ref pushAmount, ref pushDivider); if (++num6 > 65536) { CODebugBase <LogChannel> .Error(LogChannel.Core, "Invalid list detected!\n" + Environment.StackTrace); break; } } } } VehicleManager instance2 = Singleton <VehicleManager> .instance; int num7 = Mathf.Max((int)((min.x - 10f) / 32f + 270f), 0); int num8 = Mathf.Max((int)((min.z - 10f) / 32f + 270f), 0); int num9 = Mathf.Min((int)((max.x + 10f) / 32f + 270f), 539); int num10 = Mathf.Min((int)((max.z + 10f) / 32f + 270f), 539); for (int k = num8; k <= num10; k++) { for (int l = num7; l <= num9; l++) { ushort num11 = instance2.m_vehicleGrid [k * 540 + l]; int num12 = 0; while (num11 != 0) { num11 = this.CheckCollisions(instanceID, ref citizenData, segment, min, max, num11, ref instance2.m_vehicles.m_buffer [(int)num11], ref pushAmount, ref pushDivider); if (++num12 > 65536) { CODebugBase <LogChannel> .Error(LogChannel.Core, "Invalid list detected!\n" + Environment.StackTrace); break; } } } } for (int m = num8; m <= num10; m++) { for (int n = num7; n <= num9; n++) { ushort num13 = instance2.m_parkedGrid [m * 540 + n]; int num14 = 0; while (num13 != 0) { num13 = this.CheckCollisions(instanceID, ref citizenData, segment, min, max, num13, ref instance2.m_parkedVehicles.m_buffer [(int)num13], ref pushAmount, ref pushDivider); if (++num14 > 65536) { CODebugBase <LogChannel> .Error(LogChannel.Core, "Invalid list detected!\n" + Environment.StackTrace); break; } } } } if (buildingID != 0) { BuildingManager instance3 = Singleton <BuildingManager> .instance; BuildingInfo info = instance3.m_buildings.m_buffer [(int)buildingID].Info; if (info.m_props != null) { Vector3 position = instance3.m_buildings.m_buffer [(int)buildingID].m_position; float angle = instance3.m_buildings.m_buffer [(int)buildingID].m_angle; int length = instance3.m_buildings.m_buffer [(int)buildingID].Length; Matrix4x4 matrix4x = default(Matrix4x4); matrix4x.SetTRS(Building.CalculateMeshPosition(info, position, angle, length), Quaternion.AngleAxis(angle * 57.29578f, Vector3.down), Vector3.one); for (int num15 = 0; num15 < info.m_props.Length; num15++) { BuildingInfo.Prop prop = info.m_props [num15]; Randomizer randomizer = new Randomizer((int)buildingID << 6 | prop.m_index); if (randomizer.Int32(100u) < prop.m_probability && length >= prop.m_requiredLength) { Vector3 vector = matrix4x.MultiplyPoint(prop.m_position); if (vector.x >= min.x - 2f && vector.x <= max.x + 2f) { if (vector.z >= min.z - 2f && vector.z <= max.z + 2f) { PropInfo propInfo = prop.m_finalProp; TreeInfo treeInfo = prop.m_finalTree; float num16 = 0f; float num17 = 0f; if (propInfo != null) { propInfo = propInfo.GetVariation(ref randomizer); if (propInfo.m_isMarker || propInfo.m_isDecal || !propInfo.m_hasRenderer) { goto IL_7D3; } num16 = propInfo.m_generatedInfo.m_size.x * 0.5f; num17 = propInfo.m_generatedInfo.m_size.y; } else { if (treeInfo != null) { treeInfo = treeInfo.GetVariation(ref randomizer); num16 = (treeInfo.m_generatedInfo.m_size.x + treeInfo.m_generatedInfo.m_size.z) * 0.125f; num17 = treeInfo.m_generatedInfo.m_size.y; } } if (!prop.m_fixedHeight) { vector.y = Singleton <TerrainManager> .instance.SampleDetailHeight(vector); } else { if (info.m_requireHeightMap) { vector.y = Singleton <TerrainManager> .instance.SampleDetailHeight(vector) + prop.m_position.y; } } if (vector.y + num17 >= min.y && vector.y <= max.y) { num16 = this.m_info.m_radius + num16; float num19; float num18 = segment.DistanceSqr(vector, out num19); if (num18 < num16 * num16) { float num20 = num16 - Mathf.Sqrt(num18); float num21 = 1f - num18 / (num16 * num16); Vector3 a = segment.Position(num19 * 0.9f); a.y = 0f; vector.y = 0f; Vector3 vector2 = Vector3.Normalize(a - vector); Vector3 rhs = Vector3.Normalize(new Vector3(segment.b.x - segment.a.x, 0f, segment.b.z - segment.a.z)); Vector3 vector3 = new Vector3(rhs.z, 0f, -rhs.x) * Mathf.Abs(Vector3.Dot(vector2, rhs) * 0.5f); if (Vector3.Dot(vector2, vector3) >= 0f) { vector2 += vector3; } else { vector2 -= vector3; } pushAmount += vector2 * (num20 * num21); pushDivider += num21; } } } } } IL_7D3: ; } } } }
void RemoveSkippedFromBuilding(BuildingInfo info) { BuildingInfo.Prop[] props = info.m_props; if (props == null || props.Length == 0) { return; } try { //StreamWriter wp = new StreamWriter(Path.Combine(Util.GetSavePath(), "Building-props.txt"), true); //wp.WriteLine(info.name); List <BuildingInfo.Prop> keepThese = new List <BuildingInfo.Prop>(props.Length); bool skippedSome = false; for (int i = 0; i < props.Length; i++) { BuildingInfo.Prop prop = props[i]; if (prop == null) { continue; } //if (prop.m_prop != null) // wp.WriteLine(" " + prop.m_prop.name); if (prop.m_prop == null) { keepThese.Add(prop); } else if (Skip(prop.m_prop)) { //Util.DebugPrint(prop.m_prop.name, "-> RemoveSkippedFromBuilding at", Profiling.Millis, "/", info.name); prop.m_prop = prop.m_finalProp = null; skippedSome = true; } else { keepThese.Add(prop); } } if (skippedSome) { info.m_props = keepThese.ToArray(); if (info.m_props.Length == 0) { // Less log clutter. if (info.m_buildingAI is CommonBuildingAI cbai) { cbai.m_ignoreNoPropsWarning = true; } else if (info.GetComponent <BuildingAI>() is CommonBuildingAI cbai2) { cbai2.m_ignoreNoPropsWarning = true; } } } keepThese.Clear(); //wp.Close(); } catch (Exception e) { UnityEngine.Debug.LogException(e); } }