public Array32 <uint> VaryingLocations; // Making this readonly breaks AsSpan /// <summary> /// Creates a new transform feedback descriptor. /// </summary> /// <param name="bufferIndex">Index of the transform feedback</param> /// <param name="stride">Amount of bytes consumed per vertex</param> /// <param name="varyingCount">Number of varyings written into the buffer. Indicates size in bytes of <paramref name="varyingLocations"/></param> /// <param name="varyingLocations">Location of varyings to be written into the buffer. Each byte is one location</param> public TransformFeedbackDescriptor(int bufferIndex, int stride, int varyingCount, ref Array32 <uint> varyingLocations) { BufferIndex = bufferIndex; Stride = stride; VaryingCount = varyingCount; VaryingLocations = varyingLocations; }
public static void ResizeArray32 <T>(Array32 <T> array, uint newSize) { array.m_size = newSize; Array.Resize(ref array.m_buffer, (int)newSize); var unusedCount = ReflectionUtils.GetField <uint>(array, "m_unusedCount"); var unusedItems = ReflectionUtils.GetField <uint[]>(array, "m_unusedItems"); uint[] newUnusedItems = new uint[newSize]; Buffer.BlockCopy(unusedItems, 0, newUnusedItems, 0, 4 * unusedItems.Length); // Now add our own unused items for (uint i = (uint)unusedItems.Length; i < newSize + 1; i++) { newUnusedItems[i - 1] = i; } // Update the unusedCount to be in line with the new array size // This is just adding the newly sized additions. unusedCount += newSize - unusedCount; ReflectionUtils.SetField(array, "m_unusedCount", unusedCount); ReflectionUtils.SetField(array, "m_unusedItems", unusedItems); // var nextFree = ReflectionUtils.InvokeMethod<uint>(array, "NextFreeItem"); // var nextFree = array.NextFreeItem(); }
protected override void Awake() { base.Awake(); this.m_zombies = new Array32 <Zombie>(1048576u); this.m_instances = new Array16 <ZombieInstance>(65536u); this.m_zombieGrid = new ushort[4665600]; this.m_renderBuffer = new ulong[1024]; this.m_materialBlock = new MaterialPropertyBlock(); this.ID_Color = Shader.PropertyToID("_Color"); this.ID_Speed = Animator.StringToHash("Speed"); this.ID_State = Animator.StringToHash("State"); this.ID_ZombieLocation = new int[16]; this.ID_ZombieColor = new int[16]; for (int i = 0; i < 16; i++) { this.ID_ZombieLocation[i] = Shader.PropertyToID("_CitizenLocation" + i); this.ID_ZombieColor[i] = Shader.PropertyToID("_CitizenColor" + i); } this.m_zombieLayer = LayerMask.NameToLayer("Citizens"); this.m_audioGroup = new AudioGroup(5, new SavedFloat(Settings.effectAudioVolume, Settings.gameSettingsFile, DefaultSettings.effectAudioVolume, true)); uint num; this.m_zombies.CreateItem(out num); ushort num2; this.m_instances.CreateItem(out num2); }
private static void FixBrokenTrees() { var brokenCount = 0; // Fix broken trees Array32 <TreeInstance> trees = TreeManager.instance.m_trees; for (int i = 0; i < trees.m_size; i++) { if (trees.m_buffer[i].Info == null) { try { TreeManager.instance.ReleaseTree((ushort)i); brokenCount++; } catch (Exception e) { UnityEngine.Debug.LogException(e); } } } if (brokenCount > 0) { Debug.Log("Removed " + brokenCount + " broken tree instances."); } }
public static IEnumerable <T> ToSeq <T>(this Array32 <T> arr) { for (int i = 0; i < arr.m_size; i++) { yield return(arr.m_buffer[i]); } }
/// <summary> /// Creates a new GPU graphics state. /// </summary> /// <param name="earlyZForce">Early Z force enable</param> /// <param name="topology">Primitive topology</param> /// <param name="tessellationMode">Tessellation mode</param> /// <param name="alphaToCoverageEnable">Indicates whether alpha-to-coverage is enabled</param> /// <param name="alphaToCoverageDitherEnable">Indicates whether alpha-to-coverage dithering is enabled</param> /// <param name="viewportTransformDisable">Indicates whether the viewport transform is disabled</param> /// <param name="depthMode">Depth mode zero to one or minus one to one</param> /// <param name="programPointSizeEnable">Indicates if the point size is set on the shader or is fixed</param> /// <param name="pointSize">Point size if not set from shader</param> /// <param name="alphaTestEnable">Indicates whether alpha test is enabled</param> /// <param name="alphaTestCompare">When alpha test is enabled, indicates the comparison that decides if the fragment should be discarded</param> /// <param name="alphaTestReference">When alpha test is enabled, indicates the value to compare with the fragment output alpha</param> /// <param name="attributeTypes">Type of the vertex attributes consumed by the shader</param> public GpuChannelGraphicsState( bool earlyZForce, PrimitiveTopology topology, TessMode tessellationMode, bool alphaToCoverageEnable, bool alphaToCoverageDitherEnable, bool viewportTransformDisable, bool depthMode, bool programPointSizeEnable, float pointSize, bool alphaTestEnable, CompareOp alphaTestCompare, float alphaTestReference, ref Array32 <AttributeType> attributeTypes) { EarlyZForce = earlyZForce; Topology = topology; TessellationMode = tessellationMode; AlphaToCoverageEnable = alphaToCoverageEnable; AlphaToCoverageDitherEnable = alphaToCoverageDitherEnable; ViewportTransformDisable = viewportTransformDisable; DepthMode = depthMode; ProgramPointSizeEnable = programPointSizeEnable; PointSize = pointSize; AlphaTestEnable = alphaTestEnable; AlphaTestCompare = alphaTestCompare; AlphaTestReference = alphaTestReference; AttributeTypes = attributeTypes; }
public static void IterateLinkedList <T>(this Array32 <T> arr, uint startIndex, NextIndex32 <T> nextIndex, RefAction <T> action) where T : struct { var cur = startIndex; while (cur != 0) { action(cur, ref arr.m_buffer[cur]); cur = nextIndex(ref arr.m_buffer[cur]); } }
private static void EndRenderingImpl(TreeManager tm, RenderManager.CameraInfo cameraInfo) { unsafe { if (Input.GetKeyDown(KeyCode.F5) && Event.current.control) { DebugOutputPanel.AddMessage(PluginManager.MessageType.Message, string.Format("TreeLimit: TreeCount={0}, TreeLimit={1}, CanPlaceMoreTrees={2}", tm.m_treeCount, LimitTreeManager.Helper.TreeLimit, tm.CheckLimits())); Array32<TreeInstance> mTrees = tm.m_trees; DebugOutputPanel.AddMessage(PluginManager.MessageType.Message, string.Format("TreeLimit: ArraySize={0}, ItemCount={1}, UnusedCount={2}", mTrees.m_size, mTrees.ItemCount(), mTrees.GetType().GetField("m_unusedCount", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(mTrees))); } FastList<RenderGroup> mRenderedGroups = Singleton<RenderManager>.instance.m_renderedGroups; for (int i = 0; i < mRenderedGroups.m_size; i++) { RenderGroup mBuffer = mRenderedGroups.m_buffer[i]; if ((mBuffer.m_instanceMask & 1 << (tm.m_treeLayer & 31)) != 0) { int mX = mBuffer.m_x * 540 / 45; int mZ = mBuffer.m_z * 540 / 45; int num = (mBuffer.m_x + 1) * 540 / 45 - 1; int mZ1 = (mBuffer.m_z + 1) * 540 / 45 - 1; for (int j = mZ; j <= mZ1; j++) { for (int k = mX; k <= num; k++) { uint mTreeGrid = tm.m_treeGrid[j * 540 + k]; int num1 = 0; while (mTreeGrid != 0) { tm.m_trees.m_buffer[mTreeGrid].RenderInstance(cameraInfo, mTreeGrid, mBuffer.m_instanceMask); mTreeGrid = tm.m_trees.m_buffer[mTreeGrid].m_nextGridTree; int num2 = num1 + 1; num1 = num2; if (num2 < LimitTreeManager.Helper.TreeLimit) { continue; } CODebugBase<LogChannel>.Error(LogChannel.Core, string.Concat("Invalid list detected!\n", Environment.StackTrace)); break; } } } } } int num3 = PrefabCollection<TreeInfo>.PrefabCount(); for (int l = 0; l < num3; l++) { TreeInfo prefab = PrefabCollection<TreeInfo>.GetPrefab((uint)l); if (prefab != null && prefab.m_lodCount != 0) { TreeInstance.RenderLod(cameraInfo, prefab); } } } }
private static void DestroyTrees(int seed, InstanceManager.Group group, Vector3 position, float totalRadius, float removeRadius, float destructionRadiusMin, float destructionRadiusMax, float burnRadiusMin, float burnRadiusMax) { int num = Mathf.Max((int)((position.x - totalRadius) / 32f + 270f), 0); int num2 = Mathf.Max((int)((position.z - totalRadius) / 32f + 270f), 0); int num3 = Mathf.Min((int)((position.x + totalRadius) / 32f + 270f), 539); int num4 = Mathf.Min((int)((position.z + totalRadius) / 32f + 270f), 539); Array32 <global::TreeInstance> trees = Singleton <TreeManager> .instance.m_trees; uint[] treeGrid = Singleton <TreeManager> .instance.m_treeGrid; for (int i = num2; i <= num4; i++) { for (int j = num; j <= num3; j++) { uint num5 = treeGrid[i * 540 + j]; int num6 = 0; while (num5 != 0u) { uint nextGridTree = trees.m_buffer[(int)((UIntPtr)num5)].m_nextGridTree; global::TreeInstance.Flags flags = (global::TreeInstance.Flags)trees.m_buffer[(int)((UIntPtr)num5)].m_flags; if ((flags & (global::TreeInstance.Flags.Created | global::TreeInstance.Flags.Deleted)) == global::TreeInstance.Flags.Created) { Vector3 position2 = trees.m_buffer[(int)((UIntPtr)num5)].Position; float num7 = VectorUtils.LengthXZ(position2 - position); if (num7 < totalRadius) { Randomizer randomizer = new Randomizer(num5 | (uint)((uint)seed << 16)); float num8 = (burnRadiusMax - num7) / Mathf.Max(1f, burnRadiusMax - burnRadiusMin); bool flag = num7 < removeRadius; bool flag2 = (float)randomizer.Int32(1000u) < num8 * 1000f; if (flag) { Singleton <TreeManager> .instance.ReleaseTree(num5); } else if (flag2 && (flags & global::TreeInstance.Flags.FireDamage) == global::TreeInstance.Flags.None) { Singleton <TreeManager> .instance.BurnTree(num5, group, 128); } } } num5 = nextGridTree; if (++num6 >= LimitTreeManager.Helper.TreeLimit) { CODebugBase <LogChannel> .Error(LogChannel.Core, "Invalid list detected!\n" + Environment.StackTrace); break; } } } } }
private static void LocateNextTreeInstance(PrefabInfo prefab) { Array32 <TreeInstance> trees = TreeManager.instance.m_trees; for (uint i = (treeInstanceCounter + 1) % trees.m_size; i != treeInstanceCounter; i = (i + 1) % trees.m_size) { if (trees.m_buffer[i].Info == prefab) { bool isValid = ((TreeInstance.Flags)trees.m_buffer[i].m_flags != TreeInstance.Flags.None && (TreeInstance.Flags)trees.m_buffer[i].m_flags != TreeInstance.Flags.Deleted); if (!isValid) { continue; } SetCameraPosition(trees.m_buffer[i].Position); treeInstanceCounter = (i + 1) % trees.m_size; return; } } treeInstanceCounter = 0; }
public NsoExecutable(IStorage inStorage, string name = null) { NsoReader reader = new NsoReader(); reader.Initialize(inStorage.AsFile(OpenMode.Read)).ThrowIfFailure(); TextOffset = reader.Header.Segments[0].MemoryOffset; RoOffset = reader.Header.Segments[1].MemoryOffset; DataOffset = reader.Header.Segments[2].MemoryOffset; BssSize = reader.Header.BssSize; reader.GetSegmentSize(NsoReader.SegmentType.Data, out uint uncompressedSize).ThrowIfFailure(); Program = new byte[DataOffset + uncompressedSize]; TextSize = DecompressSection(reader, NsoReader.SegmentType.Text, TextOffset); RoSize = DecompressSection(reader, NsoReader.SegmentType.Ro, RoOffset); DataSize = DecompressSection(reader, NsoReader.SegmentType.Data, DataOffset); Name = name; BuildId = reader.Header.ModuleId; PrintRoSectionInfo(); }
public static void RemoveUnused <T>(this Array32 <T> arr, uint id) { ArrayXHelper <Array32 <T>, uint> .RemoveUnused(arr, id, "Array32"); }
public virtual void OnAwake() { this.m_laneLocation = new uint[262144]; this.m_laneTarget = new PathUnit.Position[262144]; this.m_buffer = new BufferItem[65536]; this.m_bufferMin = new int[1024]; this.m_bufferMax = new int[1024]; this.m_queueLock = new object(); this.m_bufferLock = Singleton<PathManager>.instance.m_bufferLock; this.m_pathUnits = Singleton<PathManager>.instance.m_pathUnits; this.m_pathFindThread = new Thread(new ThreadStart(this.PathFindThread)); this.m_pathFindThread.Name = "Pathfind"; this.m_pathFindThread.Priority = SimulationManager.SIMULATION_PRIORITY; this.m_pathFindThread.Start(); if (!this.m_pathFindThread.IsAlive) { CODebugBase<LogChannel>.Error(LogChannel.Core, "Path find thread failed to start!"); } }
/// <summary> /// Migrates from the old cache format to the new one. /// </summary> /// <param name="context">GPU context</param> /// <param name="hostStorage">Disk cache host storage (used to create the new shader files)</param> /// <returns>Number of migrated shaders</returns> public static int MigrateFromLegacyCache(GpuContext context, DiskCacheHostStorage hostStorage) { string baseCacheDirectory = CacheHelper.GetBaseCacheDirectory(GraphicsConfig.TitleId); string cacheDirectory = CacheHelper.GenerateCachePath(baseCacheDirectory, CacheGraphicsApi.Guest, "", "program"); // If the directory does not exist, we have no old cache. // Exist early as the CacheManager constructor will create the directories. if (!Directory.Exists(cacheDirectory)) { return(0); } if (GraphicsConfig.EnableShaderCache && GraphicsConfig.TitleId != null) { CacheManager cacheManager = new CacheManager(CacheGraphicsApi.OpenGL, CacheHashType.XxHash128, "glsl", GraphicsConfig.TitleId, ShaderCodeGenVersion); bool isReadOnly = cacheManager.IsReadOnly; HashSet <Hash128> invalidEntries = null; if (isReadOnly) { Logger.Warning?.Print(LogClass.Gpu, "Loading shader cache in read-only mode (cache in use by another program!)"); } else { invalidEntries = new HashSet <Hash128>(); } ReadOnlySpan <Hash128> guestProgramList = cacheManager.GetGuestProgramList(); for (int programIndex = 0; programIndex < guestProgramList.Length; programIndex++) { Hash128 key = guestProgramList[programIndex]; byte[] guestProgram = cacheManager.GetGuestProgramByHash(ref key); if (guestProgram == null) { Logger.Error?.Print(LogClass.Gpu, $"Ignoring orphan shader hash {key} in cache (is the cache incomplete?)"); continue; } ReadOnlySpan <byte> guestProgramReadOnlySpan = guestProgram; ReadOnlySpan <GuestShaderCacheEntry> cachedShaderEntries = GuestShaderCacheEntry.Parse(ref guestProgramReadOnlySpan, out GuestShaderCacheHeader fileHeader); if (cachedShaderEntries[0].Header.Stage == ShaderStage.Compute) { Debug.Assert(cachedShaderEntries.Length == 1); GuestShaderCacheEntry entry = cachedShaderEntries[0]; byte[] code = entry.Code.AsSpan(0, entry.Header.Size - entry.Header.Cb1DataSize).ToArray(); Span <byte> codeSpan = entry.Code; byte[] cb1Data = codeSpan.Slice(codeSpan.Length - entry.Header.Cb1DataSize).ToArray(); ShaderProgramInfo info = new ShaderProgramInfo( Array.Empty <BufferDescriptor>(), Array.Empty <BufferDescriptor>(), Array.Empty <TextureDescriptor>(), Array.Empty <TextureDescriptor>(), ShaderStage.Compute, false, false, 0, 0); GpuChannelComputeState computeState = new GpuChannelComputeState( entry.Header.GpuAccessorHeader.ComputeLocalSizeX, entry.Header.GpuAccessorHeader.ComputeLocalSizeY, entry.Header.GpuAccessorHeader.ComputeLocalSizeZ, entry.Header.GpuAccessorHeader.ComputeLocalMemorySize, entry.Header.GpuAccessorHeader.ComputeSharedMemorySize); ShaderSpecializationState specState = new ShaderSpecializationState(computeState); foreach (var td in entry.TextureDescriptors) { var handle = td.Key; var data = td.Value; specState.RegisterTexture( 0, handle, -1, data.UnpackFormat(), data.UnpackSrgb(), data.UnpackTextureTarget(), data.UnpackTextureCoordNormalized()); } CachedShaderStage shader = new CachedShaderStage(info, code, cb1Data); CachedShaderProgram program = new CachedShaderProgram(null, specState, shader); hostStorage.AddShader(context, program, ReadOnlySpan <byte> .Empty); } else { Debug.Assert(cachedShaderEntries.Length == Constants.ShaderStages); CachedShaderStage[] shaders = new CachedShaderStage[Constants.ShaderStages + 1]; List <ShaderProgram> shaderPrograms = new List <ShaderProgram>(); TransformFeedbackDescriptorOld[] tfd = CacheHelper.ReadTransformFeedbackInformation(ref guestProgramReadOnlySpan, fileHeader); GuestShaderCacheEntry[] entries = cachedShaderEntries.ToArray(); GuestGpuAccessorHeader accessorHeader = entries[0].Header.GpuAccessorHeader; TessMode tessMode = new TessMode(); int tessPatchType = accessorHeader.TessellationModePacked & 3; int tessSpacing = (accessorHeader.TessellationModePacked >> 2) & 3; bool tessCw = (accessorHeader.TessellationModePacked & 0x10) != 0; tessMode.Packed = (uint)tessPatchType; tessMode.Packed |= (uint)(tessSpacing << 4); if (tessCw) { tessMode.Packed |= 0x100; } PrimitiveTopology topology = accessorHeader.PrimitiveTopology switch { InputTopology.Lines => PrimitiveTopology.Lines, InputTopology.LinesAdjacency => PrimitiveTopology.LinesAdjacency, InputTopology.Triangles => PrimitiveTopology.Triangles, InputTopology.TrianglesAdjacency => PrimitiveTopology.TrianglesAdjacency, _ => PrimitiveTopology.Points }; GpuChannelGraphicsState graphicsState = new GpuChannelGraphicsState( accessorHeader.StateFlags.HasFlag(GuestGpuStateFlags.EarlyZForce), topology, tessMode); TransformFeedbackDescriptor[] tfdNew = null; if (tfd != null) { tfdNew = new TransformFeedbackDescriptor[tfd.Length]; for (int tfIndex = 0; tfIndex < tfd.Length; tfIndex++) { Array32 <uint> varyingLocations = new Array32 <uint>(); Span <byte> varyingLocationsSpan = MemoryMarshal.Cast <uint, byte>(varyingLocations.ToSpan()); tfd[tfIndex].VaryingLocations.CopyTo(varyingLocationsSpan.Slice(0, tfd[tfIndex].VaryingLocations.Length)); tfdNew[tfIndex] = new TransformFeedbackDescriptor( tfd[tfIndex].BufferIndex, tfd[tfIndex].Stride, tfd[tfIndex].VaryingLocations.Length, ref varyingLocations); } } ShaderSpecializationState specState = new ShaderSpecializationState(graphicsState, tfdNew); for (int i = 0; i < entries.Length; i++) { GuestShaderCacheEntry entry = entries[i]; if (entry == null) { continue; } ShaderProgramInfo info = new ShaderProgramInfo( Array.Empty <BufferDescriptor>(), Array.Empty <BufferDescriptor>(), Array.Empty <TextureDescriptor>(), Array.Empty <TextureDescriptor>(), (ShaderStage)(i + 1), false, false, 0, 0); // NOTE: Vertex B comes first in the shader cache. byte[] code = entry.Code.AsSpan(0, entry.Header.Size - entry.Header.Cb1DataSize).ToArray(); byte[] code2 = entry.Header.SizeA != 0 ? entry.Code.AsSpan(entry.Header.Size, entry.Header.SizeA).ToArray() : null; Span <byte> codeSpan = entry.Code; byte[] cb1Data = codeSpan.Slice(codeSpan.Length - entry.Header.Cb1DataSize).ToArray(); shaders[i + 1] = new CachedShaderStage(info, code, cb1Data); if (code2 != null) { shaders[0] = new CachedShaderStage(null, code2, cb1Data); } foreach (var td in entry.TextureDescriptors) { var handle = td.Key; var data = td.Value; specState.RegisterTexture( i, handle, -1, data.UnpackFormat(), data.UnpackSrgb(), data.UnpackTextureTarget(), data.UnpackTextureCoordNormalized()); } } CachedShaderProgram program = new CachedShaderProgram(null, specState, shaders); hostStorage.AddShader(context, program, ReadOnlySpan <byte> .Empty); } } return(guestProgramList.Length); } return(0); } }
private static IEnumerator FixEnumerableThread(ThreadBase t) { SimulationManager.instance.ForcedSimulationPaused = true; try { uint brokenCount = 0; uint confusedCount = 0; // Fix broken offers TransferManager.TransferOffer[] incomingOffers = typeof(TransferManager).GetField("m_incomingOffers", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(TransferManager.instance) as TransferManager.TransferOffer[]; TransferManager.TransferOffer[] outgoingOffers = typeof(TransferManager).GetField("m_outgoingOffers", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(TransferManager.instance) as TransferManager.TransferOffer[]; ushort[] incomingCount = typeof(TransferManager).GetField("m_incomingCount", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(TransferManager.instance) as ushort[]; ushort[] outgoingCount = typeof(TransferManager).GetField("m_outgoingCount", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(TransferManager.instance) as ushort[]; int[] incomingAmount = typeof(TransferManager).GetField("m_incomingAmount", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(TransferManager.instance) as int[]; int[] outgoingAmount = typeof(TransferManager).GetField("m_outgoingAmount", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(TransferManager.instance) as int[]; // Based on TransferManager.RemoveAllOffers for (int i = 0; i < 64; i++) { for (int j = 0; j < 8; j++) { int num = i * 8 + j; int num2 = (int)incomingCount[num]; for (int k = num2 - 1; k >= 0; k--) { int num3 = num * 256 + k; if (IsInfoNull(incomingOffers[num3])) { incomingAmount[i] -= incomingOffers[num3].Amount; incomingOffers[num3] = incomingOffers[--num2]; brokenCount++; } } incomingCount[num] = (ushort)num2; int num4 = (int)outgoingCount[num]; for (int l = num4 - 1; l >= 0; l--) { int num5 = num * 256 + l; if (IsInfoNull(outgoingOffers[num5])) { outgoingAmount[i] -= outgoingOffers[num5].Amount; outgoingOffers[num5] = outgoingOffers[--num4]; brokenCount++; } } outgoingCount[num] = (ushort)num4; } yield return(null); } if (brokenCount > 0) { Debug.Log("Removed " + brokenCount + " broken transfer offers."); } // Fix broken vehicles Array16 <Vehicle> vehicles = VehicleManager.instance.m_vehicles; for (int i = 0; i < vehicles.m_size; i++) { if (vehicles.m_buffer[i].m_flags != Vehicle.Flags.None) { bool exists = (vehicles.m_buffer[i].m_flags & Vehicle.Flags.Spawned) != Vehicle.Flags.None; // Vehicle validity InstanceID target; bool isInfoNull = vehicles.m_buffer[i].Info == null; bool isLeading = vehicles.m_buffer[i].m_leadingVehicle == 0; bool isWaiting = !exists && (vehicles.m_buffer[i].m_flags & Vehicle.Flags.WaitingSpace) != Vehicle.Flags.None; bool isConfused = exists && isLeading && !isInfoNull && vehicles.m_buffer[i].Info.m_vehicleAI.GetLocalizedStatus((ushort)i, ref vehicles.m_buffer[i], out target) == Locale.Get("VEHICLE_STATUS_CONFUSED"); if (isInfoNull || isWaiting || isConfused) { try { VehicleManager.instance.ReleaseVehicle((ushort)i); if (isInfoNull) { brokenCount++; } if (isConfused) { confusedCount++; } } catch { } } } if (i % 256 == 255) { yield return(null); } } if (confusedCount > 0) { Debug.Log("Removed " + confusedCount + " confused vehicle instances."); } Array16 <VehicleParked> vehiclesParked = VehicleManager.instance.m_parkedVehicles; for (int i = 0; i < vehiclesParked.m_size; i++) { if (vehiclesParked.m_buffer[i].Info == null) { try { VehicleManager.instance.ReleaseParkedVehicle((ushort)i); brokenCount++; } catch { } } if (i % 256 == 255) { yield return(null); } } if (brokenCount > 0) { Debug.Log("Removed " + brokenCount + " broken vehicle instances."); } brokenCount = 0; // Fix broken buildings Array16 <Building> buildings = BuildingManager.instance.m_buildings; for (int i = 0; i < buildings.m_size; i++) { if (buildings.m_buffer[i].Info == null) { try { BuildingManager.instance.ReleaseBuilding((ushort)i); brokenCount++; } catch { } } if (i % 256 == 255) { yield return(null); } } if (brokenCount > 0) { Debug.Log("Removed " + brokenCount + " broken building instances."); } brokenCount = 0; // Fix broken props Array16 <PropInstance> props = PropManager.instance.m_props; for (int i = 0; i < props.m_size; i++) { if (props.m_buffer[i].Info == null) { try { PropManager.instance.ReleaseProp((ushort)i); brokenCount++; } catch { } } if (i % 256 == 255) { yield return(null); } } if (brokenCount > 0) { Debug.Log("Removed " + brokenCount + " broken prop instances."); } brokenCount = 0; // Fix broken trees Array32 <TreeInstance> trees = TreeManager.instance.m_trees; for (int i = 0; i < trees.m_size; i++) { if (trees.m_buffer[i].Info == null) { try { TreeManager.instance.ReleaseTree((ushort)i); brokenCount++; } catch { } } if (i % 256 == 255) { yield return(null); } } if (brokenCount > 0) { Debug.Log("Removed " + brokenCount + " broken tree instances."); } brokenCount = 0; } finally { SimulationManager.instance.ForcedSimulationPaused = false; } }
/// <summary> /// Stock code that transfers people/materials between the buildings/vehicles referenced in the given offers. /// </summary> private static bool StartTransfer(TransferManager.TransferReason material, TransferManager.TransferOffer offerOut, TransferManager.TransferOffer offerIn, int delta) { try { if (offerIn.Building != 0 && TransferManagerInfo.IsCustomVehiclesBuilding(offerIn.Building)) { VehicleManagerMod.CurrentSourceBuilding = offerIn.Building; } bool active1 = offerIn.Active; bool active2 = offerOut.Active; if (active1 && offerIn.Vehicle != 0) { Array16 <Vehicle> vehicles = Singleton <VehicleManager> .instance.m_vehicles; ushort vehicle = offerIn.Vehicle; VehicleInfo info = vehicles.m_buffer[vehicle].Info; offerOut.Amount = delta; info.m_vehicleAI.StartTransfer(vehicle, ref vehicles.m_buffer[vehicle], material, offerOut); } else if (active2 && offerOut.Vehicle != 0) { Array16 <Vehicle> vehicles = Singleton <VehicleManager> .instance.m_vehicles; ushort vehicle = offerOut.Vehicle; VehicleInfo info = vehicles.m_buffer[vehicle].Info; offerIn.Amount = delta; info.m_vehicleAI.StartTransfer(vehicle, ref vehicles.m_buffer[vehicle], material, offerIn); } else if (active1 && (int)offerIn.Citizen != 0) { Array32 <Citizen> citizens = Singleton <CitizenManager> .instance.m_citizens; uint citizen = offerIn.Citizen; CitizenInfo citizenInfo = citizens.m_buffer[citizen].GetCitizenInfo(citizen); if (citizenInfo == null) { return(false); } offerOut.Amount = delta; // Workaround a bug in ResidentAI.StartTransfer if (material == TransferManager.TransferReason.ChildCare || material == TransferManager.TransferReason.ElderCare) { citizens.m_buffer[citizen].Sick = false; } citizenInfo.m_citizenAI.StartTransfer(citizen, ref citizens.m_buffer[citizen], material, offerOut); } else if (active2 && (int)offerOut.Citizen != 0) { Array32 <Citizen> citizens = Singleton <CitizenManager> .instance.m_citizens; uint citizen = offerOut.Citizen; CitizenInfo citizenInfo = citizens.m_buffer[citizen].GetCitizenInfo(citizen); if (citizenInfo == null) { return(false); } offerIn.Amount = delta; // Workaround a bug in ResidentAI.StartTransfer if (material == TransferManager.TransferReason.ChildCare || material == TransferManager.TransferReason.ElderCare) { citizens.m_buffer[citizen].Sick = false; } citizenInfo.m_citizenAI.StartTransfer(citizen, ref citizens.m_buffer[citizen], material, offerIn); } else if (active2 && offerOut.Building != 0) { Array16 <Building> buildings = Singleton <BuildingManager> .instance.m_buildings; ushort building = offerOut.Building; BuildingInfo info = buildings.m_buffer[building].Info; offerIn.Amount = delta; info.m_buildingAI.StartTransfer(building, ref buildings.m_buffer[building], material, offerIn); } else { if (!active1 || offerIn.Building == 0) { return(false); } Array16 <Building> buildings = Singleton <BuildingManager> .instance.m_buildings; ushort building = offerIn.Building; BuildingInfo info = buildings.m_buffer[building].Info; offerOut.Amount = delta; info.m_buildingAI.StartTransfer(building, ref buildings.m_buffer[building], material, offerOut); } return(true); } finally { VehicleManagerMod.CurrentSourceBuilding = 0; } }