void AddToQueue(List <Package.Asset>[] queues, CustomAssetMetaData meta, int offset, bool dontSpawn) { Package.Asset assetRef = meta.assetRef; if (assetRef == null) { Util.DebugPrint(meta.name, " Warning : NULL asset"); return; } CustomAssetMetaData.Type type = meta.type; Package package = assetRef.package; string fullName = type < CustomAssetMetaData.Type.RoadElevation ? assetRef.fullName : PillarOrElevationName(package.packageName, assetRef.name); if (!IsDuplicate(fullName, allLoads[(int)type], package)) { queues[loadQueueIndex[(int)type] + offset].Add(assetRef); metaTypes[assetRef.fullName] = type; if (dontSpawn) { dontSpawnNormally.Add(fullName); } if (type == CustomAssetMetaData.Type.Citizen) { citizenMetaDatas[fullName] = meta; } } }
void AddToQueue(List <Package.Asset>[] queues, CustomAssetMetaData meta, CustomAssetMetaData.Type type, int offset, bool dontSpawn) { Package.Asset assetRef = meta.assetRef; if (assetRef == null) { Util.DebugPrint(meta.name, " Error : NULL asset"); return; } if (assetRef.fullName == null) { Util.DebugPrint(meta.name, " Warning : NULL asset name"); } Package package = assetRef.package; string fullName = type < CustomAssetMetaData.Type.RoadElevation ? assetRef.fullName : PillarOrElevationName(package.packageName, assetRef.name); if (!IsDuplicate(assetRef, type, queues)) { int index = Math.Max(loadQueueIndex[(int)type] + offset, 0); queues[index].Add(assetRef); metaDatas[assetRef.fullName] = new SomeMetaData(meta.userDataRef, meta.name, type); if (dontSpawn) { dontSpawnNormally.Add(fullName); } if (type == CustomAssetMetaData.Type.Citizen) { citizenMetaDatas[fullName] = meta; } } }
static void AddRef(PrefabInfo info, string fullName, CustomAssetMetaData.Type type) { if (info == null) { if (type == CustomAssetMetaData.Type.Prop && instance.skipProps && SkippedProps.Contains(fullName)) { return; } // The referenced asset is missing. Package.Asset container = FindContainer(); if (container != null) { AssetReport.instance.AddReference(container, fullName, type); } } else if (info.m_isCustomContent) { string r = info.name; Package.Asset container = FindContainer(); if (!string.IsNullOrEmpty(r) && container != null) { string packageName = container.package.packageName; int i = r.IndexOf('.'); string r2; if (i >= 0 && (i != packageName.Length || !r.StartsWith(packageName)) && (r2 = FindMain(r)) != null) { AssetReport.instance.AddReference(container, r2, type); } } } }
internal void AddMissing(string fullName, CustomAssetMetaData.Type type) { if (!assets.TryGetValue(fullName, out Item child)) { assets.Add(fullName, new Missing(fullName, type, useddir: true)); } else { child.UsedDir = true; } }
internal void AddReference(Package.Asset knownRef, string fullName, CustomAssetMetaData.Type type) { if (!assets.TryGetValue(fullName, out Item child)) { assets.Add(fullName, child = new Missing(fullName, type)); } else { child.type = type; } assets[knownRef.fullName].Add(child); }
bool IsDuplicate(Package.Asset assetRef, CustomAssetMetaData.Type type, List <Package.Asset>[] queues) { string fullName = assetRef.fullName; if (!queuedLoads[(int)type].Add(fullName)) { if (suspects.TryGetValue(fullName, out List <Package.Asset> assets)) { assets.Add(assetRef); } else { int index = loadQueueIndex[(int)type]; int[] indices = index > 0 ? new int[] { index, index - 1 } : new int[] { index }; foreach (int i in indices) { foreach (Package.Asset a in queues[i]) { if (fullName == a.fullName) { suspects.Add(fullName, new List <Package.Asset>(2) { a, assetRef }); return(true); } } } suspects.Add(fullName, new List <Package.Asset>(2) { assetRef }); } return(true); } return(false); }
void Load(Package.Asset asset) { string fullName = null; try { CustomAssetMetaData assetMetaData = asset.Instantiate <CustomAssetMetaData>(); // Always remember: assetRef may point to another package because the deserialization method accepts any asset with a matching checksum. // There is a bug in the 1.6.0 game update in this. fullName = asset.package.packageName + "." + assetMetaData.assetRef.name; CustomAssetMetaData.Type type = assetMetaData.type; bool spawnNormally = (type == CustomAssetMetaData.Type.Building || type == CustomAssetMetaData.Type.SubBuilding) ? loadEnabled && IsEnabled(asset) || loadUsed && UsedAssets.instance.GotBuilding(fullName) : true; stack.Clear(); LoadImpl(fullName, assetMetaData.assetRef, spawnNormally); } catch (Exception e) { AssetFailed(fullName ?? asset.fullName, e); } }
static void ReportMissingAssets <P>(HashSet <string> customAssets, CustomAssetMetaData.Type type) where P : PrefabInfo { try { bool reportAssets = Settings.settings.reportAssets; foreach (string fullName in customAssets) { if (CustomDeserializer.FindLoaded <P>(fullName, tryName:false) == null) { AssetLoader.instance.NotFound(fullName); if (reportAssets) { AssetReport.instance.AddMissing(fullName, type); } } } } catch (Exception e) { UnityEngine.Debug.LogException(e); } }
internal static object CustomDeserialize(Package p, Type t, PackageReader r) { // Props and trees in buildings and parks. if (t == typeof(BuildingInfo.Prop)) { PropInfo pi = Get <PropInfo>(r.ReadString()); // old name format (without package name) is possible TreeInfo ti = Get <TreeInfo>(r.ReadString()); // old name format (without package name) is possible if (instance.report && UsedAssets.instance.GotAnyContainer()) { if (pi != null) { string n = pi.gameObject.name; if (!string.IsNullOrEmpty(n) && n.IndexOf('.') >= 0) { UsedAssets.instance.IndirectProps.Add(n); } } if (ti != null) { string n = ti.gameObject.name; if (!string.IsNullOrEmpty(n) && n.IndexOf('.') >= 0) { UsedAssets.instance.IndirectTrees.Add(n); } } } return(new BuildingInfo.Prop { m_prop = pi, m_tree = ti, m_position = r.ReadVector3(), m_angle = r.ReadSingle(), m_probability = r.ReadInt32(), m_fixedHeight = r.ReadBoolean() }); } // Paths (nets) in buildings. if (t == typeof(BuildingInfo.PathInfo)) { string fullName = r.ReadString(); NetInfo ni = Get <NetInfo>(fullName); BuildingInfo.PathInfo path = new BuildingInfo.PathInfo(); path.m_netInfo = ni; path.m_nodes = r.ReadVector3Array(); path.m_curveTargets = r.ReadVector3Array(); path.m_invertSegments = r.ReadBoolean(); path.m_maxSnapDistance = r.ReadSingle(); if (p.version >= 5) { path.m_forbidLaneConnection = r.ReadBooleanArray(); path.m_trafficLights = (BuildingInfo.TrafficLights[])(object) r.ReadInt32Array(); path.m_yieldSigns = r.ReadBooleanArray(); } return(path); } if (t == typeof(Package.Asset)) { return(r.ReadAsset(p)); } // It seems that trailers are listed in the save game so this is not necessary. Better to be safe however // because a missing trailer reference is fatal for the simulation thread. if (t == typeof(VehicleInfo.VehicleTrailer)) { string name = r.ReadString(); string fullName = p.packageName + "." + name; VehicleInfo vi = Get <VehicleInfo>(p, fullName, name, false); VehicleInfo.VehicleTrailer trailer; trailer.m_info = vi; trailer.m_probability = r.ReadInt32(); trailer.m_invertProbability = r.ReadInt32(); return(trailer); } if (t == typeof(NetInfo.Lane)) { return(new NetInfo.Lane { m_position = r.ReadSingle(), m_width = r.ReadSingle(), m_verticalOffset = r.ReadSingle(), m_stopOffset = r.ReadSingle(), m_speedLimit = r.ReadSingle(), m_direction = (NetInfo.Direction)r.ReadInt32(), m_laneType = (NetInfo.LaneType)r.ReadInt32(), m_vehicleType = (VehicleInfo.VehicleType)r.ReadInt32(), m_stopType = (VehicleInfo.VehicleType)r.ReadInt32(), m_laneProps = GetNetLaneProps(p, r), m_allowConnect = r.ReadBoolean(), m_useTerrainHeight = r.ReadBoolean(), m_centerPlatform = r.ReadBoolean(), m_elevated = r.ReadBoolean() }); } if (t == typeof(NetInfo.Segment)) { NetInfo.Segment segment = new NetInfo.Segment(); string checksum = r.ReadString(); segment.m_mesh = string.IsNullOrEmpty(checksum) ? null : Sharing.instance.GetMesh(checksum, p, true); checksum = r.ReadString(); segment.m_material = string.IsNullOrEmpty(checksum) ? null : Sharing.instance.GetMaterial(checksum, p, true); checksum = r.ReadString(); segment.m_lodMesh = string.IsNullOrEmpty(checksum) ? null : Sharing.instance.GetMesh(checksum, p, false); checksum = r.ReadString(); segment.m_lodMaterial = string.IsNullOrEmpty(checksum) ? null : Sharing.instance.GetMaterial(checksum, p, false); segment.m_forwardRequired = (NetSegment.Flags)r.ReadInt32(); segment.m_forwardForbidden = (NetSegment.Flags)r.ReadInt32(); segment.m_backwardRequired = (NetSegment.Flags)r.ReadInt32(); segment.m_backwardForbidden = (NetSegment.Flags)r.ReadInt32(); segment.m_emptyTransparent = r.ReadBoolean(); segment.m_disableBendNodes = r.ReadBoolean(); return(segment); } if (t == typeof(NetInfo.Node)) { NetInfo.Node node = new NetInfo.Node(); string checksum = r.ReadString(); node.m_mesh = string.IsNullOrEmpty(checksum) ? null : Sharing.instance.GetMesh(checksum, p, true); checksum = r.ReadString(); node.m_material = string.IsNullOrEmpty(checksum) ? null : Sharing.instance.GetMaterial(checksum, p, true); checksum = r.ReadString(); node.m_lodMesh = string.IsNullOrEmpty(checksum) ? null : Sharing.instance.GetMesh(checksum, p, false); checksum = r.ReadString(); node.m_lodMaterial = string.IsNullOrEmpty(checksum) ? null : Sharing.instance.GetMaterial(checksum, p, false); node.m_flagsRequired = (NetNode.Flags)r.ReadInt32(); node.m_flagsForbidden = (NetNode.Flags)r.ReadInt32(); node.m_connectGroup = (NetInfo.ConnectGroup)r.ReadInt32(); node.m_directConnect = r.ReadBoolean(); node.m_emptyTransparent = r.ReadBoolean(); return(node); } if (t == typeof(NetInfo)) { string name = r.ReadString(); CustomAssetMetaData.Type type = AssetLoader.instance.GetMetaType(AssetLoader.instance.Current); if (type == CustomAssetMetaData.Type.Road || type == CustomAssetMetaData.Type.RoadElevation) { return(Get <NetInfo>(p, name)); } else { return(Get <NetInfo>(name)); } } if (t == typeof(BuildingInfo)) { string name = r.ReadString(); CustomAssetMetaData.Type type = AssetLoader.instance.GetMetaType(AssetLoader.instance.Current); if (type == CustomAssetMetaData.Type.Road || type == CustomAssetMetaData.Type.RoadElevation) { return(Get <BuildingInfo>(p, name)); } else { return(Get <BuildingInfo>(name)); } } // Sub-buildings in buildings. if (t == typeof(BuildingInfo.SubInfo)) { string name = r.ReadString(); string fullName = p.packageName + "." + name; BuildingInfo bi = null; if (fullName == AssetLoader.instance.Current.fullName || name == AssetLoader.instance.Current.fullName) { Util.DebugPrint("Warning:", fullName, "wants to be a sub-building for itself"); } else { bi = Get <BuildingInfo>(p, fullName, name, true); } BuildingInfo.SubInfo subInfo = new BuildingInfo.SubInfo(); subInfo.m_buildingInfo = bi; subInfo.m_position = r.ReadVector3(); subInfo.m_angle = r.ReadSingle(); subInfo.m_fixedHeight = r.ReadBoolean(); return(subInfo); } // Prop variations in props. if (t == typeof(PropInfo.Variation)) { string name = r.ReadString(); string fullName = p.packageName + "." + name; PropInfo pi = null; if (fullName == AssetLoader.instance.Current.fullName) { Util.DebugPrint("Warning:", fullName, "wants to be a prop variation for itself"); } else { pi = Get <PropInfo>(p, fullName, name, false); } return(new PropInfo.Variation { m_prop = pi, m_probability = r.ReadInt32() }); } // Tree variations in trees. if (t == typeof(TreeInfo.Variation)) { string name = r.ReadString(); string fullName = p.packageName + "." + name; TreeInfo ti = null; if (fullName == AssetLoader.instance.Current.fullName) { Util.DebugPrint("Warning:", fullName, "wants to be a tree variation for itself"); } else { ti = Get <TreeInfo>(p, fullName, name, false); } return(new TreeInfo.Variation { m_tree = ti, m_probability = r.ReadInt32() }); } if (t == typeof(VehicleInfo.MeshInfo)) { VehicleInfo.MeshInfo meshinfo = new VehicleInfo.MeshInfo(); string checksum = r.ReadString(); if (!string.IsNullOrEmpty(checksum)) { Package.Asset asset = p.FindByChecksum(checksum); GameObject go = AssetDeserializer.Instantiate(asset) as GameObject; meshinfo.m_subInfo = go.GetComponent <VehicleInfoBase>(); go.SetActive(false); if (meshinfo.m_subInfo.m_lodObject != null) { meshinfo.m_subInfo.m_lodObject.SetActive(false); } } else { meshinfo.m_subInfo = null; } meshinfo.m_vehicleFlagsForbidden = (Vehicle.Flags)r.ReadInt32(); meshinfo.m_vehicleFlagsRequired = (Vehicle.Flags)r.ReadInt32(); meshinfo.m_parkedFlagsForbidden = (VehicleParked.Flags)r.ReadInt32(); meshinfo.m_parkedFlagsRequired = (VehicleParked.Flags)r.ReadInt32(); return(meshinfo); } return(PackageHelper.CustomDeserialize(p, t, r)); }
Package.Asset[] GetLoadQueue(HashSet <string> styleBuildings) { Package[] packages = PackageManager.allPackages.ToArray(); Array.Sort(packages, (a, b) => string.Compare(a.packageName, b.packageName)); List <Package.Asset> assets = new List <Package.Asset>(8); List <CustomAssetMetaData> metas = new List <CustomAssetMetaData>(8); // Why this load order? By having related and identical assets close to each other, we get more loader cache hits (of meshes and textures) // in Sharing. We also get faster disk reads. // [0] propvar and prop, citizen [1] prop, tree [2] pillar and elevation and road [3] road // [4] sub-building and building [5] building [6] trailer and vehicle [7] vehicle List <Package.Asset>[] queues = { new List <Package.Asset>(4), new List <Package.Asset>(64), new List <Package.Asset>(4), new List <Package.Asset>(4), new List <Package.Asset>(4), new List <Package.Asset>(64), new List <Package.Asset>(32), new List <Package.Asset>(32) }; SteamHelper.DLC_BitMask notMask = ~SteamHelper.GetOwnedDLCMask(); bool loadEnabled = Settings.settings.loadEnabled, loadUsed = Settings.settings.loadUsed, report = loadUsed && Settings.settings.reportAssets; //PrintPackages(packages); foreach (Package p in packages) { CustomAssetMetaData meta = null; try { assets.Clear(); assets.AddRange(p.FilterAssets(UserAssetType.CustomAssetMetaData)); if (assets.Count == 0) { continue; } if (report) { AssetReport.instance.AddPackage(p); } bool enabled = loadEnabled && IsEnabled(p); if (assets.Count == 1) // the common case { bool want = enabled || styleBuildings.Contains(assets[0].fullName); // Fast exit. if (!want && !(loadUsed && UsedAssets.instance.GotPackage(p.packageName))) { continue; } meta = AssetDeserializer.Instantiate(assets[0]) as CustomAssetMetaData; bool used = loadUsed && UsedAssets.instance.IsUsed(meta); if (used || want && (AssetImporterAssetTemplate.GetAssetDLCMask(meta) & notMask) == 0) { CustomAssetMetaData.Type type = meta.type; int offset = type == CustomAssetMetaData.Type.Trailer || type == CustomAssetMetaData.Type.SubBuilding || type == CustomAssetMetaData.Type.PropVariation || type >= CustomAssetMetaData.Type.RoadElevation ? -1 : 0; AddToQueue(queues, meta, offset, !(enabled | used)); } } else { bool want = enabled; // Fast exit. if (!want) { for (int i = 0; i < assets.Count; i++) { want = want || styleBuildings.Contains(assets[i].fullName); } if (!want && !(loadUsed && UsedAssets.instance.GotPackage(p.packageName))) { continue; } } metas.Clear(); bool used = false; for (int i = 0; i < assets.Count; i++) { meta = AssetDeserializer.Instantiate(assets[i]) as CustomAssetMetaData; metas.Add(meta); want = want && (AssetImporterAssetTemplate.GetAssetDLCMask(meta) & notMask) == 0; used = used || loadUsed && UsedAssets.instance.IsUsed(meta); } if (want | used) { metas.Sort((a, b) => b.type - a.type); // prop variation, sub-building, trailer, elevation, pillar before main asset CustomAssetMetaData.Type type = metas[0].type; int offset = type == CustomAssetMetaData.Type.Trailer || type == CustomAssetMetaData.Type.SubBuilding || type == CustomAssetMetaData.Type.PropVariation || type >= CustomAssetMetaData.Type.RoadElevation ? -1 : 0; bool dontSpawn = !(enabled | used); for (int i = 0; i < metas.Count; i++) { AddToQueue(queues, metas[i], offset, dontSpawn); } } } } catch (Exception e) { AssetFailed(meta?.assetRef?.fullName ?? p.packageName + "." + p.packageMainAsset, e); } } Package.Asset[] queue = new Package.Asset[queues.Select(lst => lst.Count).Sum()]; for (int i = 0, k = 0; i < queues.Length; k += queues[i].Count, i++) { queues[i].CopyTo(queue, k); } return(queue); }
internal void LoadImpl(Package.Asset assetRef) { try { stack.Push(assetRef); LoadingManager.instance.m_loadingProfilerCustomAsset.BeginLoading(AssetName(assetRef.name)); GameObject go = AssetDeserializer.Instantiate(assetRef) as GameObject; CustomAssetMetaData.Type type = GetMetaType(assetRef); string packageName = assetRef.package.packageName; string fullName = type < CustomAssetMetaData.Type.RoadElevation ? packageName + "." + go.name : PillarOrElevationName(packageName, go.name); go.name = fullName; go.SetActive(false); PrefabInfo info = go.GetComponent <PrefabInfo>(); info.m_isCustomContent = true; if (info.m_Atlas != null && !string.IsNullOrEmpty(info.m_InfoTooltipThumbnail) && info.m_Atlas[info.m_InfoTooltipThumbnail] != null) { info.m_InfoTooltipAtlas = info.m_Atlas; } PropInfo pi = go.GetComponent <PropInfo>(); if (pi != null) { if (pi.m_lodObject != null) { pi.m_lodObject.SetActive(false); } Initialize(pi); loadedProps.Add(fullName); } TreeInfo ti = go.GetComponent <TreeInfo>(); if (ti != null) { Initialize(ti); loadedTrees.Add(fullName); } BuildingInfo bi = go.GetComponent <BuildingInfo>(); if (bi != null) { if (bi.m_lodObject != null) { bi.m_lodObject.SetActive(false); } bi.m_dontSpawnNormally = dontSpawnNormally.Remove(fullName); Initialize(bi); loadedBuildings.Add(fullName); if (bi.GetAI() is IntersectionAI) { loadedIntersections.Add(fullName); } } VehicleInfo vi = go.GetComponent <VehicleInfo>(); if (vi != null) { if (vi.m_lodObject != null) { vi.m_lodObject.SetActive(false); } Initialize(vi); loadedVehicles.Add(fullName); } CitizenInfo ci = go.GetComponent <CitizenInfo>(); if (ci != null) { if (ci.m_lodObject != null) { ci.m_lodObject.SetActive(false); } if (ci.InitializeCustomPrefab(citizenMetaDatas[assetRef.fullName])) { citizenMetaDatas.Remove(assetRef.fullName); ci.gameObject.SetActive(true); Initialize(ci); loadedCitizens.Add(fullName); } else { CODebugBase <LogChannel> .Warn(LogChannel.Modding, "Custom citizen [" + assetRef.fullName + "] template not available in selected theme. Asset not added in game."); } } NetInfo ni = go.GetComponent <NetInfo>(); if (ni != null) { loadedNets.Add(fullName); Initialize(ni); } } finally { stack.Pop(); assetCount++; LoadingManager.instance.m_loadingProfilerCustomAsset.EndLoading(); } }
internal SomeMetaData(Package.Asset u, string n, CustomAssetMetaData.Type t) { userDataRef = u; name = n; type = t; }
Package.Asset[] GetLoadQueue(HashSet <string> styleBuildings) { Package.AssetType[] customAssets = { UserAssetType.CustomAssetMetaData }; Package[] packages = { }; try { packages = PackageManager.allPackages.Where(p => p.FilterAssets(customAssets).Any()).ToArray(); Array.Sort(packages, PackageComparison); } catch (Exception e) { UnityEngine.Debug.LogException(e); } List <Package.Asset> assets = new List <Package.Asset>(8); List <CustomAssetMetaData> metas = new List <CustomAssetMetaData>(8); // Why this load order? By having related and identical assets close to each other, we get more loader cache hits (of meshes and textures) // in Sharing. We also get faster disk reads. // [0] propvar and prop, tree, citizen [1] prop [2] pillar and elevation and road [3] road // [4] sub-building and building [5] building [6] trailer and vehicle [7] vehicle List <Package.Asset>[] queues = { new List <Package.Asset>(32), new List <Package.Asset>(64), new List <Package.Asset>(4), new List <Package.Asset>(4), new List <Package.Asset>(16), new List <Package.Asset>(64), new List <Package.Asset>(32), new List <Package.Asset>(32) }; SteamHelper.DLC_BitMask notMask = ~SteamHelper.GetOwnedDLCMask(); bool loadEnabled = Settings.settings.loadEnabled, loadUsed = Settings.settings.loadUsed; //PrintPackages(packages); foreach (Package p in packages) { CustomAssetMetaData meta = null; try { assets.Clear(); assets.AddRange(p.FilterAssets(customAssets)); int count = assets.Count; CustomDeserializer.instance.AddPackage(p); bool enabled = loadEnabled && IsEnabled(p); if (count == 1) // the common case { bool want = enabled || styleBuildings.Contains(assets[0].fullName); // Fast exit. if (!want && !(loadUsed && UsedAssets.instance.GotPackage(p.packageName))) { continue; } meta = AssetDeserializer.Instantiate(assets[0]) as CustomAssetMetaData; bool used = loadUsed && UsedAssets.instance.IsUsed(meta); if (used || want && (AssetImporterAssetTemplate.GetAssetDLCMask(meta) & notMask) == 0) { if (reportAssets) { AssetReport.instance.AddPackage(p, meta, want, used); } CustomAssetMetaData.Type type = meta.type; int offset = type == CustomAssetMetaData.Type.Trailer || type == CustomAssetMetaData.Type.SubBuilding || type == CustomAssetMetaData.Type.PropVariation || type >= CustomAssetMetaData.Type.RoadElevation ? -1 : 0; AddToQueue(queues, meta, type, offset, !(enabled | used)); } } else { bool want = enabled; // Fast exit. if (!want) { for (int i = 0; i < count; i++) { want = want || styleBuildings.Contains(assets[i].fullName); } if (!want && !(loadUsed && UsedAssets.instance.GotPackage(p.packageName))) { continue; } } metas.Clear(); bool used = false; for (int i = 0; i < count; i++) { meta = AssetDeserializer.Instantiate(assets[i]) as CustomAssetMetaData; metas.Add(meta); want = want && (AssetImporterAssetTemplate.GetAssetDLCMask(meta) & notMask) == 0; used = used || loadUsed && UsedAssets.instance.IsUsed(meta); } if (want | used) { metas.Sort((a, b) => b.type - a.type); // prop variation, sub-building, trailer, elevation, pillar before main asset CustomAssetMetaData lastmeta = metas[count - 1]; if (reportAssets) { AssetReport.instance.AddPackage(p, lastmeta, want, used); } CustomAssetMetaData.Type type = metas[0].type; int offset = type == CustomAssetMetaData.Type.Trailer || type == CustomAssetMetaData.Type.SubBuilding || type == CustomAssetMetaData.Type.PropVariation || type >= CustomAssetMetaData.Type.RoadElevation ? -1 : 0; bool treeVariations = lastmeta.type == CustomAssetMetaData.Type.Tree, dontSpawn = !(enabled | used); for (int i = 0; i < count; i++) { CustomAssetMetaData m = metas[i]; CustomAssetMetaData.Type t = m.type; if (treeVariations && t == CustomAssetMetaData.Type.PropVariation) { t = CustomAssetMetaData.Type.Tree; } AddToQueue(queues, m, t, offset, dontSpawn); } } } } catch (Exception e) { AssetFailed(meta?.assetRef, p, e); } } CheckSuspects(); for (int i = 0; i < queuedLoads.Length; i++) { queuedLoads[i].Clear(); queuedLoads[i] = null; } queuedLoads = null; Package.Asset[] queue = new Package.Asset[queues.Sum(lst => lst.Count)]; for (int i = 0, k = 0; i < queues.Length; i++) { queues[i].CopyTo(queue, k); k += queues[i].Count; queues[i].Clear(); queues[i] = null; } return(queue); }
internal void LoadImpl(Package.Asset assetRef) { try { stack.Push(assetRef); LoadingManager.instance.m_loadingProfilerCustomAsset.BeginLoading(ShortName(assetRef.name)); CustomAssetMetaData.Type type = GetMetaType(assetRef); GameObject go = AssetDeserializer.Instantiate(assetRef) as GameObject; string packageName = assetRef.package.packageName; string fullName = type < CustomAssetMetaData.Type.RoadElevation ? packageName + "." + go.name : PillarOrElevationName(packageName, go.name); go.name = fullName; go.SetActive(false); PrefabInfo info = go.GetComponent <PrefabInfo>(); info.m_isCustomContent = true; if (info.m_Atlas != null && !string.IsNullOrEmpty(info.m_InfoTooltipThumbnail) && info.m_Atlas[info.m_InfoTooltipThumbnail] != null) { info.m_InfoTooltipAtlas = info.m_Atlas; } PropInfo pi; TreeInfo ti; BuildingInfo bi; VehicleInfo vi; CitizenInfo ci; NetInfo ni; if ((pi = go.GetComponent <PropInfo>()) != null) { if (pi.m_lodObject != null) { pi.m_lodObject.SetActive(false); } Initialize(pi); } else if ((ti = go.GetComponent <TreeInfo>()) != null) { Initialize(ti); } else if ((bi = go.GetComponent <BuildingInfo>()) != null) { if (bi.m_lodObject != null) { bi.m_lodObject.SetActive(false); } bi.m_dontSpawnNormally = dontSpawnNormally.Remove(fullName); Initialize(bi); if (bi.GetAI() is IntersectionAI) { loadedIntersections.Add(fullName); } } else if ((vi = go.GetComponent <VehicleInfo>()) != null) { if (vi.m_lodObject != null) { vi.m_lodObject.SetActive(false); } Initialize(vi); } else if ((ci = go.GetComponent <CitizenInfo>()) != null) { if (ci.m_lodObject != null) { ci.m_lodObject.SetActive(false); } if (ci.InitializeCustomPrefab(citizenMetaDatas[assetRef.fullName])) { citizenMetaDatas.Remove(assetRef.fullName); ci.gameObject.SetActive(true); Initialize(ci); } else { info = null; CODebugBase <LogChannel> .Warn(LogChannel.Modding, "Custom citizen [" + assetRef.fullName + "] template not available in selected theme. Asset not added in game."); } } else if ((ni = go.GetComponent <NetInfo>()) != null) { Initialize(ni); } else { info = null; } if (info != null) { string path = Path.GetDirectoryName(assetRef.package.packagePath); if (!string.IsNullOrEmpty(path) && plugins.TryGetValue(path, out PluginInfo plugin)) { IAssetDataExtension[] extensions = plugin.GetInstances <IAssetDataExtension>(); if (extensions.Length > 0) { UserAssetData uad = GetUserAssetData(assetRef, out string name); if (uad != null) { for (int i = 0; i < extensions.Length; i++) { try { extensions[i].OnAssetLoaded(name, info, uad.Data); } catch (Exception e) { ModException ex = new ModException("The Mod " + plugin.ToString() + " has caused an error when loading " + fullName, e); UIView.ForwardException(ex); Debug.LogException(ex); } } } else { Util.DebugPrint("UserAssetData is null for", fullName); } } } } } finally { stack.Pop(); assetCount++; LoadingManager.instance.m_loadingProfilerCustomAsset.EndLoading(); } }
bool IsCommonBuilding(String fullName, Package.Asset asset, CustomAssetMetaData assetMetaData) { CustomAssetMetaData.Type type = assetMetaData.type; return(type == CustomAssetMetaData.Type.Building || type == CustomAssetMetaData.Type.SubBuilding); }