Created
November 13, 2015 17:32
-
-
Save boformer/31ec55ce97c040bbc89a to your computer and use it in GitHub Desktop.
Sub-Buildings Enabler Mod for Cities: Skylines
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using ColossalFramework.IO; | |
using ColossalFramework.Packaging; | |
using ColossalFramework.UI; | |
using ICities; | |
using System; | |
using System.Collections.Generic; | |
using System.ComponentModel; | |
using System.IO; | |
using System.Xml.Serialization; | |
using UnityEngine; | |
namespace SubBuildingsEnabler | |
{ | |
public class SubBuildingsEnablerMod : LoadingExtensionBase, IUserMod | |
{ | |
public string Name | |
{ | |
get { return "Sub-Buildings Enabler"; } | |
} | |
public string Description | |
{ | |
get { return "Adds support for large custom buildings made of multiple parts (e.g. airports with multiple gates)"; } | |
} | |
public override void OnLevelLoaded(LoadMode mode) | |
{ | |
base.OnLevelLoaded(mode); | |
// Don't load in asset editor (saving asset with sub-buildings causes error) | |
if (mode == LoadMode.NewAsset || mode == LoadMode.LoadAsset) return; | |
var subBuildingsDefParseErrors = new HashSet<string>(); | |
var checkedPaths = new List<string>(); | |
for (uint i = 0; i < PrefabCollection<BuildingInfo>.LoadedCount(); i++) | |
{ | |
var prefab = PrefabCollection<BuildingInfo>.GetLoaded(i); | |
if (prefab == null) continue; | |
// search for SubBuildingsEnabler.xml | |
var asset = PackageManager.FindAssetByName(prefab.name); | |
if (asset == null || asset.package == null) continue; | |
var crpPath = asset.package.packagePath; | |
if (crpPath == null) continue; | |
var subBuildingsDefPath = Path.Combine(Path.GetDirectoryName(crpPath), "SubBuildingsDefinition.xml"); | |
// skip files which were already parsed | |
if (checkedPaths.Contains(subBuildingsDefPath)) continue; | |
checkedPaths.Add(subBuildingsDefPath); | |
if (!File.Exists(subBuildingsDefPath)) continue; | |
SubBuildingsDefinition subBuildingsDef = null; | |
var xmlSerializer = new XmlSerializer(typeof(SubBuildingsDefinition)); | |
try | |
{ | |
using (StreamReader streamReader = new System.IO.StreamReader(subBuildingsDefPath)) | |
{ | |
subBuildingsDef = xmlSerializer.Deserialize(streamReader) as SubBuildingsDefinition; | |
} | |
} | |
catch (Exception e) | |
{ | |
Debug.LogException(e); | |
subBuildingsDefParseErrors.Add(asset.package.packageName + " - " + e.Message); | |
continue; | |
} | |
if (subBuildingsDef == null || subBuildingsDef.Buildings == null || subBuildingsDef.Buildings.Count == 0) | |
{ | |
subBuildingsDefParseErrors.Add(asset.package.packageName + " - subBuildingsDef is null or empty."); | |
continue; | |
} | |
foreach (var parentBuildingDef in subBuildingsDef.Buildings) | |
{ | |
if (parentBuildingDef == null || parentBuildingDef.Name == null) | |
{ | |
subBuildingsDefParseErrors.Add(asset.package.packageName + " - Building name missing."); | |
continue; | |
} | |
var parentBuildingPrefab = FindPrefab(parentBuildingDef.Name, asset.package.packageName); | |
if (parentBuildingPrefab == null) | |
{ | |
subBuildingsDefParseErrors.Add(asset.package.packageName + " - Building with name " + parentBuildingDef.Name + " not loaded."); | |
continue; | |
} | |
if (parentBuildingDef.SubBuildings == null || parentBuildingDef.SubBuildings.Count == 0) | |
{ | |
subBuildingsDefParseErrors.Add(asset.package.packageName + " - No sub buildings specified for " + parentBuildingDef.Name + "."); | |
continue; | |
} | |
var subBuildings = new List<BuildingInfo.SubInfo>(); | |
foreach (var subBuildingDef in parentBuildingDef.SubBuildings) | |
{ | |
if (subBuildingDef == null || subBuildingDef.Name == null) | |
{ | |
subBuildingsDefParseErrors.Add(parentBuildingDef.Name + " - Sub-building name missing."); | |
continue; | |
} | |
var subBuildingPrefab = FindPrefab(subBuildingDef.Name, asset.package.packageName); | |
if (subBuildingPrefab == null) | |
{ | |
subBuildingsDefParseErrors.Add(parentBuildingDef.Name + " - Sub-building with name " + subBuildingDef.Name + " not loaded."); | |
continue; | |
} | |
var subBuilding = new BuildingInfo.SubInfo | |
{ | |
m_buildingInfo = subBuildingPrefab, | |
m_position = new Vector3(subBuildingDef.PosX, subBuildingDef.PosY, subBuildingDef.PosZ), | |
m_angle = subBuildingDef.Angle, | |
m_fixedHeight = subBuildingDef.FixedHeight | |
}; | |
subBuildings.Add(subBuilding); | |
// this is usually done in the InitializePrefab method | |
if (subBuildingDef.FixedHeight && !parentBuildingPrefab.m_fixedHeight) parentBuildingPrefab.m_fixedHeight = true; | |
} | |
if (subBuildings.Count == 0) | |
{ | |
subBuildingsDefParseErrors.Add("No sub buildings specified for " + parentBuildingDef.Name + "."); | |
continue; | |
} | |
parentBuildingPrefab.m_subBuildings = subBuildings.ToArray(); | |
} | |
} | |
if (subBuildingsDefParseErrors.Count > 0) | |
{ | |
var errorMessage = "Error while parsing sub-building definition file(s). Contact the author of the assets. \n" | |
+ "List of errors:\n"; | |
foreach (var error in subBuildingsDefParseErrors) errorMessage += error + '\n'; | |
UIView.library.ShowModal<ExceptionPanel>("ExceptionPanel").SetMessage("Sub-Buildings Enabler", errorMessage, true); | |
} | |
} | |
private BuildingInfo FindPrefab(string prefabName, string packageName) | |
{ | |
var prefab = PrefabCollection<BuildingInfo>.FindLoaded(prefabName); | |
if (prefab == null) prefab = PrefabCollection<BuildingInfo>.FindLoaded(prefabName + "_Data"); | |
if (prefab == null) prefab = PrefabCollection<BuildingInfo>.FindLoaded(PathEscaper.Escape(prefabName) + "_Data"); | |
if (prefab == null) prefab = PrefabCollection<BuildingInfo>.FindLoaded(packageName + "." + prefabName + "_Data"); | |
if (prefab == null) prefab = PrefabCollection<BuildingInfo>.FindLoaded(packageName + "." + PathEscaper.Escape(prefabName) + "_Data"); | |
return prefab; | |
} | |
} | |
public class SubBuildingsDefinition | |
{ | |
public List<Building> Buildings { get; set; } | |
public SubBuildingsDefinition() | |
{ | |
Buildings = new List<Building>(); | |
} | |
public class Building | |
{ | |
[XmlAttribute("name"), DefaultValue(null)] | |
public string Name { get; set; } | |
public List<SubBuilding> SubBuildings { get; set; } | |
public Building() | |
{ | |
SubBuildings = new List<SubBuilding>(); | |
} | |
} | |
public class SubBuilding | |
{ | |
[XmlAttribute("name"), DefaultValue(null)] | |
public string Name { get; set; } | |
[XmlAttribute("pos-x"), DefaultValue(0f)] | |
public float PosX { get; set; } | |
[XmlAttribute("pos-y"), DefaultValue(0f)] | |
public float PosY { get; set; } | |
[XmlAttribute("pos-z"), DefaultValue(0f)] | |
public float PosZ { get; set; } | |
[XmlAttribute("angle"), DefaultValue(0f)] | |
public float Angle { get; set; } | |
[XmlAttribute("fixed-height"), DefaultValue(true)] | |
public bool FixedHeight { get; set; } | |
public SubBuilding() | |
{ | |
FixedHeight = true; | |
} | |
} | |
/* | |
public static void Save(SubBuildingsDefinition instance) | |
{ | |
if (instance != null) | |
{ | |
var configPath = "SubBuildingsEnabler.xml"; | |
XmlSerializer xmlSerializer = new XmlSerializer(typeof(SubBuildingsDefinition)); | |
XmlSerializerNamespaces noNamespaces = new XmlSerializerNamespaces(); | |
noNamespaces.Add("", ""); | |
try | |
{ | |
using (StreamWriter streamWriter = new System.IO.StreamWriter(configPath)) | |
{ | |
xmlSerializer.Serialize(streamWriter, instance, noNamespaces); | |
} | |
} | |
catch (Exception e) | |
{ | |
Debug.LogException(e); | |
} | |
} | |
} | |
*/ | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment