Eternal Lands Protocol Code Examples
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.
- Note: I am actively developing an Eternal Lands Python API called 'pyela'. You can find out more here
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));