ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/lib/cf.pm
Revision: 1.17
Committed: Mon Jun 19 10:20:07 2006 UTC (17 years, 11 months ago) by root
Branch: MAIN
Changes since 1.16: +2 -0 lines
Log Message:
put maps/perl/ into perl lib path

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.1
7     use strict;
8    
9     our %COMMAND;
10     our @EVENT;
11     our %PROP_TYPE;
12     our %PROP_IDX;
13    
14     BEGIN {
15     @EVENT = map lc, @EVENT;
16    
17     *CORE::GLOBAL::warn = sub {
18     my $msg = join "", @_;
19     $msg .= "\n"
20     unless $msg =~ /\n$/;
21    
22     print STDERR "cfperl: $msg";
23     LOG llevError, "cfperl: $msg";
24     };
25     }
26    
27 root 1.9 my %ignore_set = (MAP_PROP_PATH => 1); # I hate the plug-in api. Deeply!
28    
29 root 1.1 # generate property mutators
30     sub prop_gen {
31     my ($prefix, $class) = @_;
32    
33     no strict 'refs';
34    
35     for my $prop (keys %PROP_TYPE) {
36     $prop =~ /^\Q$prefix\E_(.*$)/ or next;
37     my $sub = lc $1;
38    
39     my $type = $PROP_TYPE{$prop};
40     my $idx = $PROP_IDX {$prop};
41    
42     *{"$class\::get_$sub"} = *{"$class\::$sub"} = sub {
43     $_[0]->get_property ($type, $idx)
44     };
45    
46     *{"$class\::set_$sub"} = sub {
47     $_[0]->set_property ($type, $idx, $_[1]);
48 root 1.9 } unless $ignore_set{$prop};
49 root 1.1 }
50     }
51    
52     # auto-generate most of the API
53    
54     prop_gen OBJECT_PROP => "cf::object";
55     # CFAPI_OBJECT_ANIMATION?
56     prop_gen PLAYER_PROP => "cf::object::player";
57    
58     prop_gen MAP_PROP => "cf::map";
59     prop_gen ARCH_PROP => "cf::arch";
60    
61     # guessed hierarchies
62    
63     @cf::object::player::ISA = 'cf::object';
64     @cf::object::map::ISA = 'cf::object';
65    
66 root 1.5 my %ext_pkg;
67 root 1.1 my @exts;
68     my @hook;
69     my %command;
70 root 1.15 my %extcmd;
71 root 1.1
72     sub inject_event {
73 root 1.14 my $extension = shift;
74     my $event_code = shift;
75 root 1.1
76 root 1.14 my $cb = $hook[$event_code]{$extension}
77 root 1.5 or return;
78    
79 root 1.14 &$cb
80 root 1.5 }
81    
82     sub inject_global_event {
83 root 1.12 my $event = shift;
84 root 1.5
85 root 1.12 my $cb = $hook[$event]
86 root 1.1 or return;
87    
88 root 1.12 List::Util::max map &$_, values %$cb
89 root 1.1 }
90    
91     sub inject_command {
92     my ($name, $obj, $params) = @_;
93    
94     for my $cmd (@{ $command{$name} }) {
95     $cmd->[1]->($obj, $params);
96     }
97    
98     -1
99     }
100    
101     sub register_command {
102     my ($name, $time, $cb) = @_;
103    
104     my $caller = caller;
105 root 1.16 #warn "registering command '$name/$time' to '$caller'";
106 root 1.4
107 root 1.1 push @{ $command{$name} }, [$time, $cb, $caller];
108     $COMMAND{"$name\000"} = List::Util::max map $_->[0], @{ $command{$name} };
109     }
110    
111 root 1.16 sub register_extcmd {
112     my ($name, $cb) = @_;
113    
114     my $caller = caller;
115     #warn "registering extcmd '$name' to '$caller'";
116    
117     $extcmd{$name} = [$cb, $caller];
118     }
119    
120 root 1.6 sub register {
121     my ($base, $pkg) = @_;
122    
123     for my $idx (0 .. $#EVENT) {
124     if (my $ref = $pkg->can ("on_$EVENT[$idx]")) {
125 root 1.16 #warn "registering $EVENT[$idx] hook to '$pkg'\n";
126 root 1.6 $hook[$idx]{$base} = $ref;
127     }
128     }
129     }
130    
131 root 1.1 sub load_extension {
132     my ($path) = @_;
133    
134     $path =~ /([^\/\\]+)\.ext$/ or die "$path";
135 root 1.5 my $base = $1;
136 root 1.1 my $pkg = $1;
137     $pkg =~ s/[^[:word:]]/_/g;
138     $pkg = "cf::ext::$pkg";
139    
140     warn "loading '$path' into '$pkg'\n";
141    
142     open my $fh, "<:utf8", $path
143     or die "$path: $!";
144    
145     my $source =
146     "package $pkg; use strict; use utf8;\n"
147     . "#line 1 \"$path\"\n{\n"
148     . (do { local $/; <$fh> })
149     . "\n};\n1";
150    
151     eval $source
152     or die "$path: $@";
153    
154     push @exts, $pkg;
155 root 1.5 $ext_pkg{$base} = $pkg;
156 root 1.1
157 root 1.6 # no strict 'refs';
158 root 1.1 # @{"$pkg\::ISA"} = cf::ext::;
159    
160 root 1.6 register $base, $pkg;
161 root 1.1 }
162    
163     sub unload_extension {
164     my ($pkg) = @_;
165    
166     warn "removing extension $pkg\n";
167    
168     # remove hooks
169     for my $idx (0 .. $#EVENT) {
170     delete $hook[$idx]{$pkg};
171     }
172    
173     # remove commands
174     for my $name (keys %command) {
175     my @cb = grep $_->[2] ne $pkg, @{ $command{$name} };
176    
177     if (@cb) {
178     $command{$name} = \@cb;
179     $COMMAND{"$name\000"} = List::Util::max map $_->[0], @cb;
180     } else {
181     delete $command{$name};
182     delete $COMMAND{"$name\000"};
183     }
184     }
185    
186 root 1.15 # remove extcmds
187 root 1.16 for my $name (grep $extcmd{$_}[1] eq $pkg, keys %extcmd) {
188     delete $extcmd{$name};
189 root 1.15 }
190    
191 root 1.1 Symbol::delete_package $pkg;
192     }
193    
194     sub load_extensions {
195     my $LIBDIR = maps_directory "perl";
196    
197     for my $ext (<$LIBDIR/*.ext>) {
198 root 1.3 next unless -r $ext;
199 root 1.2 eval {
200     load_extension $ext;
201     1
202     } or warn "$ext not loaded: $@";
203 root 1.1 }
204     }
205    
206     register_command "perl-reload", 0, sub {
207     my ($who, $arg) = @_;
208    
209     if ($who->flag (FLAG_WIZ)) {
210 root 1.3 $who->message ("reloading...");
211    
212 root 1.1 warn "reloading...\n";
213 root 1.4 eval {
214     unload_extension $_ for @exts;
215     delete $INC{"cf.pm"};
216    
217     # don't, removes xs symbols, too
218     #Symbol::delete_package $pkg;
219    
220     require cf;
221     };
222     warn $@ if $@;
223     $who->message ($@) if $@;
224 root 1.1 warn "reloaded\n";
225 root 1.3
226     $who->message ("reloaded");
227     } else {
228     $who->message ("Intruder Alert!");
229 root 1.1 }
230     };
231    
232 root 1.8 #############################################################################
233 root 1.15 # extcmd framework, basically convert ext <id> <pkg> arg1 args
234     # into pkg::->on_extcmd_arg1 (...) while shortcutting a few
235    
236     sub on_extcmd {
237     my ($pl, $buf) = @_;
238    
239 root 1.16 my ($type) = $buf =~ s/^(\S+) // ? $1 : "";
240 root 1.15
241 root 1.16 $extcmd{$type}[0]->($pl, $buf)
242     if $extcmd{$type};
243 root 1.15 }
244    
245     #############################################################################
246 root 1.8 # load/save/clean perl data associated with a map
247    
248 root 1.7 *on_mapclean = sub {
249 root 1.13 my ($map) = @_;
250 root 1.7
251     my $path = $map->tmpname;
252     defined $path or return;
253    
254     unlink "$path.cfperl";
255     };
256    
257 root 1.6 *on_mapin =
258     *on_mapload = sub {
259 root 1.13 my ($map) = @_;
260 root 1.6
261     my $path = $map->tmpname;
262     $path = $map->path unless defined $path;
263    
264     open my $fh, "<:raw", "$path.cfperl"
265     or return; # no perl data
266    
267     my $data = Storable::thaw do { local $/; <$fh> };
268    
269     $data->{version} <= 1
270     or return; # too new
271    
272     $map->_set_obs ($data->{obs});
273     };
274    
275     *on_mapout = sub {
276 root 1.13 my ($map) = @_;
277 root 1.6
278     my $path = $map->tmpname;
279     $path = $map->path unless defined $path;
280    
281     my $obs = $map->_get_obs;
282    
283     if (defined $obs) {
284     open my $fh, ">:raw", "$path.cfperl"
285     or die "$path.cfperl: $!";
286    
287 root 1.8 stat $path;
288    
289     print $fh Storable::nfreeze {
290     size => (stat _)[7],
291     time => (stat _)[9],
292     version => 1,
293     obs => $obs,
294     };
295    
296     chmod SAVE_MODE, "$path.cfperl"; # very racy, but cf-compatible *g*
297     } else {
298     unlink "$path.cfperl";
299     }
300     };
301    
302     #############################################################################
303     # load/save perl data associated with player->ob objects
304    
305     *on_player_load = sub {
306 root 1.13 my ($ob, $path) = @_;
307 root 1.8
308 root 1.11 if (open my $fh, "<:raw", "$path.cfperl") {
309 root 1.8
310 root 1.11 #d##TODO#remove
311 root 1.8
312 root 1.11 my $data = Storable::thaw do { local $/; <$fh> };
313 root 1.8
314 root 1.11 $data->{version} <= 1
315     or return; # too new
316    
317     %$ob = %{$data->{ob}};
318     return;
319     }
320    
321     for my $o ($ob, $ob->inv) {
322     if (my $value = $o->get_ob_key_value ("_perl_data")) {
323     $o->set_ob_key_value ("_perl_data");
324    
325     %$o = %{ Storable::thaw pack "H*", $value };
326     }
327     }
328 root 1.8 };
329    
330     *on_player_save = sub {
331 root 1.13 my ($ob, $path) = @_;
332 root 1.8
333 root 1.11 $_->set_ob_key_value (_perl_data => unpack "H*", Storable::nfreeze $_)
334     for grep %$_, $ob, $ob->inv;
335    
336     unlink "$path.cfperl";#d##TODO#remove
337 root 1.6 };
338    
339     register "<global>", __PACKAGE__;
340    
341 root 1.17 unshift @INC, maps_directory "perl";
342    
343 root 1.1 load_extensions;
344    
345     1
346