room level messages, client disconnection
authorChristopher Allan Webber <cwebber@dustycloud.org>
Fri, 6 May 2016 15:05:50 +0000 (10:05 -0500)
committerChristopher Allan Webber <cwebber@dustycloud.org>
Fri, 6 May 2016 15:05:50 +0000 (10:05 -0500)
mudsync/game-master.scm
mudsync/gameobj.scm
mudsync/networking.scm
mudsync/player.scm
mudsync/room.scm

index 34476b0077a892aaa553813e73df8d30f6676d3c..89fbaf6c8ca157f52bdca02ef5389306c94abf88 100644 (file)
@@ -55,7 +55,8 @@
     (client-input (wrap-apply gm-handle-client-input))
     (lookup-special (wrap-apply gm-lookup-special))
     (new-client (wrap-apply gm-new-client))
-    (write-home (wrap-apply gm-write-home)))))
+    (write-home (wrap-apply gm-write-home))
+    (client-closed (wrap-apply gm-client-closed)))))
 
 
 ;;; .. begin world init stuff ..
       #:client client-id
       #:data text))
 
+(define-mhandler (gm-client-closed gm message client)
+  ;; Do we have this client registered to an actor?  Get the id if so.
+  (define actor-id (hash-ref (gm-client-dir gm) client))
+
+  ;; Have the actor appropriately disappear / be removed from its
+  ;; room, if we have one.
+  ;; (In some games, if the user never connected)
+  (when actor-id
+    (<-wait gm actor-id 'disconnect-self-destruct)
+    ;; Unregister from the client directories.
+    (gm-unregister-client! gm client)))
+
 
 ;;; GM utilities
 
   (hash-set! (gm-client-dir gm) client-id player)
   (hash-set! (gm-reverse-client-dir gm) player client-id))
 
-(define (gm-unregister-client! gm client-id)
+(define* (gm-unregister-client! gm client-id #:optional destroy-player)
   "Remove a connection/player combo and ask them to self destruct"
   (match (hash-remove! (gm-client-dir gm) client-id)  ; Remove from our client dir
     ((_ . player-id)
      ;; Remove from reverse table too
      (hash-remove! (gm-reverse-client-dir gm) client-id)
      ;; Destroy player 
-     (<- gm player-id 'destroy-self))
+     (if destroy-player
+         (<- gm player-id 'self-destruct)))
     (#f (throw 'no-client-to-unregister
                "Can't unregister a client that doesn't exist?"
                client-id))))
index fa3554865b61eb306a66ceee6f1ce55840b52a6c..91701ac4ccd28e34edc63028e6ce6db8151cec4b 100644 (file)
             gameobj-loc
             gameobj-gm
             gameobj-name
-            gameobj-name-f
 
-            gameobj-actions))
+            gameobj-occupants
+            gameobj-actions
+            gameobj-self-destruct))
 
 ;;; Gameobj
 ;;; =======
    (get-occupants (wrap-apply gameobj-get-occupants))
    (add-occupant! (wrap-apply gameobj-add-occupant!))
    (remove-occupant! (wrap-apply gameobj-remove-occupant!))
-   (set-loc! (wrap-apply gameobj-set-loc!))
+   (set-loc! (wrap-apply gameobj-act-set-loc!))
    (get-name (wrap-apply gameobj-get-name))
    (get-desc (wrap-apply gameobj-get-desc))
    (goes-by (wrap-apply gameobj-act-goes-by))
-   (visible-name (wrap-apply gameobj-visible-name))))
+   (visible-name (wrap-apply gameobj-visible-name))
+   (self-destruct (wrap-apply gameobj-act-self-destruct))
+   (tell (wrap-apply gameobj-tell-no-op))))
 
 ;;; *all* game components that talk to players should somehow
 ;;; derive from this class.
@@ -65,8 +68,7 @@
        #:getter gameobj-loc)
   
   ;; Uses a hash table like a set (values ignored)
-  (occupants #:init-thunk make-hash-table
-             #:getter gameobj-occupants)
+  (occupants #:init-thunk make-hash-table)
 
   ;; game master id
   (gm #:init-keyword #:gm
   (desc #:init-value #f
         #:init-keyword #:desc)
 
-  ;; how to print our name
-  (name-f #:init-keyword #:name-f
-          #:getter gameobj-name-f
-          #:init-value (wrap gameobj-simple-name-f))
-
   ;; Commands we can handle
   (commands #:init-value '())
 
   "Remove an occupant from the room."
   (hash-remove! (slot-ref actor 'occupants) who))
 
+(define* (gameobj-occupants gameobj #:key exclude)
+  (hash-fold
+   (lambda (occupant _ prev)
+     (define exclude-it?
+       (match exclude
+         ;; Empty list and #f are non-exclusion
+         (() #f)
+         (#f #f)
+         ;; A list of addresses... since our address object is (annoyingly)
+         ;; currently a simple cons cell...
+         ((exclude-1 ... exclude-rest)
+          (pk 'failboat (member occupant (pk 'exclude-lst exclude))))
+         ;; Must be an individual address!
+         (_ (equal? occupant exclude))))
+     (if exclude-it?
+         prev
+         (cons occupant prev)))
+   '()
+   (slot-ref gameobj 'occupants)))
+
 (define-mhandler (gameobj-get-occupants actor message)
   "Get all present occupants of the room."
+  (define exclude (message-ref message 'exclude #f))
   (define occupants
-    (hash-map->list (lambda (key val) key)
-                    (gameobj-occupants actor)))
+    (gameobj-occupants actor #:exclude exclude))
 
   (<-reply actor message
            #:occupants occupants))
 
-;; @@: Should it really be #:id ?  Maybe #:loc-id or #:loc?
-(define-mhandler (gameobj-set-loc! actor message loc)
+(define (gameobj-set-loc! gameobj loc)
   "Set the location of this object."
-  (define old-loc (gameobj-loc actor))
+  (define old-loc (gameobj-loc gameobj))
   (format #t "DEBUG: Location set to ~s for ~s\n"
-          loc (actor-id-actor actor))
+          loc (actor-id-actor gameobj))
 
-  (slot-set! actor 'loc loc)
+  (slot-set! gameobj 'loc loc)
   ;; Change registation of where we currently are
   (if loc
-      (<-wait actor loc 'add-occupant! #:who (actor-id actor)))
+      (<-wait gameobj loc 'add-occupant! #:who (actor-id gameobj)))
   (if old-loc
-      (<-wait actor old-loc 'remove-occupant! #:who (actor-id actor))))
+      (<-wait gameobj old-loc 'remove-occupant! #:who (actor-id gameobj))))
+
+;; @@: Should it really be #:id ?  Maybe #:loc-id or #:loc?
+(define-mhandler (gameobj-act-set-loc! actor message loc)
+  "Action routine to set the location."
+  (gameobj-set-loc! actor loc))
 
 (define gameobj-get-name (simple-slot-getter 'name))
 
@@ -229,3 +250,18 @@ By default, this is whether or not the generally-visible flag is set."
           (#f #f))
         #f))
   (<-reply actor message #:text name-to-return))
+
+(define (gameobj-self-destruct gameobj)
+  "General gameobj self destruction routine"
+  ;; Unregister from being in any particular room
+  (gameobj-set-loc! gameobj #f)
+  ;; Boom!
+  (self-destruct gameobj))
+
+(define-mhandler (gameobj-act-self-destruct gameobj message)
+  "Action routine for self destruction"
+  (gameobj-self-destruct gameobj))
+
+;; Unless an actor has a tell message, we just ignore it
+(define gameobj-tell-no-op
+  (const 'no-op))
index fe641cc9a227556ee945a8fc58b18a5f3b052ea3..8c5955dd39c44b2325278573bf288ea638a31246 100644 (file)
   "Handle a closed port"
   (format #t "DEBUG: handled closed port ~x\n" client-id)
   (8sync-port-remove client)
-  (hash-remove! (nm-clients nm) client-id))
+  (hash-remove! (nm-clients nm) client-id)
+  (<- nm (nm-send-input-to nm) 'client-closed #:client client-id))
 
 (define-method (nm-handle-port-eof nm client client-id)
   "Handle seeing an EOF on port"
   (format #t "DEBUG: handled eof-object on port ~x\n" client-id)
   (close client)
   (8sync-port-remove client)
-  (hash-remove! (nm-clients nm) client-id))
+  (hash-remove! (nm-clients nm) client-id)
+  (<- nm (nm-send-input-to nm) 'client-closed #:client client-id))
 
 (define-method (nm-handle-line nm client client-id line)
   "Handle an incoming line of input from a client"
index 3d1ec7288baf6c83387046b4612436546e1105c3..8b9a22f5c72c5de58370db5843ee11bce20b0035 100644 (file)
@@ -39,7 +39,8 @@
   (build-actions
    (init (wrap-apply player-init))
    (handle-input (wrap-apply player-handle-input))
-   (tell (wrap-apply player-tell))))
+   (tell (wrap-apply player-tell))
+   (disconnect-self-destruct (wrap-apply player-disconnect-self-destruct))))
 
 (define player-actions*
   (append player-actions
   (<- player (gameobj-gm player) 'write-home
       #:text text))
 
+(define-mhandler (player-disconnect-self-destruct player message)
+  "Action routine for being told to disconnect and self destruct."
+  (define loc (gameobj-loc player))
+  (when loc
+    (<- player loc 'tell-room
+        #:exclude (actor-id player)
+        #:text (format #f "~a disappears in a puff of entropy!\n"
+                       (slot-ref player 'name))))
+  (gameobj-self-destruct player))
+
 
 ;;; Command handling
 ;;; ================
index 10932c9314fa3ff9e3b2bb7285e57ac6e562ddee..0b0e10108411c0aa1086cfd682a346c51149e43c 100644 (file)
@@ -83,6 +83,7 @@
    (cmd-go (wrap-apply room-cmd-go))
    (cmd-go-where (wrap-apply room-cmd-go-where))
    (look-room (wrap-apply room-look-room))
+   (tell-room (wrap-apply room-tell-room))
    ;; in this case the command is the same version as the normal
    ;; look-room version
    (cmd-look-room (wrap-apply room-look-room))
@@ -257,3 +258,19 @@ claim to point to."
    (else
     (<- room (message-from message) 'tell
         #:text "You don't see that here, so you can't look at it.\n"))))
+
+(define-mhandler (room-tell-room room message text)
+  "Tell the room some messages."
+  (define exclude (message-ref message 'exclude #f))
+  (define wait-delivery (message-ref message 'wait-delivery #f))
+  (define who-to-tell (gameobj-occupants room #:exclude exclude))
+  (for-each
+   (lambda (tell-me)
+     ;; @@: Does anything really care?
+     (define deliver-method
+       (if wait-delivery
+           <-wait
+           <-))
+     (deliver-method room tell-me 'tell
+                     #:text text))
+   who-to-tell))