ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/lib/cf.pm
Revision: 1.5
Committed: Wed Feb 8 03:46:15 2006 UTC (18 years, 3 months ago) by root
Branch: MAIN
Changes since 1.4: +13 -1 lines
Log Message:
*** empty log message ***

File Contents

# Content
1 package cf;
2
3 use Symbol;
4 use List::Util;
5
6 use strict;
7
8 our %COMMAND;
9 our @EVENT;
10 our %PROP_TYPE;
11 our %PROP_IDX;
12
13 BEGIN {
14 @EVENT = map lc, @EVENT;
15
16 *CORE::GLOBAL::warn = sub {
17 my $msg = join "", @_;
18 $msg .= "\n"
19 unless $msg =~ /\n$/;
20
21 print STDERR "cfperl: $msg";
22 LOG llevError, "cfperl: $msg";
23 };
24 }
25
26 # generate property mutators
27 sub prop_gen {
28 my ($prefix, $class) = @_;
29
30 no strict 'refs';
31
32 for my $prop (keys %PROP_TYPE) {
33 $prop =~ /^\Q$prefix\E_(.*$)/ or next;
34 my $sub = lc $1;
35
36 my $type = $PROP_TYPE{$prop};
37 my $idx = $PROP_IDX {$prop};
38
39 *{"$class\::get_$sub"} = *{"$class\::$sub"} = sub {
40 $_[0]->get_property ($type, $idx)
41 };
42
43 *{"$class\::set_$sub"} = sub {
44 $_[0]->set_property ($type, $idx, $_[1]);
45 };
46 }
47 }
48
49 # auto-generate most of the API
50
51 prop_gen OBJECT_PROP => "cf::object";
52 # CFAPI_OBJECT_ANIMATION?
53 prop_gen PLAYER_PROP => "cf::object::player";
54
55 prop_gen MAP_PROP => "cf::map";
56 prop_gen ARCH_PROP => "cf::arch";
57
58 # guessed hierarchies
59
60 @cf::object::player::ISA = 'cf::object';
61 @cf::object::map::ISA = 'cf::object';
62
63 my %ext_pkg;
64 my @exts;
65 my @hook;
66 my %command;
67
68 sub inject_event {
69 my ($data) = @_;
70
71 my $cb = $hook[$data->{event_code}]{$data->{extension}}
72 or return;
73
74 $cb->($data)
75 }
76
77 sub inject_global_event {
78 my ($data) = @_;
79
80 my $cb = $hook[$data->{event_code}]
81 or return;
82
83 $_->($data) for values %$cb;
84
85 ()
86 }
87
88 sub inject_command {
89 my ($name, $obj, $params) = @_;
90
91 for my $cmd (@{ $command{$name} }) {
92 $cmd->[1]->($obj, $params);
93 }
94
95 -1
96 }
97
98 sub register_command {
99 my ($name, $time, $cb) = @_;
100
101 my $caller = caller;
102
103 warn "registering command '$name/$time' to '$caller'";
104
105 push @{ $command{$name} }, [$time, $cb, $caller];
106 $COMMAND{"$name\000"} = List::Util::max map $_->[0], @{ $command{$name} };
107 }
108
109 sub load_extension {
110 my ($path) = @_;
111
112 $path =~ /([^\/\\]+)\.ext$/ or die "$path";
113 my $base = $1;
114 my $pkg = $1;
115 $pkg =~ s/[^[:word:]]/_/g;
116 $pkg = "cf::ext::$pkg";
117
118 warn "loading '$path' into '$pkg'\n";
119
120 open my $fh, "<:utf8", $path
121 or die "$path: $!";
122
123 my $source =
124 "package $pkg; use strict; use utf8;\n"
125 . "#line 1 \"$path\"\n{\n"
126 . (do { local $/; <$fh> })
127 . "\n};\n1";
128
129 eval $source
130 or die "$path: $@";
131
132 push @exts, $pkg;
133 $ext_pkg{$base} = $pkg;
134
135 no strict 'refs';
136
137 # @{"$pkg\::ISA"} = cf::ext::;
138
139 for my $idx (0 .. $#EVENT) {
140 if (my $ref = $pkg->can ("on_$EVENT[$idx]")) {
141 warn "registering $EVENT[$idx] hook\n";
142 $hook[$idx]{$base} = $ref;
143 }
144 }
145 }
146
147 sub unload_extension {
148 my ($pkg) = @_;
149
150 warn "removing extension $pkg\n";
151
152 # remove hooks
153 for my $idx (0 .. $#EVENT) {
154 delete $hook[$idx]{$pkg};
155 }
156
157 # remove commands
158 for my $name (keys %command) {
159 my @cb = grep $_->[2] ne $pkg, @{ $command{$name} };
160
161 if (@cb) {
162 $command{$name} = \@cb;
163 $COMMAND{"$name\000"} = List::Util::max map $_->[0], @cb;
164 } else {
165 delete $command{$name};
166 delete $COMMAND{"$name\000"};
167 }
168 }
169
170 Symbol::delete_package $pkg;
171 }
172
173 sub load_extensions {
174 my $LIBDIR = maps_directory "perl";
175
176 for my $ext (<$LIBDIR/*.ext>) {
177 next unless -r $ext;
178 eval {
179 load_extension $ext;
180 1
181 } or warn "$ext not loaded: $@";
182 }
183 }
184
185 register_command "perl-reload", 0, sub {
186 my ($who, $arg) = @_;
187
188 if ($who->flag (FLAG_WIZ)) {
189 $who->message ("reloading...");
190
191 warn "reloading...\n";
192 eval {
193 unload_extension $_ for @exts;
194 delete $INC{"cf.pm"};
195
196 # don't, removes xs symbols, too
197 #Symbol::delete_package $pkg;
198
199 require cf;
200 };
201 warn $@ if $@;
202 $who->message ($@) if $@;
203 warn "reloaded\n";
204
205 $who->message ("reloaded");
206 } else {
207 $who->message ("Intruder Alert!");
208 }
209 };
210
211 load_extensions;
212
213 1
214