Acme-MUDLike
view release on metacpan or search on metacpan
lib/Acme/MUDLike.pm view on Meta::CPAN
package Acme::MUDLike;
use 5.008000;
use strict;
use warnings;
use Continuity;
use Carp;
use Devel::Pointer;
our $VERSION = '0.04';
# Todo:
#
# * what would be *really* cool is doing on the fly image generation to draw an overhead map of the program based on a
# graph of which objects reference which other objects and let people go walk around inside of their program
# and then they could fight methods and use global variables as weapons!
#
# * http://zvtm.sourceforge.net/zgrviewer.html or something similar for showing the user the "map" of
# nodes/rooms/whatever made of has-a references or something.
#
# * /goto should put you inside an arbitrary object, /look should list as exits and/or items the object references contained by that object
# in other words, break away from our rigid API for inventory/room/etc.
#
# * need a black list black list, so we can re-add ourself to things that get serialized by Acme::State even though we're in %INC
#
# * need an error log viewabe by all.
#
# * eval and its output should be sent to the whole room.
#
# * Better account management.
#
# * There's code around to parse LPC and convert it to Perl. It would be neat to offer a full blown 2.4.5
# lib for people to play around in.
#
# * Acme::IRCLike would probably be more popular -- bolt an IRC server onto your app.
#
# * Also, a telnet interface beyond just an HTTP interface would be nice. Should be easy to do.
#
# * Let "players" wander between apps. Offer RPC to support this.
#
# * Optionally take an existing Continuity instance with path_session set and optionally parameters
# for the paths to use for chat pull and commands.
# Not sure how to work this; each path gets its own coroutine, but there is still only one main().
# Continuity doesn't have a registry of which paths go to which callbacks.
#
# Done:
#
# * mark/call commands should have a current object register, so you can do /call thingie whatever /next and then be calling
# into the object returned by thingie->whatever
#
# * /list (like look, but with stringified object references)
#
# * /mark <n> ... or... /mark <stringified obj ref>
#
# * messages still in duplicate when the same player logs in twice; make room's tell_object operate uniquely.
#
# * messages in triplicate because each player has three routines and is inserted into the floor three times. oops.
#
# * build the ajax.chat.js into source. -- okay, test.
#
# * eval, call
#
# * inventory's insert() method should set the insertee's environment to itself. that way, all objects have an environment.
#
# * Commands need to do $floor->tell_object or $self->tell_object rather than output directly.
#
# * Put @messages into the room ($floor). Get the chat action out of the main loop. Dispatch all
# actions. Maybe.
#
our $password; # Acme::State friendly
our $floor; # holds all other objects
our $players; # holds all players; kind of like $floor except in the future, inactive players might get removed from the floor, or there might be multiple rooms
my $continuity;
my $got_message; # diddled to wake the chat event watchers
$SIG{PIPE} = 'IGNORE';
sub new {
my $package = shift;
my %args = @_;
die "We've already got one" if $continuity;
$password = delete $args{password} if exists $args{password};
lib/Acme/MUDLike.pm view on Meta::CPAN
if ( p == this ) return false;
// Execute the right function
return (e.type == "mouseover" ? f : g).apply(this, [e]);
}
// Bind the function to the two event listeners
return this.mouseover(handleHover).mouseout(handleHover);
},
ready: function(f) {
// If the DOM is already ready
if ( jQuery.isReady )
// Execute the function immediately
f.apply( document, [jQuery] );
// Otherwise, remember the function for later
else {
// Add the function to the wait list
jQuery.readyList.push( function() { return f.apply(this, [jQuery]) } );
}
return this;
}
});
jQuery.extend({
/*
* All the code that makes DOM Ready work nicely.
*/
isReady: false,
readyList: [],
// Handle when the DOM is ready
ready: function() {
// Make sure that the DOM is not already loaded
if ( !jQuery.isReady ) {
// Remember that the DOM is ready
jQuery.isReady = true;
// If there are functions bound, to execute
if ( jQuery.readyList ) {
// Execute all of them
jQuery.each( jQuery.readyList, function(){
this.apply( document );
});
// Reset the list of functions
jQuery.readyList = null;
}
// Remove event lisenter to avoid memory leak
if ( jQuery.browser.mozilla || jQuery.browser.opera )
document.removeEventListener( "DOMContentLoaded", jQuery.ready, false );
}
}
});
new function(){
jQuery.each( ("blur,focus,load,resize,scroll,unload,click,dblclick," +
"mousedown,mouseup,mousemove,mouseover,mouseout,change,select," +
"submit,keydown,keypress,keyup,error").split(","), function(i,o){
// Handle event binding
jQuery.fn[o] = function(f){
return f ? this.bind(o, f) : this.trigger(o);
};
});
// If Mozilla is used
if ( jQuery.browser.mozilla || jQuery.browser.opera )
// Use the handy event callback
document.addEventListener( "DOMContentLoaded", jQuery.ready, false );
// If IE is used, use the excellent hack by Matthias Miller
// http://www.outofhanwell.com/blog/index.php?title=the_window_onload_problem_revisited
else if ( jQuery.browser.msie ) {
// Only works if you document.write() it
document.write("<scr" + "ipt id=__ie_init defer=true " +
"src=//:><\/script>");
// Use the defer script hack
var script = document.getElementById("__ie_init");
// script does not exist if jQuery is loaded dynamically
if ( script )
script.onreadystatechange = function() {
if ( this.readyState != "complete" ) return;
this.parentNode.removeChild( this );
jQuery.ready();
};
// Clear from memory
script = null;
// If Safari is used
} else if ( jQuery.browser.safari )
// Continually check to see if the document.readyState is valid
jQuery.safariTimer = setInterval(function(){
// loaded and complete are both valid states
if ( document.readyState == "loaded" ||
document.readyState == "complete" ) {
// If either one are found, remove the timer
clearInterval( jQuery.safariTimer );
jQuery.safariTimer = null;
// and execute any waiting functions
jQuery.ready();
}
}, 10);
// A fallback to window.onload, that will always work
jQuery.event.add( window, "load", jQuery.ready );
};
// Clean up after IE to avoid memory leaks
if (jQuery.browser.msie)
jQuery(window).one("unload", function() {
lib/Acme/MUDLike.pm view on Meta::CPAN
s.data = jQuery.param(s.data);
// append data to url for get requests
if( s.type.toLowerCase() == "get" ) {
// "?" + data or "&" + data (in case there are already params)
s.url += ((s.url.indexOf("?") > -1) ? "&" : "?") + s.data;
// IE likes to send both get and post data, prevent this
s.data = null;
}
}
// Watch for a new set of requests
if ( s.global && ! jQuery.active++ )
jQuery.event.trigger( "ajaxStart" );
var requestDone = false;
// Create the request object
var xml = new XMLHttpRequest();
// Open the socket
xml.open(s.type, s.url, s.async);
// Set the correct header, if data is being sent
if ( s.data )
xml.setRequestHeader("Content-Type", s.contentType);
// Set the If-Modified-Since header, if ifModified mode.
if ( s.ifModified )
xml.setRequestHeader("If-Modified-Since",
jQuery.lastModified[s.url] || "Thu, 01 Jan 1970 00:00:00 GMT" );
// Set header so the called script knows that it's an XMLHttpRequest
xml.setRequestHeader("X-Requested-With", "XMLHttpRequest");
// Make sure the browser sends the right content length
if ( xml.overrideMimeType )
xml.setRequestHeader("Connection", "close");
// Allow custom headers/mimetypes
if( s.beforeSend )
s.beforeSend(xml);
if ( s.global )
jQuery.event.trigger("ajaxSend", [xml, s]);
// Wait for a response to come back
var onreadystatechange = function(isTimeout){
// The transfer is complete and the data is available, or the request timed out
if ( xml && (xml.readyState == 4 || isTimeout == "timeout") ) {
requestDone = true;
// clear poll interval
if (ival) {
clearInterval(ival);
ival = null;
}
var status;
try {
status = jQuery.httpSuccess( xml ) && isTimeout != "timeout" ?
s.ifModified && jQuery.httpNotModified( xml, s.url ) ? "notmodified" : "success" : "error";
// Make sure that the request was successful or notmodified
if ( status != "error" ) {
// Cache Last-Modified header, if ifModified mode.
var modRes;
try {
modRes = xml.getResponseHeader("Last-Modified");
} catch(e) {} // swallow exception thrown by FF if header is not available
if ( s.ifModified && modRes )
jQuery.lastModified[s.url] = modRes;
// process the data (runs the xml through httpData regardless of callback)
var data = jQuery.httpData( xml, s.dataType );
// If a local callback was specified, fire it and pass it the data
if ( s.success )
s.success( data, status );
// Fire the global callback
if( s.global )
jQuery.event.trigger( "ajaxSuccess", [xml, s] );
} else
jQuery.handleError(s, xml, status);
} catch(e) {
status = "error";
jQuery.handleError(s, xml, status, e);
}
// The request was completed
if( s.global )
jQuery.event.trigger( "ajaxComplete", [xml, s] );
// Handle the global AJAX counter
if ( s.global && ! --jQuery.active )
jQuery.event.trigger( "ajaxStop" );
// Process result
if ( s.complete )
s.complete(xml, status);
// Stop memory leaks
if(s.async)
xml = null;
}
};
// don't attach the handler to the request, just poll it instead
var ival = setInterval(onreadystatechange, 13);
// Timeout checker
if ( s.timeout > 0 )
setTimeout(function(){
// Check to see if the request is still happening
if ( xml ) {
// Cancel the request
xml.abort();
if( !requestDone )
onreadystatechange( "timeout" );
}
}, s.timeout);
// Send the data
try {
xml.send(s.data);
} catch(e) {
jQuery.handleError(s, xml, null, e);
}
// firefox 1.5 doesn't fire statechange for sync requests
if ( !s.async )
onreadystatechange();
// return XMLHttpRequest to allow aborting the request etc.
return xml;
},
handleError: function( s, xml, status, e ) {
// If a local callback was specified, fire it
if ( s.error ) s.error( xml, status, e );
// Fire the global callback
if ( s.global )
jQuery.event.trigger( "ajaxError", [xml, s, e] );
},
// Counter for holding the number of active queries
active: 0,
// Determines if an XMLHttpRequest was successful or not
httpSuccess: function( r ) {
try {
return !r.status && location.protocol == "file:" ||
( r.status >= 200 && r.status < 300 ) || r.status == 304 ||
jQuery.browser.safari && r.status == undefined;
} catch(e){}
return false;
},
// Determines if an XMLHttpRequest returns NotModified
httpNotModified: function( xml, url ) {
try {
var xmlRes = xml.getResponseHeader("Last-Modified");
// Firefox always returns 200. check Last-Modified date
return xml.status == 304 || xmlRes == jQuery.lastModified[url] ||
jQuery.browser.safari && xml.status == undefined;
} catch(e){}
return false;
},
/* Get the data out of an XMLHttpRequest.
* Return parsed XML if content-type header is "xml" and type is "xml" or omitted,
* otherwise return plain text.
* (String) data - The type of data that you're expecting back,
* (e.g. "xml", "html", "script")
*/
httpData: function( r, type ) {
var ct = r.getResponseHeader("content-type");
var data = !type && ct && ct.indexOf("xml") >= 0;
data = type == "xml" || data ? r.responseXML : r.responseText;
// If the type is "script", eval it in global context
if ( type == "script" )
jQuery.globalEval( data );
// Get the JavaScript object, if JSON is used.
if ( type == "json" )
eval( "data = " + data );
// evaluate scripts within html
if ( type == "html" )
jQuery("<div>").html(data).evalScripts();
return data;
},
// Serialize an array of form elements or a set of
// key/values into a query string
param: function( a ) {
( run in 0.495 second using v1.01-cache-2.11-cpan-5a3173703d6 )