View previous topic :: View next topic |
Author |
Message |
Crispy
Joined: 26 Nov 2005 Posts: 67
|
Posted: Sat Nov 26, 2005 12:54 am Post subject: FastEvents and NET2 libraries |
|
|
Hi! I'm currently writing a game in D using SDL and OpenGL via Derelict, and so far it's shaping up pretty nicely. I like how Derelict works; it's a nice easy way of wrapping C libraries, plus it makes it REALLY easy to comply with the LGPL. Good job.
I hit a bit of a snag, however, when I tried to use SDL_net; namely, I really really don't like working with sockets.
I looked for other solutions and found the NET2 library, by Bob Pendleton. Basically it hides all the low-level socket details and uses SDL's event loop to tell you about data and errors. It relies on the same guy's FastEvents library, which uses threads to optimize the event loop by providing drop-in replacements for SDL's event-related functions (like SDL_PushEvent, SDL_PollEvent, SDL_PumpEvents, etc.).
So I decided to wrap these libraries in a Derelict-like manner. I've already done it for FastEvents (and I'm using it in my game) and I'm about to do it for NET2. Would you be interested in including these in Derelict once I'm done?
Here's FastEvents anyway, feel free to steal/modify/incorporate as you wish:
Code: | module fastevents.fastevents;
/*
NET2 is a threaded, event based, network IO library for SDL.
Copyright (C) 2002 Bob Pendleton
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public License
as published by the Free Software Foundation; either version 2.1
of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA
If you do not wish to comply with the terms of the LGPL please
contact the author as other terms are available for a fee.
Bob Pendleton
Bob@Pendleton.com
*/
private
{
import derelict.sdl.sdl;
import derelict.util.loader;
}
//==============================================================================
// FUNCTIONS
//==============================================================================
extern(C)
{
typedef int function() pfFE_Init;
typedef void function() pfFE_Quit;
pfFE_Init FE_Init;
pfFE_Quit FE_Quit;
typedef void function() pfFE_PumpEvents;
typedef int function(SDL_Event*) pfFE_PollEvent;
typedef int function(SDL_Event*) pfFE_WaitEvent;
typedef int function(SDL_Event*) pfFE_PushEvent;
pfFE_PumpEvents FE_PumpEvents;
pfFE_PollEvent FE_PollEvent;
pfFE_WaitEvent FE_WaitEvent;
pfFE_PushEvent FE_PushEvent;
typedef char* function() pfFE_GetError;
pfFE_GetError FE_GetError;
} // extern(C)
//==============================================================================
// LOADER
//==============================================================================
private SharedLib libSDLFastEvents;
private void* getProc(char[] procName)
{
return Derelict_GetProc(libSDLFastEvents, procName);
}
private void load()
{
FE_Init = cast(pfFE_Init)getProc("FE_Init");
FE_Quit = cast(pfFE_Quit)getProc("FE_Quit");
FE_PumpEvents = cast(pfFE_PumpEvents)getProc("FE_PumpEvents");
FE_PollEvent = cast(pfFE_PollEvent)getProc("FE_PollEvent");
FE_WaitEvent = cast(pfFE_WaitEvent)getProc("FE_WaitEvent");
FE_PushEvent = cast(pfFE_PushEvent)getProc("FE_PushEvent");
FE_GetError = cast(pfFE_GetError)getProc("FE_GetError");
}
public void DerelictSDLFastEvents_Load(char[] libName)
{
if(libSDLFastEvents !is null)
return;
libSDLFastEvents = Derelict_LoadSharedLib(libName);
load();
}
public void DerelictSDLFastEvents_Load()
{
version(Windows)
DerelictSDLFastEvents_Load("SDL_fastevents.dll");
version(linux)
DerelictSDLFastEvents_Load("libSDL_fastevents.so");
}
public void DerelictSDLFastEvents_Unload()
{
Derelict_UnloadSharedLib(libSDLFastEvents);
}
static ~this()
{
DerelictSDLFastEvents_Unload();
} |
I've kept the SDL prefix even though the FastEvents library itself doesn't use it, because the library is specifically designed to work on top of SDL. If you chose to incorporate it you'd just need to change the module declaration, but otherwise it conforms to Derelict's specifications.
Sound like something you'd want to include?
Edit: I understand that you're busy, and that's fine; I was just wondering if this is something you'd like to include once things have settled down a bit. |
|
Back to top |
|
|
aldacron
Joined: 05 May 2004 Posts: 1322 Location: Seoul, South Korea
|
Posted: Sat Nov 26, 2005 9:36 pm Post subject: |
|
|
Thanks for the port! I don't know if either library is something I would be interested in adding to Derelict right now. One of my criteria for new packages is that it be a library that has fairly widespread use. Maintaining all of the packages, particularly the docs, can take up a chunk of time (which I have very little of as it is), so if it's not something many people would use then I don't want to mess with it. I've never heard of either of these libraries, so I don't know what the demand is for them.
If more Derelict users are interested in these two libraries than I'll see about incorporating them in to the trunk. |
|
Back to top |
|
|
clayasaurus
Joined: 21 May 2004 Posts: 857
|
Posted: Sun Nov 27, 2005 2:21 pm Post subject: |
|
|
While aldacron might not incorporate them officially, I still think it is worthwhile for you to post your code here, chances are some D user from the future will want to use it.
I would also like to draw your attention to another alternative, I just recently got RakNet working with D ( http://svn.dsource.org/projects/bindings/trunk/raknet/ ). RakNet is a pretty decent networking library, and I have samples (chat.d, line.d, lineserver.d) completed as well.
http://www.rakkarsoft.com for more information.
Happy Networking : )
~ Clay |
|
Back to top |
|
|
Crispy
Joined: 26 Nov 2005 Posts: 67
|
Posted: Mon Nov 28, 2005 12:31 am Post subject: |
|
|
Fair enough! They don't appear to be in widespread use, no; I just like the idea of using the event loop for networking. It means I don't have to touch threads myself but I still get all the benefits.
I'll just post them here for future reference then. They're nothing special (compiling the DLLs is actually the harder part, albeit less tedious ) but maybe I'll save someone some work.
RakNet looks interesting! I think I'll stick with NET2 now that I've started, but I'll definitely keep RakNet in mind for future projects. Thanks for the tip! It looks like it'd be a challenge to get it working under D, so nice job.
Anyway, here's the binding I wrote for NET2 in case some future searcher finds it useful:
Code: | module net2.net2;
/*
NET2 is a threaded, event based, network IO library for SDL.
Copyright (C) 2002 Bob Pendleton
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public License
as published by the Free Software Foundation; either version 2.1
of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA
If you do not wish to comply with the terms of the LGPL please
contact the author as other terms are available for a fee.
Bob Pendleton
Bob@Pendleton.com
*/
private
{
import derelict.sdl.sdl;
import derelict.sdl.net;
import derelict.util.loader;
}
//==============================================================================
// CONSTANTS
//==============================================================================
enum {
NET2_ERROREVENT,
NET2_TCPACCEPTEVENT,
NET2_TCPRECEIVEEVENT,
NET2_TCPCLOSEEVENT,
NET2_UDPRECEIVEEVENT,
}
//==============================================================================
// FUNCTIONS
//==============================================================================
extern(C)
{
typedef int function() pfNET2_Init;
typedef void function() pfNET2_Quit;
pfNET2_Init NET2_Init;
pfNET2_Quit NET2_Quit;
typedef int function(SDL_Event*) pfNET2_GetEventType;
typedef int function(SDL_Event*) pfNET2_GetSocket;
typedef int function(SDL_Event*) pfNET2_GetEventData;
pfNET2_GetEventType NET2_GetEventType;
pfNET2_GetSocket NET2_GetSocket;
pfNET2_GetEventData NET2_GetEventData;
typedef char* function() pfNET2_GetError;
typedef char* function(SDL_Event*) pfNET2_GetEventError;
pfNET2_GetError NET2_GetError;
pfNET2_GetEventError NET2_GetEventError;
typedef int function(IPaddress*, char*, int) pfNET2_ResolveHost;
pfNET2_ResolveHost NET2_ResolveHost;
typedef int function(int) pfNET2_TCPAcceptOn;
typedef int function(IPaddress*) pfNET2_TCPAcceptOnIP;
typedef int function(char*, int) pfNET2_TCPConnectTo;
typedef int function(IPaddress *ip) pfNET2_TCPConnectToIP;
typedef void function(int) pfNET2_TCPClose;
typedef int function(int, char*, int) pfNET2_TCPSend;
typedef int function(int, char*, int) pfNET2_TCPRead;
typedef IPaddress* function(int) pfNET2_TCPGetPeerAddress;
pfNET2_TCPAcceptOn NET2_TCPAcceptOn;
pfNET2_TCPAcceptOnIP NET2_TCPAcceptOnIP;
pfNET2_TCPConnectTo NET2_TCPConnectTo;
pfNET2_TCPConnectToIP NET2_TCPConnectToIP;
pfNET2_TCPClose NET2_TCPClose;
pfNET2_TCPSend NET2_TCPSend;
pfNET2_TCPRead NET2_TCPRead;
pfNET2_TCPGetPeerAddress NET2_TCPGetPeerAddress;
typedef int function(int, int) pfNET2_UDPAcceptOn;
typedef void function(int) pfNET2_UDPClose;
typedef int function(IPaddress*, char*, int) pfNET2_UDPSend;
typedef UDPpacket* function(int) pfNET2_UDPRead;
typedef void function(UDPpacket*) pfNET2_UDPFreePacket;
pfNET2_UDPAcceptOn NET2_UDPAcceptOn;
pfNET2_UDPClose NET2_UDPClose;
pfNET2_UDPSend NET2_UDPSend;
pfNET2_UDPRead NET2_UDPRead;
pfNET2_UDPFreePacket NET2_UDPFreePacket;
} // extern(C)
//==============================================================================
// LOADER
//==============================================================================
private SharedLib libSDLNET2;
private void* getProc(char[] procName)
{
return Derelict_GetProc(libSDLNET2, procName);
}
private void load()
{
NET2_Init = cast(pfNET2_Init)getProc("NET2_Init");
NET2_Quit = cast(pfNET2_Quit)getProc("NET2_Quit");
NET2_GetEventType = cast(pfNET2_GetEventType)getProc("NET2_GetEventType");
NET2_GetSocket = cast(pfNET2_GetSocket)getProc("NET2_GetSocket");
NET2_GetEventData = cast(pfNET2_GetEventData)getProc("NET2_GetEventData");
NET2_GetError = cast(pfNET2_GetError)getProc("NET2_GetError");
NET2_GetEventError = cast(pfNET2_GetEventError)getProc("NET2_GetEventError");
NET2_ResolveHost = cast(pfNET2_ResolveHost)getProc("NET2_ResolveHost");
NET2_TCPAcceptOn = cast(pfNET2_TCPAcceptOn)getProc("NET2_TCPAcceptOn");
NET2_TCPAcceptOnIP = cast(pfNET2_TCPAcceptOnIP)getProc("NET2_TCPAcceptOnIP");
NET2_TCPConnectTo = cast(pfNET2_TCPConnectTo)getProc("NET2_TCPConnectTo");
NET2_TCPConnectToIP = cast(pfNET2_TCPConnectToIP)getProc("NET2_TCPConnectToIP");
NET2_TCPClose = cast(pfNET2_TCPClose)getProc("NET2_TCPClose");
NET2_TCPSend = cast(pfNET2_TCPSend)getProc("NET2_TCPSend");
NET2_TCPRead = cast(pfNET2_TCPRead)getProc("NET2_TCPRead");
NET2_TCPGetPeerAddress = cast(pfNET2_TCPGetPeerAddress)getProc("NET2_TCPGetPeerAddress");
NET2_UDPAcceptOn = cast(pfNET2_UDPAcceptOn)getProc("NET2_UDPAcceptOn");
NET2_UDPClose = cast(pfNET2_UDPClose)getProc("NET2_UDPClose");
NET2_UDPSend = cast(pfNET2_UDPSend)getProc("NET2_UDPSend");
NET2_UDPRead = cast(pfNET2_UDPRead)getProc("NET2_UDPRead");
NET2_UDPFreePacket = cast(pfNET2_UDPFreePacket)getProc("NET2_UDPFreePacket");
}
public void DerelictSDLNET2_Load(char[] libName)
{
if(libSDLNET2 !is null)
return;
libSDLNET2 = Derelict_LoadSharedLib(libName);
load();
}
public void DerelictSDLNET2_Load()
{
version(Windows)
DerelictSDLNET2_Load("net2.dll");
version(linux)
DerelictSDLNET2_Load("libnet2.so");
}
public void DerelictSDLNET2_Unload()
{
Derelict_UnloadSharedLib(libSDLNET2);
}
static ~this()
{
DerelictSDLNET2_Unload();
} |
I've been using this and the FastEvents code above for a few days now and they're working pretty well so far. FastEvents dropped right in without a hitch, and NET2 provides just enough abstraction to keep me happy. |
|
Back to top |
|
|
aldacron
Joined: 05 May 2004 Posts: 1322 Location: Seoul, South Korea
|
Posted: Mon Nov 28, 2005 4:42 am Post subject: |
|
|
You know, these libs are small enough that it might be worthwhile porting them to D. The only real problem with that is the LGPL, as it would still require dynamic libraries to avoid open sourcing an entire app. |
|
Back to top |
|
|
Crispy
Joined: 26 Nov 2005 Posts: 67
|
Posted: Mon Nov 28, 2005 6:10 pm Post subject: |
|
|
Mmm. You would probably need to include instructions on how to compile the shared libraries; it's not hard if you know what you're doing, but if you don't... well, let's just say I had to fix a few compiler errors. (Mostly complaining about implicit casts that MingW doesn't allow. Some of them were coming from the middle of a giant macro-used-as-a-template.)
Alternatively, the distribution could include a "fixed" version of the source with Windows and Linux binaries. That would probably be the way to do it. |
|
Back to top |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|