<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook V4.1//EN" [
 <!ENTITY copyrightDates '2000,2001'>
 <!ENTITY % METACOSM SYSTEM "../en.metacosm.ent">
 %METACOSM;
]>

<article lang="EN">
  <articleinfo>
    <title>RFC - Game loop</title>
    <corpauthor>&author;</corpauthor>
     <revhistory>
      <revision>
        <revnumber>0.1</revnumber>
        <date>April, 15th 2000</date>
        <authorinitials>Elkine, Horus, Ruffy</authorinitials>
      </revision>
    </revhistory>
    <abstract>
      <simpara>The goal of this document is to define the algorithm used in the main loop
      of the game server in Metacosm project.</simpara>
    </abstract>
  </articleinfo>

&license;
&project;

<sect1>
<title>Why turns?</title>
  <para>Let's begin with a fact: about all the RPG or MUD use turn-based system. There are
  few exceptions (like the Amber&trade; RPG for example).</para>

  <para>Turn-based means synchronous system and non turn-based asynchronous system.</para>

  <para>Asynchronous systems are a mess to manage. They are hard to code and even more 
  hard to understand when they run. Nevertheless, they seem closest to our perception of
  reality. It's also more flexible (at least because synchronous systems are a sub-class
  of asynchronous ones) and it's said quite adapted to object designed entities (like
  distributed agents behavior). 

  <para>Synchronous systems are easy to implement a coherent and persistent time system.
  They are compliant to the largest number of RPG systems. They are better for equity
  between players (connection speed or lag are less important), and between players and AI
  (reacting faster than a one million times faster AI is really hard). They also have a
  high reliability.</para>

  <para>It can seem that a turn-based system will be more complex to set up than an
  event-driven one, but that's only at the beginning. Dealing with asynchronicity will
  require to put more safeguards, and it will become more difficult to foresee what
  could possibly happen. We are here talking of thousands of Entities here, not just
  five or ten, and the complexity'll reach an unmanageable threshold.</para>

  <para>For all there reasons, we choose, at least for now, to use a turn-based system.
  </para>
</sect1>

<sect1>
<title>Turn notion</title>
  <para>The turn is the smallest time unit. Each action duration is a multiple of
  this unit. Actions have a default duration. An action can be interrupted at
  each turn.</para>

  <para>The turn has a duration (TURN_DURATION), but there is no guarantee this duration
  will be respected. if it doesn't, an error is logged.</para>
</sect1>

<sect1>
<title>Interruption of actions series</title>
  <para>A special keyword can be used to interrupt the current action and to flush the
  actions buffer. The I/O thread receives it and purges the actions buffer of the
  Player. At the next turn, the current action (if there is any) will be
  interrupted.</para>
</sect1>

<sect1>
<title>I/O thread</title>
  <para>The I/O thread manages connections with Players (input from Players and outputs
  to Players). It also deals with spam. Commands sent are immediately executed for
  social commands (discussions outside the game) or actions outside the game
  (exit, reading help, etc), or stored in a buffer and delayed. This is this
  buffer that can be purged.</para>
</sect1>

<sect1>
<title>The raw algorithm</title>
  <para>
<programlisting>
while the game is not stopped
  // Order for acting
  sort Players/Controllers by priority

  // Actions
  for each Player/Controller
    if command available
      execute the command
      resolve action (can throw some Stimuli and Events)
    else
      do nothing


  // StimuliDispatchers
  for each StimuliDispatcher
    send Stimuli to its listeners
    
  // EventsDispatchers
  for each EventsDispatcher
    send Events to its listeners

  // Plan new actions
  // nc = number of Controllers
  // X  = number of threads for planning
  for i from 1 to (nc div X)
    for j from 1 to N
      start thread j with Controller (i * X + j) as parameter
      wait THREAD_DURATION or all threads finish
      for each thread
        if unfinished
          stop thread
          log error for Controller
          Controller does nothing next turn
  do the same thing for (nc mod X) remaining Controllers

  // End of turn
  log if turn duration is greater than TURN_DURATION
  wait some time if necessary to make the turn duration equal to TURN_DURATION
</programlisting>
</sect1>

<sect1>
<title>Order for acting</title>
  <para>We can use the Reaction capability defined in Entity-RFC. The most you have,
  the more quickly you act.</para>
</sect1>

<sect1>
<title>Actions</title>
  <para>At its reaction level, the current action of a Controller is executed. Command
  name, source and target entities, and parameters are used to resolve the action.
  It can throw some Stimuli and/or Events.</para>
</sect1>

<sect1>
<title>StimuliDispatchers</title>
  <para>StimuliDispatchers collect Stimuli during actions resolution phase, and send
  expected Stimuli to their listeners.</para>
</sect1>

<sect1>
<title>EventsDispatchers</title>
  <para>EventsDispatchers collect Events during actions resolution phase, and send
  expected Events to their listeners.</para>
</sect1>

<sect1>
<title>Action planning</title>
  <para>Each Controller determines its action for the next turn in function of its own
  memory, of its last actions, of the received Stimuli and Events and sometimes
  of randomness. It has only a limited time (THREAD_DURATION) to do it. If it
  doesn't respect this limit, we suppose it went into trouble and decide it does
  nothing next turn.</para>

  <para>To quicken this part, we use several threads in parallel. We use X threads, so
  we group Controllers by X and the remaining will be treated at the end.
  For each group of Controllers, we link one Controller with each thread (passed
  as parameter), start the thread (it'll call the Controller method to determine
  next action).</para>

  <para>The main loop thread will wait until the THREAD_DURATION or the end of all
  threads (we can use a periodic check). If some threads are not finished, we stop
  them, log the error and decide the Controller will do nothing next turn.</para>
</sect1>

<sect1>
<title>End of turn</title>
  <para>If the turn duration is greater than TURN_DURATION, an error is logged.
  If the turn duration is lesser than TURN_DURATION, we'll wait a bit more.
  It the turn duration is equal to the TURN_DURATION, damn' we have the
  force with us! (or perhaps we cheat... :)</para>
</sect1>

<sect1>
<title>How to choose TURN_DURATION and THREAD_DURATION?</title>
  <para>These two values are highly important. They determine how much time the good guy
  in front of a display will wait...</para>

  <para>It can be fixed values.</para>

  <para>Perhaps it's better to determine them dynamically to avoid spam with log errors...
  We can use a checker which will count errors and increase TURN_DURATION and/or
  THREAD_DURATION to decrease the errors number. Sometimes, if there are no error
  during some time (NO_ERROR_DURATION :o) ), we can decrease these numbers (after
  a high overload for example, or if many Controllers disappear). It can be a good
  method to adapt the game to an overloaded machine or to calibrate automatically
  the game for the machine.</para>

  <para>Joke: can we have a vicious enough guy which will implement this type of vicious
  bot: the bot do nothing except writing the time spent since its turn activation. So
  the next time, this bot knows the value of THREAD_DURATION. So it can optimize
  and use always the max duration to think about what it can do.
  And even the worst idea: the bot really does nothing. So it creates an error and
  the THREAD_DURATION will increase. But it continues to do nothing... DoS</para>

  <para>To avoid these values become too high (really slow game, too slow so unfriendly
  for Players) or too low (really quick game, too quick for Players, bots will be
  like Superheroes for Players and move like Flash (do you imagine the scene? A
  bot (let's call it Stanley Ipkins) can put your underpants on your head before
  you can react :) ), we should bound these values (MIN_THREAD_DURATION,
  MAX_THREAD_DURATION, MIN_TURN_DURATION and MAX_TURN_DURATION).</para>

  <para>The MAX_* and MIN_* values are the max and min acceptable values for Players.</para>

  <para>And no, we won't use a MIN_MIN_TURN_DURATION, a MAX_MIN_TURN_DURATION, ... :p</para>

</article>