ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/lib/cf.pm
(Generate patch)

Comparing deliantra/server/lib/cf.pm (file contents):
Revision 1.398 by root, Wed Dec 5 11:08:34 2007 UTC vs.
Revision 1.407 by root, Sun Jan 13 09:53:53 2008 UTC

4use strict; 4use strict;
5 5
6use Symbol; 6use Symbol;
7use List::Util; 7use List::Util;
8use Socket; 8use Socket;
9use EV; 9use EV 1.86;
10use Opcode; 10use Opcode;
11use Safe; 11use Safe;
12use Safe::Hole; 12use Safe::Hole;
13use Storable (); 13use Storable ();
14 14
15use Coro 4.1 (); 15use Coro 4.32 ();
16use Coro::State; 16use Coro::State;
17use Coro::Handle; 17use Coro::Handle;
18use Coro::EV; 18use Coro::EV;
19use Coro::Timer; 19use Coro::Timer;
20use Coro::Signal; 20use Coro::Signal;
21use Coro::Semaphore; 21use Coro::Semaphore;
22use Coro::AIO; 22use Coro::AIO;
23use Coro::BDB;
23use Coro::Storable; 24use Coro::Storable;
24use Coro::Util (); 25use Coro::Util ();
25 26
26use JSON::XS 2.01 (); 27use JSON::XS 2.01 ();
27use BDB (); 28use BDB ();
68our $TMPDIR = "$LOCALDIR/" . tmpdir; 69our $TMPDIR = "$LOCALDIR/" . tmpdir;
69our $UNIQUEDIR = "$LOCALDIR/" . uniquedir; 70our $UNIQUEDIR = "$LOCALDIR/" . uniquedir;
70our $PLAYERDIR = "$LOCALDIR/" . playerdir; 71our $PLAYERDIR = "$LOCALDIR/" . playerdir;
71our $RANDOMDIR = "$LOCALDIR/random"; 72our $RANDOMDIR = "$LOCALDIR/random";
72our $BDBDIR = "$LOCALDIR/db"; 73our $BDBDIR = "$LOCALDIR/db";
74our %RESOURCE;
73 75
74our $TICK = MAX_TIME * 1e-6; # this is a CONSTANT(!) 76our $TICK = MAX_TIME * 1e-6; # this is a CONSTANT(!)
75our $TICK_WATCHER; 77our $TICK_WATCHER;
76our $AIO_POLL_WATCHER; 78our $AIO_POLL_WATCHER;
77our $NEXT_RUNTIME_WRITE; # when should the runtime file be written 79our $NEXT_RUNTIME_WRITE; # when should the runtime file be written
78our $NEXT_TICK; 80our $NEXT_TICK;
79our $NOW;
80our $USE_FSYNC = 1; # use fsync to write maps - default off 81our $USE_FSYNC = 1; # use fsync to write maps - default off
81 82
82our $BDB_POLL_WATCHER; 83our $BDB_POLL_WATCHER;
83our $BDB_DEADLOCK_WATCHER; 84our $BDB_DEADLOCK_WATCHER;
84our $BDB_CHECKPOINT_WATCHER; 85our $BDB_CHECKPOINT_WATCHER;
87 88
88our %CFG; 89our %CFG;
89 90
90our $UPTIME; $UPTIME ||= time; 91our $UPTIME; $UPTIME ||= time;
91our $RUNTIME; 92our $RUNTIME;
93our $NOW;
92 94
93our (%PLAYER, %PLAYER_LOADING); # all users 95our (%PLAYER, %PLAYER_LOADING); # all users
94our (%MAP, %MAP_LOADING ); # all maps 96our (%MAP, %MAP_LOADING ); # all maps
95our $LINK_MAP; # the special {link} map, which is always available 97our $LINK_MAP; # the special {link} map, which is always available
96 98
191 $msg =~ s/([\x00-\x08\x0b-\x1f])/sprintf "\\x%02x", ord $1/ge; 193 $msg =~ s/([\x00-\x08\x0b-\x1f])/sprintf "\\x%02x", ord $1/ge;
192 194
193 LOG llevError, $msg; 195 LOG llevError, $msg;
194 }; 196 };
195} 197}
198
199$Coro::State::DIEHOOK = sub {
200 warn Carp::longmess $_[0];
201 Coro::terminate;
202};
196 203
197@safe::cf::global::ISA = @cf::global::ISA = 'cf::attachable'; 204@safe::cf::global::ISA = @cf::global::ISA = 'cf::attachable';
198@safe::cf::object::ISA = @cf::object::ISA = 'cf::attachable'; 205@safe::cf::object::ISA = @cf::object::ISA = 'cf::attachable';
199@safe::cf::player::ISA = @cf::player::ISA = 'cf::attachable'; 206@safe::cf::player::ISA = @cf::player::ISA = 'cf::attachable';
200@safe::cf::client::ISA = @cf::client::ISA = 'cf::attachable'; 207@safe::cf::client::ISA = @cf::client::ISA = 'cf::attachable';
967 } 974 }
968 975
969 0 976 0
970} 977}
971 978
972=item $bool = cf::global::invoke (EVENT_CLASS_XXX, ...) 979=item $bool = cf::global->invoke (EVENT_CLASS_XXX, ...)
973 980
974=item $bool = $attachable->invoke (EVENT_CLASS_XXX, ...) 981=item $bool = $attachable->invoke (EVENT_CLASS_XXX, ...)
975 982
976Generate an object-specific event with the given arguments. 983Generate an object-specific event with the given arguments.
977 984
3148 { 3155 {
3149 my $faces = $facedata->{faceinfo}; 3156 my $faces = $facedata->{faceinfo};
3150 3157
3151 while (my ($face, $info) = each %$faces) { 3158 while (my ($face, $info) = each %$faces) {
3152 my $idx = (cf::face::find $face) || cf::face::alloc $face; 3159 my $idx = (cf::face::find $face) || cf::face::alloc $face;
3160
3153 cf::face::set_visibility $idx, $info->{visibility}; 3161 cf::face::set_visibility $idx, $info->{visibility};
3154 cf::face::set_magicmap $idx, $info->{magicmap}; 3162 cf::face::set_magicmap $idx, $info->{magicmap};
3155 cf::face::set_data $idx, 0, $info->{data32}, Digest::MD5::md5 $info->{data32}; 3163 cf::face::set_data $idx, 0, $info->{data32}, Digest::MD5::md5 $info->{data32};
3156 cf::face::set_data $idx, 1, $info->{data64}, Digest::MD5::md5 $info->{data64}; 3164 cf::face::set_data $idx, 1, $info->{data64}, Digest::MD5::md5 $info->{data64};
3157 3165
3158 cf::cede_to_tick; 3166 cf::cede_to_tick;
3159 } 3167 }
3160 3168
3161 while (my ($face, $info) = each %$faces) { 3169 while (my ($face, $info) = each %$faces) {
3162 next unless $info->{smooth}; 3170 next unless $info->{smooth};
3171
3163 my $idx = cf::face::find $face 3172 my $idx = cf::face::find $face
3164 or next; 3173 or next;
3174
3165 if (my $smooth = cf::face::find $info->{smooth}) { 3175 if (my $smooth = cf::face::find $info->{smooth}) {
3166 cf::face::set_smooth $idx, $smooth; 3176 cf::face::set_smooth $idx, $smooth;
3167 cf::face::set_smoothlevel $idx, $info->{smoothlevel}; 3177 cf::face::set_smoothlevel $idx, $info->{smoothlevel};
3168 } else { 3178 } else {
3169 warn "smooth face '$info->{smooth}' not found for face '$face'"; 3179 warn "smooth face '$info->{smooth}' not found for face '$face'";
3187 { 3197 {
3188 # TODO: for gcfclient pleasure, we should give resources 3198 # TODO: for gcfclient pleasure, we should give resources
3189 # that gcfclient doesn't grok a >10000 face index. 3199 # that gcfclient doesn't grok a >10000 face index.
3190 my $res = $facedata->{resource}; 3200 my $res = $facedata->{resource};
3191 3201
3192 my $soundconf = delete $res->{"res/sound.conf"};
3193
3194 while (my ($name, $info) = each %$res) { 3202 while (my ($name, $info) = each %$res) {
3203 if (defined $info->{type}) {
3195 my $idx = (cf::face::find $name) || cf::face::alloc $name; 3204 my $idx = (cf::face::find $name) || cf::face::alloc $name;
3196 my $data; 3205 my $data;
3197 3206
3198 if ($info->{type} & 1) { 3207 if ($info->{type} & 1) {
3199 # prepend meta info 3208 # prepend meta info
3200 3209
3201 my $meta = $enc->encode ({ 3210 my $meta = $enc->encode ({
3202 name => $name, 3211 name => $name,
3203 %{ $info->{meta} || {} }, 3212 %{ $info->{meta} || {} },
3204 }); 3213 });
3205 3214
3206 $data = pack "(w/a*)*", $meta, $info->{data}; 3215 $data = pack "(w/a*)*", $meta, $info->{data};
3216 } else {
3217 $data = $info->{data};
3218 }
3219
3220 cf::face::set_data $idx, 0, $data, Digest::MD5::md5 $data;
3221 cf::face::set_type $idx, $info->{type};
3207 } else { 3222 } else {
3208 $data = $info->{data}; 3223 $RESOURCE{$name} = $info;
3209 } 3224 }
3210 3225
3211 cf::face::set_data $idx, 0, $data, Digest::MD5::md5 $data;
3212 cf::face::set_type $idx, $info->{type};
3213
3214 cf::cede_to_tick; 3226 cf::cede_to_tick;
3215 } 3227 }
3216
3217 if ($soundconf) {
3218 $soundconf = $enc->decode (delete $soundconf->{data});
3219
3220 for (0 .. SOUND_CAST_SPELL_0 - 1) {
3221 my $sound = $soundconf->{compat}[$_]
3222 or next;
3223
3224 my $face = cf::face::find "sound/$sound->[1]";
3225 cf::sound::set $sound->[0] => $face;
3226 cf::sound::old_sound_index $_, $face; # gcfclient-compat
3227 }
3228
3229 while (my ($k, $v) = each %{$soundconf->{event}}) {
3230 my $face = cf::face::find "sound/$v";
3231 cf::sound::set $k => $face;
3232 }
3233 }
3234 } 3228 }
3229
3230 cf::global->invoke (EVENT_GLOBAL_RESOURCE_UPDATE);
3235 3231
3236 1 3232 1
3237} 3233}
3234
3235cf::global->attach (on_resource_update => sub {
3236 if (my $soundconf = $RESOURCE{"res/sound.conf"}) {
3237 $soundconf = JSON::XS->new->utf8->relaxed->decode ($soundconf->{data});
3238
3239 for (0 .. SOUND_CAST_SPELL_0 - 1) {
3240 my $sound = $soundconf->{compat}[$_]
3241 or next;
3242
3243 my $face = cf::face::find "sound/$sound->[1]";
3244 cf::sound::set $sound->[0] => $face;
3245 cf::sound::old_sound_index $_, $face; # gcfclient-compat
3246 }
3247
3248 while (my ($k, $v) = each %{$soundconf->{event}}) {
3249 my $face = cf::face::find "sound/$v";
3250 cf::sound::set $k => $face;
3251 }
3252 }
3253});
3238 3254
3239register_exticmd fx_want => sub { 3255register_exticmd fx_want => sub {
3240 my ($ns, $want) = @_; 3256 my ($ns, $want) = @_;
3241 3257
3242 while (my ($k, $v) = each %$want) { 3258 while (my ($k, $v) = each %$want) {
3602 3618
3603 $NOW = $tick_start = EV::now; 3619 $NOW = $tick_start = EV::now;
3604 3620
3605 cf::server_tick; # one server iteration 3621 cf::server_tick; # one server iteration
3606 3622
3607 $RUNTIME += $TICK; 3623 $RUNTIME += $TICK;
3608 $NEXT_TICK += $TICK; 3624 $NEXT_TICK = $_[0]->at;
3609 3625
3610 if ($NOW >= $NEXT_RUNTIME_WRITE) { 3626 if ($NOW >= $NEXT_RUNTIME_WRITE) {
3611 $NEXT_RUNTIME_WRITE = $NOW + 10; 3627 $NEXT_RUNTIME_WRITE = List::Util::max $NEXT_RUNTIME_WRITE + 10, $NOW + 5.;
3612 Coro::async_pool { 3628 Coro::async_pool {
3613 $Coro::current->{desc} = "runtime saver"; 3629 $Coro::current->{desc} = "runtime saver";
3614 write_runtime 3630 write_runtime
3615 or warn "ERROR: unable to write runtime file: $!"; 3631 or warn "ERROR: unable to write runtime file: $!";
3616 }; 3632 };
3629 _post_tick; 3645 _post_tick;
3630}; 3646};
3631$TICK_WATCHER->priority (EV::MAXPRI); 3647$TICK_WATCHER->priority (EV::MAXPRI);
3632 3648
3633{ 3649{
3650 # configure BDB
3651
3634 BDB::min_parallel 8; 3652 BDB::min_parallel 8;
3635 BDB::max_poll_time $TICK * 0.1; 3653 BDB::max_poll_reqs $TICK * 0.1;
3636 $BDB_POLL_WATCHER = EV::io BDB::poll_fileno, EV::READ, \&BDB::poll_cb; 3654 $Coro::BDB::WATCHER->priority (1);
3637
3638 BDB::set_sync_prepare {
3639 my $status;
3640 my $current = $Coro::current;
3641 (
3642 sub {
3643 $status = $!;
3644 $current->ready; undef $current;
3645 },
3646 sub {
3647 Coro::schedule while defined $current;
3648 $! = $status;
3649 },
3650 )
3651 };
3652 3655
3653 unless ($DB_ENV) { 3656 unless ($DB_ENV) {
3654 $DB_ENV = BDB::db_env_create; 3657 $DB_ENV = BDB::db_env_create;
3655 $DB_ENV->set_flags (BDB::AUTO_COMMIT | BDB::REGION_INIT | BDB::TXN_NOSYNC 3658 $DB_ENV->set_flags (BDB::AUTO_COMMIT | BDB::REGION_INIT | BDB::TXN_NOSYNC
3656 | BDB::LOG_AUTOREMOVE, 1); 3659 | BDB::LOG_AUTOREMOVE, 1);
3683 BDB::db_env_memp_trickle $DB_ENV, 20, 0, sub { }; 3686 BDB::db_env_memp_trickle $DB_ENV, 20, 0, sub { };
3684 }; 3687 };
3685} 3688}
3686 3689
3687{ 3690{
3691 # configure IO::AIO
3692
3688 IO::AIO::min_parallel 8; 3693 IO::AIO::min_parallel 8;
3689
3690 undef $Coro::AIO::WATCHER;
3691 IO::AIO::max_poll_time $TICK * 0.1; 3694 IO::AIO::max_poll_time $TICK * 0.1;
3692 $AIO_POLL_WATCHER = EV::io IO::AIO::poll_fileno, EV::READ, \&IO::AIO::poll_cb; 3695 $Coro::AIO::WATCHER->priority (1);
3693} 3696}
3694 3697
3695my $_log_backtrace; 3698my $_log_backtrace;
3696 3699
3697sub _log_backtrace { 3700sub _log_backtrace {

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines