--- deliantra/server/lib/cf.pm 2006/08/26 23:36:32 1.45 +++ deliantra/server/lib/cf.pm 2006/08/27 13:02:04 1.47 @@ -13,6 +13,8 @@ use strict; +_reload_1; + our %COMMAND = (); our @EVENT; our %PROP_TYPE; @@ -105,23 +107,74 @@ ############################################################################# # "new" plug-in system -=item cf::object::attach ... # NYI +=item $object->attach ($attachment, ...) + +Attach a pre-registered attachment to an object. + +=item $player->attach ($attachment, ...) + +Attach a pre-registered attachment to a player. + +=item $map->attach ($attachment, ...) # not yet persistent + +Attach a pre-registered attachment to a map. =item cf::attach_global ... -=item cf::attach_to_type $object_type, ... +Attach handlers for global events. + +This and all following C-functions expect any number of the +following handler/hook descriptions: + +=over 4 + +=item prio => $number + +Set the priority for all following handlers/hooks (unless overwritten +by another C setting). Lower priority handlers get executed +earlier. The default priority is C<0>, and many built-in handlers are +registered at priority C<-1000>, so lower priorities should not be used +unless you know what you are doing. + +=item on_I => \&cb + +Call the given code reference whenever the named event happens (event is +something like C, C, C and so on, and which +handlers are recognised generally depends on the type of object these +handlers attach to). + +See F for the full list of events supported, and their +class. + +=item package => package:: + +Look for sub functions of the name C<< on_I >> in the given +package and register them. Only handlers for eevents supported by the +object/class are recognised. + +=back + +=item cf::attach_to_type $object_type, $subtype, ... + +Attach handlers for a specific object type (e.g. TRANSPORT) and +subtype. If C<$subtype> is zero or undef, matches all objects of the given +type. =item cf::attach_to_objects ... +Attach handlers to all objects. Do not use this except for debugging or +very rare events, as handlers are (obviously) called for I objects in +the game. + =item cf::attach_to_players ... +Attach handlers to all players. + =item cf::attach_to_maps ... -=item cf:register_attachment $name, ... +Attach handlers to all maps. - prio => $number, # lower is earlier - on_xxx => \&cb, - package => package::, +=item cf:register_attachment $name, ... =cut @@ -193,8 +246,54 @@ \%undo } +sub _attach_attachment { + my ($obj, $name, @args) = @_; + + my $res; + + if (my $attach = $attachment{$name}) { + my $registry = $obj->registry; + + for (@$attach) { + my ($klass, @attach) = @$_; + $res = _attach @$registry, $klass, @attach; + } + + if (my $cb = delete $registry->[EVENT_OBJECT_INSTANTIATE]) { + for (@$cb) { + eval { $_->[1]->($obj, @args); }; + if ($@) { + warn "$@"; + warn "... while processing '$name' instantiate with args <@args>.\n"; + } + } + } + } else { + warn "object uses attachment '$name' that is not available, postponing.\n"; + } + + push @{$obj->{_attachment}}, $name; + + $res->{attachment} = $name; + $res +} + sub cf::object::attach { - die; + my ($obj, $name, @args) = @_; + + _attach_attachment $obj, $name, @args; +} + +sub cf::player::attach { + my ($obj, $name, @args) = @_; + + _attach_attachment KLASS_PLAYER, $obj, $name, @args; +} + +sub cf::map::attach { + my ($obj, $name, @args) = @_; + + _attach_attachment KLASS_MAP, $obj, $name, @args; } sub attach_global { @@ -203,8 +302,9 @@ sub attach_to_type { my $type = shift; + my $subtype = shift; - _attach @{$CB_TYPE[$type]}, KLASS_OBJECT, @_ + _attach @{$CB_TYPE[$type + $subtype * NUM_SUBTYPES]}, KLASS_OBJECT, @_ } sub attach_to_objects { @@ -222,7 +322,7 @@ sub register_attachment { my $name = shift; - $attachment{$name} = [@_]; + $attachment{$name} = [[KLASS_OBJECT, @_]]; } our $override; @@ -261,39 +361,57 @@ sub instantiate { my ($obj, $data) = @_; - my $registry = $obj->registry; $data = from_json $data; for (@$data) { - my ($pri, $name, @args) = @$_; + my ($name, $args) = @$_; + attach $obj, $name, @{$args || [] }; + } +} - if (my $attach = $attachment{$name}) { - _attach @$registry, KLASS_OBJECT, @$attach; +# basically do the same as instantiate, without calling instantiate +sub reattach { + my ($obj) = @_; + my $registry = $obj->registry; - if (my $cb = delete $registry->[EVENT_OBJECT_INSTANTIATE]) { - for (@$cb) { - eval { $_->[1]->($obj, @args); }; - if ($@) { - warn "$@"; - warn "... while processing '$name' instantiate with args <@args>\n"; - } - } + @$registry = (); + + for my $name (@{ $obj->{_attachment} }) { + if (my $attach = $attachment{$name}) { + for (@$attach) { + my ($klass, @attach) = @$_; + _attach @$registry, $klass, @attach; } } else { - warn "object uses attachment $name that is not available, postponing.\n"; + warn "object uses attachment '$name' that is not available, postponing.\n"; } + } +} + +sub object_freezer_save { + my ($filename, $objs) = @_; - push @{$obj->{_attachment}}, $name; + $filename .= ".pst"; + + if (@$objs) { + open my $fh, ">:raw", "$filename~"; + chmod $fh, SAVE_MODE; + syswrite $fh, Storable::nfreeze { version => 1, objs => $objs }; + close $fh; + rename "$filename~", $filename; + } else { + unlink $filename; } } -# basically do the same as instantiate, without calling instantiate -sub reattach { - my ($obj) = @_; - my $registry = $obj->registry; +sub object_thawer_load { + my ($filename) = @_; + + open my $fh, "<:raw:perlio", "$filename.pst" + or return; - warn "reattach<@_, $_>\n"; + eval { local $/; (Storable::thaw <$fh>)->{objs} } } attach_to_objects @@ -302,14 +420,11 @@ my ($src, $dst) = @_; @{$dst->registry} = @{$src->registry}; - warn "registry clone ", join ":", @{$src->registry};#d# %$dst = %$src; $dst->{_attachment} = [@{ $src->{_attachment} }] if exists $src->{_attachment}; - - warn "clone<@_>\n";#d# }, ; @@ -560,6 +675,7 @@ defined $path or return; unlink "$path.cfperl"; + unlink "$path.pst"; }; *cf::mapsupport::on_swapin = @@ -580,33 +696,6 @@ $map->_set_obs ($data->{obs}); }; -*cf::mapsupport::on_swapout = sub { - my ($map) = @_; - - my $path = $map->tmpname; - $path = $map->path unless defined $path; - - my $obs = $map->_get_obs; - - if (defined $obs) { - open my $fh, ">:raw", "$path.cfperl" - or die "$path.cfperl: $!"; - - stat $path; - - print $fh Storable::nfreeze { - size => (stat _)[7], - time => (stat _)[9], - version => 1, - obs => $obs, - }; - - chmod SAVE_MODE, "$path.cfperl"; # very racy, but cf-compatible *g* - } else { - unlink "$path.cfperl"; - } -}; - attach_to_maps prio => -10000, package => cf::mapsupport::; ############################################################################# @@ -628,12 +717,6 @@ } } }, - on_save => sub { - my ($pl, $path) = @_; - - $_->set_ob_key_value (_perl_data => unpack "H*", Storable::nfreeze $_) - for grep %$_, all_objects $pl->ob; - }, ; ############################################################################# @@ -781,5 +864,7 @@ }, ); +_reload_2; + 1