internal CustomAssetMetaData.Type GetMetaType(Package.Asset assetRef) { if (metaTypes.TryGetValue(assetRef.fullName, out CustomAssetMetaData.Type type)) { return(type); } try { foreach (Package.Asset asset in assetRef.package.FilterAssets(UserAssetType.CustomAssetMetaData)) { CustomAssetMetaData meta = AssetDeserializer.Instantiate(asset) as CustomAssetMetaData; if (meta?.assetRef != null) { metaTypes[meta.assetRef.fullName] = meta.type; } } if (metaTypes.TryGetValue(assetRef.fullName, out type)) { return(type); } } catch (Exception) { } Util.DebugPrint("Cannot resolve metatype:", assetRef.fullName); return(CustomAssetMetaData.Type.Unknown); }
UserAssetData GetUserAssetData(Package.Asset assetRef, out string name) { if (!metaDatas.TryGetValue(assetRef.fullName, out SomeMetaData some)) { ReadMetaData(assetRef.package); metaDatas.TryGetValue(assetRef.fullName, out some); } if (some.userDataRef != null) { try { UserAssetData uad = AssetDeserializer.Instantiate(some.userDataRef) as UserAssetData; if (uad == null) { uad = new UserAssetData(); } name = some.name; return(uad); } catch (Exception) { Util.DebugPrint("!Cannot resolve UserAssetData for", assetRef.fullName); } } name = string.Empty; return(null); }
internal Material GetMaterial(string checksum, Package package, bool isMain) { MaterialData mat; KeyValuePair <int, object> kvp; lock (mutex) { if (isMain && materialsMain.TryGetValue(checksum, out mat)) { mathit++; texhit += mat.textureCount; return(mat.material); } else if (!isMain && (materialsLod.TryGetValue(checksum, out mat) || materialsMain.TryGetValue(checksum, out mat))) { matpre++; return(new Material(mat.material)); } data.TryGetValue(checksum, out kvp); } byte[] bytes = kvp.Value as byte[]; if (bytes != null) { mat = (MaterialData)AssetDeserializer.Instantiate(package, bytes, isMain); matpre++; } else { Package.Asset asset = package.FindByChecksum(checksum); mat = (MaterialData)AssetDeserializer.Instantiate(asset, isMain); matload++; } if (shareMaterials) { lock (mutex) { if (isMain) { materialsMain[checksum] = mat; } else { materialsLod[checksum] = mat; } if (data.Remove(checksum)) { removedCount++; } } } return(mat.material); }
void ReadMetaData(Package package) { foreach (Package.Asset asset in package.FilterAssets(UserAssetType.CustomAssetMetaData)) { try { CustomAssetMetaData meta = AssetDeserializer.Instantiate(asset) as CustomAssetMetaData; metaDatas[meta.assetRef.fullName] = new SomeMetaData(meta.userDataRef, meta.name, meta.type); } catch (Exception) { Util.DebugPrint("!Cannot read metadata from", package.packageName); } } }
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 Texture2D GetTexture(string checksum, Package package, bool isMain) { Texture2D texture2D; KeyValuePair <int, object> kvp; lock (mutex) { if (isMain && texturesMain.TryGetValue(checksum, out texture2D)) { texhit++; return(texture2D); } else if (!isMain && (texturesLod.TryGetValue(checksum, out texture2D) || texturesMain.TryGetValue(checksum, out texture2D))) { texpre++; return(UnityEngine.Object.Instantiate(texture2D)); } data.TryGetValue(checksum, out kvp); } TextObj to = kvp.Value as TextObj; byte[] bytes; if (to != null) { texture2D = new Texture2D(to.width, to.height, to.format, to.mipmap, to.linear); texture2D.LoadRawTextureData(to.pixels); texture2D.Apply(); texture2D.name = to.name; texture2D.anisoLevel = to.anisoLevel; texpre++; } else if ((bytes = kvp.Value as byte[]) != null) { texture2D = AssetDeserializer.Instantiate(package, bytes, isMain) as Texture2D; texpre++; } else { Package.Asset asset = package.FindByChecksum(checksum); texture2D = AssetDeserializer.Instantiate(asset, isMain) as Texture2D; texload++; } if (shareTextures) { lock (mutex) { if (isMain) { texturesMain[checksum] = texture2D; } else { texturesLod[checksum] = texture2D; } if (data.Remove(checksum)) { removedCount++; } } } return(texture2D); }
internal Mesh GetMesh(string checksum, Package package, bool isMain) { Mesh mesh; KeyValuePair <int, object> kvp; lock (mutex) { if (meshes.TryGetValue(checksum, out mesh)) { meshit++; return(mesh); } data.TryGetValue(checksum, out kvp); } MeshObj mo = kvp.Value as MeshObj; byte[] bytes; if (mo != null) { mesh = new Mesh(); mesh.name = mo.name; mesh.vertices = mo.vertices; mesh.colors = mo.colors; mesh.uv = mo.uv; mesh.normals = mo.normals; mesh.tangents = mo.tangents; mesh.boneWeights = mo.boneWeights; mesh.bindposes = mo.bindposes; for (int i = 0; i < mo.triangles.Length; i++) { mesh.SetTriangles(mo.triangles[i], i); } mespre++; } else if ((bytes = kvp.Value as byte[]) != null) { mesh = AssetDeserializer.Instantiate(package, bytes, isMain) as Mesh; mespre++; } else { Package.Asset asset = package.FindByChecksum(checksum); mesh = AssetDeserializer.Instantiate(asset, isMain) as Mesh; mesload++; } if (shareMeshes) { lock (mutex) { meshes[checksum] = mesh; if (data.Remove(checksum)) { removedCount++; } } } return(mesh); }
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(); } }