multiplay.cpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. /*
  2. Note - does not appear to like DPSESSION_MULTICASTSERVER very much!
  3. */
  4. #include "std.h"
  5. #include "multiplay.h"
  6. #include "multiplay_setup.h"
  7. struct Player;
  8. static bool host;
  9. static map<DPID,Player*> player_map;
  10. static list<Player*> players,new_players;
  11. static int msg_type;
  12. static string msg_data;
  13. static DPID msg_from,msg_to;
  14. static char *recv_buff;
  15. static int recv_buff_sz;
  16. static char *send_buff;
  17. static int send_buff_sz;
  18. #pragma pack( push,1 )
  19. struct bbMsg{
  20. DPID from,to;
  21. char type;
  22. };
  23. #pragma pack( pop )
  24. struct Player{
  25. DPID id;
  26. string name;
  27. bool remote;
  28. Player( DPID i,const string &n,bool r ):id(i),name(n),remote(r){
  29. players.push_back( this );
  30. if( remote ) new_players.push_back( this );
  31. player_map.clear();
  32. }
  33. Player::~Player(){
  34. new_players.remove( this );
  35. players.remove( this );
  36. player_map.clear();
  37. }
  38. };
  39. static void chk(){
  40. if( !dirPlay ){
  41. RTEX( "Multiplayer game not started" );
  42. }
  43. }
  44. static void clearPlayers(){
  45. while( players.size() ) delete players.back();
  46. new_players.clear();
  47. player_map.clear();
  48. }
  49. static Player *findPlayer( DPID id ){
  50. if( !player_map.size() ){
  51. list<Player*>::iterator it;
  52. for( it=players.begin();it!=players.end();++it ){
  53. player_map.insert( pair<DPID,Player*>( (*it)->id,(*it) ) );
  54. }
  55. }
  56. map<DPID,Player*>::iterator it=player_map.find( id );
  57. return it==player_map.end() ? 0 : it->second;
  58. }
  59. static BOOL FAR PASCAL enumPlayer( DPID id,DWORD type,LPCDPNAME name,DWORD flags,LPVOID context ){
  60. Player *p=findPlayer( id );if( p ) return TRUE;
  61. p=d_new Player( id,string( name->lpszShortNameA ),true );
  62. return TRUE;
  63. }
  64. void multiplay_link( void(*rtSym)(const char*,void*) ){
  65. rtSym( "%StartNetGame",bbStartNetGame );
  66. rtSym( "%HostNetGame$game_name",bbHostNetGame );
  67. rtSym( "%JoinNetGame$game_name$ip_address",bbJoinNetGame );
  68. rtSym( "StopNetGame",bbStopNetGame );
  69. rtSym( "%CreateNetPlayer$name",bbCreateNetPlayer );
  70. rtSym( "DeleteNetPlayer%player",bbDeleteNetPlayer );
  71. rtSym( "$NetPlayerName%player",bbNetPlayerName );
  72. rtSym( "%NetPlayerLocal%player",bbNetPlayerLocal );
  73. rtSym( "%SendNetMsg%type$msg%from_player%to_player=0%reliable=1",bbSendNetMsg );
  74. rtSym( "%RecvNetMsg",bbRecvNetMsg );
  75. rtSym( "%NetMsgType",bbNetMsgType );
  76. rtSym( "%NetMsgFrom",bbNetMsgFrom );
  77. rtSym( "%NetMsgTo",bbNetMsgTo );
  78. rtSym( "$NetMsgData",bbNetMsgData );
  79. }
  80. bool multiplay_create(){
  81. recv_buff_sz=send_buff_sz=1024;
  82. recv_buff=d_new char[recv_buff_sz];
  83. send_buff=d_new char[send_buff_sz];
  84. multiplay_setup_create();
  85. return true;
  86. }
  87. bool multiplay_destroy(){
  88. bbStopNetGame();
  89. multiplay_setup_destroy();
  90. delete[] recv_buff;recv_buff=0;
  91. delete[] send_buff;send_buff=0;
  92. return true;
  93. }
  94. static int startGame( int n ){
  95. clearPlayers();
  96. if( !n ) return 0;
  97. if( dirPlay->EnumPlayers( 0,enumPlayer,0,0 )>=0 ){
  98. host=n==2;
  99. return n;
  100. }
  101. multiplay_setup_close();
  102. return 0;
  103. }
  104. int bbStartNetGame(){
  105. if( dirPlay ){
  106. RTEX( "Multiplayer game already started" );
  107. }
  108. return startGame( multiplay_setup_open() );
  109. }
  110. int bbHostNetGame( BBStr *name ){
  111. if( dirPlay ){
  112. RTEX( "Multiplayer game already started" );
  113. }
  114. string n=*name;delete name;
  115. return startGame( multiplay_setup_host( n ) );
  116. }
  117. int bbJoinNetGame( BBStr *name,BBStr *address ){
  118. if( dirPlay ){
  119. RTEX( "Multiplayer game already started" );
  120. }
  121. string n=*name,a=*address;delete name;delete address;
  122. return startGame( multiplay_setup_join( n,a ) );
  123. }
  124. void bbStopNetGame(){
  125. multiplay_setup_close();
  126. clearPlayers();
  127. }
  128. DPID bbCreateNetPlayer( BBStr *nm ){
  129. chk();
  130. string t=*nm;
  131. string t0=t+'\0';
  132. delete nm;
  133. DPID id;
  134. DPNAME name;
  135. memset( &name,0,sizeof( name ) );
  136. name.dwSize=sizeof(name);name.lpszShortNameA=(char*)t0.data();
  137. if( dirPlay->CreatePlayer( &id,&name,0,0,0,0 )<0 ) return 0;
  138. Player *p=d_new Player( id,t,false );
  139. if( players.size()==1 ){
  140. if( dirPlay->EnumPlayers( 0,enumPlayer,0,0 )<0 ){
  141. dirPlay->DestroyPlayer( id );
  142. delete p;
  143. return 0;
  144. }
  145. }
  146. return id;
  147. }
  148. void bbDeleteNetPlayer( DPID player ){
  149. chk();
  150. if( Player *p=findPlayer( player ) ){
  151. dirPlay->DestroyPlayer( player );
  152. delete p;
  153. }
  154. }
  155. BBStr *bbNetPlayerName( DPID player ){
  156. if( !player ) return d_new BBStr( "<all>" );
  157. Player *p=findPlayer( player );
  158. return d_new BBStr( p ? p->name : "<unknown>" );
  159. }
  160. int bbNetPlayerLocal( DPID player ){
  161. if( Player *p=findPlayer( player ) ) return p->remote ? 0 : 1;
  162. return 0;
  163. }
  164. int bbRecvNetMsg(){
  165. chk();
  166. msg_type=0;
  167. msg_data.resize(0);
  168. msg_from=DPID_UNKNOWN;msg_to=DPID_ALLPLAYERS;
  169. while( !msg_type ){
  170. if( new_players.size() ){
  171. msg_from=new_players.front()->id;
  172. new_players.pop_front();
  173. msg_type=100;
  174. return 1;
  175. }
  176. DPID from,to;
  177. DWORD sz=recv_buff_sz;
  178. int n=dirPlay->Receive( &from,&to,0,recv_buff,&sz );
  179. if( n==DPERR_BUFFERTOOSMALL ){
  180. sz=recv_buff_sz=sz/2+sz;
  181. delete[] recv_buff;recv_buff=d_new char[recv_buff_sz];
  182. n=dirPlay->Receive( &from,&to,0,recv_buff,&sz );
  183. }
  184. if( n!=DP_OK ) return 0;
  185. if( from==DPID_SYSMSG ){
  186. switch( *(DWORD*)recv_buff ){
  187. case DPSYS_CREATEPLAYERORGROUP:
  188. if( DPMSG_CREATEPLAYERORGROUP *msg=(DPMSG_CREATEPLAYERORGROUP*)recv_buff ){
  189. if( findPlayer( from=msg->dpId ) ) continue;
  190. d_new Player( from,string( msg->dpnName.lpszShortNameA ),true );
  191. continue;
  192. }
  193. break;
  194. case DPSYS_DESTROYPLAYERORGROUP:
  195. if( DPMSG_DESTROYPLAYERORGROUP *msg=(DPMSG_DESTROYPLAYERORGROUP*)recv_buff ){
  196. Player *p=findPlayer( msg->dpId );if( !p ) continue;
  197. delete p;msg_from=msg->dpId;msg_type=101;
  198. }
  199. break;
  200. case DPSYS_HOST:
  201. if( !host ){
  202. host=true;msg_type=102;
  203. }
  204. break;
  205. case DPSYS_SESSIONLOST:
  206. msg_type=200;
  207. break;
  208. }
  209. }else{
  210. bbMsg *m=(bbMsg*)recv_buff;
  211. Player *p=findPlayer( m->from );
  212. if( p && !p->remote ) continue;
  213. msg_data=string( (char*)(m+1),sz-sizeof(bbMsg) );
  214. msg_from=m->from;msg_to=m->to;
  215. msg_type=m->type;
  216. }
  217. }
  218. return 1;
  219. }
  220. int bbNetMsgType(){
  221. return msg_type;
  222. }
  223. BBStr *bbNetMsgData(){
  224. return d_new BBStr( msg_data );
  225. }
  226. DPID bbNetMsgFrom(){
  227. return msg_from;
  228. }
  229. DPID bbNetMsgTo(){
  230. return msg_to;
  231. }
  232. int bbSendNetMsg( int type,BBStr *msg,DPID from,DPID to,int reliable ){
  233. chk();
  234. int sz=msg->size()+sizeof(bbMsg);
  235. if( sz>send_buff_sz ){
  236. send_buff_sz=sz/2+sz;
  237. delete send_buff;send_buff=d_new char[send_buff_sz];
  238. }
  239. bbMsg *m=(bbMsg*)send_buff;
  240. m->type=type;m->from=from;m->to=to;
  241. memcpy( m+1,msg->data(),msg->size() );
  242. if( !to ) to=DPID_ALLPLAYERS;
  243. int n=dirPlay->Send( from,to,reliable ? DPSEND_GUARANTEED : 0,send_buff,sz );
  244. delete msg;
  245. return n>=0;
  246. }