Login
User Name:

Password:



Register

Forgot your password?
Changes list / Addchange
Author: Khonsu
Submitted by: Khonsu
6Dragons mp3 sound pack
Author: Vladaar
Submitted by: Vladaar
AFKMud 2.2.3
Author: AFKMud Team
Submitted by: Samson
SWFOTEFUSS 1.5
Author: Various
Submitted by: Samson
SWRFUSS 1.4
Author: Various
Submitted by: Samson
Users Online
AhrefsBot, Yandex

Members: 0
Guests: 36
Stats
Files
Topics
Posts
Members
Newest Member
488
3,788
19,631
595
Khonsu

Today's Birthdays
There are no member birthdays today.
» SmaugMuds » Codebases » SWR FUSS » Game_loop
Forum Rules | Mark all | Recent Posts

Game_loop
< Newer Topic :: Older Topic >

Pages:<< prev 1, 2 next >>
Post is unread #1 Feb 9, 2010 6:29 pm   
Go to the top of the page
Go to the bottom of the page

Keirath
Magician
GroupMembers
Posts148
JoinedJan 24, 2008

 
I'm going through trying to clean up game_loop and I really like how AFK does things. Particularly this:
 if( dlist.size(  ) > 0 )
         process_input(  );


I was curious as to if there was any way to do this in C - particularly SWR?

Post is unread #2 Feb 9, 2010 8:35 pm   
Go to the top of the page
Go to the bottom of the page

InfiniteAxis
Off the Edge of the Map
GroupAdministrators
Posts1,200
JoinedMar 21, 2006

 
Nope, because that's using std::list.

C doesn't have that. Gotta be C++

There might be an extremely ugly way to pull it off using the C Linked lists, but it's not going to look clean like that.

Post is unread #3 Feb 9, 2010 8:36 pm   Last edited Feb 9, 2010 8:38 pm by Andril
Go to the top of the page
Go to the bottom of the page

Andril
Magician
GroupMembers
Posts147
JoinedJun 9, 2009

 
Why not do a check against maxdesc > 0?

Post is unread #4 Feb 9, 2010 8:41 pm   
Go to the top of the page
Go to the bottom of the page

Keirath
Magician
GroupMembers
Posts148
JoinedJan 24, 2008

 
Is it possible to add std::list without a full conversion to C++?

I'm not QUITE ready to do the full conversion until I understand a bit more.

Post is unread #5 Feb 9, 2010 8:45 pm   
Go to the top of the page
Go to the bottom of the page

InfiniteAxis
Off the Edge of the Map
GroupAdministrators
Posts1,200
JoinedMar 21, 2006

 

Keirath said:

Is it possible to add std::list without a full conversion to C++?

I'm not QUITE ready to do the full conversion until I understand a bit more.


Yes. You merely need to be compiling using g++ to use the STL. However, it is highly recommended that anything using a member of the STL use new/delete and have an appropriate constructor/destructor to avoid.. complications.

Post is unread #6 Feb 9, 2010 9:15 pm   
Go to the top of the page
Go to the bottom of the page

Keirath
Magician
GroupMembers
Posts148
JoinedJan 24, 2008

 
Right, I can handle that. Thanks.

Post is unread #7 Feb 10, 2010 10:08 am   
Go to the top of the page
Go to the bottom of the page

Keirath
Magician
GroupMembers
Posts148
JoinedJan 24, 2008

 
Well, I'm thinking I'm just going to attempt to convert SWR1.3FUSS to C++. I figure why not. I'm not running an active MUD and am just programming for the heck of it right now. With hopes of sometime opening one in the future (who knows). So, I know Samson did this with AFK and some others have done this. Where should I start? Some pointers would be great.

Post is unread #8 Feb 10, 2010 10:26 am   Last edited Feb 10, 2010 10:29 am by Kayle
Go to the top of the page
Go to the bottom of the page

InfiniteAxis
Off the Edge of the Map
GroupAdministrators
Posts1,200
JoinedMar 21, 2006

 
You should start by not doing what I did with MW. Which was, pick a struct, convert it to a class and then proceed to completely encapsulate it. That was a nightmare. [Edit:] Don't get me wrong, now that it's done it's beautiful. The act of getting to that point was horrible. It took close to three weeks to completely finish encapsulating it. And I mean completely. Most every function that took CHAR_DATA as the only argument was turned into a member function. Everything was replaced with get/set functions. Completely encapsulated. Nightmare. Total Nightmare. You never really understand the term "spaghetti code" until you attempt this...

The easiest way to start is to figure out what should/shouldn't be a class over a struct. Once you know, change them. Give them constructors/destructors. Make sure the c'tor/d'tor work fine. Test for memory issues, and then move to the next class. Once you've got those figured out, the next step would be to pick a part of the STL and apply it.

However, if there's one thing I've learned in the... 3 times I've done this process so far. Only convert what you're working on. Unless your goal is to simply convert the entire codebase to use the STL, in which case, start with what you know, and work from there.

There are several things to keep in mind as well. Certain converstions (std::bitset comes to mind) may require rewriting the way things are handled in the core (affects comes to mind...) because of how things were originally designed. You have to keep in mind that these bases were not designed with C++, the STL, or Object Oriented programming in mind. Converting these bases to C++ is a massive undertaken, and not one that should be taken lightly.

Also worth noting is that AFKMud never completely converted to using the STL. I believe Samson only finished a third or so of the std::string replacement.

Post is unread #9 Feb 10, 2010 10:43 am   
Go to the top of the page
Go to the bottom of the page

Keirath
Magician
GroupMembers
Posts148
JoinedJan 24, 2008

 
I think I'm going to go the route of converting what I'm working on. I guess the first step would be descriptor_data since that is where I am.

Sadlly, the point I'm at it seems like it would be smarter to rip AFK down to what I want it to be. So I'm not sure. We'll see.

Post is unread #10 Feb 10, 2010 10:44 am   
Go to the top of the page
Go to the bottom of the page

InfiniteAxis
Off the Edge of the Map
GroupAdministrators
Posts1,200
JoinedMar 21, 2006

 
Learn more by doing it yourself. But keep constant backups.

Post is unread #11 Feb 10, 2010 10:57 am   
Go to the top of the page
Go to the bottom of the page

Keirath
Magician
GroupMembers
Posts148
JoinedJan 24, 2008

 
Yeah, probably the better option.

I'm going to start by converting Descriptors to classes and then encapsulate it. I guess this is the best option, guess I have a lot of figuring out to do.

Post is unread #12 Feb 10, 2010 11:07 am   
Go to the top of the page
Go to the bottom of the page

Keirath
Magician
GroupMembers
Posts148
JoinedJan 24, 2008

 
Gah, I'm having trouble just getting std::list set up in descriptors, I'm going to have to read up on this before I try.

Post is unread #13 Feb 10, 2010 2:39 pm   
Go to the top of the page
Go to the bottom of the page

Samson
Black Hand
GroupAdministrators
Posts3,685
JoinedJan 1, 2002

 
It's also probably not a good idea to use what I've done in AFKMud as an example of the right way. Most of the work focused on "does it function" and not "is this clean and proper AND functions too". I also never went to the point of encapsulating everything, but there are plenty of things that have been.

If ever there was an incarnation of spaghetti code, I'd say AFKMud qualifies. It's some kind of mutated hybrid of C and C++. :)

Post is unread #14 Feb 10, 2010 2:57 pm   
Go to the top of the page
Go to the bottom of the page

Keirath
Magician
GroupMembers
Posts148
JoinedJan 24, 2008

 
Haha, well are there any bases that have done it the "right" way - or really any code examples or websites I should check? I am the type of person that learns by example. It's how I learned C. I am in the middle of converting descriptors to 'dlist' and so far I'm understanding everything. I know when I get into some other things it could be a pain.

Post is unread #15 Feb 10, 2010 5:38 pm   
Go to the top of the page
Go to the bottom of the page

InfiniteAxis
Off the Edge of the Map
GroupAdministrators
Posts1,200
JoinedMar 21, 2006

 
SocketMUD++ might be worth looking at. I can't recall off the top of my head, and I can't get to MudBytes atm because of a serialization issue in my database entry.

Post is unread #16 Feb 10, 2010 8:05 pm   
Go to the top of the page
Go to the bottom of the page

Keirath
Magician
GroupMembers
Posts148
JoinedJan 24, 2008

 
So, can you explain more about what you mean by the new/delete and the constructors/destructors? Do you mean that DESCRIPTOR_DATA needs that or just dlist?

Do I need to rework all of descriptor_data to classes and the likes and use stuff like that or what?

Post is unread #17 Feb 10, 2010 8:50 pm   
Go to the top of the page
Go to the bottom of the page

Andril
Magician
GroupMembers
Posts147
JoinedJun 9, 2009

 
In regards to the new/delete issue, I think he was saying that you need to make sure that anything created with new is removed using delete. Same thing with new[] and delete[]. It's similar to the STRALLOC/STRFREE vs str_dup/DELETE thing.

Check out this page for examples on using new and delete.

Post is unread #18 Feb 10, 2010 11:02 pm   
Go to the top of the page
Go to the bottom of the page

Samson
Black Hand
GroupAdministrators
Posts3,685
JoinedJan 1, 2002

 
new() and delete() are basically your substitutes for CREATE and DISPOSE for the actual structs.

You can also use new[] and delete[] on char* type strings within those structs, but it isn't strictly necessary.

If you're planning to use C++ STL code within things like descriptor_data then you can't keep using CREATE/DISPOSE on it or you'll crash the game.

Post is unread #19 Feb 11, 2010 11:38 am   
Go to the top of the page
Go to the bottom of the page

InfiniteAxis
Off the Edge of the Map
GroupAdministrators
Posts1,200
JoinedMar 21, 2006

 
Well, this might be a bit over the top for an example, but here we go anyway. This is a Socket class I wrote for Elysium.

/****************************************************************************
 *             ___________.__               .__                             *
 *             \_   _____/|  | ___.__. _____|__|__ __  _____                *
 *              |    __)_ |  |<   |  |/  ___/  |  |  \/     \               *
 *              |        \|  |_\___  |\___ \|  |  |  /  Y Y  \              *
 *             /_______  /|____/ ____/____  >__|____/|__|_|  /              *
 *                     \/      \/         \/     Engine    \/               *
 * ------------------------------------------------------------------------ *
 * Elysium Engine Copyright 1999-2010 by Steven Loar                        *
 * Elysium Engine Development Team: Kayle (Steven Loar)                     *
 * ------------------------------------------------------------------------ *
 *                           Socket Class Header                            *
 ****************************************************************************/

#ifndef __SOCKET_H__
#define __SOCKET_H__

#include 
#include "libtelnet.h"
#include "strings.h"

class Socket 
{
private:
   Socket( const Socket & ); //Unused, but declared and made private so that an error gets thrown if it's ever called by accident
   Socket &operator = ( const Socket & );   //Unused, but declared and made private so that an error gets thrown if it's ever called by accident

public:
   Socket( int desc ); //Constructor - called via new
   virtual ~Socket(  ); //Destructor - called via delete

   //Member functions - Done so that there can be error checking, etc, inside the class itself 
   //rather than in every function that tries to modify things
   Elysium::String getInBuffer( )                        const { return m_InBuffer; }
   int getControl( )                                     const { return m_Control; }
   void clearInBuffer(  )                                { m_InBuffer.erase( 0, m_InBuffer.length( ) ); }
   void writeTo( Elysium::String txt );
   bool readFrom(  );
   static void TelnetHandlerCallback( telnet_t *telnet, telnet_event_t *event, void *user_data );
   void HandleTelnetEvent( telnet_event_t *event ); 

//Member fields - Private so that they can't be modified directly.
private:
   int m_Control;
   Elysium::String m_InBuffer;
   telnet_t m_Telnet;
};

#endif


Alright, So then we have the actual functions:

/****************************************************************************
 *             ___________.__               .__                             *
 *             \_   _____/|  | ___.__. _____|__|__ __  _____                *
 *              |    __)_ |  |<   |  |/  ___/  |  |  \/     \               *
 *              |        \|  |_\___  |\___ \|  |  |  /  Y Y  \              *
 *             /_______  /|____/ ____/____  >__|____/|__|_|  /              *
 *                     \/      \/         \/     Engine    \/               *
 * ------------------------------------------------------------------------ *
 * Elysium Engine Copyright 1999-2010 by Steven Loar                        *
 * Elysium Engine Development Team: Kayle (Steven Loar)                     *
 * ------------------------------------------------------------------------ *
 *                           Socket Class Module                            *
 ****************************************************************************/


#include 
#include 
#include 
#include "socket.h"

static const telnet_telopt_t my_telopts[] = {
   { TELNET_TELOPT_ECHO,      TELNET_WILL, TELNET_DONT },
   { TELNET_TELOPT_TTYPE,     TELNET_WILL, TELNET_DONT },
   { TELNET_TELOPT_COMPRESS2, TELNET_WILL, TELNET_DO   },
   { TELNET_TELOPT_MSSP,      TELNET_WONT, TELNET_DO   },
   { TELNET_TELOPT_BINARY,    TELNET_WILL, TELNET_DO   },
   { TELNET_TELOPT_NAWS,      TELNET_WILL, TELNET_DONT },
   { -1, 0, 0 }
};

//Constructor - uses initializer list where applicable, initializes everything else in a regular way.
Socket::Socket( int desc ) : 
   m_Control( desc ) 
{
   memset( &m_Telnet, 0, sizeof( m_Telnet ) );
   telnet_init( &m_Telnet, my_telopts, &Socket::TelnetHandlerCallback, 0, this );
   telnet_negotiate( &m_Telnet, TELNET_WILL, TELNET_TELOPT_COMPRESS2 );
}

//Destructor - Handles closing the socket, and freeing all data that isn't simple data (int, double, etc) Also calls destructors for STL members.
Socket::~Socket( ) 
{
   if( m_Control != -1 )
      close( m_Control );
   telnet_free( &m_Telnet ); 
}

void Socket::TelnetHandlerCallback(telnet_t *telnet, telnet_event_t *ev, void *user_data) 
{ 
     static_cast(user_data)->HandleTelnetEvent( ev ); 
}

void Socket::HandleTelnetEvent( telnet_event_t *ev )
{
   switch( ev->type ) 
   {
      case TELNET_EV_DATA:
         m_InBuffer.append( ev->buffer, ev->size );
         break;
      case TELNET_EV_SEND:
	 writeTo( m_Control, ev->buffer, ev->size );
         break;
      case TELNET_EV_ERROR:
         //Really need to come up with some kind of error reporting/bug function...
         //fatal_error("TELNET error: %s", ev->buffer);
         break;
      default:
         break;
   }
}

bool Socket::readFrom( void )  
{ 
   char temp[4096]; 
   int size; 
  
   while( true ) 
   { 
      size = read( m_Control, temp, sizeof( temp ) ); 
  
      if( size > 0 ) {
         telnet_recv( &m_Telnet, temp, size ); 
      }
      else if ( size == 0 ) 
         break; 
      else if ( errno == EAGAIN ) 
         break; 
      else 
         return false; 
   } 
       
   return true; 
}

void Socket::writeTo( Elysium::String txt )  
{ 
	telnet_send( &m_Telnet, txt.c_str(), txt.length() ); 
}


Yes, I know it's not commented as well as it could be. But the whole thing is a work in progress. Anyway. If that makes sense, great. If not, well, when the cold medicine wears off I can try and explain it again. Or David can take a crack at it if he beats me to it.

Post is unread #20 Feb 12, 2010 8:14 am   
Go to the top of the page
Go to the bottom of the page

Keirath
Magician
GroupMembers
Posts148
JoinedJan 24, 2008

 
Well, 3 days into it I totally botched my conversion of descriptors to classes. I think I took on too much at once. I'm not discouraged though - learning so much it's well worth it.
One of the biggest problems I found was when something would be a string and was being passed to another. Is this just where I should just worry about changing to strings later and concentrate on just setting up the classes and getting rid of create dispose in exchange for new/delete.

Also, someone recently mentioned using std::vector for linked lists instead of std::list. Any thoughts on this? I'm not sure how I feel about that but wanted to see what people think.

Pages:<< prev 1, 2 next >>