<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>views/mud-move.php</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -9,6 +9,7 @@ RewriteRule ^blog/(?P&lt;year&gt;\d{4})/(?P&lt;month&gt;\d{2})/(?P&lt;day&gt;\d{2})/(?P&lt;slug&gt;[-a-z
 RewriteRule ^mud$ views/mud.php [QSA,L]
 RewriteRule ^mud-say$ views/mud-say.php [QSA,L]
 RewriteRule ^mud-update$ views/mud-update.php [QSA,L]
+RewriteRule ^mud-move$ views/mud-move.php [QSA,L]
 RewriteRule ^admin/blog/delete/(?P&lt;id&gt;\d+)$ views/admin/blog-post.php?id=$1&amp;action=delete [QSA,L]
 RewriteRule ^admin/blog/edit(?:/(?P&lt;id&gt;\d+))?$ views/admin/blog-post.php?id=$1&amp;action=edit [QSA,L]
 RewriteRule ^admin/blog(?:/(?P&lt;page&gt;\d+))?$ views/admin/blog.php?page=$1 [QSA,L]</diff>
      <filename>.htaccess</filename>
    </modified>
    <modified>
      <diff>@@ -9,6 +9,7 @@ $this-&gt;map_url('^/$', 'home')
      -&gt;map_url('^/mud$', 'mud')
      -&gt;map_url('^/mud-say$', 'mud-say')
      -&gt;map_url('^/mud-update$', 'mud-update')
+     -&gt;map_url('^/mud-move$', 'mud-move')
      -&gt;map_url('^/admin/blog/delete/(?P&lt;id&gt;\d+)$', 'admin/blog-post', 'delete')
      -&gt;map_url('^/admin/blog/edit(?:/(?P&lt;id&gt;\d+))?$', 'admin/blog-post', 'edit')
      -&gt;map_url('^/admin/blog(?:/(?P&lt;page&gt;\d+))?$', 'admin/blog');</diff>
      <filename>config.php</filename>
    </modified>
    <modified>
      <diff>@@ -5,9 +5,6 @@ var EAST = 4;
 var WEST = 8;
 
 var step = 10;
-
-var input_timeout = null;
-var refresh_timeout = null;
 // }}}
 
 // {{{ init
@@ -20,8 +17,14 @@ jQuery(function () {
             .attr('type', 'text')
             .appendTo('body');
 
-    update_loop();
-    game_loop();
+    // place neighbours
+    for (i in neighbours)
+    {
+        place_avatar(neighbours[i]);
+    }
+
+    setInterval(game_loop, 60);
+    update();
 }); // }}}
 
 function game_loop() // {{{
@@ -64,20 +67,8 @@ function game_loop() // {{{
     });
     user.x = oLeft;
     user.y = oTop;
-
-    if (input_timeout)
-    {
-        clearTimeout(input_timeout);
-    }
-    input_timeout = setTimeout(game_loop, 60);
 } // }}}
 
-function update_loop()
-{
-    update();
-    refresh_timeout = setTimeout(update_loop, 500);
-}
-
 function place_avatar(data) // {{{
 {
     var avatar = document.createElement('div');
@@ -128,11 +119,10 @@ function say(avatar, msg) // {{{
         bubble.find('.text').text(msg);
     }
     bubble.show();
-    console.log(bubble);
     if (msg)
     {
         // hide the message after enough time to read it
-        var delay = 3000 + (text.split(' ').length * 250);
+        var delay = 3000 + (msg.split(' ').length * 250);
         setTimeout(function () { bubble.hide(); }, delay);
         return;
     }
@@ -150,9 +140,8 @@ function say(avatar, msg) // {{{
       .attr('fresh', 'true');
 } // }}}
 
-function enter_text(e) {
-    console.log(e.which);
-
+function enter_text(e) // {{{
+{
     if ($(this).attr('fresh') == 'true' &amp;&amp; e.which == 115)
     {
         // discard first keypress event, because it's the 's'
@@ -164,9 +153,9 @@ function enter_text(e) {
     if (e.which == 13)
     {
         $.ajax({
-            'type': 'POST',
-            'url': 'http://localhost/~andy.driver/pagezero/mud-say',
-            'data': {'user': user.user, 'says': $(this).val()},
+            &quot;type&quot;: &quot;GET&quot;,
+            &quot;url&quot;: &quot;http://localhost/~andy.driver/pagezero/mud-say&quot;,
+            &quot;data&quot;: &quot;user=&quot; + user.user + &quot;&amp;says=\&quot;&quot; + $(this).val() + &quot;\&quot;&quot;,
         });
   
         // re-enable game keyboard controls
@@ -182,7 +171,7 @@ function enter_text(e) {
     $('#avatar-' + user.user + ' .speech-bubble .text').text($(this).val() +
         String.fromCharCode(e.which));
     return true;
-}
+} // }}}
 
 function get_frame_x(state, frame) // {{{
 {
@@ -193,46 +182,53 @@ function get_frame_x(state, frame) // {{{
     return frame;
 } // }}}
 
-function update()
+function update() // {{{
 {
+    console.log('updating...');
     $.ajax({
-        'type': 'GET',
-        'url': 'http://localhost/~andy.driver/pagezero/mud-update',
-        'data': {'user': user.user, 'x': user.x, 'y': user.y},
-        'dataType': 'json',
-        'success': refresh
+        &quot;type&quot;: &quot;GET&quot;,
+        &quot;url&quot;: &quot;http://localhost/~andy.driver/pagezero/mud-update&quot;,
+        &quot;data&quot;: &quot;user=&quot; + user.user,
+        &quot;dataType&quot;: &quot;json&quot;,
+        &quot;success&quot;: function (o) { react(o); update(); },
+        &quot;error&quot;: function (xhr, msg, e) { console.log('error: ' + msg); update(); },
     });
-}
+} // }}}
 
-function refresh(json)
+function react(json) // {{{
 {
-    for (i in json.neighbours)
+    last_id = json.last_id;
+    console.log(last_id + ': ' + json.result.length);
+    for (i in json.result)
     {
-        var avatar = json.neighbours[i];
-        var sprite = $('#avatar-' + avatar.user);
-        if (sprite.length == 0)
+        var msg = json.result[i];
+        switch (msg.type)
         {
-            place_avatar(avatar);
-            sprite = $('#avatar-' + avatar.user);
+            case 0: // avatar move
+                console.log('user ' + msg.user + ' moved to ' + msg.msg);
+                eval('var coords = ' + msg.msg);
+                var avatar = $('#avatar-' + msg.user);
+                avatar.animate({
+                    'left': coords[0] + 'px',
+                    'top': coords[1] + 'px'
+                }, 'slow');
+                break;
+            case 1: // avatar say
+                console.log('user ' + msg.user + ' said ' + msg.msg);
+                say(msg.user, eval(msg.msg));
+                break;
+            case 2: // avatar enter
+                console.log('user ' + msg.user + ' entered');
+                eval('var avatar = ' + msg.msg);
+                place_avatar(avatar);
+                break;
+            case 3: // avatar exit
+                console.log('user ' + msg.user + ' exited');
+                $('#avatar-' + msg.user).remove();
+                break;
         }
-        var oLeft = sprite.attr('offsetLeft');
-        oLeft = (oLeft == avatar.x ? oLeft : avatar.x);
-        var oTop = sprite.attr('offsetTop');
-        oTop = (oTop == avatar.y ? oTop : avatar.y);
-        sprite.animate({
-            'left': oLeft + 'px',
-            'top': oTop + 'px'
-        }, 'slow');
     }
-    var out = [];
-    for (i in json.chat)
-    {
-        var msg = json.chat[i];
-        out.push(msg.user + ': &quot;' + msg.msg + '&quot;');
-        say(msg.user, msg.msg);
-    }
-    //console.log(json.last_update + ': ' + out);
-}
+} // }}}
 
 function handle_key_down(e) // {{{
 {
@@ -304,5 +300,10 @@ function handle_key_up(e) // {{{
             return true;
     }
     $('#avatar-' + user.user).attr('state', state);
+    $.ajax({
+        &quot;type&quot;: &quot;GET&quot;,
+        &quot;url&quot;: &quot;http://localhost/~andy.driver/pagezero/mud-move&quot;,
+        &quot;data&quot;: {&quot;user&quot;: user.user, &quot;x&quot;: user.x, &quot;y&quot;: user.y},
+    });
     return false;
 } // }}}</diff>
      <filename>js/mud.js</filename>
    </modified>
    <modified>
      <diff>@@ -273,6 +273,16 @@ SQL;
             return $this-&gt;_cache[0];
         }
     }
+
+    function to_array()
+    {
+        $a = array();
+        foreach ($this-&gt;items as $item)
+        {
+            $a[] = $item-&gt;to_array();
+        }
+        return $a;
+    }
 }
 
 class BreveFilter</diff>
      <filename>lib/defer.php</filename>
    </modified>
    <modified>
      <diff>@@ -1,20 +1,9 @@
 &lt;?php
-function get_last_update()
-{
-    $u = @$_COOKIE['last_update'];
-    if (!$u)
-    {
-        $u = '0';
-    }
-    return $u;
-}
-
 function update_timestamp()
 {
     // set the user's last update time to now
     $ms = microtime();
     $cs = (int)($ms * 1000);
     $now = date('YmdHis') . str_pad($cs, 3, '0', STR_PAD_LEFT);
-    setCookie('last_update', $now);
     return $now;
 }</diff>
      <filename>lib/mud.php</filename>
    </modified>
    <modified>
      <diff>@@ -26,3 +26,15 @@ breve()-&gt;register('MudChat')
        -&gt;field('area', breve()-&gt;int(array('not_null' =&gt; TRUE)))
        -&gt;field('msg', breve()-&gt;text(array('not_null' =&gt; TRUE)))
        -&gt;field('at', breve()-&gt;text(array('not_null' =&gt; TRUE)));
+
+breve()-&gt;register('MudUpdate')
+       -&gt;table('mud_update')
+       -&gt;field('id', breve()-&gt;int(array('not_null' =&gt; TRUE,
+                                         'autoincrement' =&gt; TRUE)))
+       -&gt;field('at', breve()-&gt;text(array('not_null' =&gt; TRUE,
+                                         'max_length' =&gt; 20)))
+       -&gt;field('type', breve()-&gt;int(array('not_null' =&gt; TRUE)))
+       -&gt;field('user', breve()-&gt;int(array('not_null' =&gt; TRUE)))
+       -&gt;field('area', breve()-&gt;int(array('not_null' =&gt; TRUE)))
+       -&gt;field('msg', breve()-&gt;text(array('not_null' =&gt; TRUE,
+                                          'maxlength' =&gt; 255)));</diff>
      <filename>models/mud.php</filename>
    </modified>
    <modified>
      <diff>@@ -6,23 +6,16 @@
 &lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;&lt;?php echo minim()-&gt;webroot ?&gt;/css/mud.css&quot;&gt;
 &lt;?php minim()-&gt;end_block('page_css') ?&gt;
 
-&lt;?php minim()-&gt;def_block('page_js_head') ?&gt;
+&lt;?php minim()-&gt;def_block('page_js_foot') ?&gt;
 &lt;script type=&quot;text/javascript&quot;&gt;
 var user = &lt;?php echo json_encode($user-&gt;to_array()) ?&gt;;
+var neighbours = &lt;?php echo json_encode($neighbours) ?&gt;;
 &lt;/script&gt;
-&lt;?php minim()-&gt;end_block('page_js_head') ?&gt;
-
-&lt;?php minim()-&gt;def_block('page_js_foot') ?&gt;
 &lt;script type=&quot;text/javascript&quot; src=&quot;&lt;?php echo minim()-&gt;webroot ?&gt;/js/mud.js&quot;&gt;&lt;/script&gt;
 &lt;?php minim()-&gt;end_block('page_js_foot') ?&gt;
 
 &lt;?php minim()-&gt;def_block('page_content') ?&gt;
 User: &lt;?php echo $user-&gt;user ?&gt;&lt;br&gt;
 Area: &lt;?php echo $area ?&gt;&lt;br&gt;
-Neighbours: &lt;ul&gt;
-&lt;?php foreach ($neighbours-&gt;items as $avatar): ?&gt;
-    &lt;li&gt;&lt;?php echo $avatar-&gt;user ?&gt;&lt;/li&gt;
-&lt;?php endforeach ?&gt;
-&lt;/ul&gt;
 &lt;textarea id=&quot;output&quot;&gt;&lt;/textarea&gt;
 &lt;?php minim()-&gt;end_block('page_content') ?&gt;</diff>
      <filename>templates/mud.php</filename>
    </modified>
    <modified>
      <diff>@@ -5,22 +5,16 @@ require_once minim()-&gt;lib('defer');
 require_once minim()-&gt;lib('mud');
 require_once minim()-&gt;models('mud');
 
-if (strtolower($_SERVER['REQUEST_METHOD']) == 'post')
-{
-    // get the user from the session
-    $user = $_POST['user']; //minim()-&gt;user();
+// get the user from the session
+$user = $_REQUEST['user']; //minim()-&gt;user();
 
-    $avatar = breve('MudUser')-&gt;filter(array('user__eq' =&gt; $user))-&gt;first;
+$avatar = breve('MudUser')-&gt;filter(array('user__eq' =&gt; $user))-&gt;first;
 
-    $text = $_POST['says'];
-    $msg = breve('MudChat')-&gt;from(array(
-        'user' =&gt; $user,
-        'area' =&gt; $avatar-&gt;location,
-        'msg' =&gt; $text,
-        'at' =&gt; get_last_update()
-    ))-&gt;save();
-}
-else
-{
-    header('Status: 500');
-}
+$text = $_REQUEST['says'];
+$msg = breve('MudUpdate')-&gt;from(array(
+    'user' =&gt; $user,
+    'area' =&gt; $avatar-&gt;location,
+    'msg' =&gt; $text,
+    'at' =&gt; update_timestamp(),
+    'type' =&gt; 1
+))-&gt;save();</diff>
      <filename>views/mud-say.php</filename>
    </modified>
    <modified>
      <diff>@@ -1,4 +1,6 @@
 &lt;?php
+header('Content-Type: text/plain');
+
 require_once '../lib/minim.php';
 require_once minim()-&gt;lib('breve-refactor');
 require_once minim()-&gt;lib('defer');
@@ -6,44 +8,47 @@ require_once minim()-&gt;lib('mud');
 require_once minim()-&gt;models('mud');
 
 // get the user from the session
-$user = $_GET['user']; //minim()-&gt;user();
-
+$user = @$_GET['user']; //minim()-&gt;user();
 $avatar = breve('MudUser')-&gt;filter(array('user__eq' =&gt; $user))-&gt;first;
 
-// get any chat messages since last update
-$chat = breve('MudChat')-&gt;filter(array(
-    'area__eq' =&gt; $avatar-&gt;location,
-    'user__ne' =&gt; $user,
-    'at__gte' =&gt; get_last_update()
-));
-
-// get the area
-$area = breve('MudArea')-&gt;get($avatar-&gt;location)-&gt;first;
-
-// get the user's neighbours
-$neighbours = breve('MudUser')-&gt;filter(array(
-    'user__ne' =&gt; $user,
-    'location__eq' =&gt; $avatar-&gt;location
-));
-
-// set the user's last update time to now
-$last_update = update_timestamp();
-
-// if the user's x and y coords have changed, update
-$x = @$_REQUEST['x'];
-$y = @$_REQUEST['y'];
-if (($x and $x != $avatar-&gt;x) or ($y and $y != $avatar-&gt;y))
+$last_id = @$_SESSION['last_id'];
+if (!$last_id)
 {
-    $avatar-&gt;x = $x;
-    $avatar-&gt;y = $y;
-    $avatar-&gt;save();
+    $last_id = update_timestamp();
 }
 
-header('Content-Type: text/json');
-minim()-&gt;render('mud_json', array(
-    'user' =&gt; $avatar,
-    'area' =&gt; $area-&gt;id,
-    'neighbours' =&gt; $neighbours,
-    'chat' =&gt; $chat,
-    'last_update' =&gt; $last_update
-));
+$msgs = array();
+$start = time();
+while (!$msgs and (time() - $start) &lt; 1)
+{
+    // get any changes since last update
+    $msgs = breve('MudUpdate')-&gt;filter(array(
+        'area__eq' =&gt; $avatar-&gt;location,
+        'user__ne' =&gt; $user,
+        'at__gte' =&gt; $last_id
+    ))-&gt;to_array();
+
+    if ($msgs)
+    {
+        $last_id = update_timestamp();
+        $_SESSION['last_id'] = $last_id;
+
+        // output json
+        echo json_encode(array(
+            'result' =&gt; $msgs,
+            'last_id' =&gt; $last_id
+        )), &quot;\n&quot;;
+        
+        flush();
+        break;
+    }
+    usleep(500000); // 0.5s polling interval
+}
+if (!$msgs)
+{
+    echo json_encode(array(
+        'result' =&gt; array(),
+        'last_id' =&gt; $last_id,
+        'debug' =&gt; join(&quot;\n&quot;, minim()-&gt;log_msgs)
+    ));
+}</diff>
      <filename>views/mud-update.php</filename>
    </modified>
    <modified>
      <diff>@@ -19,5 +19,5 @@ $neighbours = breve('MudUser')-&gt;filter(array(
 minim()-&gt;render('mud', array(
     'user' =&gt; $avatar,
     'area' =&gt; $area-&gt;id,
-    'neighbours' =&gt; $neighbours,
+    'neighbours' =&gt; $neighbours-&gt;to_array(),
 ));</diff>
      <filename>views/mud.php</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>1224f089b8dc2de68a51484b45fbf13379487570</id>
    </parent>
  </parents>
  <author>
    <name>Andy Driver</name>
    <email>andy.driver@gcapmedia.com</email>
  </author>
  <url>http://github.com/andyhd/minim/commit/ef51cc401e1171aaf2abd62b7b0b1bea267f2d33</url>
  <id>ef51cc401e1171aaf2abd62b7b0b1bea267f2d33</id>
  <committed-date>2008-09-05T00:40:02-07:00</committed-date>
  <authored-date>2008-09-05T00:40:02-07:00</authored-date>
  <message>Refactored MUD to use long polling AJAX, solves increasing delay problem</message>
  <tree>e9866519ae532b6779b038e49805db04083e52c9</tree>
  <committer>
    <name>Andy Driver</name>
    <email>andy.driver@gcapmedia.com</email>
  </committer>
</commit>
