text: //-----------------------------------------------------------------------------------
  //
  //   Torque Network Library
  //   Copyright (C) 2004 GarageGames.com, Inc.
  //   For more information see http://www.opentnl.org
  //
  //   This program is free software; you can redistribute it and/or modify
  //   it under the terms of the GNU General Public License as published by
  //   the Free Software Foundation; either version 2 of the License, or
  //   (at your option) any later version.
  //
  //   For use in products that are not compatible with the terms of the GNU 
  //   General Public License, alternative licensing options are available 
  //   from GarageGames.com.
  //
  //   This program 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 General Public License for more details.
  //
  //   You should have received a copy of the GNU General Public License
  //   along with this program; if not, write to the Free Software
  //   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  //
  //------------------------------------------------------------------------------------
  
  #ifndef _TNL_RPC_H_
  #define _TNL_RPC_H_
  
  #ifndef _TNL_NETEVENT_H_
  #include "tnlNetEvent.h"
  #endif
  
  #ifndef _TNL_METHODDISPATCH_H_
  #include "tnlMethodDispatch.h"
  #endif
  
  namespace TNL {
  
  /*! @page rpcdesc RPC in the Torque Network Library
  
  The Torque Network Library has a powerful, yet simple to use Remote
  Procedure Call framework for passing information through a network
  connection.  Subclasses of EventConnection and NetObject can declare
  member functions using the RPC macros so that when called the function 
  arguments are sent to the remote EventConnection or NetObject(s) associated
  with that object.
  
  For example, suppose you have a connection class called SimpleEventConnection:
  @code
  class SimpleEventConnection : public EventConnection
  {
  public:
     TNL_DECLARE_RPC(rpcPrintString, (StringPtr theString, U32 messageCount));
  };
  
  TNL_IMPLEMENT_RPC(SimpleEventConnection, rpcPrintString, 
     (StringPtr theString, messageCount), (theString, messageCount),
     NetClassGroupGameMask, RPCGuaranteedOrdered, RPCDirAny, 0)
  {
     for(U32 i = 0; i < messageCount; i++)
        printf("%s", theString.getString());
  }
   
   ...
  void somefunction(SimpleEventConnection *connection)
  {
     connection->rpcPrintString("Hello World!", 5);
  }
  @endcode
  
  In this example the class SimpleEventConnection is declared to have
  a single RPC method named rpcPrintString.  The TNL_DECLARE_RPC macro
  can just be viewed as a different way of declaring a class's member functions,
  with the name as the first argument and the parenthesized parameter list
  as the second.  Since RPC calls execute on a remote host, they never have
  a return value - although a second RPC could be declared to pass messages
  in the other direction.
  
  The body of the RPC method is declared using the TNL_IMPLEMENT_RPC macro,
  which has some additional arguments: the named parameter list without the types,
  which NetClassMask the RPC is valid in, what level of data guarantee it uses, 
  the direction it is allowed to be called on the connection and a version number.  
  The body of the function, which in this case prints the passed message "Hello, World!" 5 times
  to stdout, is executed on the remote host from which the method was originally invoked.
  
  As the somefunction code demonstrates, RPC's are invoked in the same way
  as any other member function in the class.
  
  RPCs behave like virtual functions in that their bodies can be overridden
  in subclasses that want to implement new behavior for the message.  The class
  declaration for an overridden RPC should include the TNL_DECLARE_RPC_OVERRIDE
  macro used for each method that will be redefined.  The TNL_IMPLEMENT_RPC_OVERRIDE
  macro should be used outside the declaration of the class to implement
  the body of the new RPC.
  
  Internally the RPC macros construct new NetEvent classes and encapsulate the
  function call arguments using the FunctorDecl template classes.  By default
  the following types are allowed as parameters to RPC methods:
  
   - S8, U8
   - S16, U16
   - S32, U32
   - F32
   - Int<>
   - SignedInt<>
   - Float<>
   - SignedFloat<>
   - RangedU32<>
   - bool
   - StringPtr
   - StringTableEntry
   - ByteBufferPtr
   - IPAddress
   - Vector<> of all the preceding types
  
  New types can be supported by implementing a template override for the
  Types::read and Types::write functions.  All arguments to RPCs must be
  passed by value (ie no reference or pointer types).
  
  The Int, SignedInt, Float, SignedFloat and RangedU32 template types use the
  template parameter(s) to specify the number of bits necessary to transmit that
  variable across the network.  For example:
  
  @code
    ...
   TNL_DECLARE_RPC(someTestFunction, (Int<4> fourBitInt, SignedFloat<7> aFloat, 
      RangedU32<100, 199> aRangedU32);
    ...
  @endcode
  The preceding RPC method would use 4 + 7 + 7 = 18 bits to transmit the arguments
  to the function over the network, not including the RPC event overhead.
  */
  
  /// Enumeration for valid directions that RPC messages can travel
  enum RPCDirection {
     RPCDirAny            = NetEvent::DirAny,           ///< This RPC can be sent from the server or the client
     RPCDirServerToClient = NetEvent::DirServerToClient,///< This RPC can only be sent from the server to the client
     RPCDirClientToServer = NetEvent::DirClientToServer,///< This RPC can only be sent from the client to the server
  };
  
  /// Type of data guarantee this RPC should use
  enum RPCGuaranteeType {
     RPCGuaranteedOrdered = NetEvent::GuaranteedOrdered, ///< RPC event delivery is guaranteed and will be processed in the order it was sent relative to other ordered events and RPCs
     RPCGuaranteed        = NetEvent::Guaranteed,        ///< RPC event delivery is guaranteed and will be processed in the order it was received
     RPCUnguaranteed      = NetEvent::Unguaranteed       ///< Event delivery is not guaranteed - however, the event will remain ordered relative to other unguaranteed events
  };
  
  /// Macro used to declare the implementation of an RPC method on an EventConnection subclass.
  ///
  /// The macro should be used in place of a member function parameter declaration,
  /// with the body code (to be executed on the remote side of the RPC) immediately
  /// following the TNL_IMPLEMENT_RPC macro call.
  #define TNL_IMPLEMENT_RPC(className, name, args, argNames, groupMask, guaranteeType, eventDirection, rpcVersion) \
  class RPC_##className##_##name : public TNL::RPCEvent { \
  public: \
     TNL::FunctorDecl<void (className::*) args > mFunctorDecl;\
     RPC_##className##_##name() : TNL::RPCEvent(guaranteeType, eventDirection), mFunctorDecl(&className::name##_remote) { mFunctor = &mFunctorDecl; } \
     TNL_DECLARE_CLASS( RPC_##className##_##name ); \
     bool checkClassType(TNL::Object *theObject) { return dynamic_cast<className *>(theObject) != NULL; } }; \
     TNL_IMPLEMENT_NETEVENT( RPC_##className##_##name, groupMask, rpcVersion ); \
     void className::name args { RPC_##className##_##name *theEvent = new RPC_##className##_##name; theEvent->mFunctorDecl.set argNames ; postNetEvent(theEvent); } \
     TNL::NetEvent * className::name##_construct args { RPC_##className##_##name *theEvent = new RPC_##className##_##name; theEvent->mFunctorDecl.set argNames ; return theEvent; } \
     void className::name##_test args { RPC_##className##_##name *theEvent = new RPC_##className##_##name; theEvent->mFunctorDecl.set argNames ; TNL::PacketStream ps; theEvent->pack(this, &ps); ps.setBytePosition(0); theEvent->unpack(this, &ps); theEvent->process(this); } \
     void className::name##_remote args
  
  /// Base class for RPC events.
  ///
  /// All declared RPC methods create subclasses of RPCEvent to send data across the wire
  class RPCEvent : public NetEvent
  {
  public:
     Functor *mFunctor;
     /// Constructor call from within the rpc<i>Something</i> method generated by the TNL_IMPLEMENT_RPC macro.
     RPCEvent(RPCGuaranteeType gType, RPCDirection dir);
     void pack(EventConnection *ps, BitStream *bstream);
     void unpack(EventConnection *ps, BitStream *bstream);
     virtual bool checkClassType(Object *theObject) = 0;
  
     void process(EventConnection *ps);
  };
  
  /// Declares an RPC method within a class declaration.  Creates two method prototypes - one for the host side of the RPC call, and one for the receiver, which performs the actual method.
  #define TNL_DECLARE_RPC(name, args) void name args; void name##_test args; virtual TNL::NetEvent * name##_construct args; virtual void name##_remote args
  
  /// Declares an override to an RPC method declared in a parent class.
  #define TNL_DECLARE_RPC_OVERRIDE(name, args) void name##_remote args
  
  /// Macro used to declare the body of an overridden RPC method.
  #define TNL_IMPLEMENT_RPC_OVERRIDE(className, name, args) \
     void className::name##_remote args
  
  /// Constructs a NetEvent that will represent the specified RPC invocation.  This
  /// macro is used to construct a single RPC that can then be posted to multiple
  /// connections, instead of allocating an RPCEvent for each connection.
  #define TNL_RPC_CONSTRUCT_NETEVENT(object, rpcMethod, args) (object)->rpcMethod##_construct args
  
  };
  
  #endif
  