Jump to content

RakNet in LE Lua


Rick
 Share

Recommended Posts

[EDIT] Title shouldn't have LE just Lua at this point.

 

This is still pretty early stage but I was able to get a wrapper around RakNet working in Lua. I'm simply using C methods currently so it's not like I did class wrapping for all of RakNet as that would be pretty intense and overkill for what I need.

 

I'll show how I'm doing it in case anyone else is interested, but you would have to download RakNet yourself and compile the code because that's how the RakNet developer wants you do work with his code. He doesn't want precompiled wrappers around his code distributed.

 

RakNetLua.dll is my wrapper. The below code will load the dll for Lua to use. Inside the DLL I define a table as 'raknet' so after calling this that's how you use the methods in the dll.

 

After loading the dll and binding to the connection success message (those all caps are ints that use the same values from RakNet's header) I connect to my server. The connect is async so it then hits the main loop calling an update method for RakNet to check for packets coming in. The server gets my connection request and accepts, causing my ConnectionSuccess lua function to get called. Inside that method I'm create a BitStream (just a structure that you write your data to and then send it after you are finished writing to it) and send the server a game message. In my test server when it see's this game message 1, it'll write back game message 2 and since I've bound that message the GameMessage2 lua method will fire in which it reads the string that the server sent.

 

 

*Note* This lua example isn't from inside LE. It was basic Lua exe that you can download. I didn't want to introduce LE yet, but there should be no reason this won't work in LE Lua which I will be doing today or tomorrow pending time.

 

package.loadlib("RakNetLua.dll", "luaopen_raknet")()

-- this lua function will get called by the DLL given the binding that happens below
function ConnectionSuccess(reader)
print "Connection success!"

-- create a bitstream and write something to it
local writer = raknet.net_CreateBitStream(ID_GAME_MESSAGE_1)
raknet.net_WriteBitStream(writer, "Welcome")

-- send this bitstream to the server
raknet.net_Send(writer)
end

function GameMessage2(reader)
print "Inside game message 2"

local msg = ""
msg = raknet.net_ReadBitStream(reader, TYPE_STRING)

print(msg)
end

-- Bind connection success!
raknet.net_BindMessageEvent(ID_CONNECTION_REQUEST_ACCEPTED, "ConnectionSuccess")

-- Bind game message
raknet.net_BindMessageEvent(ID_GAME_MESSAGE_2, "GameMessage2")

raknet.net_Connect("127.0.0.1", 60000)

while i == 1 do
raknet.net_Update()
end

 

 

Currently this only supports strings and doubles but that's the basic building blocks of most data anyway.

 

Below is the DLL I currently have. It'll change as I refine this. If you were to duplicate this the idea is that you link in Lua 5.1 and RakNet lib which you've registered to download yourself and compiled. Given the post here you should be able to make this yourself if you are interested in using RakNet via Lua.

 

#define LUA_API_EXP __declspec(dllexport)

#include "RakPeerInterface.h"
#include "MessageIdentifiers.h"
#include "BitStream.h"
#include "RakNetTypes.h"  // MessageID
#include <string>
#include <map>

using namespace std;

extern "C" 
{
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"

// prevents the function name from being mangled
LUA_API_EXP int luaopen_raknet(lua_State *L);
}

RakNet::RakPeerInterface *peer = RakNet::RakPeerInterface::GetInstance();
RakNet::Packet *packet;
RakNet::SystemAddress serverAddress;

map<RakNet::MessageID, string> luaHandlers;

static int NetConnect(lua_State* L)
{
const char* ip = luaL_checkstring(L, 1);
int port = luaL_checknumber(L, 2);

peer->Startup(1, &RakNet::SocketDescriptor(), 1);
peer->Connect(ip, port, 0,0);

return 0;
}

static int NetSend(lua_State* L)
{
//luaL_checktype(L, 1, LUA_TLIGHTUSERDATA);

// cast the first param to the bitstream to send
RakNet::BitStream *stream = static_cast<RakNet::BitStream*>(lua_touserdata(L, 1));

// send the bitstream to the server
peer->Send(stream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, serverAddress, false);

return 0;
}

static int NetCreateBitStream(lua_State* L)
{
RakNet::BitStream *stream = new RakNet::BitStream();

// the first parameter is the message id
int v1 = luaL_checknumber(L, 1);

// write the message id to the bitstream
stream->Write((RakNet::MessageID)v1);

// return the bitstream to lua
lua_pushlightuserdata(L, stream);

return 1;
}

static int NetWriteBitStream(lua_State* L)
{
// cast the first param to the bitstream to send
RakNet::BitStream *stream = static_cast<RakNet::BitStream*>(lua_touserdata(L, 1));

// get the type of the value we want to write to the bitstream
int type = lua_type(L, 2);
//double vDbl;
//const char* vStr;

switch(type)
{
	case LUA_TNUMBER:
		double vDbl;
		vDbl = luaL_checknumber(L, 2);
		stream->Write(vDbl);
		break;
	case LUA_TBOOLEAN:
		// TODO: implement boolean values
		break;
	case LUA_TSTRING:
		const char* vStr;
		vStr = luaL_checkstring(L, 2);
		RakNet::RakString str = vStr;
		stream->Write(str);
		break;
}

return 0;
}

static int NetReadBitStream(lua_State* L)
{
// cast the first param to the bitstream to send
RakNet::BitStream *stream = static_cast<RakNet::BitStream*>(lua_touserdata(L, 1));

// get the type to read
int type = luaL_checknumber(L, 2);

switch(type)
{
case 0:		// double (constant in Lua)
	double v;
	stream->Read(v);
	lua_pushnumber (L, v);
	break;
case 1:		// string (constant in Lua)
	RakNet::RakString str;
	stream->Read(str);
	lua_pushstring(L, str.C_String());
	break;
}

return 1;
}

static int NetBindMessageEvent(lua_State* L)
{
int msgID = luaL_checknumber(L, 1);
const char* luaFunctionName = luaL_checkstring(L, 2);
string functionName = luaFunctionName;

// link the lua function name to this msg id
luaHandlers[msgID] = functionName;

return 0;
}

static int NetUpdate(lua_State* L)
{
// check for new packets
for (packet=peer->Receive(); packet; peer->DeallocatePacket(packet), packet=peer->Receive())
{
	switch(packet->data[0])
	{
		// if we get connected store off the servers address to use when we send data
		case ID_CONNECTION_REQUEST_ACCEPTED:
			serverAddress = packet->systemAddress;
			break;
	}

	// get the lua method to call
	if(luaHandlers.find(packet->data[0]) != luaHandlers.end())
	{
		lua_getglobal(L, luaHandlers[packet->data[0]].c_str());

		// push the bitstream pointer on the lua stack
		RakNet::BitStream reader(packet->data,packet->length,false);
		reader.IgnoreBytes(sizeof(RakNet::MessageID));

		lua_pushlightuserdata(L, &reader);

		// call the function (1 param, 0 return)
		lua_pcall(L, 1, 0, 0);
	}
}

return 0;
}

static const luaL_reg netLib[] =
{
{"net_Connect", NetConnect},
{"net_Update", NetUpdate},
{"net_BindMessageEvent", NetBindMessageEvent},
{"net_CreateBitStream", NetCreateBitStream},
{"net_Send", NetSend},
{"net_WriteBitStream", NetWriteBitStream},
{"net_ReadBitStream", NetReadBitStream},
{NULL, NULL}
};

// lua calls this to open the library
LUA_API_EXP int luaopen_raknet (lua_State *L)
{
luaL_openlib(L, "raknet", netLib, 0);

return 1;
}

 

 

I'm open to suggestions/comments/thoughts.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...