Welcome!

Join our community of MMO enthusiasts and game developers! By registering, you'll gain access to discussions on the latest developments in MMO server files and collaborate with like-minded individuals. Join us today and unlock the potential of MMO server development!

Join Today!

Creating emulator

Initiate Mage
Joined
Oct 15, 2014
Messages
13
Reaction score
0
Hello, forum. I'm trying to write a server emulator for R2 Online. I do it in C#.
Programm.cs

And Client.cs

I only partially parsed the package in the buffer Post array. Found in it ip and port of the server and the client.The client writes no error about missing server, but nothing happens.Please explain what to do next.
 
Joined
Jun 10, 2009
Messages
658
Reaction score
140
Hello, forum. I'm trying to write a server emulator for R2 Online. I do it in C#.
Programm.cs

And Client.cs

I only partially parsed the package in the buffer Post array. Found in it ip and port of the server and the client.The client writes no error about missing server, but nothing happens.Please explain what to do next.

Server emulator is a software that emulates an existing server for a specific client. The code you shared is just a simple TCP server as well as client. If you are writing your own client then it is not an emulator. You need to really understand the game structure in order to build an emulator. It will take lot of time and creativity to do it. You need start capturing game packets while playing, figure out encryption used (if any). Once you have enough data try writing a simple server which replays the exact same packet and see if client works. From there you need to start implementing each and every functionality yourself which might take years! Good luck to you sir :8:
 
Initiate Mage
Joined
Oct 15, 2014
Messages
13
Reaction score
0
Server emulator is a software that emulates an existing server for a specific client. The code you shared is just a simple TCP server as well as client. If you are writing your own client then it is not an emulator. You need to really understand the game structure in order to build an emulator. It will take lot of time and creativity to do it. You need start capturing game packets while playing, figure out encryption used (if any). Once you have enough data try writing a simple server which replays the exact same packet and see if client works. From there you need to start implementing each and every functionality yourself which might take years! Good luck to you sir :8:
I don't know how to deal with the structure of TCP packet... I find in packet - ip`s and ports.. And I know the encryption method - XOR.I don't know how to combine it. And what will be the difference between my server and another?
 
Joined
Jun 10, 2009
Messages
658
Reaction score
140
I don't know how to deal with the structure of TCP packet... I find in packet - ip`s and ports.. And I know the encryption method - XOR.I don't know how to combine it. And what will be the difference between my server and another?

Look at some example emulators like
 
Junior Spellweaver
Joined
Oct 27, 2008
Messages
165
Reaction score
89
You should avoid using a multi-threaded approach, because it will get slow with the number of connections:

Main
PHP:
private static MainServer server = new MainServer();
static void Main(string[] args)
{
   try
  {
     server.Startup();
     server.Run();
  }  
  catch (Exception ex)
  {
     // log the error
  }

   server.Shutdown();
}

Main Server:
PHP:
public class MainServer
    {
        #region Constants 
        const int STATE_CLOSE = 0;
        const int STATE_LOGIN = 1;
        const int STATE_PLAYING = 2;
        const int REQUESTS_PER_MIN = 60;
        #endregion Constasnts

        #region Fields
        protected int m_nPort = 12345;
        protected string m_strHost = "0.0.0.0";

        protected bool m_bRunning = false;
        protected Thread m_mainThread = null;

        protected object m_objLock = new object();

        protected Socket m_serverSocket = null;
        protected Dictionary<Socket, ClientSocket> m_dicConnections = new Dictionary<Socket, ClientSocket>();
        protected ConcurrentQueue<NetworkMessage> m_messageQueue = new ConcurrentQueue<NetworkMessage>();
        protected AutoResetEvent m_evWaitForPendingMessages = new AutoResetEvent(false);
        #endregion Fields


        internal void Startup()
        {
            AutoResetEvent evWqaitForThreadToStart = new AutoResetEvent(false);
            m_mainThread = new Thread(new ParameterizedThreadStart(MessageHandlerThread));
            m_mainThread.Start(evWqaitForThreadToStart);
            evWqaitForThreadToStart.WaitOne();

            m_serverSocket = new Socket(AddressFamily.InterNetwork,
                         SocketType.Stream, ProtocolType.Tcp);

            IPAddress host = IPAddress.Parse(m_strHost);
            IPEndPoint iep = new IPEndPoint(host, m_nPort);

            m_serverSocket.Bind(iep);
            m_serverSocket.Listen(2);
        }

        internal void Shutdown()
        {
            // stop running client thread
            m_bRunning = false;
            m_evWaitForPendingMessages.Set();
            m_mainThread.Join();

            // close server connections and disconnect existing clients
            m_serverSocket.Close();
            foreach (var key in m_dicConnections.Keys)
            {
                m_dicConnections[key].Disconnect();
            }
            m_dicConnections.Clear();
        }

        private void MessageHandlerThread(object obj)
        {
            m_bRunning = true;
            AutoResetEvent evWqaitForThreadToStart = obj as AutoResetEvent;
            evWqaitForThreadToStart .Set();

            while (m_bRunning)
            {
                if (m_messageQueue.Count == 0)
                {
                    m_evWaitForPendingMessages.WaitOne();
                }

                NetworkMessage netMsg = null;
                m_messageQueue.TryDequeue(out netMsg);
                if (netMsg == null)
                {
                    continue;
                }

                switch (netMsg.Index)
                {
                    // process network messages
                    default:
                        break;
                }
            }

            // Shutting down
            m_bRunning = false;
        }


        public void Run()
        {
            while (m_bRunning)
            {
                ListenForConnctions();
                ManageInputData();
                ManageOutputData();

                // sleep 100 ms, suggest use a proper management of CPU overhead
                Thread.Sleep(100);
            }
        }

        private void ManageInputData()
        {
            // Make a copy
            ArrayList copyList = new ArrayList();
            foreach (var key in m_dicConnections.Keys)
            {
                copyList.Add(m_dicConnections[key].Socket);
            }

            if(copyList.Count ==  0)
            {
                return;
            }

            Socket.Select(copyList, null, null, 0);
            for (int nSocket = 0; nSocket < copyList.Count; nSocket++)
            {
                Socket socket = copyList[nSocket] as Socket;
                ClientSocket client = m_dicConnections[socket];
                if (client == null)
                {
                    continue;
                }

                if (client.State == STATE_LOGIN)
                {
                    client.LoginRequest++;
                    if (client.LoginRequest > REQUESTS_PER_MIN)
                    {
                        client.Disconnect();
                        m_dicConnections.Remove(socket);
                        continue;
                    }
                }

                if (client.Receive() <= 0)
                {
                    client.Disconnect();
                    m_dicConnections.Remove(socket);
                    continue;
                }
         
                while (client.InputQueue.Count > 0)
                {
                    NetworkMessage netMsg = client.InputQueue.Dequeue();
                    if (netMsg == null)
                    {
                        continue;
                    }

                    m_messageQueue.Enqueue(netMsg);
                    m_evWaitForPendingMessages.Set();
                }
            }
        }

       private void ManageOutputData()
        {
            List<Socket> socketsToDisconnect = new List<Socket>();
            for (int nIndex = 0; nIndex < m_dicConnections.Count; nIndex++)
            {
                Socket socket = m_dicConnections.ElementAt(nIndex).Key;
                ClientSocket client = m_dicConnections.ElementAt(nIndex).Value;
                if (client.State == STATE_CLOSE || client.Send() <= 0)
                {
                    client.Disconnect();
                    socketsToDisconnect.Add(socket);
                    continue;
                }
            }

            for (int nIndex = 0; nIndex < socketsToDisconnect.Count; nIndex++)
            {
                Socket socket = socketsToDisconnect[nIndex];
                m_dicConnections.Remove(socket);
            }
        }

        private void ListenForConnctions()
        {
            try
            {
                ArrayList copyList = new ArrayList();
                copyList.Add(m_serverSocket);

                Socket.Select(copyList, null, null, 0);
                if (copyList.Count == 0)
                {
                    return;
                }

                Socket socket = m_serverSocket.Accept();
                ClientSocket client = new ClientSocket(socket);
                client.State = STATE_LOGIN;

                m_dicConnections[socket] = (client);
            }
            catch (Exception ex)
            {
                // Socket error
            }
        }
    }

Client
PHP:
public class ClientSocket
    {
        #region Constants 
        protected const int READ_DATA_SIZE = 1024;
        #endregion Constants

        #region Fields     
        protected int m_nState = 0;
        protected int m_nLoginRequest = 0;
        protected byte[] m_data = new byte[READ_DATA_SIZE];
        protected Socket m_socket = null;

        // input and output Message Queue
        protected Queue<NetworkMessage> m_inputQueue = new Queue<NetworkMessage>();
        protected Queue<NetworkMessage> m_outputQueue = new Queue<NetworkMessage>();
        #endregion Fields

        #region Constructors
        public ClientSocket(Socket socket)
        {
            m_socket = socket;
        }

        #endregion Constructors

        #region Properties 
        public Socket Socket { get { return m_socket; } }
        public Queue<NetworkMessage> InputQueue { get { return m_inputQueue; } }
        public Queue<NetworkMessage> OutputQueue { get { return m_outputQueue; } }

        public int State
        {
            get { return m_nState; }
            set { m_nState = value; }
        }

        public int LoginRequest
        {
            get { return m_nLoginRequest; }
            set { m_nLoginRequest = value; }
        }
        #endregion Properties

        public void Disconnect()
        {
            m_socket.Close();
        }

        public int Receive()
        {
            int nSize = m_socket.Receive(m_data);
            if (nSize <= 0)
            {
                m_nState = 0; // 0 - STATE_CLOSE
                return nSize;
            }

            // Process network packets / packets(there could be multiple packets)
            // Also use a buffer on the client to read partial packets
            bool bStop = false;
            while (!bStop)
            {
                int nMsgIndex = -1;
                //..
                NetworkMessage netMsg = new NetworkMessage(nMsgIndex);
                // Add network data
                // ...
                m_inputQueue.Enqueue(netMsg);
            }

            return nSize;
        }

        public int Send()
        {
            int nResult = 0;
            int nQueueSize = m_outputQueue.Count;
            for (int nIndex = 0; nIndex < nQueueSize; ++nIndex)
            {
                NetworkMessage netMsg = m_outputQueue.Dequeue();
                int nMsgSize = m_socket.Send(netMsg.RawData);
                if (nMsgSize <= 0)
                {
                    return nMsgSize;
                }

                nResult += nMsgSize;
            }

            return nResult;
        }
    }
 
Last edited:
Initiate Mage
Joined
Oct 15, 2014
Messages
13
Reaction score
0
can you give me NetworkMessage class please



You should avoid using a multi-threaded approach, because it will get slow with the number of connections:

Main
PHP:
private static MainServer server = new MainServer();
static void Main(string[] args)
{
   try
  {
     server.Startup();
     server.Run();
  }  
  catch (Exception ex)
  {
     // log the error
  }

   server.Shutdown();
}

Main Server:
PHP:
public class MainServer
    {
        #region Constants 
        const int STATE_CLOSE = 0;
        const int STATE_LOGIN = 1;
        const int STATE_PLAYING = 2;
        const int REQUESTS_PER_MIN = 60;
        #endregion Constasnts

        #region Fields
        protected int m_nPort = 12345;
        protected string m_strHost = "0.0.0.0";

        protected bool m_bRunning = false;
        protected Thread m_mainThread = null;

        protected object m_objLock = new object();

        protected Socket m_serverSocket = null;
        protected Dictionary<Socket, ClientSocket> m_dicConnections = new Dictionary<Socket, ClientSocket>();
        protected ConcurrentQueue<NetworkMessage> m_messageQueue = new ConcurrentQueue<NetworkMessage>();
        protected AutoResetEvent m_evWaitForPendingMessages = new AutoResetEvent(false);
        #endregion Fields


        internal void Startup()
        {
            AutoResetEvent evWqaitForThreadToStart = new AutoResetEvent(false);
            m_mainThread = new Thread(new ParameterizedThreadStart(MessageHandlerThread));
            m_mainThread.Start(evWqaitForThreadToStart);
            evWqaitForThreadToStart.WaitOne();

            m_serverSocket = new Socket(AddressFamily.InterNetwork,
                         SocketType.Stream, ProtocolType.Tcp);

            IPAddress host = IPAddress.Parse(m_strHost);
            IPEndPoint iep = new IPEndPoint(host, m_nPort);

            m_serverSocket.Bind(iep);
            m_serverSocket.Listen(2);
        }

        internal void Shutdown()
        {
            // stop running client thread
            m_bRunning = false;
            m_evWaitForPendingMessages.Set();
            m_mainThread.Join();

            // close server connections and disconnect existing clients
            m_serverSocket.Close();
            foreach (var key in m_dicConnections.Keys)
            {
                m_dicConnections[key].Disconnect();
            }
            m_dicConnections.Clear();
        }

        private void MessageHandlerThread(object obj)
        {
            m_bRunning = true;
            AutoResetEvent evWqaitForThreadToStart = obj as AutoResetEvent;
            evWqaitForThreadToStart .Set();

            while (m_bRunning)
            {
                if (m_messageQueue.Count == 0)
                {
                    m_evWaitForPendingMessages.WaitOne();
                }

                NetworkMessage netMsg = null;
                m_messageQueue.TryDequeue(out netMsg);
                if (netMsg == null)
                {
                    continue;
                }

                switch (netMsg.Index)
                {
                    // process network messages
                    default:
                        break;
                }
            }

            // Shutting down
            m_bRunning = false;
        }


        public void Run()
        {
            while (m_bRunning)
            {
                ListenForConnctions();
                ManageInputData();
                ManageOutputData();

                // sleep 100 ms, suggest use a proper management of CPU overhead
                Thread.Sleep(100);
            }
        }

        private void ManageInputData()
        {
            // Make a copy
            ArrayList copyList = new ArrayList();
            foreach (var key in m_dicConnections.Keys)
            {
                copyList.Add(m_dicConnections[key].Socket);
            }

            if(copyList.Count ==  0)
            {
                return;
            }

            Socket.Select(copyList, null, null, 0);
            for (int nSocket = 0; nSocket < copyList.Count; nSocket++)
            {
                Socket socket = copyList[nSocket] as Socket;
                ClientSocket client = m_dicConnections[socket];
                if (client == null)
                {
                    continue;
                }

                if (client.State == STATE_LOGIN)
                {
                    client.LoginRequest++;
                    if (client.LoginRequest > REQUESTS_PER_MIN)
                    {
                        client.Disconnect();
                        m_dicConnections.Remove(socket);
                        continue;
                    }
                }

                if (client.Receive() <= 0)
                {
                    client.Disconnect();
                    m_dicConnections.Remove(socket);
                    continue;
                }
         
                while (client.InputQueue.Count > 0)
                {
                    NetworkMessage netMsg = client.InputQueue.Dequeue();
                    if (netMsg == null)
                    {
                        continue;
                    }

                    m_messageQueue.Enqueue(netMsg);
                    m_evWaitForPendingMessages.Set();
                }
            }
        }

       private void ManageOutputData()
        {
            List<Socket> socketsToDisconnect = new List<Socket>();
            for (int nIndex = 0; nIndex < m_dicConnections.Count; nIndex++)
            {
                Socket socket = m_dicConnections.ElementAt(nIndex).Key;
                ClientSocket client = m_dicConnections.ElementAt(nIndex).Value;
                if (client.State == STATE_CLOSE || client.Send() <= 0)
                {
                    client.Disconnect();
                    socketsToDisconnect.Add(socket);
                    continue;
                }
            }

            for (int nIndex = 0; nIndex < socketsToDisconnect.Count; nIndex++)
            {
                Socket socket = socketsToDisconnect[nIndex];
                m_dicConnections.Remove(socket);
            }
        }

        private void ListenForConnctions()
        {
            try
            {
                ArrayList copyList = new ArrayList();
                copyList.Add(m_serverSocket);

                Socket.Select(copyList, null, null, 0);
                if (copyList.Count == 0)
                {
                    return;
                }

                Socket socket = m_serverSocket.Accept();
                ClientSocket client = new ClientSocket(socket);
                client.State = STATE_LOGIN;

                m_dicConnections[socket] = (client);
            }
            catch (Exception ex)
            {
                // Socket error
            }
        }
    }

Client
PHP:
public class ClientSocket
    {
        #region Constants 
        protected const int READ_DATA_SIZE = 1024;
        #endregion Constants

        #region Fields     
        protected int m_nState = 0;
        protected int m_nLoginRequest = 0;
        protected byte[] m_data = new byte[READ_DATA_SIZE];
        protected Socket m_socket = null;

        // input and output Message Queue
        protected Queue<NetworkMessage> m_inputQueue = new Queue<NetworkMessage>();
        protected Queue<NetworkMessage> m_outputQueue = new Queue<NetworkMessage>();
        #endregion Fields

        #region Constructors
        public ClientSocket(Socket socket)
        {
            m_socket = socket;
        }

        #endregion Constructors

        #region Properties 
        public Socket Socket { get { return m_socket; } }
        public Queue<NetworkMessage> InputQueue { get { return m_inputQueue; } }
        public Queue<NetworkMessage> OutputQueue { get { return m_outputQueue; } }

        public int State
        {
            get { return m_nState; }
            set { m_nState = value; }
        }

        public int LoginRequest
        {
            get { return m_nLoginRequest; }
            set { m_nLoginRequest = value; }
        }
        #endregion Properties

        public void Disconnect()
        {
            m_socket.Close();
        }

        public int Receive()
        {
            int nSize = m_socket.Receive(m_data);
            if (nSize <= 0)
            {
                m_nState = 0; // 0 - STATE_CLOSE
                return nSize;
            }

            // Process network packets / packets(there could be multiple packets)
            // Also use a buffer on the client to read partial packets
            bool bStop = false;
            while (!bStop)
            {
                int nMsgIndex = -1;
                //..
                NetworkMessage netMsg = new NetworkMessage(nMsgIndex);
                // Add network data
                // ...
                m_inputQueue.Enqueue(netMsg);
            }

            return nSize;
        }

        public int Send()
        {
            int nResult = 0;
            int nQueueSize = m_outputQueue.Count;
            for (int nIndex = 0; nIndex < nQueueSize; ++nIndex)
            {
                NetworkMessage netMsg = m_outputQueue.Dequeue();
                int nMsgSize = m_socket.Send(netMsg.RawData);
                if (nMsgSize <= 0)
                {
                    return nMsgSize;
                }

                nResult += nMsgSize;
            }

            return nResult;
        }
    }
can you give me NetworkMessage class please
 
Junior Spellweaver
Joined
Oct 27, 2008
Messages
165
Reaction score
89
You should analyze more network packets, try to use a sniffer, to capture more packets and see what all the packets have in common, like a packet header, usually the packet header is the first bytes in the packet most of the times not encrypted and it specifies the size of the packet.

About encryption, if the packet encryption is xor you only have to xor your data with the packet to get the encryption key, on big packets you will notice small keys will repeat themselves, if it is another type of encryption you will need to actually reverse it.

Then try to classify packets on their type, and structure them with the information you get by sending to the server or client the same packet type with different information.

Also the client and client files contains a lot of useful information about the game, like types of items, etc.
Ashime posted a link to start.


Network Message is a stream, that handles reading and writing
PHP:
 public class NetworkMessage
    {
        protected const int READ_DATA_SIZE = 1024;

        protected int m_nIndex = 0;
        protected byte[] m_buffer = new byte[READ_DATA_SIZE];
        protected MemoryStream m_stream = null;
        private ClientSocket m_socket;

        public NetworkMessage(int nIndex)
        {
            m_nIndex = nIndex;
            m_stream = new MemoryStream(m_buffer);
        }

        public ClientSocket Socket
        {
            get { return m_socket; }
            set { m_socket = value; ; }
        }

        public int Index
        {
            get { return m_nIndex; }
        }

        public byte[] Buffer
        {
            get { return m_buffer; }
        }

        public int Read(byte[] buffer, int nSize)
        {
            return m_stream.Read(buffer, 0, nSize);
        }

        public void Write(byte[] buffer, int nSize)
        {
            m_stream.Write(buffer, 0, nSize);
        }
    }
 
Joined
Oct 8, 2006
Messages
740
Reaction score
289
I'm using Socket Sniffer for sniffing out packets sent by client (It is possible if the game doesn't have a GameGuard or Anti-Sniffing shields,etc,etc). But, you can use WireShark(pretty powerful) or Socket Sniffer(easy interface with attaching the client.exe process into the software and sniff the s*** out of it, of course, pretty sure every packet you'll see is encrypted.. or maybe not if you are lucky).
 
Joined
Jun 10, 2009
Messages
658
Reaction score
140
I'm using Socket Sniffer for sniffing out packets sent by client (It is possible if the game doesn't have a GameGuard or Anti-Sniffing shields,etc,etc). But, you can use WireShark(pretty powerful) or Socket Sniffer(easy interface with attaching the client.exe process into the software and sniff the s*** out of it, of course, pretty sure every packet you'll see is encrypted.. or maybe not if you are lucky).

Or he can use this tool I made
 
Back
Top