Eternal Lands Protocol Code Examples

From wiki.alexcollins.org
Jump to: navigation, search

Contents

Code Examples By Language

This article is for providing working examples of code, in any language, that will communicate correctly with the Eternal Lands server. The intention is to provide an article, separate from the protocol description (that shows examples only in C), that will allow those familiar with other languages to learn the protocol by example.

Java

LOG_IN

 byte[] name = "somestuff".getBytes("ISO8859-1");
 String pass = "politicalcommentary".getBytes("ISO8859-1");
 int size = name.length() + 1 + pass.length() + 1;
 byte[] out = new byte[size + 2];
//java primitives are signed, we're receiving unsigned. bit shift! out[0] = (byte)140; out[1] = (byte)((size >> 8) & 0xFF); out[2] = (byte)((size) & 0xFF);
int offset = 3; System.arraycopy(name, 0, byte, offset, name.length); offset += name.length + 1; byte[offset - 1] = " ".getBytes("ISO8859-1")[0]; System.arraycopy(pass, 0, byte, offset, pass.length); //send to server

HEART_BEAT

 byte[] dat = new byte[3];
 dat[0] = 14;
 dat[1] = 1;
 //send to server

RAW_TEXT

 String message;
 byte[] msg = message.getBytes("ISO8859-1");
 byte[] send = new byte[msg.length + 4];
 int size = send.length - 2;
 send[1] = (byte)((size >> 8) & 0xFF);
 send[2] = (byte)((size) & 0xFF);
 send[3] = CHANNUM;// the channel number
 System.arraycopy(msg, 0, send, 4, msg.length);

Python

Receiving rough inventory list

Notice that I use struct.unpack('<HIBB'). This is because if you don't use '<', it will try to pad things to the largest datatype size. I kept wondering why Python kept giving me length errors and that was the reason....I was neglecting to use '<'. Without it, python will be a pain and try to pad the data to the largest datatype size for each piece of data. That is extremely annoying.

It is worth noting that the '<' character is recommended for use with pack/unpack as the protocol byte ordering is specifically little-endian.

    if self.command==HERE_YOUR_INVENTORY:
           print "We have HERE_YOUR_INVENTORY!\n"
           inventory_count=ord(self.packet_data[0])
           self.my_inventory={}
           inventory_list=[]
           for item in range(0,inventory_count):
               temp=self.packet_data[item*8+1:]
               print debug_data(temp[:8])
               item_id,quantity,position,flags,=struct.unpack('<HIBB',temp[:8])
               self.my_inventory[position]=inv_item(item_id,quantity,flags)
               print "POS:",position,"ID:",item_id,"AMOUNT:",quantity,"FLAGS:",flags
               inventory_list.append(self.my_inventory[position].text())
           inventory_list=", ".join(inventory_list)
           c=0
           for x in self.message:
               if hasattr(x,'text'):
                   if x.text.upper() in ["INVENTORY","INV"]:
                       x.done=True
                       print self.packet_data
                       self.reply("Here is what I have...."+str(inventory_count)+"...."+inventory_list,c)
               c=c+1

Sending a message

 def send_message (message, data = ''):
   length = len (data)+ 1
   to_send = struct.pack ('<BH', message, length)+ data
   
   try:
     # sock is a socket.socket object
     sock.sendall (to_send)
   except:
     # Handle errors here

LOG_IN

 name = 'Vytas'
 password = 'somecoolpassword'
 send_message (140, name+ ' '+ password+ '\0')

HEART_BEAT

 send_message (14)

SIT_DOWN

 # Stand up = 0, sit down = 1
 sit = 1
 send_message (7, chr (sit))

RAW_TEXT

 # Let's join the market channel
 text = '#jc 3'
 send_message (0, text)

SEND_PM

 name = 'Placid'
 text = 'Look at my Python examples'
 send_message (2, name+ ' '+ text)

VB.NET

Here are some Visual Basic .Net examples.

Sending a message

If there's a better way to do this, please do let me know.


       Public Sub Send(ByVal cmd As Integer, ByVal data As String)
               Dim l1 As Integer
               Dim l2 As Integer
               Dim length As Integer
               '
       	length = Len(data) + 1
       	If length > 255 Then
       		l1 = length Mod 256
               	l2 = length / 256
          	Else
       		l1 = length
       	End If
       '	
       	socket.Send(Chr(CShort(cmd)) & Chr(l1) & Chr(l2) & data)
       	
       End Sub

Login

       Public Sub Login() 
               Dim username as string 
               Dim password as string 
       '	
               username = "Bob"
               password = "secret"
       '
               Send(140, username & " " & password & VariantType.Null)
       End Sub


Reading storage categories

A proof-of-concept in Visual Basic (?):

       Public Sub updateCats(ByVal data As String)
               'We assume that the command and length are already removed from the DATA variable.
               Dim cats() As String
               Dim i As Long
               Dim name As String
               Dim num As Long
               '
               msgbox("There are " & Asc(Mid(data, 1, 1)) & " catagories")
               cats = Split(Mid(data, 2), Chr(0))
               '
               For i = 0 To UBound(cats) - 1
               '    
                   num = Asc(Mid(cats(i), 1, 1))
                   name = Mid(cats(i), 2)
                   msgbox(num & " " & name)
               Next i
               ' 
               '     
       End Sub

PHP

Send message to server

              function SendMessage($cmd, $data) {
                  $length = strlen($data) + 1;
                  $packet = $cmd .chr($length) .chr(0) .$data;
                  fwrite($server['SOCKET'], $packet;
              }   

Send Log in

               define("LOG_IN", chr(140));
               $data = $charname. " " .$password ."\0";
               SendMessage(LOG_IN, $data);

Send Heartbeat

               define("HEART_BEAT", chr(14));
               $data = "";
               SendMessage(HEART_BEAT, $data);

Send PM

               define("SEND_PM", chr(2));
               $data = $charname ." " ."Here's my PM";
               SendMessage(SEND_PM, $data);

Send raw text

               define("RAW_TEXT",chr(0));
               $data = "Some raw text";
               SendMessage(RAW_TEXT, $data);

Unpack message from server

               /* 
               we read the the first three bytes of the socket stream of which the first  
               gives us the server command and the next two give us the data length
               */
               $bytes= fread($server['SOCKET'],3); 
               $cmd=unpack("C",substr($bytes,0,1));
               $datalength=unpack("v",substr($bytes,1,2));
               /*
               Once we know the data length we then read that number of bytes from the socket
               stream to give us the data 
               */  
               $data=fread($server['SOCKET'], $datalength[1]);

Receiving the channels list

               /* On receiving command 71 from the server, unpack the data as follows */ 
               $activechannel=unpack("C", substr($data,0,1));
               $channel1=unpack("V", substr($data,1,4));
               $channel2=unpack("V", substr($data,5,4));
               $channel3=unpack("V", substr($data,9,4));
Personal tools
Namespaces
Variants
Actions
Navigation
Eternal Lands
alexcollins.org
Toolbox