示例#1
0
        public void PropagateU(GhostNetFrame frame)
        {
            // U is always handled after M. Even if sending this fails, we shouldn't worry about loosing M chunks.
            for (int i = 0; i < Connections.Count; i++)
            {
                GhostNetConnection otherCon = Connections[i];
                if (otherCon == null || (!AllowLoopbackUpdates && i == frame.HHead.PlayerID))
                {
                    continue;
                }

                ChunkMPlayer otherPlayer;
                if (!PlayerMap.TryGetValue((uint)i, out otherPlayer) || otherPlayer == null ||
                    frame.MPlayer.SID != otherPlayer.SID ||
                    frame.MPlayer.Mode != otherPlayer.Mode
                    )
                {
                    continue;
                }

                if (!(otherCon is GhostNetRemoteConnection))
                {
                    otherCon.SendUpdate(frame, false);
                }
                else if (otherCon.UpdateEndPoint != null && !GhostNetModule.Settings.SendUFramesInMStream)
                {
                    UpdateConnection.SendUpdate(frame, otherCon.UpdateEndPoint, false);
                }
                else
                {
                    // Fallback for UDP-less clients.
                    otherCon.SendManagement(frame, false);
                }
            }
        }
示例#2
0
        public ChunkMChat SendMChat(GhostNetConnection con, GhostNetFrame frame, string text, string tag = null, Color?color = null, bool fillVars = false)
        {
            ChunkMChat msg = CreateMChat(frame, text, tag, color, fillVars);

            con.SendManagement(new GhostNetFrame {
                new ChunkHHead {
                    PlayerID = uint.MaxValue
                },
                msg
            }, true);
            return(msg);
        }
示例#3
0
 public void PropagateM(GhostNetFrame frame)
 {
     for (int i = 0; i < Connections.Count; i++)
     {
         GhostNetConnection otherCon = Connections[i];
         if (otherCon == null)
         {
             continue;
         }
         otherCon.SendManagement(frame, false);
     }
 }
示例#4
0
        public virtual void HandleMPlayer(GhostNetConnection con, GhostNetFrame frame)
        {
            frame.MPlayer.Name = frame.MPlayer.Name.Replace("*", "").Replace("\r", "").Replace("\n", "").Trim();
            if (frame.MPlayer.Name.Length > GhostNetModule.Settings.ServerMaxNameLength)
            {
                frame.MPlayer.Name = frame.MPlayer.Name.Substring(0, GhostNetModule.Settings.ServerMaxNameLength);
            }

            if (string.IsNullOrWhiteSpace(frame.MPlayer.Name))
            {
                frame.MPlayer.Name = "#" + frame.HHead.PlayerID;
            }

            // Logger.Log(LogLevel.Verbose, "ghostnet-s", $"Received nM0 from #{frame.PlayerID} ({con.EndPoint})");
            Logger.Log(LogLevel.Info, "ghostnet-s", $"#{frame.HHead.PlayerID} {frame.MPlayer.Name} in {frame.MPlayer.SID} {(char) ('A' + frame.MPlayer.Mode)} {frame.MPlayer.Level}");

            // Propagate status to all other players.
            frame.MPlayer.IsEcho = true;
            frame.PropagateM     = true;

            if (!PlayerMap.ContainsKey(frame.HHead.PlayerID))
            {
                // Player just connected.
                if (!string.IsNullOrWhiteSpace(GhostNetModule.Settings.ServerMessageGreeting))
                {
                    BroadcastMChat(frame, GhostNetModule.Settings.ServerMessageGreeting, fillVars: true);
                    SendMChat(con, frame, GhostNetModule.Settings.ServerMessageMOTD, fillVars: true);
                }
            }

            // Inform the player about all existing ghosts.
            lock (PlayerMap) {
                PlayerMap[frame.HHead.PlayerID] = frame.MPlayer;
                foreach (KeyValuePair <uint, ChunkMPlayer> otherStatus in PlayerMap)
                {
                    if (otherStatus.Value == null || (!AllowLoopbackUpdates && otherStatus.Key == frame.HHead.PlayerID))
                    {
                        continue;
                    }
                    con.SendManagement(new GhostNetFrame {
                        HHead = new ChunkHHead {
                            PlayerID = otherStatus.Key
                        },

                        MPlayer = otherStatus.Value.Clone() as ChunkMPlayer
                    }, true);
                }
            }
        }
示例#5
0
        public GhostNetFrame Request(Type type, GhostNetConnection con, long timeout = 5000)
        {
            GhostNetFrame response = null;

            // Temporary handler to grab the response.
            GhostNetFrameHandler filter = (filterCon, filterFrame) => {
                if (response != null)
                {
                    return; // Already received a response.
                }
                if (filterCon != con)
                {
                    return; // Not the player we sent the request to.
                }
                if (!filterFrame.Has(type))
                {
                    return; // Doesn't contain the awaited response.
                }
                response = filterFrame;
            };

            OnHandle += filter;

            // Send a request.
            con.SendManagement(new GhostNetFrame {
                new ChunkHHead {
                    PlayerID = int.MaxValue,
                },
                new ChunkMRequest {
                    ID = GhostNetFrame.GetChunkID(type)
                }
            }, true);

            // Wait for the response.
            Stopwatch timeoutWatch = new Stopwatch();

            timeoutWatch.Start();
            while (response == null && timeoutWatch.ElapsedMilliseconds < timeout)
            {
                Thread.Sleep(0);
            }

            // If we still get a response after the timeout elapsed but before the handler has been removed, deal with it.
            OnHandle -= filter;

            return(response);
        }
示例#6
0
        public virtual void Accept(GhostNetConnection con)
        {
            uint id = (uint)Connections.Count;

            Logger.Log(LogLevel.Verbose, "ghostnet-s", $"Client #{id} ({con.ManagementEndPoint}) accepted");
            Connections.Add(con);
            ConnectionMap[con.ManagementEndPoint] = con;
            UpdateConnectionQueue[con.ManagementEndPoint.Address] = con;
            con.SendManagement(new GhostNetFrame {
                new ChunkHHead {
                    PlayerID = id
                },
                new ChunkMServerInfo {
                    Name = GhostNetModule.Settings.ServerNameAuto
                },
                new ChunkMRequest {
                    ID = ChunkMPlayer.ChunkID
                }
            }, true);
        }
            public void Move(uint playerID, int index, GhostNetFrame frame = null)
            {
                Logger.Log(LogLevel.Verbose, "ghostnet-race", $"Moving player {playerID} to index {index}");
                GhostNetConnection con = Manager.Server.Connections[(int)playerID];
                ChunkMPlayer       playerCached;

                if (con == null || !Manager.Server.PlayerMap.TryGetValue(playerID, out playerCached) || playerCached == null)
                {
                    return;
                }
                Indices[playerID] = index;
                if (index == -1 && WaitingForStart.Contains(playerID) && string.IsNullOrEmpty(playerCached.SID))
                {
                    WaitingForStart.Remove(playerID);
                    return;
                }

                ChunkMPlayer player = new ChunkMPlayer {
                    Name  = playerCached.Name,
                    SID   = index == -1 ? "" : Areas[index].Item1,
                    Mode  = index == -1 ? AreaMode.Normal : Areas[index].Item2,
                    Level = ""
                };

                if (frame == null)
                {
                    con.SendManagement(new GhostNetFrame {
                        HHead = new ChunkHHead {
                            PlayerID = playerID
                        },

                        MPlayer = player
                    }, true);
                }
                else
                {
                    frame.MPlayer    = player;
                    frame.PropagateM = true;
                }
            }
            public ChunkMChat Send(GhostNetFrame frame, string text, string tag = "race", Color?color = null, bool fillVars = false, uint?id = null)
            {
                ChunkMChat    msg      = Manager.Server.CreateMChat(frame, text, tag, color ?? (frame != null ? ColorDefault : ColorBroadcast), fillVars, id);
                GhostNetFrame frameMsg = new GhostNetFrame {
                    frame?.HHead ?? new ChunkHHead {
                        PlayerID = uint.MaxValue
                    },
                    msg
                };

                lock (Players) {
                    foreach (uint playerID in Players)
                    {
                        GhostNetConnection con = Manager.Server.Connections[(int)playerID];
                        if (con == null)
                        {
                            continue;
                        }
                        con.SendManagement(frameMsg, false);
                    }
                }
                return(msg);
            }
示例#9
0
        public virtual void HandleMChat(GhostNetConnection con, GhostNetFrame frame)
        {
            ChunkMChat msg = frame;

            msg.Text = msg.Text.TrimEnd();
            // Logger.Log(LogLevel.Info, "ghostnet-s", $"#{frame.HHead.PlayerID} said: {frame.MChat.Text}");

            if (!msg.Logged)
            {
                lock (ChatLog) {
                    msg.ID = (uint)ChatLog.Count;
                    ChatLog.Add(msg);
                }
            }

            // Handle commands if necessary.
            if (msg.Text.StartsWith(GhostNetModule.Settings.ServerCommandPrefix))
            {
                // Echo the chat chunk separately.
                msg.Color = GhostNetModule.Settings.ServerColorCommand;
                con.SendManagement(new GhostNetFrame {
                    frame.HHead,
                    msg
                }, true);

                GhostNetCommandEnv env = new GhostNetCommandEnv {
                    Server     = this,
                    Connection = con,
                    Frame      = frame
                };

                string prefix = GhostNetModule.Settings.ServerCommandPrefix;

                // TODO: This is basically a port of disbot-neo's Handler.

                string cmdName = env.Text.Substring(prefix.Length);
                cmdName = cmdName.Split(GhostNetCommand.CommandNameDelimiters)[0].ToLowerInvariant();
                if (cmdName.Length == 0)
                {
                    return;
                }

                GhostNetCommand cmd = GetCommand(cmdName);
                if (cmd != null)
                {
                    GhostNetFrame cmdFrame = frame;
                    Task.Run(() => {
                        try {
                            cmd.Parse(env);
                        } catch (Exception e) {
                            SendMChat(con, cmdFrame, $"Command {cmdName} failed: {e.Message}", color: GhostNetModule.Settings.ServerColorError, fillVars: false);
                            if (e.GetType() != typeof(Exception))
                            {
                                Logger.Log(LogLevel.Warn, "ghostnet-s", $"cmd failed: {env.Text}");
                                e.LogDetailed();
                            }
                        }
                    });
                }
                else
                {
                    SendMChat(con, frame, $"Command {cmdName} not found!", color: GhostNetModule.Settings.ServerColorError, fillVars: false);
                }

                return;
            }

            if (!msg.CreatedByServer)
            {
                msg.Text.Replace("\r", "").Replace("\n", "");
                if (msg.Text.Length > GhostNetModule.Settings.ServerMaxChatTextLength)
                {
                    msg.Text = msg.Text.Substring(0, GhostNetModule.Settings.ServerMaxChatTextLength);
                }

                msg.Tag   = "";
                msg.Color = Color.White;
            }

            msg.Date = DateTime.UtcNow;

            frame.PropagateM = true;
        }