public void SendStrategyMessage(Strategy strategy) { var msgData = NetworkMain.CliMsgFactory.CreateNewMessageData <ShareProgressStrategyMsgData>(); msgData.Strategy.Name = strategy.Config.Name; var configNode = ConvertStrategyToConfigNode(strategy); if (configNode == null) { return; } var data = ConfigNodeSerializer.Serialize(configNode); var numBytes = data.Length; msgData.Strategy.NumBytes = numBytes; if (msgData.Strategy.Data.Length < numBytes) { msgData.Strategy.Data = new byte[numBytes]; } Array.Copy(data, msgData.Strategy.Data, numBytes); SendMessage(msgData); }
public void SendKerbal(ProtoCrewMember pcm) { if (pcm == null) { return; } if (VesselCommon.IsSpectating) { return; } if (pcm.type == ProtoCrewMember.KerbalType.Tourist) { //Don't send tourists LunaLog.Log($"[LMP]: Skipping sending of tourist: {pcm.name}"); return; } ConfigNode.ClearData(); pcm.Save(ConfigNode); var kerbalBytes = ConfigNodeSerializer.Serialize(ConfigNode); if (kerbalBytes == null || kerbalBytes.Length == 0) { LunaLog.LogError("[LMP]: Error sending kerbal - bytes are null or 0"); return; } SendKerbalProtoMessage(pcm.name, kerbalBytes); }
public void HandleMessage(IServerMessageBase msg) { if (!(msg.Data is ScenarioBaseMsgData msgData)) { return; } if (msgData.ScenarioMessageType == ScenarioMessageType.Data) { var data = (ScenarioDataMsgData)msgData; for (var i = 0; i < data.ScenarioCount; i++) { var scenarioNode = ConfigNodeSerializer.Deserialize(data.ScenariosData[i].Data, data.ScenariosData[i].NumBytes); if (scenarioNode != null) { var entry = new ScenarioEntry { ScenarioName = data.ScenariosData[i].Module, ScenarioNode = scenarioNode }; System.ScenarioQueue.Enqueue(entry); } else { LunaLog.LogError($"[LMP]: Scenario data has been lost for {data.ScenariosData[i].Module}"); ScreenMessages.PostScreenMessage($"Scenario data has been lost for {data.ScenariosData[i].Module}", 5f, ScreenMessageStyle.UPPER_CENTER); } } MainSystem.NetworkState = ClientState.ScenariosSynced; } }
/// <summary> /// In this method we get the new vessel data and set it to the dictionary of all the player vessels. /// We set it as UNLOADED as perhaps vessel data has changed. /// </summary> public void HandleVesselProtoData(byte[] vesselData, Guid vesselId) { TaskFactory.StartNew(() => { UniverseSyncCache.QueueToCache(vesselData); var vesselNode = ConfigNodeSerializer.Deserialize(vesselData); if (vesselNode != null && vesselId == Common.ConvertConfigStringToGuid(vesselNode.GetValue("pid"))) { var vesselProtoUpdate = new VesselProtoUpdate(vesselNode, vesselId); if (vesselProtoUpdate.ProtoVessel == null) { return; } if (!AllPlayerVessels.TryGetValue(vesselId, out var existingProtoData)) { AllPlayerVessels.TryAdd(vesselId, vesselProtoUpdate); } else if (VesselCommon.ProtoVesselHasChanges(existingProtoData.ProtoVessel, vesselProtoUpdate.ProtoVessel)) { //Vessel exists and contain changes so replace it AllPlayerVessels.TryUpdate(vesselId, vesselProtoUpdate, existingProtoData); } } }); }
public void SendVesselMessage(Vessel vessel) { if (vessel == null) { return; } //Update the protovessel definition! vessel.BackupVessel(); //Defend against NaN orbits if (VesselHasNaNPosition(vessel.protoVessel)) { LunaLog.Log($"[LMP]: Vessel {vessel.id} has NaN position"); return; } foreach (var pps in vessel.protoVessel.protoPartSnapshots) { //Remove tourists from the vessel //TODO: Probably this can be done in the CleanUpVesselNode method foreach (var pcm in pps.protoModuleCrew.Where(pcm => pcm.type == ProtoCrewMember.KerbalType.Tourist).ToArray()) { pps.protoModuleCrew.Remove(pcm); } } var vesselNode = new ConfigNode(); try { vessel.protoVessel.Save(vesselNode); } catch (Exception) { LunaLog.LogError("[LMP]: Error while saving vessel"); return; } //Clean up the vessel so we send only the important data CleanUpVesselNode(vesselNode, vessel.id); var vesselBytes = ConfigNodeSerializer.Serialize(vesselNode); if (vesselBytes.Length > 0) { UniverseSyncCache.QueueToCache(vesselBytes); SendMessage(new VesselProtoMsgData { VesselId = vessel.id, VesselData = vesselBytes }); } else { LunaLog.LogError($"[LMP]: Failed to create byte[] data for {vessel.id}"); } }
public void HandleMessage(IMessageData messageData) { var msgData = messageData as ScenarioBaseMsgData; if (msgData?.ScenarioMessageType == ScenarioMessageType.Data) { var data = ((ScenarioDataMsgData)messageData).ScenarioNameData; foreach (var scenario in data) { var scenarioNode = ConfigNodeSerializer.Deserialize(scenario.Value); if (scenarioNode != null) { var entry = new ScenarioEntry { ScenarioName = scenario.Key, ScenarioNode = scenarioNode }; System.ScenarioQueue.Enqueue(entry); } else { LunaLog.LogError($"[LMP]: Scenario data has been lost for {scenario.Key}"); ScreenMessages.PostScreenMessage($"Scenario data has been lost for {scenario.Key}", 5f, ScreenMessageStyle.UPPER_CENTER); } } MainSystem.NetworkState = ClientState.ScneariosSynced; } }
/// <summary> /// Convert a byte array to a ConfigNode and then to a ProgressNode. /// If anything goes wrong it will return null. /// </summary> /// <param name="data">The byte array that represents the configNode</param> /// <param name="numBytes">The length of the byte array</param> /// <param name="progressNodeId">The Id of the ProgressNode</param> /// <returns></returns> private static ProgressNode ConvertByteArrayToAchievement(byte[] data, int numBytes, string progressNodeId) { ConfigNode node; try { node = ConfigNodeSerializer.Deserialize(data, numBytes); } catch (Exception e) { LunaLog.LogError($"[LMP]: Error while deserializing achievement configNode: {e}"); return(null); } if (node == null) { LunaLog.LogError("[LMP]: Error, the achievement configNode was null."); return(null); } ProgressNode achievement; try { achievement = new ProgressNode(progressNodeId, false); achievement.Load(node); } catch (Exception e) { LunaLog.LogError($"[LMP]: Error while deserializing achievement: {e}"); return(null); } return(achievement); }
/// <summary> /// Sends the parsed config nodes to the server after doing basic checks /// </summary> private void SendModulesConfigNodes() { ScenarioData.Clear(); ScenarioName.Clear(); foreach (var scenarioConfigNode in ScenariosConfigNodes) { var scenarioBytes = ConfigNodeSerializer.Serialize(scenarioConfigNode.Item2); var scenarioHash = Common.CalculateSha256Hash(scenarioBytes); if (scenarioBytes.Length == 0) { LunaLog.Log($"[LMP]: Error writing scenario data for {scenarioConfigNode.Item1}"); continue; } //Data is the same since last time - Skip it. if (CheckData.ContainsKey(scenarioConfigNode.Item1) && CheckData[scenarioConfigNode.Item1] == scenarioHash) { continue; } CheckData[scenarioConfigNode.Item1] = scenarioHash; ScenarioName.Add(scenarioConfigNode.Item1); ScenarioData.Add(scenarioBytes); } if (ScenarioName.Any()) { MessageSender.SendScenarioModuleData(ScenarioName, ScenarioData); } }
/// <summary> /// Convert a byte array to a ConfigNode. /// If anything goes wrong it will return null. /// </summary> private static ConfigNode ConvertByteArrayToConfigNode(byte[] data, int numBytes) { ConfigNode node; try { node = ConfigNodeSerializer.Deserialize(data, numBytes); } catch (Exception e) { LunaLog.LogError($"[LMP]: Error while deserializing strategy configNode: {e}"); return(null); } if (node == null) { LunaLog.LogError("[LMP]: Error, the strategy configNode was null."); return(null); } if (!node.HasValue("isActive")) { LunaLog.LogError("[LMP]: Error, the strategy configNode is invalid (isActive missing)."); return(null); } return(node); }
public ProtoVessel CreateProtoVessel() { var configNode = ConfigNodeSerializer.Deserialize(RawData, NumBytes); if (configNode == null || VesselCommon.VesselHasNaNPosition(configNode)) { LunaLog.LogError($"Received a malformed vessel from SERVER. Id {VesselId}"); VesselRemoveSystem.Singleton.KillVessel(VesselId, "Malformed vessel"); VesselRemoveSystem.Singleton.AddToKillList(VesselId, "Malformed vessel"); return(null); } var newProto = VesselSerializer.CreateSafeProtoVesselFromConfigNode(configNode, VesselId); if (newProto == null) { LunaLog.LogError($"Received a malformed vessel from SERVER. Id {VesselId}"); VesselRemoveSystem.Singleton.KillVessel(VesselId, "Malformed vessel"); VesselRemoveSystem.Singleton.AddToKillList(VesselId, "Malformed vessel"); return(null); } if (VesselCommon.ProtoVesselHasInvalidParts(newProto)) { return(null); } return(newProto); }
public void SendAchievementsMessage(ProgressNode achievement) { //We only send the ProgressNodes that are CelestialBodySubtree var foundNode = ProgressTracking.Instance.FindNode(achievement.Id); if (foundNode == null) { var traverse = new Traverse(achievement).Field <CelestialBody>("body"); var body = traverse.Value ? traverse.Value.name : null; if (body != null) { foundNode = ProgressTracking.Instance.FindNode(body); } } if (foundNode != null) { var configNode = ConvertAchievementToConfigNode(foundNode); if (configNode == null) { return; } //Build the packet and send it. var msgData = NetworkMain.CliMsgFactory.CreateNewMessageData <ShareProgressAchievementsMsgData>(); msgData.Id = foundNode.Id; msgData.Data = ConfigNodeSerializer.Serialize(configNode); msgData.NumBytes = msgData.Data.Length; System.MessageSender.SendMessage(msgData); } }
public void SendKerbal(ProtoCrewMember pcm) { if (pcm == null) { return; } if (VesselCommon.IsSpectating) { return; } ConfigNode.ClearData(); pcm.Save(ConfigNode); var kerbalBytes = ConfigNodeSerializer.Serialize(ConfigNode); if (kerbalBytes == null || kerbalBytes.Length == 0) { LunaLog.LogError("[LMP]: Error sending kerbal - bytes are null or 0"); return; } SendKerbalProtoMessage(pcm.name, kerbalBytes); }
public void SendAchievementsMessage(ProgressNode[] achievements) { //Convert the achievements to AchievementInfo's. var achievementInfos = new List <AchievementInfo>(); foreach (var achievement in achievements) { var configNode = ConvertAchievementToConfigNode(achievement); if (configNode == null) { break; } var data = ConfigNodeSerializer.Serialize(configNode); var numBytes = data.Length; achievementInfos.Add(new AchievementInfo { Id = achievement.Id, Data = data, NumBytes = numBytes }); } //Build the packet and send it. var msgData = NetworkMain.CliMsgFactory.CreateNewMessageData <ShareProgressAchievementsMsgData>(); msgData.Achievements = achievementInfos.ToArray(); msgData.AchievementsCount = msgData.Achievements.Length; System.MessageSender.SendMessage(msgData); }
public void SendTechnologyMessage(RDTech tech) { var msgData = NetworkMain.CliMsgFactory.CreateNewMessageData <ShareProgressTechnologyMsgData>(); msgData.TechNode.Id = tech.techID; var configNode = ConvertTechNodeToConfigNode(tech); if (configNode == null) { return; } var data = ConfigNodeSerializer.Serialize(configNode); var numBytes = data.Length; msgData.TechNode.NumBytes = numBytes; if (msgData.TechNode.Data.Length < numBytes) { msgData.TechNode.Data = new byte[numBytes]; } Array.Copy(data, msgData.TechNode.Data, numBytes); SendMessage(msgData); }
public void SendScienceSubjectMessage(ScienceSubject subject) { var msgData = NetworkMain.CliMsgFactory.CreateNewMessageData <ShareProgressScienceSubjectMsgData>(); msgData.ScienceSubject.Id = subject.id; var configNode = ConvertScienceSubjectToConfigNode(subject); if (configNode == null) { return; } var data = ConfigNodeSerializer.Serialize(configNode); var numBytes = data.Length; msgData.ScienceSubject.NumBytes = numBytes; if (msgData.ScienceSubject.Data.Length < numBytes) { msgData.ScienceSubject.Data = new byte[numBytes]; } Array.Copy(data, msgData.ScienceSubject.Data, numBytes); SendMessage(msgData); LunaLog.Log($"Science experiment \"{subject.id}\" sent"); }
public void SendContractMessage(Contract[] contracts) { //Convert the Contract's to ContractInfo's. var contractInfos = new List <ContractInfo>(); foreach (var contract in contracts) { var configNode = ConvertContractToConfigNode(contract); if (configNode == null) { break; } var data = ConfigNodeSerializer.Serialize(configNode); var numBytes = data.Length; contractInfos.Add(new ContractInfo { ContractGuid = contract.ContractGuid, Data = data, NumBytes = numBytes }); } //Build the packet and send it. var msgData = NetworkMain.CliMsgFactory.CreateNewMessageData <ShareProgressContractsMsgData>(); msgData.Contracts = contractInfos.ToArray(); msgData.ContractCount = msgData.Contracts.Length; System.MessageSender.SendMessage(msgData); }
/// <summary> /// In this method we get the new vessel data and set it to the dictionary of all the player vessels. /// We set it as UNLOADED as perhaps vessel data has changed. /// </summary> private static void HandleVesselProtoData(byte[] vesselData, Guid vesselId) { UniverseSyncCache.QueueToCache(vesselData); var vesselNode = ConfigNodeSerializer.Deserialize(vesselData); var configGuid = vesselNode?.GetValue("pid"); if (!string.IsNullOrEmpty(configGuid) && vesselId == Common.ConvertConfigStringToGuid(configGuid)) { var vesselProtoUpdate = new VesselProtoUpdate(vesselNode, vesselId); if (vesselProtoUpdate.ProtoVessel == null) { return; } if (System.AllPlayerVessels.ContainsKey(vesselId)) { //Vessel exists so replace it System.AllPlayerVessels[vesselId] = vesselProtoUpdate; } else { System.AllPlayerVessels.TryAdd(vesselId, vesselProtoUpdate); } } }
/// <summary> /// Serializes a vessel to a previous preallocated array (avoids garbage generation) /// </summary> public static void SerializeVesselToArray(ProtoVessel protoVessel, byte[] data, out int numBytes) { if (PreSerializationChecks(protoVessel, out var configNode)) { ConfigNodeSerializer.SerializeToArray(configNode, data, out numBytes); } else { numBytes = 0; } }
/// <summary> /// This method uses a lot of memory so try to call it as less as possible and only when needed /// </summary> public void DeserializeVesselBytes() { lock (_vesselDataSyncLock) { _needToDeserializeData = false; var newVesselNode = ConfigNodeSerializer.Deserialize(_vesselData, _numBytes); if (!VesselCommon.VesselHasNaNPosition(newVesselNode)) { //In case there's a deserialization error skip it and keep the older node _vesselNode = newVesselNode; } if (_vesselNode == null) { LunaLog.LogError($"Received a malformed vessel from SERVER. Id {VesselId}"); VesselRemoveSystem.Singleton.KillVessel(VesselId, "Malformed vessel"); VesselRemoveSystem.Singleton.AddToKillList(VesselId, "Malformed vessel"); return; } var newProto = VesselSerializer.CreateSafeProtoVesselFromConfigNode(_vesselNode, VesselId); //In case there's a deserialization error skip it and keep the older proto if (newProto != null) { HasInvalidParts = VesselCommon.ProtoVesselHasInvalidParts(newProto); if (newProto.vesselID != VesselId) { LunaLog.LogError($"Tried to update the Vessel with a proto from a different vessel ID. Proto: {newProto.vesselID} CorrectId: {VesselId}"); } else { _deserializedProtoVessel = newProto; } } //If protovessel is still null then unfortunately we must remove that vessel as the server sent us a bad vessel if (_deserializedProtoVessel == null) { LunaLog.LogError($"Received a malformed vessel from SERVER. Id {VesselId}"); VesselRemoveSystem.Singleton.KillVessel(VesselId, "Malformed vessel"); VesselRemoveSystem.Singleton.AddToKillList(VesselId, "Malformed vessel"); } else { _vesselParts.Clear(); foreach (var protoPart in _deserializedProtoVessel.protoPartSnapshots) { _vesselParts.TryAdd(protoPart.flightID, protoPart); } } } }
/// <summary> /// Check if the scenario has changed and sends it to the server /// This method is not optimized and take several ms to run /// </summary> public void SendScenarioModules() { if (!Enabled || !SystemsContainer.Get <MainSystem>().GameRunning) { return; } var modules = ScenarioRunner.GetLoadedModules().ToArray(); //I tried to do this method in another thread as it takes a lot of time to run //but appear several empty lines in the log... Perhaps we cannot do it :( var scenarioName = new List <string>(); var scenarioData = new List <byte[]>(); foreach (var scenarioModule in modules) { var scenarioType = scenarioModule.GetType().Name; if (!IsScenarioModuleAllowed(scenarioType)) { continue; } var scenarioNode = new ConfigNode(); scenarioModule.Save(scenarioNode); var scenarioBytes = ConfigNodeSerializer.Serialize(scenarioNode); var scenarioHash = Common.CalculateSha256Hash(scenarioBytes); if (scenarioBytes.Length == 0) { LunaLog.Log($"[LMP]: Error writing scenario data for {scenarioType}"); continue; } //Data is the same since last time - Skip it. if (CheckData.ContainsKey(scenarioType) && CheckData[scenarioType] == scenarioHash) { continue; } CheckData[scenarioType] = scenarioHash; scenarioName.Add(scenarioType); scenarioData.Add(scenarioBytes); } if (scenarioName.Any()) { MessageSender.SendScenarioModuleData(scenarioName.ToArray(), scenarioData.ToArray()); } }
/// <summary> /// Appends the received kerbal to the dictionary /// </summary> private static void ProcessKerbal(byte[] kerbalData, int numBytes) { var kerbalNode = ConfigNodeSerializer.Deserialize(kerbalData, numBytes); if (kerbalNode != null) { System.KerbalsToProcess.Enqueue(kerbalNode); } else { LunaLog.LogError("[LMP]: Failed to load kerbal!"); } }
/// <summary> /// Creates a new Kerbal /// </summary> private void CreateKerbal(ProtoCrewMember protoCrew) { HighLogic.CurrentGame.CrewRoster.AddCrewMember(protoCrew); var kerbalNode = new ConfigNode(); protoCrew.Save(kerbalNode); var kerbalBytes = ConfigNodeSerializer.Serialize(kerbalNode); if (kerbalBytes != null && kerbalBytes.Length != 0) { ServerKerbals[protoCrew.name] = Common.CalculateSha256Hash(kerbalBytes); } }
/// <summary> /// Just load the received kerbal into game /// </summary> /// <param name="messageData"></param> private static void HandleKerbalProto(KerbalProtoMsgData messageData) { var kerbalNode = ConfigNodeSerializer.Deserialize(messageData.KerbalData); if (kerbalNode != null) { System.LoadKerbal(kerbalNode); } else { LunaLog.LogError("[LMP]: Failed to load kerbal!"); } }
/// <summary> /// Deserialize a byte array into a protovessel /// </summary> public static ProtoVessel DeserializeVessel(byte[] data, int numBytes) { try { var vesselNode = ConfigNodeSerializer.Deserialize(data, numBytes); var configGuid = vesselNode?.GetValue("pid"); return(CreateSafeProtoVesselFromConfigNode(vesselNode, new Guid(configGuid))); } catch (Exception e) { LunaLog.LogError($"[LMP]: Error while deserializing vessel: {e}"); return(null); } }
/// <summary> /// Convert a byte array to a ConfigNode and then to a ScienceSubject. /// If anything goes wrong it will return null. /// </summary> private static ScienceSubject ConvertByteArrayToScienceSubject(byte[] data, int numBytes) { var node = new ConfigNode("Science"); try { node.AddData(ConfigNodeSerializer.Deserialize(data, numBytes)); } catch (Exception e) { LunaLog.LogError($"[LMP]: Error while deserializing science subject configNode: {e}"); return(null); } return(new ScienceSubject(node)); }
/// <summary> /// We store all the kerbals in the KerbalProtoQueue dictionary so later once the game starts we load them /// </summary> /// <param name="messageData"></param> private static void HandleKerbalReply(KerbalReplyMsgData messageData) { foreach (var kerbal in messageData.KerbalsData) { var kerbalNode = ConfigNodeSerializer.Deserialize(kerbal.Value); if (kerbalNode != null) { System.KerbalQueue.Enqueue(kerbalNode); } else { LunaLog.LogError("[LMP]: Failed to load kerbal!"); } } LunaLog.Log("[LMP]: Kerbals Synced!"); MainSystem.NetworkState = ClientState.KerbalsSynced; }
private static void QueueScenarioBytes(string scenarioModule, byte[] scenarioData, int numBytes) { var scenarioNode = ConfigNodeSerializer.Deserialize(scenarioData, numBytes); if (scenarioNode != null) { var entry = new ScenarioEntry { ScenarioModule = scenarioModule, ScenarioNode = scenarioNode }; System.ScenarioQueue.Enqueue(entry); } else { LunaLog.LogError($"[LMP]: Scenario data has been lost for {scenarioModule}"); } }
private void ParseAndSendModules(IEnumerable <ScenarioModule> modules) { var scenarioName = new List <string>(); var scenarioData = new List <byte[]>(); foreach (var scenarioModule in modules) { var scenarioType = scenarioModule.GetType().Name; if (!IsScenarioModuleAllowed(scenarioType)) { continue; } var scenarioNode = new ConfigNode(); scenarioModule.Save(scenarioNode); var scenarioBytes = ConfigNodeSerializer.Serialize(scenarioNode); var scenarioHash = Common.CalculateSha256Hash(scenarioBytes); if (scenarioBytes.Length == 0) { LunaLog.Log($"[LMP]: Error writing scenario data for {scenarioType}"); continue; } //Data is the same since last time - Skip it. if (CheckData.ContainsKey(scenarioType) && CheckData[scenarioType] == scenarioHash) { continue; } CheckData[scenarioType] = scenarioHash; scenarioName.Add(scenarioType); scenarioData.Add(scenarioBytes); } if (scenarioName.Any()) { MessageSender.SendScenarioModuleData(scenarioName.ToArray(), scenarioData.ToArray()); } }
/// <summary> /// Here we receive the vessel list msg from the server.We rty to get the vessels from the cache and if /// it fails or we don't have it in the cache we request that vessel info to the server. /// </summary> private static void HandleVesselList(VesselListReplyMsgData messageData) { var serverVessels = new List <string>(messageData.Vessels); var cacheObjects = new List <string>(UniverseSyncCache.GetCachedObjects()); var requestedObjects = new List <string>(); foreach (var serverVessel in serverVessels) { if (cacheObjects.Contains(serverVessel)) { //Try to get it from cache... var vesselBytes = UniverseSyncCache.GetFromCache(serverVessel); var vesselNode = ConfigNodeSerializer.Deserialize(vesselBytes); if (vesselNode != null) { var vesselId = Common.ConvertConfigStringToGuid(vesselNode.GetValue("pid")); if (vesselBytes.Length != 0 && vesselId != Guid.Empty) { var update = new VesselProtoUpdate(vesselNode, vesselId); if (update.ProtoVessel != null) { System.AllPlayerVessels.TryAdd(vesselId, update); } } else { LunaLog.LogError($"[LMP]: Cached object {serverVessel} is damaged"); requestedObjects.Add(serverVessel); } } } else { requestedObjects.Add(serverVessel); } } //Request the vessel data that we don't have. NetworkSender.QueueOutgoingMessage(MessageFactory.CreateNew <VesselCliMsg> (new VesselsRequestMsgData { RequestList = requestedObjects.ToArray() })); }
/// <summary> /// Just load the received kerbal into game /// </summary> /// <param name="messageData"></param> private static void HandleKerbalProto(KerbalProtoMsgData messageData) { var kerbalNode = ConfigNodeSerializer.Deserialize(messageData.KerbalData); if (kerbalNode != null) { if (MainSystem.NetworkState < ClientState.TimeLocked) { System.KerbalQueue.Enqueue(kerbalNode); } else { System.LoadKerbal(kerbalNode); } } else { LunaLog.LogError("[LMP]: Failed to load kerbal!"); } }