FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

FastEvents and NET2 libraries

 
Post new topic   Reply to topic     Forum Index -> Derelict
View previous topic :: View next topic  
Author Message
Crispy



Joined: 26 Nov 2005
Posts: 67

PostPosted: Sat Nov 26, 2005 12:54 am    Post subject: FastEvents and NET2 libraries Reply with quote

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. Smile

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. Very Happy

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. Smile
Back to top
View user's profile Send private message
aldacron



Joined: 05 May 2004
Posts: 1322
Location: Seoul, South Korea

PostPosted: Sat Nov 26, 2005 9:36 pm    Post subject: Reply with quote

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
View user's profile Send private message Send e-mail
clayasaurus



Joined: 21 May 2004
Posts: 857

PostPosted: Sun Nov 27, 2005 2:21 pm    Post subject: Reply with quote

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
View user's profile Send private message AIM Address
Crispy



Joined: 26 Nov 2005
Posts: 67

PostPosted: Mon Nov 28, 2005 12:31 am    Post subject: Reply with quote

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. Wink

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 Smile) 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. Smile

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. Razz
Back to top
View user's profile Send private message
aldacron



Joined: 05 May 2004
Posts: 1322
Location: Seoul, South Korea

PostPosted: Mon Nov 28, 2005 4:42 am    Post subject: Reply with quote

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
View user's profile Send private message Send e-mail
Crispy



Joined: 26 Nov 2005
Posts: 67

PostPosted: Mon Nov 28, 2005 6:10 pm    Post subject: Reply with quote

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
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic     Forum Index -> Derelict All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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