public void HandleTransferRequest(TransferRequestMessage request) { string[] filePaths = FileOperations.GetFilteredFilePaths(logsSourcePath, request.TimeRangeLocal, request.FullCategories); if (filePaths.Length == 0) { SendResponseMessage(ResponseCode.Error, "No files found that match request"); return; } // send response SendResponseMessage(ResponseCode.Ok); // transfer files logger.Log("Transferring files..."); for (int i = 0; i < filePaths.Length; i++) { string path = filePaths[i]; logger.Log("Transferring: " + path); string fileName = Path.GetFileName(path); byte[] fileBytes = File.ReadAllBytes(path); byte[] fileBytesCompressed = ByteCompression.GZipCompress(fileBytes); var message = new TransferOperationMessage( i + 1, filePaths.Length, fileName, fileBytesCompressed); client.Writer.Write(message); } logger.Log("Transfer operation complete"); }
public static void PositionCompressionTest(float x, float y, float z) { var defaultPositionBounds = ByteCompression.PositionBounds; try { var position = new Vector3(x, y, z); TestSinglePosition(position); var maxElementSize = Mathf.Max(Mathf.Abs(x), Mathf.Abs(y), Mathf.Abs(z)) * 2; ByteCompression.SetPositionBounds( new Bounds(Vector3.zero, new Vector3(maxElementSize, maxElementSize, maxElementSize))); TestSinglePosition(position); ByteCompression.SetPositionBounds(new Bounds(position, Vector3.one)); TestSinglePosition(position); ByteCompression.SetPositionBounds( new Bounds( new Vector3(-maxElementSize / 3, maxElementSize / 3, -maxElementSize / 5), new Vector3(2 * maxElementSize, 2 * maxElementSize, 2 * maxElementSize))); TestSinglePosition(position); } finally { ByteCompression.SetPositionBounds(defaultPositionBounds); } }
/// <inheritdoc/> public void ReceiveMessage(IPeerManager sender, Message message) { var command = (IdsRegisterCommandType)message.Content.PopInt(ByteCompression .RequiredBytes <IdsRegisterCommandType>()); var key = message.Content.PopString(); var id = message.Content.PopInt(BytesPerId); switch (command) { case IdsRegisterCommandType.BindIdAndKey: if (AssignIds) { return; } BindReceiver(key, id); break; case IdsRegisterCommandType.UnbindIdAndKey: if (AssignIds) { return; } UnbindKeyId(key, id); break; } }
public void RequiredBytesTest() { var value = 0; Assert.True(ByteCompression.RequiredBytes(value) == 1, $"Required bytes in {typeof(ByteCompression).Name} returns invalid bytes count for value {value}."); value = 1; Assert.True(ByteCompression.RequiredBytes(value) == 1, $"Required bytes in {typeof(ByteCompression).Name} returns invalid bytes count for value {value}."); value = 0xFF; Assert.True(ByteCompression.RequiredBytes(value) == 1, $"Required bytes in {typeof(ByteCompression).Name} returns invalid bytes count for value {value}."); value = 0x100; Assert.True(ByteCompression.RequiredBytes(value) == 2, $"Required bytes in {typeof(ByteCompression).Name} returns invalid bytes count for value {value}."); value = 0x1FF; Assert.True(ByteCompression.RequiredBytes(value) == 2, $"Required bytes in {typeof(ByteCompression).Name} returns invalid bytes count for value {value}."); value = 0x10000; Assert.True(ByteCompression.RequiredBytes(value) == 3, $"Required bytes in {typeof(ByteCompression).Name} returns invalid bytes count for value {value}."); value = 0x1FFFF; Assert.True(ByteCompression.RequiredBytes(value) == 3, $"Required bytes in {typeof(ByteCompression).Name} returns invalid bytes count for value {value}."); value = 0x1FFFFFF; Assert.True(ByteCompression.RequiredBytes(value) == 4, $"Required bytes in {typeof(ByteCompression).Name} returns invalid bytes count for value {value}."); value = int.MaxValue; Assert.True(ByteCompression.RequiredBytes(value) == 4, $"Required bytes in {typeof(ByteCompression).Name} returns invalid bytes count for value {value}."); value = -1; Assert.True(ByteCompression.RequiredBytes(value) == 4, $"Required bytes in {typeof(ByteCompression).Name} returns invalid bytes count for value {value}."); }
public void FloatCompressionTests(float value, float minValue, float maxValue, int bytesCount) { var precision = (maxValue - minValue) / (1 << (bytesCount * 8)); var bytesStack = new BytesStack(ByteCompression.PositionRequiredBytes); bytesStack.PushInt(ByteCompression.CompressFloatToInt(value, minValue, maxValue, bytesCount), bytesCount); var resultFloat = ByteCompression.DecompressFloatFromInt(bytesStack.PopInt(bytesCount), minValue, maxValue, bytesCount); Assert.True(Mathf.Abs(value - resultFloat) <= precision, $"Compression-decompression operation of the float value result exceeds precision. Tested float: {value}, result float: {resultFloat}, precision {precision}."); }
public void PushPeekPopLongTests(long value) { var bytesCount = ByteCompression.RequiredBytes(value); var bytesStack = new BytesStack(bytesCount); bytesStack.PushLong(value, bytesCount); var result = bytesStack.PeekLong(bytesCount); Assert.True(value == result, "PeekLong returns different value than was pushed."); result = bytesStack.PopLong(bytesCount); Assert.True(value == result, "PopLong returns different value than was pushed."); Assert.True(bytesStack.Count == 0, "BytesStack is not empty after PopLong alone long."); }
public void PushPeekPopIntTests(uint value) { var bytesCount = ByteCompression.RequiredBytes(value); var bytesStack = new BytesStack(bytesCount); bytesStack.PushUint(value, bytesCount); var result = bytesStack.PeekUint(bytesCount); Assert.True(value == result, "PeekUint returns different value than was pushed."); result = bytesStack.PopUint(bytesCount); Assert.True(value == result, "PopUint returns different value than was pushed."); Assert.True(bytesStack.Count == 0, "BytesStack is not empty after PopUint alone integer."); }
/// <inheritdoc/> public void ReceiveMessage(IPeerManager sender, Message message) { var commandType = (DistributedRootCommandType)message.Content.PopInt( ByteCompression.RequiredBytes <DistributedRootCommandType>()); switch (commandType) { case DistributedRootCommandType.InstantiateDistributedObject: InstantiatePrefab(message.Content.PopInt(), message.Content.PopString(), message.Content.PopString()); break; default: throw new ArgumentOutOfRangeException(); } }
public async override Task HandleOperationUpdates() { doneReceiving = false; // producer thread ThreadPool.QueueUserWorkItem(ReceivingAndDecodingWork); // consumer thread await Task.Run(() => { // while still receiving or something still in queue while (!doneReceiving || !operationMessageQueue.IsEmpty) { if (operationMessageQueue.IsEmpty) { autoEvent.WaitOne(); // wait here until a message is decoded and added to the queue } // create a file from the message if (operationMessageQueue.TryDequeue(out TransferOperationMessage msg)) { string filePath = Path.Combine(folderPath, msg.FileName); Console.WriteLine("Decompressing: " + msg.FileName); byte[] bytesUncompressed = ByteCompression.GZipDecompress( msg.FileBytesCompressed); if (zipLocal) { using (ZipArchive archive = ZipFile.Open(folderPath, ZipArchiveMode.Update)) { var zipEntry = archive.CreateEntry(msg.FileName); using (var originalFileStream = new MemoryStream(bytesUncompressed)) using (var zipEntryStream = zipEntry.Open()) { //Copy the attachment stream to the zip entry stream originalFileStream.CopyTo(zipEntryStream); } } } else { CreateLogFile(filePath, bytesUncompressed); } OnProgressUpdated(msg.NumFilesCompleted, msg.NumTotalFiles); } } }); }
private void LockingCommandOnExecuted(ILockingCommand executedCommand) { executedCommand.Executed -= LockingCommandOnExecuted; lockingCommands.Remove(executedCommand); ActionsSemaphore.Unlock(); var isClient = Loader.Instance.Network.IsClient; if (!isClient) { return; } var message = MessagesPool.Instance.GetMessage( ByteCompression.RequiredBytes <MessageType>()); message.AddressKey = Key; message.Content.PushEnum <MessageType>((int)MessageType.LockingCommandExecuted); message.Type = DistributedMessageType.ReliableOrdered; BroadcastMessage(message); }
private DistributedMessage GetSpawnMessage(NPCSpawnData data) { var message = MessagesPool.Instance.GetMessage( ByteCompression.RotationMaxRequiredBytes + ByteCompression.PositionRequiredBytes + 12 + BytesStack.GetMaxByteCount(data.GenId) + 1 + ByteCompression.RequiredBytes <NPCManagerCommandType>()); message.AddressKey = Key; var indexOfPrefab = NPCVehicles.FindIndex(npc => npc.Equals(data.Template)); message.Content.PushCompressedRotation(data.Rotation); message.Content.PushCompressedPosition(data.Position); message.Content.PushCompressedColor(data.Color, 1); message.Content.PushInt(data.Seed); message.Content.PushInt(indexOfPrefab, 2); message.Content.PushString(data.GenId); message.Content.PushBool(data.Active); message.Content.PushEnum <NPCManagerCommandType>((int)NPCManagerCommandType.SpawnNPC); message.Type = DistributedMessageType.ReliableOrdered; return(message); }
/// <inheritdoc/> public void ReceiveMessage(IPeerManager sender, DistributedMessage distributedMessage) { var command = (IdsRegisterCommandType)distributedMessage.Content.PopInt( ByteCompression .RequiredBytes <IdsRegisterCommandType>()); var key = distributedMessage.Content.PopString(); var id = distributedMessage.Content.PopInt(BytesPerId); IIdentifiedObject registeredObject; int awaitingId; switch (command) { case IdsRegisterCommandType.BindIdAndKey: if (AssignIds) { return; } //Check if object is already registered if ((idToObjectDictionary.TryGetValue(id, out registeredObject) && registeredObject.Key == key) || (awaitingKeyIdBinds.TryGetValue(key, out awaitingId) && awaitingId == id)) { return; } //New bind to the id received before receiving unbind command if (registeredObject != null) { UnbindKeyId(key, id); idRegistrationTimestamp.Remove(id); } idRegistrationTimestamp.Add(id, distributedMessage.ServerTimestamp); TryBindReceiver(key, id); break; case IdsRegisterCommandType.UnbindIdAndKey: if (AssignIds) { return; } //Remove awaiting binding if it is available if (awaitingKeyIdBinds.TryGetValue(key, out awaitingId) && awaitingId == id) { awaitingKeyIdBinds.Remove(key); idRegistrationTimestamp.Remove(id); return; } //Check if object have not been unbounded already if (!idToObjectDictionary.TryGetValue(id, out registeredObject)) { return; } //Check if bound object has the same key if (registeredObject.Key != key) { return; } UnbindKeyId(key, id); idRegistrationTimestamp.Remove(id); break; } }
void Update() { while (ApiLock.IsUnlocked && Actions.TryDequeue(out var action)) { try { var isMasterSimulation = Loader.Instance.Network.IsMaster; if (action.Command is ILockingCommand lockingCommand) { ApiLock.RegisterNewCommand(lockingCommand); } if (action.Command is IDelegatedCommand delegatedCommand && isMasterSimulation) { var endpoint = delegatedCommand.TargetNodeEndPoint(action.Arguments); //If there is a connection to this endpoint forward the command, otherwise execute it locally if (Loader.Instance.Network.Master.IsConnectedToClient(endpoint)) { var message = MessagesPool.Instance.GetMessage( BytesStack.GetMaxByteCount(action.Arguments) + BytesStack.GetMaxByteCount(action.Command.Name) + ByteCompression.RequiredBytes <MessageType>()); message.AddressKey = Key; message.Content.PushString(action.Arguments.ToString()); message.Content.PushString(action.Command.Name); message.Content.PushEnum <MessageType>((int)MessageType.Command); UnicastMessage(endpoint, message); } else { action.Command.Execute(action.Arguments); } } else { action.Command.Execute(action.Arguments); if (action.Command is IDistributedCommand && isMasterSimulation) { var message = MessagesPool.Instance.GetMessage( BytesStack.GetMaxByteCount(action.Arguments) + BytesStack.GetMaxByteCount(action.Command.Name) + ByteCompression.RequiredBytes <MessageType>()); message.AddressKey = Key; message.Content.PushString(action.Arguments.ToString()); message.Content.PushString(action.Command.Name); message.Content.PushEnum <MessageType>((int)MessageType.Command); message.Type = DistributedMessageType.ReliableOrdered; BroadcastMessage(message); } } } catch (Exception ex) { UnityEngine.Debug.LogException(ex); var st = new StackTrace(ex, true); StackFrame frame = null; int i = 0; while (i < st.FrameCount) { frame = st.GetFrame(i++); if (frame.GetFileLineNumber() != 0) { break; } frame = null; } if (frame == null) { SendError(ex.Message); } else { var fname = frame.GetFileName(); var line = frame.GetFileLineNumber(); SendError($"{ex.Message} at {fname}@{line}"); } ApiLock.ForceUnlock(); } }
public void Init(int?seed = null) { if (ApiManager.Instance != null) { FixedUpdateManager = ApiManager.Instance; IsAPI = true; } else { FixedUpdateManager = Instance; IsAPI = false; } controls = new SimulatorControls(); controls.Enable(); SimulationConfig config = null; if (Loader.Instance != null) { config = Loader.Instance.SimConfig; } var masterSeed = seed ?? config?.Seed ?? new System.Random().Next(); RandomGenerator = new System.Random(masterSeed); //Calculate map bounds and limit position compression if (Loader.Instance != null && Loader.Instance.Network.IsClusterSimulation) { var mapBounds = CalculateMapBounds(); //Add margin to the bounds mapBounds.size += Vector3.one * 10; ByteCompression.SetPositionBounds(mapBounds); } ManagerHolder = new GameObject("ManagerHolder"); ManagerHolder.transform.SetParent(transform); AnalysisManager = Instantiate(analysisManagerPrefab, ManagerHolder.transform); AgentManager = Instantiate(agentManagerPrefab, ManagerHolder.transform); CameraManager = Instantiate(cameraManagerPrefab, ManagerHolder.transform); ControllableManager = Instantiate(controllableManagerPrefab, ManagerHolder.transform); MapManager = Instantiate(mapManagerPrefab, ManagerHolder.transform); NPCManager = Instantiate(npcManagerPrefab, ManagerHolder.transform); NPCManager.InitRandomGenerator(RandomGenerator.Next()); PedestrianManager = Instantiate(pedestrianManagerPrefab, ManagerHolder.transform); PedestrianManager.InitRandomGenerator(RandomGenerator.Next()); EnvironmentEffectsManager = Instantiate(environmentEffectsManagerPrefab, ManagerHolder.transform); EnvironmentEffectsManager.InitRandomGenerator(RandomGenerator.Next()); UIManager = Instantiate(uiManagerPrefab, ManagerHolder.transform); if (SystemInfo.operatingSystemFamily == OperatingSystemFamily.Linux && Application.isEditor) { // empty } else { controls.Simulator.ToggleNPCS.performed += ctx => NPCManager.NPCActive = !NPCManager.NPCActive; controls.Simulator.TogglePedestrians.performed += ctx => PedestrianManager.PedestriansActive = !PedestrianManager.PedestriansActive; controls.Simulator.ToggleAgent.performed += ctx => { if (int.TryParse(ctx.control.name, out int index)) { AgentManager.SetCurrentActiveAgent(index - 1); } }; controls.Simulator.ToggleReset.performed += ctx => AgentManager.ResetAgent(); controls.Simulator.ToggleControlsUI.performed += ctx => UIManager.UIActive = !UIManager.UIActive; } if (config != null) { simulationName = config.Name; clusterName = config.ClusterName; mapName = config.MapName; NPCManager.NPCActive = config.UseTraffic; PedestrianManager.PedestriansActive = config.UsePedestrians; if (config.Agents != null) { AgentManager.SpawnAgents(config.Agents); } apiMode = config.ApiOnly; headless = config.Headless; interactive = config.Interactive; useSeed = config.Seed.HasValue; npc = config.UseTraffic; pedestrian = config.UsePedestrians; timeOfDay = config.TimeOfDay.ToString("HH:mm"); rain = config.Rain; wet = config.Wetness; fog = config.Fog; cloud = config.Cloudiness; if (headless) { controls.Disable(); } } SIM.APIOnly = apiMode; SIM.LogSimulation(SIM.Simulation.SimulationStart, simulationName); SIM.LogSimulation(SIM.Simulation.ClusterNameStart, clusterName); SIM.LogSimulation(SIM.Simulation.MapStart, string.IsNullOrEmpty(mapName) ? UnityEngine.SceneManagement.SceneManager.GetActiveScene().name : mapName); SIM.LogSimulation(SIM.Simulation.HeadlessModeStart, state: headless); SIM.LogSimulation(SIM.Simulation.InteractiveModeStart, state: interactive); SIM.LogSimulation(SIM.Simulation.UsePredefinedSeedStart, state: useSeed); SIM.LogSimulation(SIM.Simulation.NPCStart, state: npc); SIM.LogSimulation(SIM.Simulation.RandomPedestrianStart, state: pedestrian); SIM.LogSimulation(SIM.Simulation.TimeOfDayStart, timeOfDay == "" ? string.Format("{0:hh}:{0:mm}", TimeSpan.FromHours(EnvironmentEffectsManager.currentTimeOfDay)) : timeOfDay); SIM.LogSimulation(SIM.Simulation.RainStart, rain == 0f ? EnvironmentEffectsManager.rain.ToString() : rain.ToString()); SIM.LogSimulation(SIM.Simulation.WetnessStart, wet == 0f ? EnvironmentEffectsManager.wet.ToString() : wet.ToString()); SIM.LogSimulation(SIM.Simulation.FogStart, fog == 0f ? EnvironmentEffectsManager.fog.ToString() : fog.ToString()); SIM.LogSimulation(SIM.Simulation.CloudinessStart, cloud == 0f ? EnvironmentEffectsManager.cloud.ToString() : cloud.ToString()); InitSegmenationColors(); WireframeBoxes = gameObject.AddComponent <WireframeBoxes>(); if (Loader.Instance != null) { TimeManager.Initialize(Loader.Instance.Network.MessagesManager); } Sensors.Initialize(); Loader.ResetMaterials(); // TODO remove Editor hack for 2019.3.3 bug once fixed IsInitialized = true; }
public void Init(int?seed = null) { if (ApiManager.Instance != null) { FixedUpdateManager = ApiManager.Instance; IsAPI = true; } else { FixedUpdateManager = Instance; IsAPI = false; } controls = new SimulatorControls(); controls.Enable(); SimulationConfig config = null; if (Loader.Instance != null) { config = Loader.Instance.SimConfig; } var masterSeed = seed ?? config?.Seed ?? new System.Random().Next(); RandomGenerator = new System.Random(masterSeed); segmentationIdMapping = new SegmentationIdMapping(); //Calculate map bounds and limit position compression if (Loader.Instance != null && Loader.Instance.Network.IsClusterSimulation) { var mapBounds = CalculateMapBounds(); //Add margin to the bounds mapBounds.size += Vector3.one * 50; ByteCompression.SetPositionBounds(mapBounds); } ManagerHolder = new GameObject("ManagerHolder"); ManagerHolder.transform.SetParent(transform); BridgeMessageDispatcher = new BridgeMessageDispatcher(); AnalysisManager = InstantiateManager(analysisManagerPrefab, ManagerHolder.transform); AgentManager = InstantiateManager(agentManagerPrefab, ManagerHolder.transform); CameraManager = InstantiateManager(cameraManagerPrefab, ManagerHolder.transform); ControllableManager = InstantiateManager(controllableManagerPrefab, ManagerHolder.transform); MapManager = InstantiateManager(mapManagerPrefab, ManagerHolder.transform); NPCManager = InstantiateManager(npcManagerPrefab, ManagerHolder.transform); NPCManager.InitRandomGenerator(RandomGenerator.Next()); PedestrianManager = InstantiateManager(pedestrianManagerPrefab, ManagerHolder.transform); PedestrianManager.InitRandomGenerator(RandomGenerator.Next()); EnvironmentEffectsManager = InstantiateManager(environmentEffectsManagerPrefab, ManagerHolder.transform); EnvironmentEffectsManager.InitRandomGenerator(RandomGenerator.Next()); CustomPassManager = InstantiateManager(customPassManagerPrefab, ManagerHolder.transform); UIManager = InstantiateManager(uiManagerPrefab, ManagerHolder.transform); controls.Simulator.ToggleNPCS.performed += ctx => NPCManager.NPCActive = !NPCManager.NPCActive; controls.Simulator.TogglePedestrians.performed += ctx => PedestrianManager.PedestriansActive = !PedestrianManager.PedestriansActive; controls.Simulator.ToggleAgent.performed += ctx => { if (int.TryParse(ctx.control.name, out int index)) { AgentManager.SetCurrentActiveAgent(index - 1); } }; controls.Simulator.ToggleReset.performed += ctx => AgentManager.ResetAgent(); controls.Simulator.ToggleControlsUI.performed += ctx => UIManager.UIActive = !UIManager.UIActive; if (config != null) { simulationName = config.Name; clusterName = config.ClusterName; mapName = config.MapName; NPCManager.NPCActive = config.UseTraffic; PedestrianManager.PedestriansActive = config.UsePedestrians; if (config.Agents != null) { AgentManager.SpawnAgents(config.Agents); } apiMode = config.ApiOnly; headless = config.Headless; interactive = config.Interactive; useSeed = config.Seed.HasValue; npc = config.UseTraffic; pedestrian = config.UsePedestrians; timeOfDay = config.TimeOfDay.ToString("HH:mm"); rain = config.Rain; wet = config.Wetness; fog = config.Fog; cloud = config.Cloudiness; Damage = config.Damage; if (headless) { controls.Disable(); } } InitSegmenationColors(); WireframeBoxes = gameObject.AddComponent <WireframeBoxes>(); if (Loader.Instance != null) { TimeManager.Initialize(Loader.Instance.Network.MessagesManager); } Sensors.Initialize(); IsInitialized = true; }
public static void UpdateAPI() { string rawAPIFile = global.ProSwapperFolder + "api.ProSwapper"; string rawGlobalFile = global.ProSwapperFolder + "global.ProSwapper"; GlobalAPI.Root globalapi = null; #if DEBUG apidata = JsonConvert.DeserializeObject <APIRoot>(File.ReadAllText("api.json")); apidata.timestamp = global.GetEpochTime(); globalapi = JsonConvert.DeserializeObject <GlobalAPI.Root>(File.ReadAllText("global.json")); string json = JsonConvert.SerializeObject(apidata, Formatting.None, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore//Makes filesize smaller hehe }); byte[] compressedapi = MessagePackSerializer.ConvertFromJson(json, MessagePackSerializerOptions.Standard); File.WriteAllBytes($"{global.version}.json", ByteCompression.Compress(compressedapi)); #else try { download : double TimeNow = global.GetEpochTime(); if (global.CurrentConfig.LastOpenedAPI + 3600 < TimeNow) { //Get api coz it wasnt fetched more than an hour ago using (WebClient web = new WebClient()) { //Download api & global byte[] rawAPI = web.DownloadData($"{ProSwapperEndpoint}/{global.version}.json"); string rawGlobal = web.DownloadString($"{ProSwapperEndpoint}/global.json"); //Decompress api & set apidata = JsonConvert.DeserializeObject <APIRoot>(MessagePackSerializer.ConvertToJson(ByteCompression.Decompress(rawAPI))); globalapi = JsonConvert.DeserializeObject <GlobalAPI.Root>(rawGlobal); File.WriteAllBytes(rawAPIFile, rawAPI); File.WriteAllText(rawGlobalFile, rawGlobal); } global.CurrentConfig.LastOpenedAPI = TimeNow; } else { if (!File.Exists(rawAPIFile) || !File.Exists(rawGlobalFile)) { global.CurrentConfig.LastOpenedAPI = 0; goto download; } //Was fetched within the hour //Download api & global byte[] rawAPI = File.ReadAllBytes(rawAPIFile); string rawGlobal = File.ReadAllText(rawGlobalFile); //Decompress api & set apidata = JsonConvert.DeserializeObject <APIRoot>(MessagePackSerializer.ConvertToJson(ByteCompression.Decompress(rawAPI))); globalapi = JsonConvert.DeserializeObject <GlobalAPI.Root>(rawGlobal); } } catch (Exception ex) { Program.logger.LogError(ex.Message); Main.ThrowError($"Pro Swapper needs an Internet connection to run, if you are already connected to the Internet Pro Swapper's API may be blocked in your country, please use a VPN or try disabling your firewall, if you are already doing this please refer to this error: \n\n{ex.Message}", true); } #endif apidata.discordurl = globalapi.discordurl; apidata.version = globalapi.version; apidata.status[0] = globalapi.status[0]; }