home *** CD-ROM | disk | FTP | other *** search
/ Big Green CD 8 / BGCD_8_Dev.iso / OPENSTEP / Games / Empire-0.6-MIS / ServerController.m < prev    next >
Encoding:
Text File  |  1997-10-30  |  11.3 KB  |  404 lines

  1. //
  2. // $Id: ServerController.m,v 1.10 1997/10/31 04:52:07 nygard Exp $
  3. //
  4.  
  5. //
  6. //  This file is a part of Empire, a game of exploration and conquest.
  7. //  Copyright (C) 1996  Steve Nygard
  8. //
  9. //  This program is free software; you can redistribute it and/or modify
  10. //  it under the terms of the GNU General Public License as published by
  11. //  the Free Software Foundation; either version 2 of the License, or
  12. //  (at your option) any later version.
  13. //
  14. //  This program is distributed in the hope that it will be useful,
  15. //  but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17. //  GNU General Public License for more details.
  18. //
  19. //  You should have received a copy of the GNU General Public License
  20. //  along with this program; if not, write to the Free Software
  21. //  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  22. //
  23. //  You may contact the author by:
  24. //     e-mail:  nygard@telusplanet.net
  25. //
  26.  
  27. #import "Empire.h"
  28.  
  29. RCSID ("$Id: ServerController.m,v 1.10 1997/10/31 04:52:07 nygard Exp $");
  30.  
  31. #import "ServerController.h"
  32.  
  33. #import "Client.h"
  34. #import <Foundation/NSProtocolChecker.h>
  35. #import <Foundation/NSDistantObject.h>
  36.  
  37. //======================================================================
  38. // The ServerController provides a window for interactively establishing
  39. // and disconnecting the named port of the server.  It also lists the
  40. // clients that are currently connected, and provides a textview for
  41. // reporting status messages.
  42. //
  43. // A client can be "pinged" by double clicking its row in the table.
  44. //
  45. // This also provides notification to observers when clients are added
  46. // and removed.  This is used, for example, by the NewGameController to
  47. // provide popup lists of the available remote hosts.
  48. //======================================================================
  49.  
  50. #define ServerController_VERSION 1
  51.  
  52. @implementation ServerController
  53.  
  54. + (void) initialize
  55. {
  56.     if (self == [ServerController class])
  57.     {
  58.         [self setVersion:ServerController_VERSION];
  59.     }
  60. }
  61.  
  62. //----------------------------------------------------------------------
  63.  
  64. - (void) awakeFromNib
  65. {
  66.     [serverWindow setTitle:[NSString stringWithFormat:@"Server  %c  %@", 208, [[NSHost currentHost] name]]];
  67.  
  68.     // There doesn't appear to be a way of setting this in InterfaceBuilder.
  69.     [clientTable setDoubleAction:@selector (doubleAction:)];
  70.     [clientTable setTarget:self];
  71. }
  72.  
  73. //----------------------------------------------------------------------
  74.  
  75. - init
  76. {
  77.     NSString *nibFile;
  78.     BOOL loaded;
  79.  
  80.     [super init];
  81.  
  82.     nibFile = @"ServerWindow.nib";
  83.     loaded = [NSBundle loadNibNamed:nibFile owner:self];
  84.     if (loaded == NO)
  85.     {
  86.         NSLog (@"Could not load %@.", nibFile);
  87.         [super dealloc];
  88.         return nil;
  89.     }
  90.  
  91.     serverConnection = nil;
  92.     clientList = [[NSMutableArray array] retain];
  93.  
  94.     observers = [[NSMutableArray array] retain];
  95.  
  96.     return self;
  97. }
  98.  
  99. //----------------------------------------------------------------------
  100.  
  101. - (void) dealloc
  102. {
  103.     SNRelease (clientList);
  104.  
  105.     // If this were really deallocated, we might want to notify the
  106.     // remaining observers that we are going away, so that they don't
  107.     // try detaching.
  108.  
  109.     SNRelease (observers);
  110.     SNRelease (serverConnection);
  111.  
  112.     [super dealloc];
  113. }
  114.  
  115. //----------------------------------------------------------------------
  116.  
  117. - (void) showPanel
  118. {
  119.     [serverWindow makeKeyAndOrderFront:self];
  120. }
  121.  
  122. //----------------------------------------------------------------------
  123.  
  124. - (void) establishServer:sender
  125. {
  126.     NSProtocolChecker *protocolChecker;
  127.     BOOL success;
  128.  
  129.     NSAssert (serverConnection == nil, @"Server already running");
  130.  
  131.     if (serverConnection != nil )
  132.     {
  133.         [self showText:@"The server is already running."];
  134.         return;
  135.     }
  136.  
  137.     protocolChecker = [NSProtocolChecker protocolCheckerWithTarget:self
  138.                                          protocol:@protocol (EmpireServerConnectionProtocol)];
  139.  
  140.     NSAssert (protocolChecker != nil, @"A protocol checker could not be allocated.");
  141.  
  142.     serverConnection = [[NSConnection alloc] init];
  143.     NSAssert (serverConnection != nil, @"Could not allocate server connection.");
  144.  
  145.     [[NSNotificationCenter defaultCenter] addObserver:self
  146.                                           selector:@selector (connectionDidDie:)
  147.                                           name:NSConnectionDidDieNotification
  148.                                           object:serverConnection];
  149.  
  150.     [serverConnection setRootObject:protocolChecker];
  151.  
  152.     success = [serverConnection registerName:SERVER_PORT_NAME];
  153.     NSAssert (success == YES, @"Could not name server connection.");
  154.  
  155.     [statusTextfield setStringValue:@"Running..."];
  156.     [serverConnection setDelegate:self];
  157. }
  158.  
  159. //----------------------------------------------------------------------
  160.  
  161. - (void) stopServer:sender
  162. {
  163.     NSAssert (serverConnection != nil, @"Server not running.");
  164.  
  165.     [serverConnection registerName:nil];
  166.     [serverConnection invalidate];
  167.  
  168.     SNRelease (serverConnection);
  169.     
  170.     [statusTextfield setStringValue:@"Stopped."];
  171. }
  172.  
  173. //----------------------------------------------------------------------
  174.  
  175. - (void) doubleAction:sender
  176. {
  177.     int row = [sender selectedRow];
  178.  
  179.     if (row >= 0 && row < [clientList count])
  180.     {
  181.         NS_DURING
  182.             {
  183.                 [[[clientList objectAtIndex:row] client] ping];
  184.             }
  185.         NS_HANDLER
  186.             {
  187.                 EHAND;
  188.             }
  189.         NS_ENDHANDLER;
  190.     }
  191. }
  192.  
  193. //----------------------------------------------------------------------
  194.  
  195. - (void) showText:(NSString *)format, ...
  196. {
  197.     NSMutableString *message;
  198.     NSRange selected;
  199.     va_list ap;
  200.  
  201.     va_start(ap, format);
  202.     message = [[[NSMutableString alloc] initWithFormat:format arguments:ap] autorelease];
  203.     [message appendString:@"\n"];
  204.     va_end(ap);
  205.  
  206.     [messageText selectAll:nil];
  207.     selected = [messageText selectedRange];
  208.     selected.location = selected.length;
  209.     selected.length = 0;
  210.     [messageText setSelectedRange:selected];
  211.     [messageText replaceCharactersInRange:selected withString:message];
  212.     [messageText scrollRangeToVisible:selected];
  213. }
  214.  
  215. //----------------------------------------------------------------------
  216.  
  217. - (void) connectionDidDie:(NSNotification *)notification
  218. {
  219.     id object;
  220.     Client *client;
  221.     NSEnumerator *clientEnumerator;
  222.     int l = 0;
  223.  
  224.     object = [notification object];
  225.     
  226.     clientEnumerator = [clientList objectEnumerator];
  227.     while (client = [clientEnumerator nextObject])
  228.     {
  229.         if ([client clientConnection] == object)
  230.         {
  231.             [clientList removeObjectAtIndex:l];
  232.             [self removedClientHostNumber:l];
  233.             [clientTable reloadData];
  234.             break;
  235.         }
  236.  
  237.         l++;
  238.     }
  239.  
  240.     [[NSNotificationCenter defaultCenter] removeObserver:self
  241.                                           name:nil
  242.                                           object:object];
  243. }
  244.  
  245. //----------------------------------------------------------------------
  246.  
  247. - (BOOL) connection:(NSConnection *)parentConnection shouldMakeNewConnection:(NSConnection *)newConnection
  248. {
  249.     return YES;
  250. }
  251.  
  252. //----------------------------------------------------------------------
  253.  
  254. - (Client *) clientAtIndex:(int)index
  255. {
  256.     return [clientList objectAtIndex:index];
  257. }
  258.  
  259. //======================================================================
  260. // EmpireServerConnectionProtocol
  261. //======================================================================
  262.  
  263. - (void) ping
  264. {
  265.     [self showText:@"We were pinged."];
  266. }
  267.  
  268. //----------------------------------------------------------------------
  269. // I can't seem to get it to accept (id <EmpireClientConnectionProtocol>) as the type,
  270. // since it will complain that -connectionForProxy isn't part of the protocol!
  271. //----------------------------------------------------------------------
  272.  
  273. - (void) client:clientController onHost:(NSString *)hostname
  274. {
  275.     Client *client;
  276.  
  277.     [self showText:@"Client hostname is %@", hostname];
  278.     
  279.     [clientController setProtocolForProxy:@protocol (EmpireClientConnectionProtocol)];
  280.  
  281.     [[NSNotificationCenter defaultCenter] addObserver:self
  282.                                           selector:@selector (connectionDidDie:)
  283.                                           name:NSConnectionDidDieNotification
  284.                                           object:[clientController connectionForProxy]];
  285.  
  286.     client = [[[Client alloc] initWithClient:clientController fromHost:hostname] autorelease];
  287.  
  288.     [clientList addObject:client];
  289.     [self newClientHost:[client numberedHostname]];
  290.     [clientTable reloadData];
  291. }
  292.  
  293. //----------------------------------------------------------------------
  294.  
  295. - (void) aboutToDisconnect:sender
  296. {
  297.     [[sender connectionForProxy] invalidate];
  298. }
  299.  
  300. //======================================================================
  301. // NSTableDataSource
  302. //======================================================================
  303.  
  304. - (int) numberOfRowsInTableView:(NSTableView *)aTableView
  305. {
  306.     return [clientList count];
  307. }
  308.  
  309. //----------------------------------------------------------------------
  310.  
  311. - tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex
  312. {
  313.     NSString *identifier;
  314.     id value;
  315.  
  316.     value = nil;
  317.     identifier = [aTableColumn identifier];
  318.     
  319.     if ([identifier isEqualToString:@"Client"] == YES)
  320.     {
  321.         value = [[clientList objectAtIndex:rowIndex] hostname];
  322.     }
  323.     else if ([identifier isEqualToString:@"Index"] == YES)
  324.     {
  325.         value = [NSNumber numberWithInt:rowIndex + 1];
  326.     }
  327.     else if ([identifier isEqualToString:@"Identifier"] == YES)
  328.     {
  329.         value = [NSNumber numberWithUnsignedLong:(unsigned long)[clientList objectAtIndex:rowIndex]];
  330.     }
  331.  
  332.     return value;
  333. }
  334.  
  335. //======================================================================
  336. // ObserverPattern
  337. //======================================================================
  338.  
  339. - (void) attach:observer
  340. {
  341.     [observers addObject:observer];
  342.  
  343.     if ([observer respondsToSelector:@selector (newClientHost:)] == YES)
  344.     {
  345.         NSEnumerator *enumerator;
  346.         id object;
  347.  
  348.         enumerator = [clientList objectEnumerator];
  349.         while (object = [enumerator nextObject])
  350.         {
  351.             [observer newClientHost:[object numberedHostname]];
  352.         }
  353.     }
  354. }
  355.  
  356. //----------------------------------------------------------------------
  357.  
  358. - (void) detach:observer
  359. {
  360.     int l, count;
  361.     
  362.     [observers removeObject:observer];
  363.  
  364.     if ([observer respondsToSelector:@selector (removedClientHostNumber:)] == YES)
  365.     {
  366.         count = [observers count];
  367.         
  368.         for (l = count - 1; l >= 0; l--)
  369.             [observer removedClientHostNumber:l];
  370.     }
  371. }
  372.  
  373. //----------------------------------------------------------------------
  374.  
  375. - (void) newClientHost:(NSString *)hostname
  376. {
  377.     NSEnumerator *enumerator;
  378.     id observer;
  379.  
  380.     enumerator = [observers objectEnumerator];
  381.     while (observer = [enumerator nextObject])
  382.     {
  383.         if ([observer respondsToSelector:@selector (newClientHost:)] == YES)
  384.             [observer newClientHost:hostname];
  385.     }
  386. }
  387.  
  388. //----------------------------------------------------------------------
  389.  
  390. - (void) removedClientHostNumber:(int)index
  391. {
  392.     NSEnumerator *enumerator;
  393.     id observer;
  394.  
  395.     enumerator = [observers objectEnumerator];
  396.     while (observer = [enumerator nextObject])
  397.     {
  398.         if ([observer respondsToSelector:@selector (removedClientHostNumber:)] == YES)
  399.             [observer removedClientHostNumber:index];
  400.     }
  401. }
  402.  
  403. @end
  404.