private void UpdateVehicleEffects() { eventVehicleUpdateStart?.Invoke(); try { effectPlacementRequests = new List <VehicleEffectsDefinition.Vehicle>(); vehicleEffectsDefParseErrors = new HashSet <string>(); var lockedVehicles = new HashSet <VehicleInfo>(); var checkedPaths = new List <string>(); var loadedDefinitions = new List <VehicleEffectsDefinition>(); var definitionPackages = new Dictionary <VehicleEffectsDefinition, string>(); // Load definitions from mod folders foreach (var current in ColossalFramework.Plugins.PluginManager.instance.GetPluginsInfo()) { if (current.isEnabled) { var vehicleEffectsDefPath = Path.Combine(current.modPath, filename); // skip files which were already parsed if (checkedPaths.Contains(vehicleEffectsDefPath)) { continue; } checkedPaths.Add(vehicleEffectsDefPath); if (!File.Exists(vehicleEffectsDefPath)) { continue; } VehicleEffectsDefinition vehicleEffectsDef = null; var xmlSerializer = new XmlSerializer(typeof(VehicleEffectsDefinition)); try { using (var streamReader = new System.IO.StreamReader(vehicleEffectsDefPath)) { vehicleEffectsDef = xmlSerializer.Deserialize(streamReader) as VehicleEffectsDefinition; } } catch (Exception e) { Logging.LogException(e); vehicleEffectsDefParseErrors.Add(current.name + " - " + e.Message); continue; } Logging.Log("Loading definition from Mod " + current.name); vehicleEffectsDef.LoadedFromMod = true; loadedDefinitions.Add(vehicleEffectsDef); definitionPackages.Add(vehicleEffectsDef, current.name); } } // Load definitions from prefabs for (uint i = 0; i < PrefabCollection <VehicleInfo> .LoadedCount(); i++) { var prefab = PrefabCollection <VehicleInfo> .GetLoaded(i); if (prefab == null) { continue; } // search for VehicleEffectsDefinition.xml var asset = PackageManager.FindAssetByName(prefab.name); var crpPath = asset?.package?.packagePath; if (crpPath == null) { continue; } var vehicleEffectsDefPath = Path.Combine(Path.GetDirectoryName(crpPath) ?? "", filename); // skip files which were already parsed if (checkedPaths.Contains(vehicleEffectsDefPath)) { continue; } checkedPaths.Add(vehicleEffectsDefPath); if (!File.Exists(vehicleEffectsDefPath)) { continue; } VehicleEffectsDefinition vehicleEffectsDef = null; var xmlSerializer = new XmlSerializer(typeof(VehicleEffectsDefinition)); try { using (var streamReader = new System.IO.StreamReader(vehicleEffectsDefPath)) { vehicleEffectsDef = xmlSerializer.Deserialize(streamReader) as VehicleEffectsDefinition; } } catch (Exception e) { Logging.LogException(e); vehicleEffectsDefParseErrors.Add(asset.package.packageName + " - " + e.Message); continue; } loadedDefinitions.Add(vehicleEffectsDef); definitionPackages.Add(vehicleEffectsDef, asset.package.packageName); } // Apply the effects foreach (var vehicleEffectsDef in loadedDefinitions) { if (vehicleEffectsDef?.Vehicles == null || vehicleEffectsDef.Vehicles.Count == 0) { vehicleEffectsDefParseErrors.Add(definitionPackages[vehicleEffectsDef] + " - vehicleEffectDef is null or empty."); continue; } foreach (var vehicleDef in vehicleEffectsDef.Vehicles) { ParseVehicleDefinition(vehicleDef, definitionPackages[vehicleEffectsDef], ref changes, ref vehicleEffectsDefParseErrors, ignoreModVehicleParseErrors ? vehicleEffectsDef.LoadedFromMod : false); // Mods can be used as packs, not all vehicles may be loaded so we surpress vehicle parse errors } } } catch (Exception e) { Logging.LogException(e); } if (vehicleEffectsDefParseErrors?.Count > 0 && showParseErrors) { var errorMessage = vehicleEffectsDefParseErrors.Aggregate("Error while parsing vehicle effect definition file(s). Assets will work but may have effects missing. Contact the author of the asset(s). \n" + "List of errors:\n", (current, error) => current + (error + '\n')); UIView.library.ShowModal <ExceptionPanel>("ExceptionPanel").SetMessage("Vehicle Effects", errorMessage, false); } vehicleEffectsDefParseErrors = null; hasChangedPrefabs = true; eventVehicleUpdateFinished?.Invoke(); }
public static void ParseEffectDefinition(VehicleEffectsDefinition.Vehicle vehicleDef, VehicleEffectsDefinition.Effect effectDef, List <VehicleInfo.Effect> effectsList, ref HashSet <string> parseErrors) { if (effectDef?.Name == null) { parseErrors.Add(vehicleDef.Name + " - Effect name missing."); return; } string effectName = (effectDef.Replacment == null) ? effectDef.Name : effectDef.Replacment; effectName += (effectDef.Base != null) ? " - " + effectDef.Base : ""; var effectPrefab = FindEffect(effectName); if (effectPrefab == null) { //This effect is either a 'special' effect or simply non existent if (effectName.StartsWith("Vehicle Effect Wrapper")) { // Wrapper for effects if (effectDef.Base != null) { var baseEffect = FindEffect(effectDef.Base); if (baseEffect != null) { effectPrefab = CustomVehicleEffect.CreateEffect(effectDef, baseEffect); if (effectPrefab == null) { parseErrors.Add(vehicleDef.Name + ": An error occured trying to create a custom effect. Check debug log for details."); return; } } else { // Try fallback if (effectDef.Fallback != null) { Logging.Log(vehicleDef.Name + ": trying to use fallback " + effectDef.Fallback + " for " + effectName); if (effectDef.Fallback.StartsWith("None")) { // None specified as fallback, just exit return; } else if (effectDef.Fallback.StartsWith("Remove") && effectDef.Replacment != null) { // Remove the existing effect effectName = "Remove"; effectPrefab = null; } else { baseEffect = FindEffect(effectDef.Fallback); if (baseEffect != null) { effectPrefab = CustomVehicleEffect.CreateEffect(effectDef, baseEffect); if (effectPrefab == null) { parseErrors.Add(vehicleDef.Name + ": An error occured trying to create a custom effect. Check debug log for details."); return; } } else { parseErrors.Add(vehicleDef.Name + ": Vehicle Effect Wrapper fallback " + effectDef.Fallback + " was needed for " + effectDef.Base + " but not loaded either!"); } } } else { parseErrors.Add(vehicleDef.Name + ": Vehicle Effect Wrapper base effect " + effectDef.Base + " was not loaded and no fallback was specified!"); return; } } } else { parseErrors.Add(vehicleDef.Name + ": Vehicle Effect Wrapper requires a base effect but it wasn't given"); return; } } else if (effectName.StartsWith("Vehicle Effect Multi")) { // Custom MultiEffect defined in the xml if (effectDef.SubEffects != null) { List <MultiEffect.SubEffect> loadedSubEffects = new List <MultiEffect.SubEffect>(); foreach (var subEffect in effectDef.SubEffects) { var dummyList = new List <VehicleInfo.Effect>(); ParseEffectDefinition(vehicleDef, subEffect.Effect, dummyList, ref parseErrors); if (dummyList.Count > 0) { loadedSubEffects.Add(new MultiEffect.SubEffect() { m_effect = dummyList[0].m_effect, m_endTime = subEffect.EndTime, m_startTime = subEffect.StartTime, m_probability = subEffect.Probability }); } } effectPrefab = CustomVehicleMultiEffect.CreateEffect(effectDef, loadedSubEffects.ToArray(), effectDef.Duration, effectDef.UseSimulationTime); } else { parseErrors.Add(vehicleDef.Name + " Vehicle Effect Multi with no sub effects!"); return; } } else if (effectName.StartsWith("None") || effectName.StartsWith("Remove")) { // Not a real effect, but keywords used for removal of an existing effect. // 'None' included for < 1.2c compatibility effectName = "Remove"; effectPrefab = null; } else { // Try fallback if (effectDef.Fallback != null) { Logging.Log(vehicleDef.Name + ": trying to use fallback " + effectDef.Fallback + " for " + effectName); if (effectDef.Fallback.StartsWith("None")) { // None specified as fallback, just exit return; } else if (effectDef.Fallback.StartsWith("Remove") && effectDef.Replacment != null) { // Remove the existing effect effectName = "Remove"; effectPrefab = null; } else { effectPrefab = FindEffect(effectDef.Fallback); if (effectPrefab == null) { parseErrors.Add(vehicleDef.Name + " requested non-existing effect " + effectName + " and fallback " + effectDef.Fallback + " could not be found either!"); return; } } } else { parseErrors.Add(vehicleDef.Name + " requested non-existing effect " + effectName + " and no fallback was specified"); return; } } } if (effectPrefab == null && !effectName.Equals("Remove")) { parseErrors.Add(vehicleDef.Name + " - Effect with name " + effectDef.Name + " not loaded."); return; } var vehicleInfoEffect = new VehicleInfo.Effect { m_effect = effectPrefab, m_parkedFlagsForbidden = VehicleParked.Flags.Created, m_parkedFlagsRequired = VehicleParked.Flags.None, m_vehicleFlagsForbidden = (Vehicle.Flags)effectDef.ForbiddenFlags, m_vehicleFlagsRequired = ((Vehicle.Flags)effectDef.RequiredFlags) | Vehicle.Flags.Created }; if (effectDef.Replacment == null) { effectsList.Add(vehicleInfoEffect); } else { int indexToRemove = -1; for (int i = 0; i < effectsList.Count; i++) { if (effectsList[i].m_effect.name.Equals(effectDef.Name)) { if (effectDef.Replacment.Equals("Remove")) { indexToRemove = i; break; } effectsList[i] = vehicleInfoEffect; break; } } if (indexToRemove >= 0) { effectsList.RemoveAt(indexToRemove); } } }
public void ReloadVehicleEffects() { Logging.Log("Reloading Vehicle Effects"); ResetVehicleEffects(); UpdateVehicleEffects(); }