/// <summary> /// We received a position information from a player /// Then we rewrite the vesselproto with that last information so players that connect later receive an update vesselproto /// </summary> public static void WritePositionDataToFile(VesselBaseMsgData message) { if (!(message is VesselPositionMsgData msgData)) { return; } if (VesselContext.RemovedVessels.Contains(msgData.VesselId)) { return; } if (!LastPositionUpdateDictionary.TryGetValue(msgData.VesselId, out var lastUpdated) || (DateTime.Now - lastUpdated).TotalMilliseconds > FilePositionUpdateIntervalMs) { LastPositionUpdateDictionary.AddOrUpdate(msgData.VesselId, DateTime.Now, (key, existingVal) => DateTime.Now); Task.Run(() => { var path = Path.Combine(ServerContext.UniverseDirectory, "Vessels", $"{msgData.VesselId}.txt"); if (!File.Exists(path)) { return; //didn't found a vessel to rewrite so quit } var protoVesselLines = FileHandler.ReadFileLines(path); var updatedText = UpdateProtoVesselFileWithNewPositionData(protoVesselLines, msgData); FileHandler.WriteToFile(path, updatedText); }); } }
private static void HandleVesselDock(ClientStructure client, VesselBaseMsgData message) { var msgData = (VesselDockMsgData)message; LunaLog.Debug($"Docking message received! Dominant vessel: {msgData.DominantVesselId}"); if (VesselContext.RemovedVessels.Contains(msgData.WeakVesselId)) { return; } if (VesselStoreSystem.VesselExists(msgData.DominantVesselId)) { LunaLog.Debug($"Saving DOCKED vessel {msgData.DominantVesselId} from {client.PlayerName}. Bytes: {msgData.NumBytes}"); } VesselDataUpdater.RawConfigNodeInsertOrUpdate(msgData.DominantVesselId, Encoding.UTF8.GetString(msgData.FinalVesselData, 0, msgData.NumBytes)); //Now remove the weak vessel but DO NOT add to the removed vessels as they might undock!!! LunaLog.Debug($"Removing weak docked vessel {msgData.WeakVesselId}"); VesselStoreSystem.RemoveVessel(msgData.WeakVesselId); MessageQueuer.RelayMessage <VesselSrvMsg>(client, msgData); //Tell all clients to remove the weak vessel var removeMsgData = ServerContext.ServerMessageFactory.CreateNewMessageData <VesselRemoveMsgData>(); removeMsgData.VesselId = msgData.WeakVesselId; MessageQueuer.SendToAllClients <VesselSrvMsg>(removeMsgData); }
/// <summary> /// This method relays a message to the other clients in the same subspace and in case there are other players /// in older subspaces it stores it for further processing /// </summary> public static void HandleVesselMessage(ClientStructure client, VesselBaseMsgData msg) { if (client.Subspace == -1) { return; } MessageQueuer.RelayMessageToSubspace <VesselSrvMsg>(client, msg); if (GeneralSettings.SettingsStore.ShowVesselsInThePast) { foreach (var subspace in WarpSystem.GetFutureSubspaces(client.Subspace)) { MessageQueuer.RelayMessageToSubspace <VesselSrvMsg>(client, msg, subspace); } } //The client is running in the future so here we adjust the real sent time of the message msg.SentTime += WarpSystem.GetSubspaceTimeDifference(client.Subspace); foreach (var subspace in WarpSystem.GetPastSubspaces(client.Subspace)) { if (!OldVesselMessages.ContainsKey(client.Subspace)) { OldVesselMessages.TryAdd(subspace, new ConcurrentQueue <VesselBaseMsgData>()); } OldVesselMessages[subspace].Enqueue(msg); } }
/// <summary> /// We received a eva state change from a player /// Then we rewrite the vesselproto with that last information so players that connect later receive an updated vesselproto /// </summary> public static void WriteEvaDataToFile(VesselBaseMsgData message) { if (!(message is VesselEvaMsgData msgData)) { return; } if (VesselContext.RemovedVessels.Contains(msgData.VesselId)) { return; } //Sync eva state ALWAYS and ignore the rate they arrive Task.Run(() => { lock (Semaphore.GetOrAdd(msgData.VesselId, new object())) { if (!VesselStoreSystem.CurrentVesselsInXmlFormat.TryGetValue(msgData.VesselId, out var xmlData)) { return; } var updatedText = UpdateProtoVesselFileWithNewEvaData(xmlData, msgData); VesselStoreSystem.CurrentVesselsInXmlFormat.TryUpdate(msgData.VesselId, updatedText, xmlData); } }); }
/// <summary> /// We received a position information from a player /// Then we rewrite the vesselproto with that last information so players that connect later receive an updated vesselproto /// </summary> public static void WritePositionDataToFile(VesselBaseMsgData message) { if (!(message is VesselPositionMsgData msgData)) { return; } if (VesselContext.RemovedVessels.Contains(msgData.VesselId)) { return; } if (!LastPositionUpdateDictionary.TryGetValue(msgData.VesselId, out var lastUpdated) || (DateTime.Now - lastUpdated).TotalMilliseconds > FilePositionUpdateIntervalMs) { LastPositionUpdateDictionary.AddOrUpdate(msgData.VesselId, DateTime.Now, (key, existingVal) => DateTime.Now); Task.Run(() => { lock (Semaphore.GetOrAdd(msgData.VesselId, new object())) { if (!VesselStoreSystem.CurrentVesselsInXmlFormat.TryGetValue(msgData.VesselId, out var xmlData)) { return; } var updatedText = UpdateProtoVesselWithNewPositionData(xmlData, msgData); VesselStoreSystem.CurrentVesselsInXmlFormat.TryUpdate(msgData.VesselId, updatedText, xmlData); } }); } }
/// <summary> /// We received a flight state information from a player /// Then we rewrite the vesselproto with that last information so players that connect later receive an updated vesselproto /// </summary> public static void WriteFlightstateDataToFile(VesselBaseMsgData message) { if (!(message is VesselFlightStateMsgData msgData)) { return; } if (VesselContext.RemovedVessels.Contains(msgData.VesselId)) { return; } if (!LastFlightStateUpdateDictionary.TryGetValue(msgData.VesselId, out var lastUpdated) || (DateTime.Now - lastUpdated).TotalMilliseconds > FileFlightStateUpdateIntervalMs) { LastFlightStateUpdateDictionary.AddOrUpdate(msgData.VesselId, DateTime.Now, (key, existingVal) => DateTime.Now); Task.Run(() => { lock (Semaphore.GetOrAdd(msgData.VesselId, new object())) { if (!VesselStoreSystem.CurrentVessels.TryGetValue(msgData.VesselId, out var vessel)) { return; } vessel.CtrlState.UpdateValue("pitch", msgData.Pitch.ToString(CultureInfo.InvariantCulture)); vessel.CtrlState.UpdateValue("yaw", msgData.Yaw.ToString(CultureInfo.InvariantCulture)); vessel.CtrlState.UpdateValue("roll", msgData.Roll.ToString(CultureInfo.InvariantCulture)); vessel.CtrlState.UpdateValue("trimPitch", msgData.PitchTrim.ToString(CultureInfo.InvariantCulture)); vessel.CtrlState.UpdateValue("trimYaw", msgData.YawTrim.ToString(CultureInfo.InvariantCulture)); vessel.CtrlState.UpdateValue("trimRoll", msgData.RollTrim.ToString(CultureInfo.InvariantCulture)); vessel.CtrlState.UpdateValue("mainThrottle", msgData.MainThrottle.ToString(CultureInfo.InvariantCulture)); } }); } }
/// <summary> /// We received a part module change from a player /// Then we rewrite the vesselproto with that last information so players that connect later receive an updated vesselproto /// </summary> public static void WritePartSyncFieldDataToFile(VesselBaseMsgData message) { if (!(message is VesselPartSyncFieldMsgData msgData)) { return; } if (VesselContext.RemovedVessels.Contains(msgData.VesselId)) { return; } //Sync part changes ALWAYS and ignore the rate they arrive Task.Run(() => { lock (Semaphore.GetOrAdd(msgData.VesselId, new object())) { if (!VesselStoreSystem.CurrentVessels.TryGetValue(msgData.VesselId, out var vessel)) { return; } UpdateProtoVesselFileWithNewPartSyncFieldData(vessel, msgData); } }); }
private static void HandleVesselRemove(ClientStructure client, VesselBaseMsgData message) { var data = (VesselRemoveMsgData)message; if (data.Force) { LunaLog.Debug($"Received a FORCED remove against vessel {data.VesselId} from {client.PlayerName}"); } if (!data.Force && LockSystem.LockQuery.ControlLockExists(data.VesselId) && !LockSystem.LockQuery.ControlLockBelongsToPlayer(data.VesselId, client.PlayerName)) { return; } if (VesselStoreSystem.VesselExists(data.VesselId)) { LunaLog.Debug($"Removing vessel {data.VesselId} from {client.PlayerName}"); VesselStoreSystem.RemoveVessel(data.VesselId); } if (data.AddToKillList) { VesselContext.RemovedVessels.Add(data.VesselId); } //Relay the message. MessageQueuer.SendToAllClients <VesselSrvMsg>(data); }
public VesselRelayItem(int subspaceId, Guid vesselId, double gameTime, VesselBaseMsgData msg) { SubspaceId = subspaceId; VesselId = vesselId; GameTime = gameTime; Msg = msg; }
private static void HandleVesselsSync(ClientStructure client, VesselBaseMsgData message) { var msgData = (VesselSyncMsgData)message; var allVessels = VesselStoreSystem.CurrentVessels.Keys.ToList(); for (var i = 0; i < msgData.VesselsCount; i++) { allVessels.Remove(msgData.VesselIds[i]); } var vesselsToSend = allVessels; foreach (var vesselId in vesselsToSend) { var vesselData = VesselStoreSystem.GetVesselInConfigNodeFormat(vesselId); if (vesselData.Length > 0) { var protoMsg = ServerContext.ServerMessageFactory.CreateNewMessageData <VesselProtoMsgData>(); protoMsg.Data = Encoding.UTF8.GetBytes(vesselData); protoMsg.NumBytes = vesselData.Length; protoMsg.VesselId = vesselId; MessageQueuer.SendToClient <VesselSrvMsg>(client, protoMsg); } } if (allVessels.Count > 0) { LunaLog.Debug($"Sending {client.PlayerName} {vesselsToSend.Count} vessels"); } }
/// <summary> /// We received a action group information from a player /// Then we rewrite the vesselproto with that last information so players that connect later receive an updated vesselproto /// </summary> public static void WriteActionGroupDataToFile(VesselBaseMsgData message) { if (!(message is VesselActionGroupMsgData msgData)) { return; } if (VesselContext.RemovedVessels.Contains(msgData.VesselId)) { return; } //Sync part changes ALWAYS and ignore the rate they arrive Task.Run(() => { lock (Semaphore.GetOrAdd(msgData.VesselId, new object())) { if (!VesselStoreSystem.CurrentVessels.TryGetValue(msgData.VesselId, out var vessel)) { return; } vessel.ActionGroups.Update(msgData.ActionGroupString, msgData.Value.ToString(CultureInfo.InvariantCulture)); } }); }
/// <summary> /// We received a position information from a player /// Then we rewrite the vesselproto with that last information so players that connect later receive an updated vesselproto /// </summary> public static void WritePositionDataToFile(VesselBaseMsgData message) { if (!(message is VesselPositionMsgData msgData)) { return; } if (VesselContext.RemovedVessels.Contains(msgData.VesselId)) { return; } if (!LastPositionUpdateDictionary.TryGetValue(msgData.VesselId, out var lastUpdated) || (DateTime.Now - lastUpdated).TotalMilliseconds > FilePositionUpdateIntervalMs) { LastPositionUpdateDictionary.AddOrUpdate(msgData.VesselId, DateTime.Now, (key, existingVal) => DateTime.Now); Task.Run(() => { lock (Semaphore.GetOrAdd(msgData.VesselId, new object())) { if (!VesselStoreSystem.CurrentVessels.TryGetValue(msgData.VesselId, out var vessel)) { return; } vessel.Fields.Update("lat", msgData.LatLonAlt[0].ToString(CultureInfo.InvariantCulture)); vessel.Fields.Update("lon", msgData.LatLonAlt[1].ToString(CultureInfo.InvariantCulture)); vessel.Fields.Update("alt", msgData.LatLonAlt[2].ToString(CultureInfo.InvariantCulture)); vessel.Fields.Update("hgt", msgData.HeightFromTerrain.ToString(CultureInfo.InvariantCulture)); vessel.Fields.Update("nrm", $"{msgData.NormalVector[0].ToString(CultureInfo.InvariantCulture)}," + $"{msgData.NormalVector[1].ToString(CultureInfo.InvariantCulture)}," + $"{msgData.NormalVector[2].ToString(CultureInfo.InvariantCulture)}"); vessel.Fields.Update("rot", $"{msgData.SrfRelRotation[0].ToString(CultureInfo.InvariantCulture)}," + $"{msgData.SrfRelRotation[1].ToString(CultureInfo.InvariantCulture)}," + $"{msgData.SrfRelRotation[2].ToString(CultureInfo.InvariantCulture)}," + $"{msgData.SrfRelRotation[3].ToString(CultureInfo.InvariantCulture)}"); vessel.Orbit.Update("INC", msgData.Orbit[0].ToString(CultureInfo.InvariantCulture)); vessel.Orbit.Update("ECC", msgData.Orbit[1].ToString(CultureInfo.InvariantCulture)); vessel.Orbit.Update("SMA", msgData.Orbit[2].ToString(CultureInfo.InvariantCulture)); vessel.Orbit.Update("LAN", msgData.Orbit[3].ToString(CultureInfo.InvariantCulture)); vessel.Orbit.Update("LPE", msgData.Orbit[4].ToString(CultureInfo.InvariantCulture)); vessel.Orbit.Update("MNA", msgData.Orbit[5].ToString(CultureInfo.InvariantCulture)); vessel.Orbit.Update("EPH", msgData.Orbit[6].ToString(CultureInfo.InvariantCulture)); vessel.Orbit.Update("REF", msgData.Orbit[7].ToString(CultureInfo.InvariantCulture)); } }); } }
/// <summary> /// We received a update information from a player /// Then we rewrite the vesselproto with that last information so players that connect later receive an updated vesselproto /// </summary> public static void WriteUpdateDataToFile(VesselBaseMsgData message) { if (!(message is VesselUpdateMsgData msgData)) { return; } if (VesselContext.RemovedVessels.Contains(msgData.VesselId)) { return; } if (!LastUpdateDictionary.TryGetValue(msgData.VesselId, out var lastUpdated) || (DateTime.Now - lastUpdated).TotalMilliseconds > FileUpdateIntervalMs) { LastUpdateDictionary.AddOrUpdate(msgData.VesselId, DateTime.Now, (key, existingVal) => DateTime.Now); Task.Run(() => { lock (Semaphore.GetOrAdd(msgData.VesselId, new object())) { if (!VesselStoreSystem.CurrentVessels.TryGetValue(msgData.VesselId, out var vessel)) { return; } vessel.Fields.Update("name", msgData.Name); vessel.Fields.Update("type", msgData.Type); vessel.Fields.Update("distanceTraveled", msgData.DistanceTraveled.ToString(CultureInfo.InvariantCulture)); vessel.Fields.Update("sit", msgData.Situation); vessel.Fields.Update("landed", msgData.Landed.ToString(CultureInfo.InvariantCulture)); vessel.Fields.Update("landedAt", msgData.LandedAt); vessel.Fields.Update("displaylandedAt", msgData.DisplayLandedAt); vessel.Fields.Update("splashed", msgData.Splashed.ToString(CultureInfo.InvariantCulture)); vessel.Fields.Update("met", msgData.MissionTime.ToString(CultureInfo.InvariantCulture)); vessel.Fields.Update("lct", msgData.LaunchTime.ToString(CultureInfo.InvariantCulture)); vessel.Fields.Update("lastUT", msgData.LastUt.ToString(CultureInfo.InvariantCulture)); vessel.Fields.Update("prst", msgData.Persistent.ToString(CultureInfo.InvariantCulture)); vessel.Fields.Update("ref", msgData.RefTransformId.ToString(CultureInfo.InvariantCulture)); vessel.Fields.Update("cln", msgData.AutoClean.ToString(CultureInfo.InvariantCulture)); vessel.Fields.Update("clnRsn", msgData.AutoCleanReason); vessel.Fields.Update("ctrl", msgData.WasControllable.ToString(CultureInfo.InvariantCulture)); vessel.Fields.Update("stg", msgData.Stage.ToString(CultureInfo.InvariantCulture)); //NEVER! patch the CoM in the protovessel as then it will be drawn with incorrect CommNet lines! //vessel.Fields.Update("CoM", $"{msgData.Com[0].ToString(CultureInfo.InvariantCulture)}," + // $"{msgData.Com[1].ToString(CultureInfo.InvariantCulture)}," + // $"{msgData.Com[2].ToString(CultureInfo.InvariantCulture)}"); } }); } }
private static void HandleVesselRemove(ClientStructure client, VesselBaseMsgData message) { var data = (VesselRemoveMsgData)message; //Don't care about the Subspace on the server. LunaLog.Debug(!data.IsDockingUpdate ? $"Removing vessel {data.VesselId} from {client.PlayerName}" : $"Removing DOCKED vessel {data.VesselId} from {client.PlayerName}"); Universe.RemoveFromUniverse(Path.Combine(ServerContext.UniverseDirectory, "Vessels", data.VesselId + ".txt")); VesselContext.RemovedVessels.Add(data.VesselId); //Relay the message. MessageQueuer.RelayMessage <VesselSrvMsg>(client, data); }
/// <summary> /// This method relays a message to the other clients in the same subspace. /// In case there are other players in OLDER subspaces it stores it in their queue for further processing /// </summary> public static void HandleVesselMessage(ClientStructure client, VesselBaseMsgData msg) { switch (GeneralSettings.SettingsStore.RelaySystemMode) { case RelaySystemMode.Dictionary: VesselRelaySystemDictionary.HandleVesselMessage(client, msg); break; case RelaySystemMode.Database: VesselRelaySystemDataBase.HandleVesselMessage(client, msg); break; default: throw new ArgumentOutOfRangeException(); } }
private static void HandleVesselProto(ClientStructure client, VesselBaseMsgData message) { var msgData = (VesselProtoMsgData)message; if (VesselContext.RemovedVessels.Contains(msgData.VesselId)) { return; } var path = Path.Combine(ServerContext.UniverseDirectory, "Vessels", $"{msgData.VesselId}.txt"); if (!File.Exists(path)) { LunaLog.Debug($"Saving vessel {msgData.VesselId} from {client.PlayerName}"); } FileHandler.WriteToFile(path, msgData.VesselData); VesselRelaySystem.HandleVesselMessage(client, message); }
private static void HandleVesselRemove(ClientStructure client, VesselBaseMsgData message) { var data = (VesselRemoveMsgData)message; //Don't care about the Subspace on the server. LunaLog.Debug($"Removing vessel {data.VesselId} from {client.PlayerName}"); Universe.RemoveFromUniverse(Path.Combine(ServerContext.UniverseDirectory, "Vessels", $"{data.VesselId}.txt")); VesselContext.RemovedVessels.Add(data.VesselId); //Relay the message. if (data.Broadcast) { MessageQueuer.SendToAllClients <VesselSrvMsg>(data); } else { MessageQueuer.RelayMessage <VesselSrvMsg>(client, data); } }
private static void HandleVesselRemove(ClientStructure client, VesselBaseMsgData message) { var data = (VesselRemoveMsgData)message; var path = Path.Combine(ServerContext.UniverseDirectory, "Vessels", $"{data.VesselId}.txt"); if (FileHandler.FileExists(path)) { LunaLog.Debug($"Removing vessel {data.VesselId} from {client.PlayerName}"); Universe.RemoveFromUniverse(Path.Combine(ServerContext.UniverseDirectory, "Vessels", $"{data.VesselId}.txt")); } if (data.AddToKillList) { VesselContext.RemovedVessels.Add(data.VesselId); } //Relay the message. MessageQueuer.SendToAllClients <VesselSrvMsg>(data); }
/// <summary> /// We received a resource information from a player /// Then we rewrite the vesselproto with that last information so players that connect later received an update vesselproto /// </summary> public static void WriteResourceDataToFile(VesselBaseMsgData message) { if (!(message is VesselResourceMsgData msgData)) { return; } if (VesselContext.RemovedVessels.Contains(msgData.VesselId)) { return; } if (!LastResourcesUpdateDictionary.TryGetValue(msgData.VesselId, out var lastUpdated) || (DateTime.Now - lastUpdated).TotalMilliseconds > FileResourcesUpdateIntervalMs) { LastResourcesUpdateDictionary.AddOrUpdate(msgData.VesselId, DateTime.Now, (key, existingVal) => DateTime.Now); Task.Run(() => { lock (Semaphore.GetOrAdd(msgData.VesselId, new object())) { if (!VesselStoreSystem.CurrentVessels.TryGetValue(msgData.VesselId, out var vessel)) { return; } foreach (var resource in msgData.Resources) { var part = vessel.GetPart(resource.PartFlightId); if (part != null) { var resourceNode = part.Resources.GetSingle(resource.ResourceName).Value; if (resourceNode != null) { resourceNode.UpdateValue("amount", resource.Amount.ToString(CultureInfo.InvariantCulture)); resourceNode.UpdateValue("flowState", resource.FlowState.ToString(CultureInfo.InvariantCulture)); } } } } }); } }
/// <summary> /// Creates a new subspace and sets its message queue from a past subspace. /// Must be called AFTER the subspace is created in the warp context. /// </summary> public static void CreateNewSubspace(int subspaceId) { //If the new subspace is the most advanced in time skip all this method if (!WarpSystem.GetFutureSubspaces(subspaceId).Any()) { return; } var subspaceTime = WarpSystem.GetCurrentSubspaceTime(subspaceId); //Here we get the PAST subspace that is closest in time to the one we got as parameter var pastSubspaces = WarpSystem.GetPastSubspaces(subspaceId); if (pastSubspaces.Any()) { var closestPastSubspace = WarpContext.Subspaces .Where(s => pastSubspaces.Contains(s.Key)) .OrderByDescending(s => s.Value) .Select(s => s.Key) .First(); var originalqueue = OldVesselMessages[closestPastSubspace]; var messages = new VesselBaseMsgData[originalqueue.Count]; originalqueue.CopyTo(messages, 0); var messageQueue = new ConcurrentQueue <VesselBaseMsgData>(messages); //Now we remove the messages that are too old for this subspace VesselBaseMsgData msg; while (messageQueue.TryDequeue(out msg)) { if (msg.SentTime >= subspaceTime) { break; } } OldVesselMessages.TryAdd(subspaceId, messageQueue); } }
private static void HandleVesselProto(ClientStructure client, VesselBaseMsgData message) { var msgData = (VesselProtoMsgData)message; if (VesselContext.RemovedVessels.Contains(msgData.Vessel.VesselId)) { return; } if (msgData.Vessel.NumBytes == 0) { LunaLog.Warning($"Received a vessel with 0 bytes ({msgData.Vessel.VesselId}) from {client.PlayerName}."); return; } if (!VesselStoreSystem.VesselExists(msgData.Vessel.VesselId)) { LunaLog.Debug($"Saving vessel {msgData.Vessel.VesselId} from {client.PlayerName}. Bytes: {msgData.Vessel.NumBytes}"); } VesselDataUpdater.RawConfigNodeInsertOrUpdate(msgData.Vessel.VesselId, Encoding.UTF8.GetString(msgData.Vessel.Data, 0, msgData.Vessel.NumBytes)); MessageQueuer.RelayMessage <VesselSrvMsg>(client, msgData); }
private static void HandleVesselCouple(ClientStructure client, VesselBaseMsgData message) { var msgData = (VesselCoupleMsgData)message; LunaLog.Debug($"Coupling message received! Dominant vessel: {msgData.VesselId}"); MessageQueuer.RelayMessage <VesselSrvMsg>(client, msgData); if (VesselContext.RemovedVessels.Contains(msgData.CoupledVesselId)) { return; } //Now remove the weak vessel but DO NOT add to the removed vessels as they might undock!!! LunaLog.Debug($"Removing weak coupled vessel {msgData.CoupledVesselId}"); VesselStoreSystem.RemoveVessel(msgData.CoupledVesselId); //Tell all clients to remove the weak vessel var removeMsgData = ServerContext.ServerMessageFactory.CreateNewMessageData <VesselRemoveMsgData>(); removeMsgData.VesselId = msgData.CoupledVesselId; MessageQueuer.SendToAllClients <VesselSrvMsg>(removeMsgData); }
public VesselRelayDbItem(int subspaceId, Guid vesselId, double gameTime, VesselBaseMsgData msg) : base(subspaceId, vesselId, gameTime, msg) { }