ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/lib/cf.pm
Revision: 1.72
Committed: Sun Oct 1 11:41:37 2006 UTC (17 years, 7 months ago) by root
Branch: MAIN
Changes since 1.71: +15 -0 lines
Log Message:
support %cf::CFG hash

File Contents

# User Rev Content
1 root 1.1 package cf;
2    
3     use Symbol;
4     use List::Util;
5 root 1.6 use Storable;
6 root 1.23 use Opcode;
7     use Safe;
8     use Safe::Hole;
9 root 1.19
10 root 1.72 use YAML::Syck ();
11 root 1.32 use Time::HiRes;
12 root 1.18 use Event;
13 root 1.19 $Event::Eval = 1; # no idea why this is required, but it is
14 root 1.1
15 root 1.72 # work around bug in YAML::Syck - bad news for perl6, will it be as broken wrt. unicode?
16     $YAML::Syck::ImplicitUnicode = 1;
17    
18 root 1.1 use strict;
19    
20 root 1.63 _init_vars;
21 root 1.47
22 root 1.39 our %COMMAND = ();
23 root 1.1 our @EVENT;
24 root 1.27 our $LIBDIR = maps_directory "perl";
25 root 1.1
26 root 1.35 our $TICK = MAX_TIME * 1e-6;
27     our $TICK_WATCHER;
28     our $NEXT_TICK;
29    
30 root 1.70 our %CFG;
31    
32     #############################################################################
33    
34     =head2 GLOBAL VARIABLES
35    
36     =over 4
37    
38     =item $cf::LIBDIR
39    
40     The perl library directory, where extensions and cf-specific modules can
41     be found. It will be added to C<@INC> automatically.
42    
43     =item $cf::TICK
44    
45     The interval between server ticks, in seconds.
46    
47     =item %cf::CFG
48    
49     Configuration for the server, loaded from C</etc/crossfire/config>, or
50     from wherever your confdir points to.
51    
52     =back
53    
54     =cut
55    
56 root 1.1 BEGIN {
57     *CORE::GLOBAL::warn = sub {
58     my $msg = join "", @_;
59     $msg .= "\n"
60     unless $msg =~ /\n$/;
61    
62     print STDERR "cfperl: $msg";
63     LOG llevError, "cfperl: $msg";
64     };
65     }
66    
67 root 1.41 @safe::cf::object::player::ISA = @cf::object::player::ISA = 'cf::object';
68 root 1.25
69 root 1.41 # we bless all objects into (empty) derived classes to force a method lookup
70 root 1.25 # within the Safe compartment.
71 root 1.50 for my $pkg (qw(cf::object cf::object::player cf::player cf::map cf::party cf::region cf::arch cf::living)) {
72 root 1.25 no strict 'refs';
73 root 1.41 @{"safe::$pkg\::wrap::ISA"} = @{"$pkg\::wrap::ISA"} = $pkg;
74 root 1.25 }
75 root 1.1
76 root 1.18 $Event::DIED = sub {
77     warn "error in event callback: @_";
78     };
79    
80 root 1.5 my %ext_pkg;
81 root 1.1 my @exts;
82     my @hook;
83     my %command;
84 root 1.15 my %extcmd;
85 root 1.1
86 root 1.70 =head2 UTILITY FUNCTIONS
87    
88     =over 4
89    
90     =cut
91 root 1.44
92 root 1.45 use JSON::Syck (); # TODO# replace by JSON::PC once working
93 root 1.44
94 root 1.70 =item $ref = cf::from_json $json
95    
96     Converts a JSON string into the corresponding perl data structure.
97    
98     =cut
99    
100 root 1.45 sub from_json($) {
101     $JSON::Syck::ImplicitUnicode = 1; # work around JSON::Syck bugs
102     JSON::Syck::Load $_[0]
103 root 1.44 }
104    
105 root 1.70 =item $json = cf::to_json $ref
106    
107     Converts a perl data structure into its JSON representation.
108    
109     =cut
110    
111 root 1.45 sub to_json($) {
112     $JSON::Syck::ImplicitUnicode = 0; # work around JSON::Syck bugs
113     JSON::Syck::Dump $_[0]
114 root 1.44 }
115    
116 root 1.70 =back
117    
118 root 1.71 =cut
119    
120 root 1.44 #############################################################################
121 root 1.39
122 root 1.70 =head2 EVENTS AND OBJECT ATTACHMENTS
123 root 1.55
124     =over 4
125    
126 root 1.48 =item $object->attach ($attachment, key => $value...)
127 root 1.46
128 root 1.53 =item $object->detach ($attachment)
129    
130     Attach/detach a pre-registered attachment to an object.
131 root 1.46
132 root 1.48 =item $player->attach ($attachment, key => $value...)
133 root 1.46
134 root 1.53 =item $player->detach ($attachment)
135    
136     Attach/detach a pre-registered attachment to a player.
137    
138     =item $map->attach ($attachment, key => $value...)
139 root 1.46
140 root 1.53 =item $map->detach ($attachment)
141 root 1.46
142 root 1.53 Attach/detach a pre-registered attachment to a map.
143 root 1.39
144 root 1.55 =item $bool = $object->attached ($name)
145    
146     =item $bool = $player->attached ($name)
147    
148     =item $bool = $map->attached ($name)
149    
150     Checks wether the named attachment is currently attached to the object.
151    
152 root 1.40 =item cf::attach_global ...
153 root 1.39
154 root 1.46 Attach handlers for global events.
155    
156     This and all following C<attach_*>-functions expect any number of the
157     following handler/hook descriptions:
158    
159     =over 4
160    
161     =item prio => $number
162    
163     Set the priority for all following handlers/hooks (unless overwritten
164     by another C<prio> setting). Lower priority handlers get executed
165     earlier. The default priority is C<0>, and many built-in handlers are
166     registered at priority C<-1000>, so lower priorities should not be used
167     unless you know what you are doing.
168    
169     =item on_I<event> => \&cb
170    
171     Call the given code reference whenever the named event happens (event is
172     something like C<instantiate>, C<apply>, C<use_skill> and so on, and which
173     handlers are recognised generally depends on the type of object these
174     handlers attach to).
175    
176     See F<include/eventinc.h> for the full list of events supported, and their
177     class.
178    
179     =item package => package::
180    
181     Look for sub functions of the name C<< on_I<event> >> in the given
182     package and register them. Only handlers for eevents supported by the
183     object/class are recognised.
184    
185     =back
186    
187 root 1.47 =item cf::attach_to_type $object_type, $subtype, ...
188 root 1.39
189 root 1.47 Attach handlers for a specific object type (e.g. TRANSPORT) and
190     subtype. If C<$subtype> is zero or undef, matches all objects of the given
191     type.
192 root 1.46
193 root 1.40 =item cf::attach_to_objects ...
194 root 1.39
195 root 1.46 Attach handlers to all objects. Do not use this except for debugging or
196     very rare events, as handlers are (obviously) called for I<all> objects in
197     the game.
198    
199 root 1.40 =item cf::attach_to_players ...
200 root 1.39
201 root 1.46 Attach handlers to all players.
202    
203 root 1.40 =item cf::attach_to_maps ...
204 root 1.39
205 root 1.46 Attach handlers to all maps.
206    
207 root 1.45 =item cf:register_attachment $name, ...
208    
209 root 1.52 Register an attachment by name through which objects can refer to this
210     attachment.
211    
212 root 1.55 =item cf:register_player_attachment $name, ...
213    
214     Register an attachment by name through which players can refer to this
215     attachment.
216    
217 root 1.52 =item cf:register_map_attachment $name, ...
218    
219     Register an attachment by name through which maps can refer to this
220     attachment.
221    
222 root 1.39 =cut
223    
224 root 1.40 # the following variables are defined in .xs and must not be re-created
225 root 1.39 our @CB_GLOBAL = (); # registry for all global events
226 root 1.45 our @CB_OBJECT = (); # all objects (should not be used except in emergency)
227 root 1.40 our @CB_PLAYER = ();
228 root 1.39 our @CB_TYPE = (); # registry for type (cf-object class) based events
229 root 1.40 our @CB_MAP = ();
230 root 1.39
231 root 1.45 my %attachment;
232    
233 root 1.39 sub _attach_cb($\%$$$) {
234     my ($registry, $undo, $event, $prio, $cb) = @_;
235    
236     use sort 'stable';
237    
238     $cb = [$prio, $cb];
239    
240     @{$registry->[$event]} = sort
241     { $a->[0] cmp $b->[0] }
242     @{$registry->[$event] || []}, $cb;
243    
244     push @{$undo->{cb}}, [$event, $cb];
245     }
246    
247     # attach handles attaching event callbacks
248     # the only thing the caller has to do is pass the correct
249     # registry (== where the callback attaches to).
250 root 1.45 sub _attach(\@$@) {
251     my ($registry, $klass, @arg) = @_;
252 root 1.39
253     my $prio = 0;
254    
255     my %undo = (
256     registry => $registry,
257     cb => [],
258     );
259    
260     my %cb_id = map +("on_" . lc $EVENT[$_][0], $_) , grep $EVENT[$_][1] == $klass, 0 .. $#EVENT;
261    
262 root 1.45 while (@arg) {
263     my $type = shift @arg;
264 root 1.39
265     if ($type eq "prio") {
266 root 1.45 $prio = shift @arg;
267 root 1.39
268     } elsif ($type eq "package") {
269 root 1.45 my $pkg = shift @arg;
270 root 1.39
271     while (my ($name, $id) = each %cb_id) {
272     if (my $cb = $pkg->can ($name)) {
273     _attach_cb $registry, %undo, $id, $prio, $cb;
274     }
275     }
276    
277     } elsif (exists $cb_id{$type}) {
278 root 1.45 _attach_cb $registry, %undo, $cb_id{$type}, $prio, shift @arg;
279 root 1.39
280     } elsif (ref $type) {
281     warn "attaching objects not supported, ignoring.\n";
282    
283     } else {
284 root 1.45 shift @arg;
285 root 1.39 warn "attach argument '$type' not supported, ignoring.\n";
286     }
287     }
288    
289     \%undo
290     }
291    
292 root 1.46 sub _attach_attachment {
293 root 1.48 my ($obj, $name, %arg) = @_;
294 root 1.46
295 root 1.55 return if exists $obj->{_attachment}{$name};
296    
297 root 1.46 my $res;
298    
299     if (my $attach = $attachment{$name}) {
300     my $registry = $obj->registry;
301    
302 root 1.47 for (@$attach) {
303     my ($klass, @attach) = @$_;
304     $res = _attach @$registry, $klass, @attach;
305     }
306 root 1.46
307 root 1.48 $obj->{$name} = \%arg;
308 root 1.46 } else {
309     warn "object uses attachment '$name' that is not available, postponing.\n";
310     }
311    
312 root 1.50 $obj->{_attachment}{$name} = undef;
313 root 1.46
314     $res->{attachment} = $name;
315     $res
316     }
317    
318 root 1.54 *cf::object::attach =
319     *cf::player::attach =
320     *cf::map::attach = sub {
321 root 1.48 my ($obj, $name, %arg) = @_;
322 root 1.46
323 root 1.48 _attach_attachment $obj, $name, %arg;
324 root 1.55 };
325 root 1.46
326 root 1.54 # all those should be optimised
327     *cf::object::detach =
328     *cf::player::detach =
329     *cf::map::detach = sub {
330     my ($obj, $name) = @_;
331 root 1.46
332 root 1.54 delete $obj->{_attachment}{$name};
333 root 1.55 reattach ($obj);
334     };
335    
336     *cf::object::attached =
337     *cf::player::attached =
338     *cf::map::attached = sub {
339     my ($obj, $name) = @_;
340    
341     exists $obj->{_attachment}{$name}
342 root 1.54 };
343 root 1.53
344 root 1.39 sub attach_global {
345     _attach @CB_GLOBAL, KLASS_GLOBAL, @_
346     }
347    
348 root 1.40 sub attach_to_type {
349 root 1.39 my $type = shift;
350 root 1.47 my $subtype = shift;
351 root 1.45
352 root 1.47 _attach @{$CB_TYPE[$type + $subtype * NUM_SUBTYPES]}, KLASS_OBJECT, @_
353 root 1.39 }
354    
355     sub attach_to_objects {
356 root 1.40 _attach @CB_OBJECT, KLASS_OBJECT, @_
357 root 1.39 }
358    
359     sub attach_to_players {
360 root 1.40 _attach @CB_PLAYER, KLASS_PLAYER, @_
361 root 1.39 }
362    
363     sub attach_to_maps {
364 root 1.40 _attach @CB_MAP, KLASS_MAP, @_
365 root 1.39 }
366    
367 root 1.45 sub register_attachment {
368     my $name = shift;
369    
370 root 1.47 $attachment{$name} = [[KLASS_OBJECT, @_]];
371 root 1.45 }
372    
373 root 1.55 sub register_player_attachment {
374     my $name = shift;
375    
376     $attachment{$name} = [[KLASS_PLAYER, @_]];
377     }
378    
379 root 1.52 sub register_map_attachment {
380     my $name = shift;
381    
382     $attachment{$name} = [[KLASS_MAP, @_]];
383     }
384    
385 root 1.39 our $override;
386 root 1.45 our @invoke_results = (); # referenced from .xs code. TODO: play tricks with reify and mortals?
387 root 1.39
388 root 1.45 sub override {
389     $override = 1;
390     @invoke_results = ();
391 root 1.39 }
392    
393 root 1.45 sub do_invoke {
394 root 1.39 my $event = shift;
395 root 1.40 my $callbacks = shift;
396 root 1.39
397 root 1.45 @invoke_results = ();
398    
399 root 1.39 local $override;
400    
401 root 1.40 for (@$callbacks) {
402 root 1.39 eval { &{$_->[1]} };
403    
404     if ($@) {
405     warn "$@";
406 root 1.64 warn "... while processing $EVENT[$event][0](@_) event, skipping processing altogether.\n";
407 root 1.39 override;
408     }
409    
410     return 1 if $override;
411     }
412    
413     0
414     }
415    
416 root 1.55 =item $bool = cf::invoke EVENT_GLOBAL_XXX, ...
417    
418     =item $bool = $object->invoke (EVENT_OBJECT_XXX, ...)
419    
420     =item $bool = $player->invoke (EVENT_PLAYER_XXX, ...)
421    
422     =item $bool = $map->invoke (EVENT_MAP_XXX, ...)
423    
424     Generate a global/object/player/map-specific event with the given arguments.
425    
426     This API is preliminary (most likely, the EVENT_KLASS_xxx prefix will be
427     removed in future versions), and there is no public API to access override
428     results (if you must, access C<@cf::invoke_results> directly).
429    
430     =back
431    
432 root 1.71 =cut
433    
434 root 1.70 #############################################################################
435    
436     =head2 METHODS VALID FOR ALL CORE OBJECTS
437 root 1.55
438     =over 4
439    
440 root 1.70 =item $object->valid, $player->valid, $map->valid
441 root 1.55
442     Just because you have a perl object does not mean that the corresponding
443     C-level object still exists. If you try to access an object that has no
444     valid C counterpart anymore you get an exception at runtime. This method
445     can be used to test for existence of the C object part without causing an
446     exception.
447    
448     =back
449    
450     =cut
451    
452     *cf::object::valid =
453     *cf::player::valid =
454     *cf::map::valid = \&cf::_valid;
455    
456 root 1.39 #############################################################################
457 root 1.45 # object support
458    
459     sub instantiate {
460     my ($obj, $data) = @_;
461    
462     $data = from_json $data;
463    
464     for (@$data) {
465 root 1.46 my ($name, $args) = @$_;
466 root 1.49
467     $obj->attach ($name, %{$args || {} });
468 root 1.46 }
469     }
470    
471     # basically do the same as instantiate, without calling instantiate
472     sub reattach {
473     my ($obj) = @_;
474     my $registry = $obj->registry;
475 root 1.45
476 root 1.47 @$registry = ();
477    
478 root 1.50 delete $obj->{_attachment} unless scalar keys %{ $obj->{_attachment} || {} };
479 root 1.49
480 root 1.50 for my $name (keys %{ $obj->{_attachment} || {} }) {
481 root 1.45 if (my $attach = $attachment{$name}) {
482 root 1.47 for (@$attach) {
483     my ($klass, @attach) = @$_;
484     _attach @$registry, $klass, @attach;
485     }
486 root 1.45 } else {
487 root 1.46 warn "object uses attachment '$name' that is not available, postponing.\n";
488 root 1.45 }
489 root 1.46 }
490     }
491 root 1.45
492 root 1.46 sub object_freezer_save {
493 root 1.59 my ($filename, $rdata, $objs) = @_;
494 root 1.46
495 root 1.60 if (length $$rdata) {
496     warn sprintf "saving %s (%d,%d)\n",
497     $filename, length $$rdata, scalar @$objs;
498 root 1.59
499 root 1.60 if (open my $fh, ">:raw", "$filename~") {
500 root 1.59 chmod SAVE_MODE, $fh;
501 root 1.60 syswrite $fh, $$rdata;
502 root 1.59 close $fh;
503 root 1.60
504     if (@$objs && open my $fh, ">:raw", "$filename.pst~") {
505     chmod SAVE_MODE, $fh;
506     syswrite $fh, Storable::nfreeze { version => 1, objs => $objs };
507     close $fh;
508     rename "$filename.pst~", "$filename.pst";
509     } else {
510     unlink "$filename.pst";
511     }
512    
513     rename "$filename~", $filename;
514 root 1.59 } else {
515 root 1.60 warn "FATAL: $filename~: $!\n";
516 root 1.59 }
517 root 1.46 } else {
518 root 1.60 unlink $filename;
519     unlink "$filename.pst";
520 root 1.45 }
521     }
522    
523 root 1.46 sub object_thawer_load {
524     my ($filename) = @_;
525    
526 root 1.61 local $/;
527    
528     my $av;
529    
530     #TODO: use sysread etc.
531     if (open my $data, "<:raw:perlio", $filename) {
532     $data = <$data>;
533     if (open my $pst, "<:raw:perlio", "$filename.pst") {
534     $av = eval { (Storable::thaw <$pst>)->{objs} };
535     }
536     return ($data, $av);
537     }
538 root 1.45
539 root 1.61 ()
540 root 1.45 }
541    
542     attach_to_objects
543     prio => -1000000,
544     on_clone => sub {
545     my ($src, $dst) = @_;
546    
547     @{$dst->registry} = @{$src->registry};
548    
549     %$dst = %$src;
550    
551 root 1.50 %{$dst->{_attachment}} = %{$src->{_attachment}}
552 root 1.45 if exists $src->{_attachment};
553     },
554     ;
555    
556     #############################################################################
557 root 1.39 # old plug-in events
558    
559 root 1.1 sub inject_event {
560 root 1.14 my $extension = shift;
561     my $event_code = shift;
562 root 1.1
563 root 1.14 my $cb = $hook[$event_code]{$extension}
564 root 1.5 or return;
565    
566 root 1.14 &$cb
567 root 1.5 }
568    
569     sub inject_global_event {
570 root 1.12 my $event = shift;
571 root 1.5
572 root 1.12 my $cb = $hook[$event]
573 root 1.1 or return;
574    
575 root 1.12 List::Util::max map &$_, values %$cb
576 root 1.1 }
577    
578     sub inject_command {
579     my ($name, $obj, $params) = @_;
580    
581     for my $cmd (@{ $command{$name} }) {
582     $cmd->[1]->($obj, $params);
583     }
584    
585     -1
586     }
587    
588     sub register_command {
589     my ($name, $time, $cb) = @_;
590    
591     my $caller = caller;
592 root 1.16 #warn "registering command '$name/$time' to '$caller'";
593 root 1.4
594 root 1.1 push @{ $command{$name} }, [$time, $cb, $caller];
595     $COMMAND{"$name\000"} = List::Util::max map $_->[0], @{ $command{$name} };
596     }
597    
598 root 1.16 sub register_extcmd {
599     my ($name, $cb) = @_;
600    
601     my $caller = caller;
602     #warn "registering extcmd '$name' to '$caller'";
603    
604     $extcmd{$name} = [$cb, $caller];
605     }
606    
607 root 1.6 sub register {
608     my ($base, $pkg) = @_;
609    
610 root 1.45 #TODO
611 root 1.6 }
612    
613 root 1.1 sub load_extension {
614     my ($path) = @_;
615    
616     $path =~ /([^\/\\]+)\.ext$/ or die "$path";
617 root 1.5 my $base = $1;
618 root 1.1 my $pkg = $1;
619     $pkg =~ s/[^[:word:]]/_/g;
620 root 1.41 $pkg = "ext::$pkg";
621 root 1.1
622     warn "loading '$path' into '$pkg'\n";
623    
624     open my $fh, "<:utf8", $path
625     or die "$path: $!";
626    
627     my $source =
628     "package $pkg; use strict; use utf8;\n"
629     . "#line 1 \"$path\"\n{\n"
630     . (do { local $/; <$fh> })
631     . "\n};\n1";
632    
633     eval $source
634     or die "$path: $@";
635    
636     push @exts, $pkg;
637 root 1.5 $ext_pkg{$base} = $pkg;
638 root 1.1
639 root 1.6 # no strict 'refs';
640 root 1.23 # @{"$pkg\::ISA"} = ext::;
641 root 1.1
642 root 1.6 register $base, $pkg;
643 root 1.1 }
644    
645     sub unload_extension {
646     my ($pkg) = @_;
647    
648     warn "removing extension $pkg\n";
649    
650     # remove hooks
651 root 1.45 #TODO
652     # for my $idx (0 .. $#PLUGIN_EVENT) {
653     # delete $hook[$idx]{$pkg};
654     # }
655 root 1.1
656     # remove commands
657     for my $name (keys %command) {
658     my @cb = grep $_->[2] ne $pkg, @{ $command{$name} };
659    
660     if (@cb) {
661     $command{$name} = \@cb;
662     $COMMAND{"$name\000"} = List::Util::max map $_->[0], @cb;
663     } else {
664     delete $command{$name};
665     delete $COMMAND{"$name\000"};
666     }
667     }
668    
669 root 1.15 # remove extcmds
670 root 1.16 for my $name (grep $extcmd{$_}[1] eq $pkg, keys %extcmd) {
671     delete $extcmd{$name};
672 root 1.15 }
673    
674 root 1.43 if (my $cb = $pkg->can ("unload")) {
675 elmex 1.31 eval {
676     $cb->($pkg);
677     1
678     } or warn "$pkg unloaded, but with errors: $@";
679     }
680    
681 root 1.1 Symbol::delete_package $pkg;
682     }
683    
684     sub load_extensions {
685     my $LIBDIR = maps_directory "perl";
686    
687     for my $ext (<$LIBDIR/*.ext>) {
688 root 1.3 next unless -r $ext;
689 root 1.2 eval {
690     load_extension $ext;
691     1
692     } or warn "$ext not loaded: $@";
693 root 1.1 }
694     }
695    
696 root 1.8 #############################################################################
697 root 1.28 # extcmd framework, basically convert ext <msg>
698 root 1.15 # into pkg::->on_extcmd_arg1 (...) while shortcutting a few
699    
700 root 1.44 attach_to_players
701 root 1.43 on_extcmd => sub {
702     my ($pl, $buf) = @_;
703    
704     my $msg = eval { from_json $buf };
705    
706     if (ref $msg) {
707     if (my $cb = $extcmd{$msg->{msgtype}}) {
708     if (my %reply = $cb->[0]->($pl, $msg)) {
709     $pl->ext_reply ($msg->{msgid}, %reply);
710     }
711 root 1.28 }
712 root 1.43 } else {
713     warn "player " . ($pl->ob->name) . " sent unparseable ext message: <$buf>\n";
714 root 1.28 }
715 root 1.15
716 root 1.43 cf::override;
717     },
718     ;
719 root 1.15
720     #############################################################################
721 root 1.8 # load/save/clean perl data associated with a map
722    
723 root 1.39 *cf::mapsupport::on_clean = sub {
724 root 1.13 my ($map) = @_;
725 root 1.7
726     my $path = $map->tmpname;
727     defined $path or return;
728    
729 root 1.46 unlink "$path.pst";
730 root 1.7 };
731    
732 root 1.39 attach_to_maps prio => -10000, package => cf::mapsupport::;
733    
734 root 1.8 #############################################################################
735     # load/save perl data associated with player->ob objects
736    
737 root 1.33 sub all_objects(@) {
738     @_, map all_objects ($_->inv), @_
739     }
740    
741 root 1.60 # TODO: compatibility cruft, remove when no longer needed
742 root 1.39 attach_to_players
743     on_load => sub {
744     my ($pl, $path) = @_;
745    
746     for my $o (all_objects $pl->ob) {
747     if (my $value = $o->get_ob_key_value ("_perl_data")) {
748     $o->set_ob_key_value ("_perl_data");
749 root 1.8
750 root 1.39 %$o = %{ Storable::thaw pack "H*", $value };
751     }
752 root 1.11 }
753 root 1.39 },
754     ;
755 root 1.6
756 root 1.22 #############################################################################
757 root 1.70
758     =head2 CORE EXTENSIONS
759    
760     Functions and methods that extend core crossfire objects.
761    
762     =over 4
763 root 1.22
764 root 1.23 =item cf::player::exists $login
765    
766     Returns true when the given account exists.
767    
768     =cut
769    
770     sub cf::player::exists($) {
771     cf::player::find $_[0]
772     or -f sprintf "%s/%s/%s/%s.pl", cf::localdir, cf::playerdir, ($_[0]) x 2;
773     }
774    
775 root 1.28 =item $player->reply ($npc, $msg[, $flags])
776    
777     Sends a message to the player, as if the npc C<$npc> replied. C<$npc>
778     can be C<undef>. Does the right thing when the player is currently in a
779     dialogue with the given NPC character.
780    
781     =cut
782    
783 root 1.22 # rough implementation of a future "reply" method that works
784     # with dialog boxes.
785 root 1.23 sub cf::object::player::reply($$$;$) {
786     my ($self, $npc, $msg, $flags) = @_;
787    
788     $flags = cf::NDI_BROWN | cf::NDI_UNIQUE unless @_ >= 4;
789 root 1.22
790 root 1.24 if ($self->{record_replies}) {
791     push @{ $self->{record_replies} }, [$npc, $msg, $flags];
792     } else {
793     $msg = $npc->name . " says: $msg" if $npc;
794     $self->message ($msg, $flags);
795     }
796 root 1.22 }
797    
798 root 1.28 =item $player->ext_reply ($msgid, $msgtype, %msg)
799    
800     Sends an ext reply to the player.
801    
802     =cut
803    
804     sub cf::player::ext_reply($$$%) {
805     my ($self, $id, %msg) = @_;
806    
807     $msg{msgid} = $id;
808    
809     $self->send ("ext " . to_json \%msg);
810     }
811    
812 root 1.70 =back
813    
814     =cut
815    
816 root 1.22 #############################################################################
817 root 1.70
818     =head2 SAFE SCRIPTING
819    
820     Functions that provide a safe environment to compile and execute
821     snippets of perl code without them endangering the safety of the server
822     itself. Looping constructs, I/O operators and other built-in functionality
823     is not available in the safe scripting environment, and the number of
824     functions and methods that cna be called is greatly reduced.
825    
826     =cut
827 root 1.23
828 root 1.42 our $safe = new Safe "safe";
829 root 1.23 our $safe_hole = new Safe::Hole;
830    
831     $SIG{FPE} = 'IGNORE';
832    
833     $safe->permit_only (Opcode::opset qw(:base_core :base_mem :base_orig :base_math sort time));
834    
835 root 1.25 # here we export the classes and methods available to script code
836    
837 root 1.70 =pod
838    
839     The following fucntions and emthods are available within a safe environment:
840    
841     cf::object contr pay_amount pay_player
842     cf::object::player player
843     cf::player peaceful
844    
845     =cut
846    
847 root 1.25 for (
848 root 1.27 ["cf::object" => qw(contr pay_amount pay_player)],
849 root 1.25 ["cf::object::player" => qw(player)],
850     ["cf::player" => qw(peaceful)],
851     ) {
852     no strict 'refs';
853     my ($pkg, @funs) = @$_;
854 root 1.41 *{"safe::$pkg\::$_"} = $safe_hole->wrap (\&{"$pkg\::$_"})
855 root 1.25 for @funs;
856     }
857 root 1.23
858 root 1.70 =over 4
859    
860     =item @retval = safe_eval $code, [var => value, ...]
861    
862     Compiled and executes the given perl code snippet. additional var/value
863     pairs result in temporary local (my) scalar variables of the given name
864     that are available in the code snippet. Example:
865    
866     my $five = safe_eval '$first + $second', first => 1, second => 4;
867    
868     =cut
869    
870 root 1.23 sub safe_eval($;@) {
871     my ($code, %vars) = @_;
872    
873     my $qcode = $code;
874     $qcode =~ s/"/‟/g; # not allowed in #line filenames
875     $qcode =~ s/\n/\\n/g;
876    
877     local $_;
878 root 1.41 local @safe::cf::_safe_eval_args = values %vars;
879 root 1.23
880 root 1.42 my $eval =
881 root 1.23 "do {\n"
882     . "my (" . (join ",", map "\$$_", keys %vars) . ") = \@cf::_safe_eval_args;\n"
883     . "#line 0 \"{$qcode}\"\n"
884     . $code
885     . "\n}"
886 root 1.25 ;
887    
888     sub_generation_inc;
889 root 1.42 my @res = wantarray ? $safe->reval ($eval) : scalar $safe->reval ($eval);
890 root 1.25 sub_generation_inc;
891    
892 root 1.42 if ($@) {
893     warn "$@";
894     warn "while executing safe code '$code'\n";
895     warn "with arguments " . (join " ", %vars) . "\n";
896     }
897    
898 root 1.25 wantarray ? @res : $res[0]
899 root 1.23 }
900    
901 root 1.69 =item cf::register_script_function $function => $cb
902    
903     Register a function that can be called from within map/npc scripts. The
904     function should be reasonably secure and should be put into a package name
905     like the extension.
906    
907     Example: register a function that gets called whenever a map script calls
908     C<rent::overview>, as used by the C<rent> extension.
909    
910     cf::register_script_function "rent::overview" => sub {
911     ...
912     };
913    
914     =cut
915    
916 root 1.23 sub register_script_function {
917     my ($fun, $cb) = @_;
918    
919     no strict 'refs';
920 root 1.41 *{"safe::$fun"} = $safe_hole->wrap ($cb);
921 root 1.23 }
922    
923 root 1.70 =back
924    
925 root 1.71 =cut
926    
927 root 1.23 #############################################################################
928 root 1.65
929     =head2 EXTENSION DATABASE SUPPORT
930    
931     Crossfire maintains a very simple database for extension use. It can
932     currently store anything that can be serialised using Storable, which
933     excludes objects.
934    
935     The parameter C<$family> should best start with the name of the extension
936     using it, it should be unique.
937    
938     =over 4
939    
940     =item $hashref = cf::db_get $family
941    
942     Return a hashref for use by the extension C<$family>, which can be
943     modified. After modifications, you have to call C<cf::db_dirty> or
944     C<cf::db_sync>.
945    
946     =item $value = cf::db_get $family => $key
947    
948     Returns a single value from the database
949    
950     =item cf::db_put $family => $hashref
951    
952     Stores the given family hashref into the database. Updates are delayed, if
953     you want the data to be synced to disk immediately, use C<cf::db_sync>.
954    
955     =item cf::db_put $family => $key => $value
956    
957     Stores the given C<$value> in the family hash. Updates are delayed, if you
958     want the data to be synced to disk immediately, use C<cf::db_sync>.
959    
960     =item cf::db_dirty
961    
962     Marks the database as dirty, to be updated at a later time.
963    
964     =item cf::db_sync
965    
966     Immediately write the database to disk I<if it is dirty>.
967    
968     =cut
969    
970     {
971     my $db;
972 root 1.66 my $path = cf::localdir . "/database.pst";
973 root 1.65
974     sub db_load() {
975     warn "loading database $path\n";#d# remove later
976     $db = stat $path ? Storable::retrieve $path : { };
977     }
978    
979     my $pid;
980    
981     sub db_save() {
982     warn "saving database $path\n";#d# remove later
983     waitpid $pid, 0 if $pid;
984 root 1.67 if (0 == ($pid = fork)) {
985 root 1.65 $db->{_meta}{version} = 1;
986     Storable::nstore $db, "$path~";
987     rename "$path~", $path;
988     cf::_exit 0 if defined $pid;
989     }
990     }
991    
992     my $dirty;
993    
994     sub db_sync() {
995     db_save if $dirty;
996     undef $dirty;
997     }
998    
999     my $idle = Event->idle (min => $TICK * 2.8, max => 10, repeat => 0, cb => sub {
1000     db_sync;
1001     });
1002    
1003     sub db_dirty() {
1004     $dirty = 1;
1005     $idle->start;
1006     }
1007    
1008     sub db_get($;$) {
1009     @_ >= 2
1010     ? $db->{$_[0]}{$_[1]}
1011     : ($db->{$_[0]} ||= { })
1012     }
1013    
1014     sub db_put($$;$) {
1015     if (@_ >= 3) {
1016     $db->{$_[0]}{$_[1]} = $_[2];
1017     } else {
1018     $db->{$_[0]} = $_[1];
1019     }
1020     db_dirty;
1021     }
1022 root 1.67
1023     attach_global
1024     prio => 10000,
1025     on_cleanup => sub {
1026     db_sync;
1027     },
1028     ;
1029 root 1.65 }
1030    
1031     #############################################################################
1032 root 1.34 # the server's main()
1033    
1034 root 1.72 sub load_cfg {
1035     open my $fh, "<:utf8", cf::confdir . "/config"
1036     or return;
1037    
1038     local $/;
1039     *CFG = YAML::Syck::Load <$fh>;
1040    
1041     use Data::Dumper; warn Dumper \%CFG;
1042     }
1043    
1044 root 1.39 sub main {
1045 root 1.72 load_cfg;
1046 root 1.65 db_load;
1047 root 1.61 load_extensions;
1048 root 1.34 Event::loop;
1049     }
1050    
1051     #############################################################################
1052 root 1.22 # initialisation
1053    
1054 root 1.65 sub _perl_reload(&) {
1055     my ($msg) = @_;
1056    
1057     $msg->("reloading...");
1058    
1059     eval {
1060     # cancel all watchers
1061     $_->cancel for Event::all_watchers;
1062    
1063     # unload all extensions
1064     for (@exts) {
1065     $msg->("unloading <$_>");
1066     unload_extension $_;
1067     }
1068    
1069     # unload all modules loaded from $LIBDIR
1070     while (my ($k, $v) = each %INC) {
1071     next unless $v =~ /^\Q$LIBDIR\E\/.*\.pm$/;
1072    
1073     $msg->("removing <$k>");
1074     delete $INC{$k};
1075    
1076     $k =~ s/\.pm$//;
1077     $k =~ s/\//::/g;
1078    
1079     if (my $cb = $k->can ("unload_module")) {
1080     $cb->();
1081     }
1082    
1083     Symbol::delete_package $k;
1084     }
1085    
1086     # sync database to disk
1087     cf::db_sync;
1088    
1089     # get rid of safe::, as good as possible
1090     Symbol::delete_package "safe::$_"
1091     for qw(cf::object cf::object::player cf::player cf::map cf::party cf::region);
1092    
1093     # remove register_script_function callbacks
1094     # TODO
1095    
1096     # unload cf.pm "a bit"
1097     delete $INC{"cf.pm"};
1098    
1099     # don't, removes xs symbols, too,
1100     # and global variables created in xs
1101     #Symbol::delete_package __PACKAGE__;
1102    
1103     # reload cf.pm
1104     $msg->("reloading cf.pm");
1105     require cf;
1106    
1107     # load database again
1108     cf::db_load;
1109    
1110     # load extensions
1111     $msg->("load extensions");
1112     cf::load_extensions;
1113    
1114     # reattach attachments to objects
1115     $msg->("reattach");
1116     _global_reattach;
1117     };
1118     $msg->($@) if $@;
1119    
1120     $msg->("reloaded");
1121     };
1122    
1123     sub perl_reload() {
1124     _perl_reload {
1125     warn $_[0];
1126     print "$_[0]\n";
1127     };
1128     }
1129    
1130     register_command "perl-reload", 0, sub {
1131     my ($who, $arg) = @_;
1132    
1133     if ($who->flag (FLAG_WIZ)) {
1134     _perl_reload {
1135     warn $_[0];
1136     $who->message ($_[0]);
1137     };
1138     }
1139     };
1140    
1141 root 1.6 register "<global>", __PACKAGE__;
1142    
1143 root 1.27 unshift @INC, $LIBDIR;
1144 root 1.17
1145 root 1.35 $TICK_WATCHER = Event->timer (
1146     prio => 1,
1147     at => $NEXT_TICK || 1,
1148     cb => sub {
1149     cf::server_tick; # one server iteration
1150    
1151     my $NOW = Event::time;
1152     $NEXT_TICK += $TICK;
1153    
1154 root 1.37 # if we are delayed by four ticks, skip them all
1155     $NEXT_TICK = $NOW if $NOW >= $NEXT_TICK + $TICK * 4;
1156 root 1.35
1157     $TICK_WATCHER->at ($NEXT_TICK);
1158     $TICK_WATCHER->start;
1159     },
1160     );
1161    
1162 root 1.1 1
1163