Jump to content


  • Content Count

  • Joined

  • Last visited

Community Reputation

16 Good

About miko93

  • Rank

Profile Information

  • Gender
  • Location
    Regensburg, Germany
  1. Updated the source zip. Removed some unneeded files. It is a tad smaller now
  2. Uhm, I've got the standard here, so can't really check. But as some C compiling is involved (also for the client), I'd assume the full version be needed...
  3. Thought I could write my first Blog entry and report about my ventures into network programming with Leadwerks, ENet and Lua. Also, provide some source code. Okay, here we go: What I wanted to do My test app should be a client-server setup where clients can connect to the server, see each other's avatar, send chat lines and move around their avatar on a plane. Nothing fancy really, just to get into the topic. The ENet network library (http://http://enet.bespin.org/) should be used, and network functions should be exposed from C to Leadwerk's lua engine (as I wanted to do the main 'game coding' in lua). The clients are intended to run on Windows, while the server should first be run as console app on Win, might later be moved to a remote rented Linux server. The Network Concept For the first testing, I tried to make the server part very "light-weight", and leave many things to the client(s). Probably not the right thing to do for a full scale MMOG (mainly due to cheat concerns) - but, well, this test app is far from that anyway ;-) So, the server will - aside from some administrative tasks - mainly receive messages from a client and distribute to the others. As for the communication, a rather simple protocol layer was created on top of ENet (i.e., a definition of message formats and identifiers). Note that not everything a client sends will be distributed - it would first be checked for (some very basic) consistency. Network Messages Seven network messages were defined, some for client->server or server->client only, some for both ways. The messages are wrapped into ENet's 'ENetPacket' and sent, to be evaluated by the receiver. MSG_TYPE_ID_REQ(a clients requests a unique identification number from the server) MSG_TYPE_NAME (a client sends its chat name) MSG_TYPE_POS (a client or the server sends info about position/rotation of an avatar) MSG_TYPE_CHAT (a client or the server sends info about a chat line) MSG_TYPE_CLIENT_ON (the server sends info about a new client online - also used to inform a new client about existing ones) MSG_TYPE_CLIENT_OFF (the server sends info about a client leaving) MSG_TYPE_CLIENT_ID (the server sends a unique identification number to the client that requsted one) The message formats used would look like so (complete source available below): struct MSG_POS // Sending a client pos and rot info { BYTE cMsgType = MSG_TYPE_POS; UINT16 ClientID; float fPosX, fPosY, fPosZ; float fRotX, fRotY, fRotZ; }; The Server This is a win console C app, which should - with some tweaking - compile and run on Linux also. Actually, I started out with doing it on Ubuntu on a VMWare Player, but moved to Win console later on. Just for the ease of use. The server will detect when a new client connected (using ENet functionality), and wait for the initial 'request for ID' message. After assignment, it informs the other clients about the new one (and vice versa). On server side, only the unique ID and the client's chat name are stored. When receiving e.g. a "Chatline" message, the server would check if the sender's client ID and the message type both are valid, then distribute the message to all clients. Upon disconnection of a client (again using ENet functionality), remaining clients would be informed also. The Client Networking here is done as a two-stage concept: Extending the Leadwerks App with some networking C functions and exposing some of them to lua (where the main 'game programming' is to happen). Note that Leadwerks also comes with the ENet headers and libs, so it is not necessary to include it here. You can just use it in your C code. As for the connection between C and lua, two possibilities must be considered: Calling a (new) network function from lua and calling back from C into lua when e.g. a certain message arrived. Exposing a new function to lua would look like this (returning the connected state of the network): lua_register(Interpreter::L, "NW_IsConnected", NW_IsConnected); extern "C" int NW_IsConnected(lua_State* L) { lua_pushboolean(L, gl_Networking.m_bConnected); return 1; } Preparing a callback from C into lua looked like so (this is a callback when a new client is reported by the server). Note that (obviously) the global function "NW_Callback_Connected" must be present in the lua code, to be called. void Callback_Connected(unsigned short int iID) { lua_getglobal(Leadwerks::Interpreter::L, "NW_Callback_Connected") if (!lua_isfunction(Leadwerks::Interpreter::L, -1)) { lua_pop(Leadwerks::Interpreter::L, 1); return; } lua_pushnumber(Leadwerks::Interpreter::L, iID); /* do the call (1 argument, 0 result) */ if (lua_pcall(Leadwerks::Interpreter::L, 1, 0, 0) != 0) { printf("NW_Callback_Connected ERROR: %s\n", lua_tostring(Leadwerks::Interpreter::L, -1)); return; } } For the test app, several functions were exposed to lua from the added network C code, and also several possible callbacks are provided. To avoid any multi-threading issues, the function "NW_Update()" must periodically called from lua (e.g. in WorldUpdate). Within there, callbacks are then triggered. Callbacks, invoked from network (when NW_Update() called) NW_Callback_Connected(id) // called when we are connected to the network NW_Callback_ClientJoined(id) // called when a client joined the network NW_Callback_ClientLeft(id) // called when a client left the network NW_Callback_ClientPosRot(id,Px,Py,Pz,Rx,Ry,Rz) // called when a client pos/rot message arrived NW_Callback_ClientName(id,name) // called when a client sent its name NW_Callback_ClientChat(id,chatline) // called when a client sent a chatline Functions, to be called from lua NW_Connect() // do this once, e.g. in Script:Start() NW_IsConnected() // call this to see if server connection is established NW_Update() // do this regularly, e.g. in Script:UpdateWorld() NW_SendPosRot(Px,Py,Pz,Rx,Ry,Rz) // when pos/rot changes, send all e.g. 200ms NW_SendName(name) // send your client name once (15 chars max); NW_SendChatline(chatline) // send chatlines (255 chars max) to other clients Within lua, it is then the client's task to respond to e.g. a 'NW_Callback_ClientJoined' message. Like, create a new avatar and move it around. The client is sending its own position every 200ms, to be distributed further by the server. Within the client, only very few measures have been taken to compensate for network lag. It will interpolate incoming positions for remote avatars (moving them with constant speed), but does not really apply such high-sophisticated methods like movement prediction and whatnot. To move one's own avatar, use WASD. To submit a chat line, hit enter (submit with enter again, cancel with esc). Note that as for now, a connection attempt is only done at startup. So the server must be started before any client. Also, 'localhost' as server IP is currently hardcoded. Final Words While I did dive into ENet before, this was my rather first time with all that lua mumbo-jumbo. Actually, after getting used to it, writing scripts in lua is quite fast (relaxing, even). Think I will stick to the idea of doing some basic stuff in C, but adding game logic in lua. Now on to that movement prediction et al! Links A short video, showing the whole mess in action: Link to executables (server+client): http://www.mikoweb.eu/tmp/LWEN_Networking_Exe.zip (10MB) Link to Source (VS2013+LW): http://www.mikoweb.eu/tmp/LWEN_Networking_Source.zip (25MB) Pictures The test app (here, 3 clients and the server running on Win)
  4. Rather than creating a new topic, I feel free to jump in here with a related question. Anyone got objects (Vec3, in my case) passed between lua and C? For e.g. int types, I would do like (calling from lua into C) lua_register(Interpreter::L, "CalledFromLua", CalledFromLua); extern "C" int CalledFromLua(lua_State* L) { int i = lua_tointeger(Leadwerks::Interpreter::L,1) CallMyFunc(i); return 0; } and (calling from C into lua) void CalledFromC(int i) { lua_getglobal(Leadwerks::Interpreter::L, "AFunction"); if (!lua_isfunction(Leadwerks::Interpreter::L, -1)) { lua_pop(Leadwerks::Interpreter::L, 1); return; } lua_pushinteger(Leadwerks::Interpreter::L, i); if (lua_pcall(Leadwerks::Interpreter::L, 1, 0, 0) != 0) { printf("Callback_ClientPosRot ERROR: %s\n", lua_tostring(Leadwerks::Interpreter::L, -1)); return; } } But with e.g. Vec3, this seems to be a bit more complicated. Like, using 'userdata' or such things. Any hints?
  5. Lol, wanted to integrate enet with LW - just to discover it is already in 8-)

    1. funnygamemaker


      Do you know if enet is only with the c++ version or is it also with the lua version?


    2. miko93


      Please refer to this forum post: http://www.leadwerks.com/werkspace/topic/8739-enet-and-leadwerks/page__hl__enet

      Looks like it is not exposed to lua for now.

  6. Just for the records: I have seen a similar effect as tinyboss.
  7. Thank you all for the tips! Had a play with FFSplit now - and it looks good. My first video there:
  8. Guys, the tool of choice for making LW dev videos is Fraps, right? Or is there something else you would recommend (also, something for post-editing)? Thanks
  9. Nothing really new - but anyway, these are my key points: - the C++ API (hell, I still can't be arsed to dive into lua) - full shader access - helpful and responsive community - regular dev presence in forums
  10. Wonderful landscape, grats! Say, could you elaborate a bit more on how you made the terrain, the vegetation and such? Or, maybe, did you do so already someplace else? Thanks a lot.
  11. Thanks for your comments. Ah, I see - yeah, keyframe animation is the word. So, I will try to rig that thing and then see how it goes. For clarification: Yes, I did export with animation and that could be interpreted by UU3D. I did not export again from UU3D and try with LW then afterwards, tho.
  12. Hi Folks, I have set up a very basic animated model in C4D (R15 in my case) and exported to fbx. It is just a cube spinning on a platform (no rigging or whatnot). Upon LW import, the animation does not show up, tho. It imports well into UU3D and others. The fbx can be found here: http://www.mikoweb.eu/tmp/LW_Testmodel.zip Anyone got such animation into LW directly from C4D (R15 in my case)? (I know I could/should try using e.g. UU3D or Blender as "middleware", but would love to get it in directly...) Thanks for your comments.
  13. Think I have the same problem here. After exiting LW, I can't close Steam, as it thinks LW is still active. Also, I get the "already running" message on restarting LW.
  14. At least for Windows, I assume LW is using the Win API ShowCursor function. See here: http://msdn.microsoft.com/de-de/library/windows/desktop/ms648396%28v=vs.85%29.aspx This function actually uses a counter, not just switching the cursor on/off. Starting with 0 = mouse ON (!). Counting through your code: Program Start: 0 Call to ShowMouse: 1 Call to Hidemouse: 0 Call to ShowMouse: 1 Call to HideMouse: 0 As Windows hides the mouse with counter -1 and below, it is never hidden - I think. If this really is the case, the LW docs might need a bit of updating...
  15. Actually, I have a stub dll test case in place now. Got me the SDK and linked it with a dll which in turn is loaded dynamically at runtime now (or, well, not - as one prefers). During testing, I noticed that the steam.dll keeps rather passive, as long as the SDK's SteamAPI_Init() isn't called. So, to me, it seems Leadwerks invokes the SteamAPI_Init() not only during a call of Steamworks::Initialize (what I was assuming), but always. If this is correct, some remedy could be achieved by moving the call to Steamworks::Initialize and only execute on demand. No need to fiddle with steam_appid.txt etc then, if a user doesn't call Steamworks::Initialize anyway... my 2 cents
  • Create New...