Acme-MUDLike
view release on metacpan or search on metacpan
lib/Acme/MUDLike.pm view on Meta::CPAN
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.
lib/Acme/MUDLike.pm view on Meta::CPAN
$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};
$password ||= join('', map { $_->[int rand scalar @$_] } (['a'..'z', 'A'..'Z', '0'..'9']) x 8),
my $staticp = sub {
# warn "staticp: url->path: ``@{[ $_[0]->url->path ]}''";
return 0 if $_[0]->url->path =~ m/\.js$/;
# warn "staticp: dynamic js handling override not engaged";
return $_[0]->url->path =~ m/\.(jpg|jpeg|gif|png|css|ico|js)$/
};
$continuity = $args{continuity} || Continuity->new(
staticp => sub { $staticp->(@_); },
lib/Acme/MUDLike.pm view on Meta::CPAN
sub tell_object {
my $self = shift;
my $msg = shift;
push @{$self->{messages}}, $msg;
shift @{$self->{messages}} if @{$self->{messages}} > 100;
$got_message = 1; # XXX wish this didn't happen for each player but only once after all players got their message
}
sub get_html_messages {
my $self = shift;
return join "<br>\n", map { s{<}{\<}gs; s{\n}{<br>\n}g; $_ } $self->get_messages;
}
sub get_messages {
my $self = shift;
my @ret;
# this is written out long because I keep changing it around
for my $i (1..20) {
exists $self->{messages}->[-$i] or last;
my $msg = $self->{messages}->[-$i];
push @ret, $msg;
lib/Acme/MUDLike.pm view on Meta::CPAN
# this is called by login() immediately after verifying credientials
if($request->request->url->path =~ m/pushstream/) {
# warn "pushstream path_session handling XXX";
my $w = Coro::Event->var(var => \$got_message, poll => 'w');
while(1) {
$w->next;
# warn "got_message diddled XXX";
# on submitting the form without a JS background post, the poll HTTP connection gets broken
$SIG{PIPE} = 'IGNORE';
$request->print( join "<br>\n", map { s{<}{\<}gs; s{\n}{<br>\n}g; $_ } $self->get_messages );
$request->next;
}
}
if($request->request->url->path =~ m/sendmessage/) {
while(1) {
# warn "sendmessage path_session handling XXX";
my $msg = $request->param('message');
$self->parse_command($msg);
# $request->print("Got message.\n");
lib/Acme/MUDLike.pm view on Meta::CPAN
};
$self->tell_object(join '', "Call: ", eval { $ob->can($func)->($ob, @args); } || "Error: ``$@''.");
1;
}
sub _list {
my $self = shift;
my $i = 0;
$self->tell_object(join '',
"Here, you see:\n",
map qq{$_\n},
map { $i . ': ' . $_ }
$self->environment->contents, $self->inventory->contents,
);
}
sub _mark {
my $self = shift;
my $item = shift;
my $ob = $self->item_by_arg($item) or do {
$self->tell_object("mark: no item by that name/number/package name here");
return;
lib/Acme/MUDLike.pm view on Meta::CPAN
}
sub _who {
my $self = shift;
$self->_look(@_); # for now
}
sub _look {
my $self = shift;
my @args = @_;
# $self->tell_object(join '', "Here, you see:\n", map qq{$_\n}, map $_->name, $floor->contents);
$self->tell_object(join '',
"Here, you see:\n",
map qq{$_\n},
map { $_->can('name') ? $_->name : ref($_) }
$self->environment->contents
);
}
sub _inv {
my $self = shift;
$self->_inventory(@_);
}
sub _i {
my $self = shift;
$self->_inventory(@_);
}
sub _inventory {
my $self = shift;
my @args = @_;
$self->tell_object(join '',
"You are holding:\n",
map qq{$_\n},
map { $_->can('name') ? $_->name : ''.$_ }
$self->inventory->contents
);
}
sub _take {
my $self = shift;
my @args = @_;
if(@args == 1) {
# take thingie
my $item = $floor->delete($args[0]) or do { $self->tell_object("No ``$args[0]'' here."); return; };
lib/Acme/MUDLike.pm view on Meta::CPAN
$server->loop; # or call the Event or AnyEvent event loop
Connect to the URL provided and cut and paste into the text box:
/eval package sword; our @ISA = qw/Acme::MUDLike::object/; sub new { my $pack = shift; $pack->SUPER::new(name=>"sword", @_); }
/clone sword
/i
/call sword name
wee, fun! oh, hai everyone!
/eval no strict "refs"; join '', map "$_\n", keys %{"main::"};
/call Acme::MUDLike::player=HASH(0x8985e10) name
=head1 DESCRIPTION
Multi user chat, general purpose object tracer, eval, and give/drop/take/clone/dest/look.
Adds a social element to software development and develop it from within.
Chat within the application, eval code inside of it (sort of like a simple Read-Eval-Parse Loop).
Call methods in objects from the command line.
Create instances of objects, give them to people, drop them on the floor.
lib/Acme/MUDLike.pm view on Meta::CPAN
},
after: function() {
return this.domManip(arguments, false, -1, function(a){
this.parentNode.insertBefore( a, this.nextSibling );
});
},
end: function() {
return this.prevObject || jQuery([]);
},
find: function(t) {
return this.pushStack( jQuery.map( this, function(a){
return jQuery.find(t,a);
}), t );
},
clone: function(deep) {
return this.pushStack( jQuery.map( this, function(a){
var a = a.cloneNode( deep != undefined ? deep : true );
a.$events = null; // drop $events expando to avoid firing incorrect events
return a;
}) );
},
filter: function(t) {
return this.pushStack(
jQuery.isFunction( t ) &&
jQuery.grep(this, function(el, index){
lib/Acme/MUDLike.pm view on Meta::CPAN
var result = [];
// Go through the array, only saving the items
// that pass the validator function
for ( var i = 0, el = elems.length; i < el; i++ )
if ( !inv && fn(elems[i],i) || inv && !fn(elems[i],i) )
result.push( elems[i] );
return result;
},
map: function(elems, fn) {
// If a string is passed in for the function, make a function
// for it (a handy shortcut)
if ( typeof fn == "string" )
fn = new Function("a","return " + fn);
var result = [], r = [];
// Go through the array, translating each of the items to their
// new value (or values).
for ( var i = 0, el = elems.length; i < el; i++ ) {
lib/Acme/MUDLike.pm view on Meta::CPAN
jQuery.each({
parent: "a.parentNode",
parents: "jQuery.parents(a)",
next: "jQuery.nth(a,2,'nextSibling')",
prev: "jQuery.nth(a,2,'previousSibling')",
siblings: "jQuery.sibling(a.parentNode.firstChild,a)",
children: "jQuery.sibling(a.firstChild)"
}, function(i,n){
jQuery.fn[ i ] = function(a) {
var ret = jQuery.map(this,n);
if ( a && typeof a == "string" )
ret = jQuery.multiFilter(a,ret);
return this.pushStack( ret );
};
});
jQuery.each({
appendTo: "append",
prependTo: "prepend",
insertBefore: "before",
lib/Acme/MUDLike.pm view on Meta::CPAN
// Look for pre-defined expression tokens
for ( var i = 0; i < jQuery.token.length; i += 2 ) {
// Attempt to match each, individual, token in
// the specified order
var re = jQuery.token[i];
var m = re.exec(t);
// If the token match was found
if ( m ) {
// Map it against the token's handler
r = ret = jQuery.map( ret, jQuery.isFunction( jQuery.token[i+1] ) ?
jQuery.token[i+1] :
function(a){ return eval(jQuery.token[i+1]); });
// And remove the token
t = jQuery.trim( t.replace( re, "" ) );
foundToken = true;
break;
}
}
}
( run in 1.153 second using v1.01-cache-2.11-cpan-49f99fa48dc )