#! perl # mandatory # player scheduler, evoking players from ram our $SCHEDULE_INTERVAL = $cf::CFG{player_schedule_interval} || 10; # time the player scheduler sleeps between runs our $SAVE_TIMEOUT = $cf::CFG{player_save_interval} || 20; # save players every n seconds our $SCHEDULER = cf::async_ext { $Coro::current->{desc} = "player scheduler"; while () { Coro::EV::timer_once $SCHEDULE_INTERVAL; # this weird form of iteration over values is used because # the hash changes underneath us frequently, and for # keeps a direct reference to the value without (in 5.8 perls) # keeping a reference, so this is prone to crashes or worse. my @players = keys %cf::PLAYER; for (@players) { my $pl = $cf::PLAYER{$_} or next; $pl->valid or next; eval { if ($pl->{last_save} + $SAVE_TIMEOUT <= $cf::RUNTIME) { $pl->save; unless ($pl->active || $pl->ns) { # check refcounts, this is tricky and needs to be adjusted to fit server internals my $ob = $pl->ob; my $pl_ref = $pl->refcnt_cnt; my $ob_ref = $ob->refcnt_cnt; ## pl_ref == $pl + ob->contr + %cf::PLAYER ## ob_ref == $ob + pl->observe + simply being an object if ($pl_ref == 3 && $ob_ref == 3) { warn "player-scheduler destroy ", $ob->name;#d# # remove from sight and get fresh "copies" $pl = delete $cf::PLAYER{$ob->name}; $ob = $pl->ob; $pl->destroy; # destroys $ob } else { my $a_ = $pl->refcnt;#d# my $b_ = $ob->refcnt;#d# warn "player-scheduler refcnt ", $ob->name, " pl $pl_ref/3 ob $ob_ref/3 (C pl $a_/1 ob $b_/2)\n";#d# } } } }; warn $@ if $@; cf::cede_to_tick; }; } }; $SCHEDULER->prio (1);