void MyMultiplayerLobby_ClientLeft(ulong userId, ChatMemberStateChangeEnum stateChange) { Peer2Peer.CloseSession(userId); MySandboxGame.Log.WriteLineAndConsole("Player left: " + GetMemberName(userId) + " (" + userId + ")"); MyTrace.Send(TraceWindow.Multiplayer, "Player left: " + stateChange.ToString()); }
private bool ReceiveOne() { uint length; if ((MySteam.IsActive || MySteam.Server != null) && Peer2Peer.IsPacketAvailable(out length, Channel)) { ulong sender; var msg = GetMessage((int)length); if (Peer2Peer.ReadPacket(msg.Data, out length, out sender, Channel)) { if (m_timestampProvider != null) { msg.Timestamp = m_timestampProvider(); } msg.ReceiveTime = Stopwatch.GetTimestamp(); msg.Length = (int)length; msg.UserId = sender; m_receiveQueue.Enqueue(msg); return(true); } else { m_messagePool.Return(msg); return(false); } } else { return(false); } }
private void CloseClient() { MyTrace.Send(TraceWindow.Multiplayer, "Multiplayer client closed"); if (m_clientJoined) { MyControlDisconnectedMsg msg = new MyControlDisconnectedMsg(); msg.Client = MySteam.UserId; SendControlMessage(ServerId, ref msg); } OnJoin = null; //TODO: Any better way? P2P needs to be closed from both sides. If closed right after Send, message //can stay not sent. Thread.Sleep(200); //WARN: If closed here, previous control message probably not come Peer2Peer.CloseSession(ServerId); CloseMemberSessions(); Peer2Peer.ConnectionFailed -= Peer2Peer_ConnectionFailed; Peer2Peer.SessionRequest -= Peer2Peer_SessionRequest; }
void MyMultiplayerClient_ClientLeft(ulong user, ChatMemberStateChangeEnum stateChange) { if (user == ServerId) { RaiseHostLeft(); return; } if (m_members.Contains(user)) { m_members.Remove(user); MySandboxGame.Log.WriteLineAndConsole("Player disconnected: " + MySteam.API.Friends.GetPersonaName(user) + " (" + user + ")"); MyTrace.Send(TraceWindow.Multiplayer, "Player disconnected: " + stateChange.ToString()); if (MySandboxGame.IsGameReady && MySteam.UserId != user) { var clientLeft = new MyHudNotification(MySpaceTexts.NotificationClientDisconnected, 5000, level: MyNotificationLevel.Important); clientLeft.SetTextFormatArguments(MySteam.API.Friends.GetPersonaName(user)); MyHud.Notifications.Add(clientLeft); } Peer2Peer.CloseSession(user); } m_memberData.Remove(user); }
protected void SendControlMessage <T>(ulong user, ref T message) where T : struct { ITransportCallback handler; MyControlMessageEnum messageEnum; m_controlMessageTypes.TryGetValue(typeof(T), out messageEnum); m_controlMessageHandlers.TryGetValue((int)messageEnum, out handler); var callback = ((MyControlMessageCallback <T>)handler); if (!MySyncLayer.CheckSendPermissions(user, callback.Permission)) { return; } m_controlSendStream.Position = 0; m_controlSendStream.WriteUShort((ushort)messageEnum); callback.Write(m_controlSendStream, ref message); if (!Peer2Peer.SendPacket(user, m_controlSendStream.Data, (int)m_controlSendStream.Position, P2PMessageEnum.Reliable, MyMultiplayer.ControlChannel)) { System.Diagnostics.Debug.Fail("P2P packet not sent"); } // Peer2Peer.SendPacket(user, (byte*)&msg, sizeof(ControlMessageStruct), P2PMessageEnum.Reliable, MyMultiplayer.ControlChannel); }
static void SendHandler(ulong remoteUser, byte[] data, int byteCount, P2PMessageEnum msgType, int channel) { if (!Peer2Peer.SendPacket(remoteUser, data, byteCount, msgType, channel)) { System.Diagnostics.Debug.Fail("P2P packet send fail"); } }
public static unsafe bool SendPreemble(ulong sendTo, int channel) { bool ok = true; byte data = PREEMBLE_HEADER; ok &= Peer2Peer.SendPacket(sendTo, &data, 1, P2PMessageEnum.Reliable, channel); return(ok); }
void Peer2Peer_SessionRequest(ulong remoteUserId) { if (IsClientKickedOrBanned(remoteUserId)) { return; } Peer2Peer.AcceptSession(remoteUserId); }
void Matchmaking_LobbyChatUpdate(Lobby lobby, ulong changedUser, ulong makingChangeUser, ChatMemberStateChangeEnum stateChange) { //System.Diagnostics.Debug.Assert(MySession.Static != null); if (lobby.LobbyId == Lobby.LobbyId) { if (stateChange == ChatMemberStateChangeEnum.Entered) { MySandboxGame.Log.WriteLineAndConsole("Player entered: " + MySteam.API.Friends.GetPersonaName(changedUser) + " (" + changedUser + ")"); MyTrace.Send(TraceWindow.Multiplayer, "Player entered"); Peer2Peer.AcceptSession(changedUser); RaiseClientJoined(changedUser); if (MySandboxGame.IsGameReady && changedUser != ServerId) { var playerJoined = new MyHudNotification(MySpaceTexts.NotificationClientConnected, 5000, level: MyNotificationLevel.Important); playerJoined.SetTextFormatArguments(MySteam.API.Friends.GetPersonaName(changedUser)); MyHud.Notifications.Add(playerJoined); } } else { // Kicked client can be already removed from Clients if (Sync.Clients.HasClient(changedUser)) { RaiseClientLeft(changedUser, stateChange); } if (changedUser == ServerId) { MyTrace.Send(TraceWindow.Multiplayer, "Host left: " + stateChange.ToString()); RaiseHostLeft(); MyGuiScreenMainMenu.UnloadAndExitToMenu(); MyGuiSandbox.AddScreen(MyGuiSandbox.CreateMessageBox( messageCaption: MyTexts.Get(MySpaceTexts.MessageBoxCaptionError), messageText: MyTexts.Get(MySpaceTexts.MultiplayerErrorServerHasLeft))); // Set new server //ServerId = Lobby.GetOwner(); //if (ServerId == Sync.MyId) //{ // Lobby.SetLobbyData(HostNameTag, Sync.MyName); //} } else if (MySandboxGame.IsGameReady) { var playerLeft = new MyHudNotification(MySpaceTexts.NotificationClientDisconnected, 5000, level: MyNotificationLevel.Important); playerLeft.SetTextFormatArguments(MySteam.API.Friends.GetPersonaName(changedUser)); MyHud.Notifications.Add(playerLeft); } } } }
private void CloseSession() { OnJoin = null; //WARN: If closed here, previous control message probably not come Peer2Peer.CloseSession(ServerId); Peer2Peer.ConnectionFailed -= Peer2Peer_ConnectionFailed; Peer2Peer.SessionRequest -= Peer2Peer_SessionRequest; }
private void AcceptMemberSessions() { for (int i = 0; i < Lobby.MemberCount; i++) { var member = Lobby.GetLobbyMemberByIndex(i); if (member != MySteam.UserId) { Peer2Peer.AcceptSession(member); } } }
unsafe private void SendHeader() { int headerSize = sizeof(byte) + sizeof(int) + sizeof(int) + sizeof(int); byte *block = stackalloc byte[headerSize]; // First byte is header block[0] = MyMultipartMessage.START_HEADER; ((int *)(&block[1]))[0] = m_blockCount; ((int *)(&block[1]))[1] = m_blockSize; ((int *)(&block[1]))[2] = m_dataLength; Peer2Peer.SendPacket(m_sendTo, block, headerSize, P2PMessageEnum.ReliableWithBuffering, m_channel); }
protected void CloseMemberSessions() { for (int i = 0; i < MemberCount; i++) { var member = GetMemberByIndex(i); if (member != Sync.MyId && member == ServerId) { Peer2Peer.CloseSession(member); } } }
private void AcceptMemberSessions() { for (int i = 0; i < Lobby.MemberCount; i++) { var member = Lobby.GetLobbyMemberByIndex(i); if (member != Sync.MyId && member == ServerId) { Peer2Peer.AcceptSession(member); } } }
protected void CloseMemberSessions() { for (int i = 0; i < MemberCount; i++) { var member = GetMemberByIndex(i); if (member != MySteam.UserId) { Peer2Peer.CloseSession(member); } } }
public void GetIP(ulong steamId = 0) { var state = new P2PSessionState(); if (steamId == 0) { steamId = Context.Player.SteamUserId; } Peer2Peer.GetSessionState(steamId, ref state); var ip = new IPAddress(BitConverter.GetBytes(state.RemoteIP).Reverse().ToArray()); Context.Respond($"Your IP is {ip}"); }
void SendHandler(ulong remoteUser, byte[] data, int byteCount, P2PMessageEnum msgType, int channel) { if (msgType == P2PMessageEnum.ReliableWithBuffering) { m_pendingFlushes.Add(remoteUser); } ByteCountSent += byteCount; if (!Peer2Peer.SendPacket(remoteUser, data, byteCount, msgType, channel)) { System.Diagnostics.Debug.Fail("P2P packet send fail"); } }
//Largely copied from SE private void ValidateAuthTicketResponse(ulong steamId, JoinResult response, ulong steamOwner) { var state = new P2PSessionState(); Peer2Peer.GetSessionState(steamId, ref state); var ip = state.GetRemoteIP(); _log.Debug($"ValidateAuthTicketResponse(user={steamId}, response={response}, owner={steamOwner})"); _log.Info($"Connection attempt by {steamId} from {ip}"); // TODO implement IP bans var config = (TorchConfig)Torch.Config; if (config.EnableWhitelist && !config.Whitelist.Contains(steamId)) { _log.Warn($"Rejecting user {steamId} because they are not whitelisted in Torch.cfg."); UserRejected(steamId, JoinResult.NotInGroup); } else if (Torch.CurrentSession.KeenSession.OnlineMode == MyOnlineModeEnum.OFFLINE && !Torch.CurrentSession.KeenSession.IsUserAdmin(steamId)) { _log.Warn($"Rejecting user {steamId}, world is set to offline and user is not admin."); UserRejected(steamId, JoinResult.TicketCanceled); } else if (MySandboxGame.ConfigDedicated.GroupID == 0uL) { RunEvent(new ValidateAuthTicketEvent(steamId, steamOwner, response, 0, true, false)); } else if (_getServerAccountType(MySandboxGame.ConfigDedicated.GroupID) != MyGameServiceAccountType.Clan) { UserRejected(steamId, JoinResult.GroupIdInvalid); } else if (MyGameService.GameServer.RequestGroupStatus(steamId, MySandboxGame.ConfigDedicated.GroupID)) { lock (_waitingForGroupLocal) { if (_waitingForGroupLocal.Count >= _waitListSize) { _waitingForGroupLocal.RemoveAt(0); } _waitingForGroupLocal.Add(new WaitingForGroup(steamId, response, steamOwner)); } } else { UserRejected(steamId, JoinResult.SteamServersOffline); } }
public unsafe void Tick() { foreach (var steamId in m_pendingFlushes) { byte data = 0; if (!Peer2Peer.SendPacket(steamId, &data, 0, P2PMessageEnum.Reliable, m_channel)) { System.Diagnostics.Debug.Fail("P2P packet send fail (flush)"); } } m_pendingFlushes.Clear(); int totalSum = 0; NetProfiler.Begin("Avg per frame (60 frames window)"); for (int i = 0; i < MessageTypeCount; i++) { var window = m_slidingWindows[i]; window.Enqueue(m_thisFrameTraffic[i]); m_thisFrameTraffic[i] = 0; while (window.Count > 60) { window.Dequeue(); } int sum = 0; foreach (var item in window) { sum += item; } if (sum > 0) { NetProfiler.Begin(MyEnum <MyMessageId> .GetName((MyMessageId)i)); NetProfiler.End(sum / 60.0f, sum / 1024.0f, "{0} KB/s"); } totalSum += sum; } NetProfiler.End(totalSum / 60.0f, totalSum / 1024.0f, "{0} KB/s"); }
void MyDedicatedServer_ClientLeft(ulong user, ChatMemberStateChangeEnum arg2) { Peer2Peer.CloseSession(user); MyLog.Default.WriteLineAndConsole("User left " + GetMemberName(user)); if (m_members.Contains(user)) { m_members.Remove(user); } if (m_pendingMembers.ContainsKey(user)) { m_pendingMembers.Remove(user); } if (m_waitingForGroup.Contains(user)) { m_waitingForGroup.Remove(user); } if (arg2 != ChatMemberStateChangeEnum.Kicked && arg2 != ChatMemberStateChangeEnum.Banned) { foreach (var member in m_members) { if (member != ServerId) { MyControlDisconnectedMsg msg = new MyControlDisconnectedMsg(); msg.Client = user; SendControlMessage(member, ref msg); } } } SteamSDK.SteamServerAPI.Instance.GameServer.SendUserDisconnect(user); m_memberData.Remove(user); }
private void SendVoice(ulong user, byte[] data, uint dataSize) { Peer2Peer.SendPacket(user, data, (int)dataSize, P2PMessageEnum.UnreliableNoDelay, MyMultiplayer.VoiceChatChannel); }
private static void DownloadWorld(MyGuiScreenProgress progress, MyMultiplayerBase multiplayer) { if (progress.Text != null) { progress.Text.Clear(); progress.Text.Append(MyTexts.Get(MySpaceTexts.MultiplayerStateConnectingToServer)); } MyLog.Default.WriteLine("World requested"); const float worldRequestTimeout = 40; // in seconds Stopwatch worldRequestTime = Stopwatch.StartNew(); ulong serverId = multiplayer.GetOwner(); bool connected = false; progress.Tick += () => { P2PSessionState state = default(P2PSessionState); Peer2Peer.GetSessionState(multiplayer.ServerId, ref state); if (!connected && state.ConnectionActive) { MyLog.Default.WriteLine("World requested - connection alive"); connected = true; if (progress.Text != null) { progress.Text.Clear(); progress.Text.Append(MyTexts.Get(MySpaceTexts.MultiplayerStateWaitingForServer)); } } //progress.Text.Clear(); //progress.Text.AppendLine("Connecting: " + state.Connecting); //progress.Text.AppendLine("ConnectionActive: " + state.ConnectionActive); //progress.Text.AppendLine("Relayed: " + state.UsingRelay); //progress.Text.AppendLine("Bytes queued: " + state.BytesQueuedForSend); //progress.Text.AppendLine("Packets queued: " + state.PacketsQueuedForSend); //progress.Text.AppendLine("Last session error: " + state.LastSessionError); //progress.Text.AppendLine("Original server: " + serverId); //progress.Text.AppendLine("Current server: " + multiplayer.Lobby.GetOwner()); //progress.Text.AppendLine("Game version: " + multiplayer.AppVersion); if (serverId != multiplayer.GetOwner()) { MyLog.Default.WriteLine("World requested - failed, server changed"); progress.Cancel(); MyGuiSandbox.Show(MySpaceTexts.MultiplayerErrorServerHasLeft); multiplayer.Dispose(); } if (worldRequestTime.IsRunning && worldRequestTime.Elapsed.TotalSeconds > worldRequestTimeout) { MyLog.Default.WriteLine("World requested - failed, server changed"); progress.Cancel(); MyGuiSandbox.Show(MySpaceTexts.MultiplaterJoin_ServerIsNotResponding); multiplayer.Dispose(); } }; var downloadResult = multiplayer.DownloadWorld(); downloadResult.ProgressChanged += (result) => { worldRequestTime.Stop(); OnDownloadProgressChanged(progress, result, multiplayer); }; progress.ProgressCancelled += () => { downloadResult.Cancel(); multiplayer.Dispose(); //var joinScreen = MyScreenManager.GetScreenWithFocus() as MyGuiScreenJoinGame; //if (joinScreen != null) // joinScreen.ReloadList(); }; }
void Matchmaking_LobbyChatUpdate(Lobby lobby, ulong changedUser, ulong makingChangeUser, ChatMemberStateChangeEnum stateChange) { //System.Diagnostics.Debug.Assert(MySession.Static != null); if (lobby.LobbyId == Lobby.LobbyId) { if (stateChange == ChatMemberStateChangeEnum.Entered) { MySandboxGame.Log.WriteLineAndConsole("Player entered: " + MySteam.API.Friends.GetPersonaName(changedUser) + " (" + changedUser + ")"); MyTrace.Send(TraceWindow.Multiplayer, "Player entered"); Peer2Peer.AcceptSession(changedUser); // When some clients connect at the same time then some of them can have already added clients // (see function MySyncLayer.RegisterClientEvents which registers all Members in Lobby). if (Sync.Clients == null || !Sync.Clients.HasClient(changedUser)) { RaiseClientJoined(changedUser); } if (MySandboxGame.IsGameReady && changedUser != ServerId) { // Player is able to connect to the battle which already started - player is then kicked and we do not want to show connected message in HUD. bool showMsg = true; if (MyFakes.ENABLE_BATTLE_SYSTEM && MySession.Static != null && MySession.Static.Battle && !BattleCanBeJoined) { showMsg = false; } if (showMsg) { var playerJoined = new MyHudNotification(MyCommonTexts.NotificationClientConnected, 5000, level: MyNotificationLevel.Important); playerJoined.SetTextFormatArguments(MySteam.API.Friends.GetPersonaName(changedUser)); MyHud.Notifications.Add(playerJoined); } } } else { // Kicked client can be already removed from Clients if (Sync.Clients == null || Sync.Clients.HasClient(changedUser)) { RaiseClientLeft(changedUser, stateChange); } if (changedUser == ServerId) { MyTrace.Send(TraceWindow.Multiplayer, "Host left: " + stateChange.ToString()); RaiseHostLeft(); MySessionLoader.UnloadAndExitToMenu(); MyGuiSandbox.AddScreen(MyGuiSandbox.CreateMessageBox( messageCaption: MyTexts.Get(MyCommonTexts.MessageBoxCaptionError), messageText: MyTexts.Get(MyCommonTexts.MultiplayerErrorServerHasLeft))); // Set new server //ServerId = Lobby.GetOwner(); //if (ServerId == Sync.MyId) //{ // Lobby.SetLobbyData(HostNameTag, Sync.MyName); //} } else if (MySandboxGame.IsGameReady) { var playerLeft = new MyHudNotification(MyCommonTexts.NotificationClientDisconnected, 5000, level: MyNotificationLevel.Important); playerLeft.SetTextFormatArguments(MySteam.API.Friends.GetPersonaName(changedUser)); MyHud.Notifications.Add(playerLeft); } } } }