using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Networking;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("worldGenAccelerator")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("worldGenAccelerator")]
[assembly: AssemblyCopyright("Copyright © 2023")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("FBB901EA-0092-4689-8EE8-776E5CBFBC26")]
[assembly: AssemblyFileVersion("0.1.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = "")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.0.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
internal sealed class NullableAttribute : Attribute
{
public readonly byte[] NullableFlags;
public NullableAttribute(byte P_0)
{
NullableFlags = new byte[1] { P_0 };
}
public NullableAttribute(byte[] P_0)
{
NullableFlags = P_0;
}
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
internal sealed class NullableContextAttribute : Attribute
{
public readonly byte Flag;
public NullableContextAttribute(byte P_0)
{
Flag = P_0;
}
}
}
namespace worldGenAccelerator
{
public static class Analytics
{
private const string PingUrl = "https://mod-analytics.vercel.app/api/ping";
private static bool _hasSentPing;
public static void Init(ConfigFile config, string modId, string modVersion)
{
if (!_hasSentPing)
{
ConfigEntry<bool> val = config.Bind<bool>("Analytics", "Enabled", true, "Send a single anonymous ping when the game starts. No gameplay data is collected.");
ConfigEntry<string> val2 = config.Bind<string>("Analytics", "InstanceID", Guid.NewGuid().ToString(), "Random anonymous ID. Change or delete to reset.");
if (!val.Value)
{
worldGenAcceleratorPlugin.TemplateLogger.LogDebug((object)"Analytics disabled by config");
return;
}
_hasSentPing = true;
((MonoBehaviour)ThreadingHelper.Instance).StartCoroutine(SendPing(modId, modVersion, val2.Value));
}
}
private static IEnumerator SendPing(string modId, string modVersion, string instanceId)
{
string json = "{\"mod_id\":\"" + Escape(modId) + "\",\"mod_version\":\"" + Escape(modVersion) + "\",\"instance_id\":\"" + Escape(instanceId) + "\"}";
byte[] body = Encoding.UTF8.GetBytes(json);
UnityWebRequest req = new UnityWebRequest("https://mod-analytics.vercel.app/api/ping", "POST");
try
{
req.uploadHandler = (UploadHandler)new UploadHandlerRaw(body);
req.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
req.SetRequestHeader("Content-Type", "application/json");
req.timeout = 10;
yield return req.SendWebRequest();
if ((int)req.result == 1)
{
worldGenAcceleratorPlugin.TemplateLogger.LogDebug((object)"Analytics ping sent");
}
else
{
worldGenAcceleratorPlugin.TemplateLogger.LogDebug((object)("Analytics ping failed: " + req.error));
}
}
finally
{
((IDisposable)req)?.Dispose();
}
}
private static string Escape(string s)
{
return s.Replace("\\", "\\\\").Replace("\"", "\\\"");
}
}
public class BiomeZoneCache
{
private Dictionary<Biome, List<Vector2i>> m_zonesByBiome = new Dictionary<Biome, List<Vector2i>>();
private Dictionary<Vector2i, BiomeArea> m_zoneBiomeArea = new Dictionary<Vector2i, BiomeArea>();
private int m_cachedZoneCount;
private bool m_built;
public static BiomeZoneCache Instance { get; private set; } = new BiomeZoneCache();
public void Build()
{
//IL_0080: Unknown result type (might be due to invalid IL or missing references)
//IL_0082: Unknown result type (might be due to invalid IL or missing references)
//IL_0087: Unknown result type (might be due to invalid IL or missing references)
//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
//IL_00da: Unknown result type (might be due to invalid IL or missing references)
if (m_built)
{
return;
}
Stopwatch stopwatch = Stopwatch.StartNew();
m_zonesByBiome.Clear();
m_zoneBiomeArea.Clear();
m_cachedZoneCount = 0;
WorldGenerator instance = WorldGenerator.instance;
float zoneSize = ZoneSystem.instance.m_zoneSize;
float worldRadius = ExpandWorldSizeBridge.GetWorldRadius();
int num = Mathf.CeilToInt(worldRadius / zoneSize);
double num2 = (double)worldRadius * (double)worldRadius;
Vector2i val = default(Vector2i);
for (int i = -num; i <= num; i++)
{
for (int j = -num; j <= num; j++)
{
((Vector2i)(ref val))..ctor(i, j);
Vector3 zonePos = ZoneSystem.GetZonePos(val);
if (!((double)((Vector3)(ref zonePos)).sqrMagnitude >= num2))
{
Biome biome = instance.GetBiome(zonePos);
BiomeArea biomeArea = instance.GetBiomeArea(zonePos);
if (!m_zonesByBiome.TryGetValue(biome, out List<Vector2i> value))
{
value = new List<Vector2i>();
m_zonesByBiome[biome] = value;
}
value.Add(val);
m_zoneBiomeArea[val] = biomeArea;
m_cachedZoneCount++;
}
}
}
stopwatch.Stop();
m_built = true;
worldGenAcceleratorPlugin.TemplateLogger.LogInfo((object)($"BiomeZoneCache built in {stopwatch.ElapsedMilliseconds}ms " + $"({m_cachedZoneCount} zones cached, worldRadius={worldRadius}m, gridRadius={num})"));
}
public List<Vector2i> GetCandidateZones(Biome biomeMask, BiomeArea biomeAreaMask)
{
//IL_0021: Unknown result type (might be due to invalid IL or missing references)
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
//IL_0029: Invalid comparison between Unknown and I4
//IL_0044: Unknown result type (might be due to invalid IL or missing references)
//IL_0049: Unknown result type (might be due to invalid IL or missing references)
//IL_0052: Unknown result type (might be due to invalid IL or missing references)
//IL_0054: Unknown result type (might be due to invalid IL or missing references)
//IL_0059: Unknown result type (might be due to invalid IL or missing references)
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
//IL_005c: Invalid comparison between Unknown and I4
//IL_0066: Unknown result type (might be due to invalid IL or missing references)
List<Vector2i> list = new List<Vector2i>();
foreach (KeyValuePair<Biome, List<Vector2i>> item in m_zonesByBiome)
{
if ((item.Key & biomeMask) == 0)
{
continue;
}
foreach (Vector2i item2 in item.Value)
{
if ((m_zoneBiomeArea[item2] & biomeAreaMask) > 0)
{
list.Add(item2);
}
}
}
return list;
}
public void Reset()
{
m_zonesByBiome.Clear();
m_zoneBiomeArea.Clear();
m_cachedZoneCount = 0;
m_built = false;
}
}
public static class ExpandWorldSizeBridge
{
private const string PluginGuid = "expand_world_size";
private const string ConfigTypeName = "ExpandWorldSize.Configuration";
private const string RadiusPropertyName = "WorldRadius";
public const float VanillaWorldRadius = 10000f;
private static bool s_resolved;
private static PropertyInfo? s_radiusProperty;
public static float GetWorldRadius()
{
PropertyInfo radiusProperty = GetRadiusProperty();
if (radiusProperty == null)
{
return 10000f;
}
try
{
object value = radiusProperty.GetValue(null);
if (value is float)
{
float num = (float)value;
if (num > 0f)
{
return num;
}
}
}
catch (Exception ex)
{
worldGenAcceleratorPlugin.TemplateLogger.LogWarning((object)("Failed to read ExpandWorldSize.Configuration.WorldRadius from ExpandWorldSize: " + ex.Message + ". Falling back to vanilla radius."));
}
return 10000f;
}
private static PropertyInfo? GetRadiusProperty()
{
if (s_resolved)
{
return s_radiusProperty;
}
s_resolved = true;
if (!Chainloader.PluginInfos.TryGetValue("expand_world_size", out var value))
{
return null;
}
Assembly assembly = ((object)value.Instance).GetType().Assembly;
Type type = assembly.GetType("ExpandWorldSize.Configuration");
if (type == null)
{
worldGenAcceleratorPlugin.TemplateLogger.LogWarning((object)"ExpandWorldSize is loaded but type ExpandWorldSize.Configuration was not found. Falling back to vanilla radius.");
return null;
}
PropertyInfo property = type.GetProperty("WorldRadius", BindingFlags.Static | BindingFlags.Public);
if (property == null)
{
worldGenAcceleratorPlugin.TemplateLogger.LogWarning((object)"ExpandWorldSize is loaded but ExpandWorldSize.Configuration.WorldRadius was not found. Falling back to vanilla radius.");
return null;
}
s_radiusProperty = property;
return property;
}
}
[BepInPlugin("warpalicious.worldGenAccelerator", "worldGenAccelerator", "1.0.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class worldGenAcceleratorPlugin : BaseUnityPlugin
{
private const string ModName = "worldGenAccelerator";
private const string ModVersion = "1.0.0";
private const string Author = "warpalicious";
private const string ModGUID = "warpalicious.worldGenAccelerator";
private static string ConfigFileName = "warpalicious.worldGenAccelerator.cfg";
private static string ConfigFileFullPath;
private readonly Harmony HarmonyInstance = new Harmony("warpalicious.worldGenAccelerator");
public static readonly ManualLogSource TemplateLogger;
private static ConfigEntry<bool> _enableOptimization;
private static ConfigEntry<bool> _enableTimingLogs;
private DateTime _lastReloadTime;
private const long RELOAD_DELAY = 10000000L;
public static bool OptimizationEnabled => _enableOptimization.Value;
public static bool TimingLogsEnabled => _enableTimingLogs.Value;
public void Awake()
{
Analytics.Init(((BaseUnityPlugin)this).Config, "warpalicious.worldGenAccelerator", "1.0.0");
_enableOptimization = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableOptimization", true, "Enable the biome zone cache optimization for faster world generation. Disabling this uses vanilla generation logic. Note: Optimized worlds will have different layouts than vanilla for the same seed.");
_enableTimingLogs = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableTimingLogs", true, "Log detailed timing information for each location placement and total generation time.");
Assembly executingAssembly = Assembly.GetExecutingAssembly();
HarmonyInstance.PatchAll(executingAssembly);
SetupWatcher();
}
private void OnDestroy()
{
((BaseUnityPlugin)this).Config.Save();
}
private void SetupWatcher()
{
_lastReloadTime = DateTime.Now;
FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(Paths.ConfigPath, ConfigFileName);
fileSystemWatcher.Changed += ReadConfigValues;
fileSystemWatcher.Created += ReadConfigValues;
fileSystemWatcher.Renamed += ReadConfigValues;
fileSystemWatcher.IncludeSubdirectories = true;
fileSystemWatcher.EnableRaisingEvents = true;
}
private void ReadConfigValues(object sender, FileSystemEventArgs e)
{
DateTime now = DateTime.Now;
long num = now.Ticks - _lastReloadTime.Ticks;
if (File.Exists(ConfigFileFullPath) && num >= 10000000)
{
try
{
TemplateLogger.LogInfo((object)"Attempting to reload configuration...");
((BaseUnityPlugin)this).Config.Reload();
TemplateLogger.LogInfo((object)"Configuration reloaded successfully!");
}
catch
{
TemplateLogger.LogError((object)("There was an issue loading " + ConfigFileName));
return;
}
_lastReloadTime = now;
if ((Object)(object)ZNet.instance != (Object)null && !ZNet.instance.IsDedicated())
{
TemplateLogger.LogInfo((object)"Updating runtime configurations...");
}
}
}
static worldGenAcceleratorPlugin()
{
string configPath = Paths.ConfigPath;
char directorySeparatorChar = Path.DirectorySeparatorChar;
ConfigFileFullPath = configPath + directorySeparatorChar + ConfigFileName;
TemplateLogger = Logger.CreateLogSource("worldGenAccelerator");
_enableOptimization = null;
_enableTimingLogs = null;
}
}
[HarmonyPatch]
public static class ZoneSystemPatch
{
private static Stopwatch s_totalGenerationTimer = new Stopwatch();
[HarmonyPatch(typeof(ZoneSystem), "GenerateLocations")]
[HarmonyPrefix]
private static void GenerateLocations_Prefix()
{
if (worldGenAcceleratorPlugin.TimingLogsEnabled)
{
s_totalGenerationTimer.Restart();
}
if (worldGenAcceleratorPlugin.OptimizationEnabled)
{
BiomeZoneCache.Instance.Reset();
BiomeZoneCache.Instance.Build();
}
}
[HarmonyPatch(typeof(ZoneSystem), "set_LocationsGenerated")]
[HarmonyPostfix]
private static void LocationsGenerated_Postfix(bool value)
{
if (value && worldGenAcceleratorPlugin.TimingLogsEnabled && s_totalGenerationTimer.IsRunning)
{
s_totalGenerationTimer.Stop();
worldGenAcceleratorPlugin.TemplateLogger.LogInfo((object)$"Total location generation completed in {s_totalGenerationTimer.ElapsedMilliseconds}ms");
}
}
[HarmonyPatch(typeof(ZoneSystem), "GenerateLocationsTimeSliced", new Type[]
{
typeof(ZoneLocation),
typeof(Stopwatch),
typeof(ZPackage)
})]
[HarmonyPrefix]
private static bool GenerateLocationsTimeSliced_Prefix(ZoneSystem __instance, ZoneLocation location, Stopwatch timeSliceStopwatch, ZPackage iterationsPkg, ref IEnumerator __result)
{
if (!worldGenAcceleratorPlugin.OptimizationEnabled)
{
return true;
}
__result = OptimizedGenerateLocationsTimeSliced(__instance, location, timeSliceStopwatch, iterationsPkg);
return false;
}
private static IEnumerator OptimizedGenerateLocationsTimeSliced(ZoneSystem zoneSystem, ZoneLocation location, Stopwatch timeSliceStopwatch, ZPackage iterationsPkg)
{
ZoneSystem zoneSystem2 = zoneSystem;
Stopwatch locationTimer = null;
if (worldGenAcceleratorPlugin.TimingLogsEnabled)
{
locationTimer = Stopwatch.StartNew();
}
int seed = WorldGenerator.instance.GetSeed() + StringExtensionMethods.GetStableHashCode(location.m_prefab.Name);
State state = Random.state;
Random.InitState(seed);
float maxRadius = Mathf.Max(location.m_exteriorRadius, location.m_interiorRadius);
int iterations = 0;
int placed = zoneSystem2.CountNrOfLocation(location);
if (!location.m_unique || placed <= 0)
{
zoneSystem2.s_tempVeg.Clear();
List<Vector2i> candidates = BiomeZoneCache.Instance.GetCandidateZones(location.m_biome, location.m_biomeArea);
candidates.RemoveAll((Vector2i z) => zoneSystem2.m_locationInstances.ContainsKey(z) || zoneSystem2.m_generatedZones.Contains(z));
int candidateCount = candidates.Count;
if (location.m_centerFirst)
{
candidates.Sort(delegate(Vector2i a, Vector2i b)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
Vector3 zonePos = ZoneSystem.GetZonePos(a);
float magnitude2 = ((Vector3)(ref zonePos)).magnitude;
zonePos = ZoneSystem.GetZonePos(b);
float magnitude3 = ((Vector3)(ref zonePos)).magnitude;
return magnitude2.CompareTo(magnitude3);
});
}
else
{
for (int i = candidates.Count - 1; i > 0; i--)
{
int k = Random.Range(0, i + 1);
Vector2i tmp = candidates[i];
candidates[i] = candidates[k];
candidates[k] = tmp;
}
}
Color mask1 = default(Color);
float delta = default(float);
Vector3 slopeDir = default(Vector3);
Color mask2 = default(Color);
for (int j = 0; j < candidates.Count; j++)
{
if (placed >= location.m_quantity)
{
break;
}
Vector2i zoneID = candidates[j];
if (timeSliceStopwatch.Elapsed.TotalSeconds >= (double)zoneSystem2.m_timeSlicedGenerationTimeBudget)
{
State insideState = Random.state;
Random.state = state;
yield return null;
timeSliceStopwatch.Restart();
state = Random.state;
Random.state = insideState;
}
if (zoneSystem2.m_locationInstances.ContainsKey(zoneID))
{
continue;
}
for (int l = 0; l < 20; l++)
{
if (timeSliceStopwatch.Elapsed.TotalSeconds >= (double)zoneSystem2.m_timeSlicedGenerationTimeBudget)
{
State insideState = Random.state;
Random.state = state;
yield return null;
timeSliceStopwatch.Restart();
state = Random.state;
Random.state = insideState;
}
iterations++;
Vector3 randomPointInZone = ZoneSystem.GetRandomPointInZone(zoneID, maxRadius);
float magnitude = ((Vector3)(ref randomPointInZone)).magnitude;
if (((double)location.m_minDistance != 0.0 && (double)magnitude < (double)location.m_minDistance) || ((double)location.m_maxDistance != 0.0 && (double)magnitude > (double)location.m_maxDistance) || (location.m_biome & WorldGenerator.instance.GetBiome(randomPointInZone)) == 0)
{
continue;
}
randomPointInZone.y = WorldGenerator.instance.GetHeight(randomPointInZone.x, randomPointInZone.z, ref mask1);
float altitude = randomPointInZone.y - 30f;
if ((double)altitude < (double)location.m_minAltitude || (double)altitude > (double)location.m_maxAltitude)
{
continue;
}
if (location.m_inForest)
{
float forestFactor = WorldGenerator.GetForestFactor(randomPointInZone);
if ((double)forestFactor < (double)location.m_forestTresholdMin || (double)forestFactor > (double)location.m_forestTresholdMax)
{
continue;
}
}
if ((double)location.m_minDistanceFromCenter > 0.0 || (double)location.m_maxDistanceFromCenter > 0.0)
{
float lengthXZ = Utils.LengthXZ(randomPointInZone);
if (((double)location.m_minDistanceFromCenter > 0.0 && (double)lengthXZ < (double)location.m_minDistanceFromCenter) || ((double)location.m_maxDistanceFromCenter > 0.0 && (double)lengthXZ > (double)location.m_maxDistanceFromCenter))
{
continue;
}
}
WorldGenerator.instance.GetTerrainDelta(randomPointInZone, location.m_exteriorRadius, ref delta, ref slopeDir);
if ((double)delta > (double)location.m_maxTerrainDelta || (double)delta < (double)location.m_minTerrainDelta || ((double)location.m_minDistanceFromSimilar > 0.0 && zoneSystem2.HaveLocationInRange(location.m_prefab.Name, location.m_group, randomPointInZone, location.m_minDistanceFromSimilar, false)) || ((double)location.m_maxDistanceFromSimilar > 0.0 && !zoneSystem2.HaveLocationInRange(location.m_prefabName, location.m_groupMax, randomPointInZone, location.m_maxDistanceFromSimilar, true)))
{
continue;
}
float vegMask = mask1.a;
if (((double)location.m_minimumVegetation > 0.0 && (double)vegMask <= (double)location.m_minimumVegetation) || ((double)location.m_maximumVegetation < 1.0 && (double)vegMask >= (double)location.m_maximumVegetation))
{
continue;
}
if (location.m_surroundCheckVegetation)
{
float num3 = 0f;
for (int index1 = 0; index1 < location.m_surroundCheckLayers; index1++)
{
float num4 = (float)(index1 + 1) / (float)location.m_surroundCheckLayers * location.m_surroundCheckDistance;
for (int index2 = 0; index2 < 6; index2++)
{
float f = (float)((double)index2 / 6.0 * 3.1415927410125732 * 2.0);
Vector3 samplePos = randomPointInZone + new Vector3(Mathf.Sin(f) * num4, 0f, Mathf.Cos(f) * num4);
WorldGenerator.instance.GetHeight(samplePos.x, samplePos.z, ref mask2);
float num5 = (float)(((double)location.m_surroundCheckDistance - (double)num4) / ((double)location.m_surroundCheckDistance * 2.0));
num3 += mask2.a * num5;
mask2 = default(Color);
}
}
zoneSystem2.s_tempVeg.Add(num3);
if (zoneSystem2.s_tempVeg.Count < 10)
{
continue;
}
float maxVeg = zoneSystem2.s_tempVeg.Max();
float avgVeg = zoneSystem2.s_tempVeg.Average();
float threshold = avgVeg + (maxVeg - avgVeg) * location.m_surroundBetterThanAverage;
if ((double)num3 < (double)threshold)
{
continue;
}
}
zoneSystem2.RegisterLocation(location, randomPointInZone, false);
placed++;
break;
}
}
if (placed < location.m_quantity)
{
worldGenAcceleratorPlugin.TemplateLogger.LogWarning((object)$" {location.m_prefab.Name}: placed {placed}/{location.m_quantity} (incomplete)");
}
if (worldGenAcceleratorPlugin.TimingLogsEnabled && locationTimer != null)
{
worldGenAcceleratorPlugin.TemplateLogger.LogInfo((object)($" {location.m_prefab.Name}: placed {placed}/{location.m_quantity} " + $"({candidateCount} candidate zones, {iterations} point iterations) " + $"in {locationTimer.ElapsedMilliseconds}ms"));
}
}
Random.state = state;
iterationsPkg.Write(iterations);
iterationsPkg.SetPos(0);
}
}
}