Thread: My Mud

  1. #1
    Registered User
    Join Date
    Jan 2003
    Posts
    21

    My Mud

    Is pretty much a disaster zone at the moment and its not really code issues im having problems with its more Concept issues.

    This post could really fit into Network Board, Game Board and Linux Board so if the moderators feel it should be moved then by all means please do.

    Im posting because im hoping there someone out there who has wrote a little mud and could help me out. Ive looked everywhere for basic MUD Tutorials but it seems like majority of people use existing codebases and I cant learn too much from them as they are way more advanced than my simple mud and it would destroy the point of trying to write my own.

    Ok well it all started out good, I wrote the server based on the "select" C function and was allowing characters who connected to move around from room to room using a MySQL backend database. They could talk to each other, etc etc.

    Then I decided I would try and add some combat routines to give the characters something to do, this is where my probs have started.

    I was storing the incoming data in a struct and passing a pointer of it into a function to process and perform various tasks. Anyway once someone started a combat scenario the loop would freeze everyone else up until the combat was over, I posted a question on this in the windows section and was told by a guy called Adrian about threads etc. anyway i got that to work in a little test on a windows machine and figured the same logic would apply to linux and I discovered pthread_create. Thinking this would fix my problem i changed the code to start a new thread on a combat request, and great it worked people could talk and see the combat at the same time.. until i had someone else started a combat loop they "stole" the other persons thread and got their data returned to them aswell, all started getting really messy.

    Ok so i checked out some mud codebases and they looked uber complex to me but they all didnt seem to use pthread and instead used "forks" and had the MUD update every 1 second which would send out all the data it needed to every second, im not sure if this is a bad way to write a mud or exactly how a fork is different to a thread.

    I realise i need to implement some kind of timer system so that monsters dissapear for a while and then respawn after x amount of time so i dont think my current structure will work here.

    Seems to me i just need something like

    StartMud()
    .. some kind of timer loop
    .. process mud every second
    .. check for respawns, send out data to clients.
    EndMud()

    gah ive just re-read this and I know its a real ramble but im in desperate need of some structure ideas and perhaps some pointers as to what the basic concept of how a mud loops is.

    im not asking for code as im more than happy to try and learn myself but even if you know of any tutorials that would help as all I can find after hours of google searching is just code bases.

    thanks in advance and sorry for the rambling

    mrpickle.

    edit: i realise i have bitten off more than i can chew here but im determined to carry on and try and accomplish something
    Last edited by mrpickle; 12-29-2003 at 09:00 AM.

  2. #2
    Registered User
    Join Date
    Jul 2003
    Posts
    450
    Good luck I think this should probably be in the linux forum.

    Sounds like you need to lock access to your data somehow as you would do in windows when using threads.

    Sorry I can't offer anymore advice as I am pretty ignorant about threads especially in linux, but I hope to educate myself as to their nuances in the near future so I hope you get a decent reply to your post.

  3. #3
    mov.w #$1337,D0 Jeremy G's Avatar
    Join Date
    Nov 2001
    Posts
    704
    This is very much a game programming topic, it deals with structure of a game.


    It sounds like you are only using one thread for combat, if this is the case I think you need to resort to multithreading. New combatents should be creating their own thread, not sharing an existing one.

    Lemme see if I can explain a suitable structure. This will be one option of several possibilities.

    Consider the main game loop:
    --check the time and deal with any time oriented functionality
    .....spawns[monsters,items], penalties[poisen,antidotes,damage over time]
    --handle registered commands from users
    .....move commands, fight commands, item commands

    These two things are must do's every loop of the game.
    I'll start in reverse order for explination.

    In tandem with this loop you should have a thread running for your winsock component. It's task is to constantly listen from incomming data, when an incoming data is detected a new thread should be spawned to handle the data, structure(de) it and *pop it on the register stack*, when that is completed the thread process should end(destroyed).

    The stack is your datastructure that you should use to store all the messages/commands sent by users. A (simple)example of the structure may look like this:
    Code:
    int stacks;// current ammount of stack commands
    bool locked;  // being accessed by a thread to be updated?
    struct sSTACK {
         char* cmdString; // the command/chat/whatever sent by user
         int connectionId; // the user who sent it
    };
    sSTACK theStack[100]; // stack
    When a thread is recieved the data, and made sure its complete and not corrupted it goes into a thread wait, until the locked variable is false, then immediatly sets it to true, and adds the information to the top of the stack. Now to insure that this goes un-interupted you have to set whats called "critical data section". Its the part of the thread that cannot be interupted, must be completed before a new task can run. Your data manipulation is always in critical area. Im pretty sure this is the same thing has having a lock variable, but Im not sure, i threw that in there to be on the safe side.


    In the main loop (thread) we handle the registered commands, these are the commands that are currently on the stack, not including any commands currently being handled by other threads. Again, we enter the critical section area to parse the complete stack, taking care of all the commands, and reseting the stack to zero(empty). then we leave the critical section to perform the other main loop tasks (at this points the other threads--that have been waiting to update the stack, can now resume registering their data).

    When you are handling the commands from the stack, when you run into a combat command or any other command that requires a lot of focus, you spawn a new thread speciffically to handle that event. When ever you start to manipulate the player information (health, item count etc) you make sure you enter the critical section to insure un-interupted data manipulation, then exit that section immediatly. Remember your thread is not suppose to be one huge critical section, critical sections should be as small as possible to prevent hang ups. Only enter the section to manipulate data.

    In the main thread simultaniously you will be handling timing events, such as spawns and damage over time(DOT may actually be done in the fighting loop for related illness, but effects that act outside of the initial combat will need to be dealt with globaly). You may want to make a stack for DOT's and other time oriented events to hold whos being affected, for what, how often, when there time penalty has been played, they are removed from the time stack, and the stack is shuffled appropriatly. When ever you are modifing the data in a thread, you must enter crtical section!



    I hope that can help you a bit.
    c++->visualc++->directx->opengl->c++;
    (it should be realized my posts are all in a light hearted manner. And should not be taken offense to.)

  4. #4
    Registered User
    Join Date
    May 2003
    Posts
    161
    I just wanted to point out that I've disected quite a few mud sources and I've never seen a robust multi-threaded mud. Quite simply, there are too many interactions going on at once to handle every possible race condition.

    As for your combat problem.. you need to make combat run on "ticks". Don't run the entire sequence in one function. Perhaps you could add some sort of callback system where you can register functions with time delays and have them called from your main loop.

    So your combat could look something like this:
    Code:
    void
    do_combat(void* data)
    {
      attack_data* ad = (attack_data*)data;
      CHAR* attacker = ad->attacker;
      CHAR* victim = ad->victim;
    
      /* do one round of attack */
    
      /* re-register so it is called again */
      register_callback(do_combat, ad, 3);
    }
    
    void
    enter_combat(CHAR* attacker, CHAR* victim)
    {
      attack_data* ad = malloc(sizeof(attack_data));
      ad->attacker = attacker;
      ad->victim = victim;
      register_callback(do_combat, ad, 3);
    }
    Obviously, register_callback() would take a function pointer of type void func(void*), a void* data parameter, and a number of seconds for delay. It would store the data in a linked list, traverse it every few loop cycles, and execute the functions that have met the specified delay. You could also use this type of callback system for any other necessary timers in your mud.

    Hope that helps.

    -tf

  5. #5
    If you want a good tutorial pick up the book MUD Game Programming by Ron Penton.

  6. #6
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    I've not coded any MUDs but it sounds like your battles must finish entirely before someone else can initiate one. Thus only one battle can take place at any one time which is why people can interrupt another battle with theirs.

    The ticks idea is great. Since your task is going to be switched about a zillion times using threads and such, you must change your thinking into slices rather than the whole.

    But to do this you must also keep track of each battle's progress and the variables associated with it. But, if you have one struct to define a battle sequence then a simple array or linked list of these structures would suffice. So when your thread or your battle gets the go ahead from Windows - execute one slice of the battle, save its state, and then Windows will time slice to another thread.

    It sounds like you also might need to mutex a battle sequence or place a semaphore that indicates that battle cannot be touched until it is over. A semaphore could be a simple variable that indicates whether or not a current battle is executing. Check with Test() and set the variable with Set(). You can also do TestAndSet(), etc.

    Another thing that you might want to do is have several battle 'slots' sitting out there like an array or something. When that slot becomes active hence a battle has been initiated and your code has selected an empty battle slot - then you can iterate through the battle's every frame of the game or every tick - or whatever time slice you decide. In this way each battle would be updated correctly.

    Code:
    if (NewBattle)
    ...find empty battle slot
    ...activate slot
    fi
    
    for (int i=0;i<TotalBattlesInWorld;i++)
    {
      if (Battles[i].IsActive())
      {
          ....Load battle states/variables from Battles[]
          ....Run code for battle with state info - one slice of time
          ....Transfer new character states to respectable players
          ....Save all new states in Battles[]
       }
    }
    Or something like that.

  7. #7
    Registered User
    Join Date
    Feb 2002
    Posts
    465
    my primary language is C++, and i can only assume that since you are on the cprogramming boards you write in either C or C++.

    the most simple solution i can think of, from an object-oriented standpoint, is to have each player contain a state and a pointer to a "target" that is anything that is attackable.

    for a sort of pseudo-code:

    Code:
    class Player
    { 
       int state, damage;
       Target *target;
    };
    and every loop check the player's state. if they are attacking, deal their damage to their target and the continue the game loop

    Code:
    switch (Player.state)
    {
    case ATTACKING:
      Player.target->ApplyDamage(Player.damage);
    // ...
    }
    its late and maybe i missed the point of the question, but i hope that helped some.
    I came up with a cool phrase to put down here, but i forgot it...

  8. #8
    Registered User
    Join Date
    Jan 2003
    Posts
    21
    Hi all,

    Thanks for all your suggestions, I think i will experiment with the "tick" concept as it seems a little easier than the thread concept. One thing I have realised since reading these replies is that to do this correctly is alot more difficult that I initially thought.

    Anyway ill try the ticks method and post here if I get stuck. Thanks again for all your ideas and responses.

    MrPickle.

  9. #9
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Most muds aren't multithreaded. The reason being, for the most part, there is no point in having multiple threads. Combat (Diku and kin) is done like in rounds. In a given round of combat you get N amount of actions done. Usually, you do like one spell, a kick, a few attacks. That sort of thing.

    You may also want to consider using an event queue. This way you only have to run through the events scheduled for this time through the loop.

    Basicly you just schedule the event to take place N pulses into the future, and when that time happens, assuming nothing has prevented the action, it takes place.

    Example: I swing a sword, it schedules it to strike later in this same pulse. It strikes, it schedules damage to occur later in this same pulse. I cast a spell that takes some time, it schedules it to trigger say two pulses down the road, and I'm set in a 'casting' state or something.

    The only time multithreading is usually used is for the host lookup. Basicly so when you log in, it doesn't lag the whole mud while it tries to gethostbyname() or whatever.

    Everything else is usually done in one big loop.

    Quzah.
    Hope is the first step on the road to disappointment.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Seeking Head Coder for MUD Partnership
    By Draconar in forum Projects and Job Recruitment
    Replies: 0
    Last Post: 06-25-2006, 04:05 PM
  2. MUD.. telnet problems.
    By dizolve in forum Game Programming
    Replies: 0
    Last Post: 10-13-2001, 02:06 PM
  3. MUD Programming: Combat
    By dizolve in forum C++ Programming
    Replies: 5
    Last Post: 10-12-2001, 10:14 AM