157 lines
3.8 KiB
Perl
157 lines
3.8 KiB
Perl
package LasTres::EventLoop;
|
|
|
|
use v5.36.0;
|
|
|
|
use strict;
|
|
use warnings;
|
|
|
|
use feature 'signatures';
|
|
|
|
use Moo;
|
|
use JSON qw/to_json from_json/;
|
|
|
|
use LasTres::Battle;
|
|
|
|
has _app => ( is => 'lazy' );
|
|
|
|
has _schema => ( is => 'lazy' );
|
|
|
|
has _redis => ( is => 'lazy' );
|
|
|
|
sub _build__app {
|
|
require LasTres;
|
|
return LasTres->new;
|
|
}
|
|
|
|
sub _build__schema {
|
|
require LasTres::Schema;
|
|
return LasTres::Schema->Schema;
|
|
}
|
|
|
|
sub _build__redis {
|
|
require LasTres::Redis;
|
|
return LasTres::Redis->new;
|
|
}
|
|
|
|
sub _exit_the_program {
|
|
exit 0;
|
|
}
|
|
|
|
$SIG{CHLD} = 'IGNORE';
|
|
$SIG{INT} = \&_exit_the_program;
|
|
$SIG{QUIT} = \&_exit_the_program;
|
|
$SIG{TERM} = \&_exit_the_program;
|
|
|
|
sub loop ($self) {
|
|
my $child_pid = fork;
|
|
if ( !$child_pid ) {
|
|
$self->_real_loop;
|
|
exit(0);
|
|
}
|
|
}
|
|
|
|
sub _work_frame ($self) {
|
|
$self->_increment_frame_for_movers();
|
|
$self->_increment_frame_for_combats;
|
|
}
|
|
|
|
sub _increment_frame_for_combats ($self) {
|
|
my $schema = $self->_schema;
|
|
my $result_set_teams = $schema->resultset('Team');
|
|
my @teams = $result_set_teams->search(
|
|
{
|
|
current_battle => { '!=' => undef },
|
|
},
|
|
);
|
|
for my $battle_uuid ( map { $_->current_battle } @teams ) {
|
|
$self->_increment_frame_for_combat($battle_uuid);
|
|
}
|
|
}
|
|
|
|
sub _expire_battle($self, $battle_uuid) {
|
|
my $schema = $self->_schema;
|
|
my $result_set_teams = $schema->resultset('Team');
|
|
my @teams_in_expired_battle = $result_set_teams->search(
|
|
{
|
|
current_battle => $battle_uuid
|
|
}
|
|
);
|
|
for my $team (@teams_in_expired_battle) {
|
|
$team->current_battle(undef);
|
|
$team->update;
|
|
}
|
|
}
|
|
sub _increment_frame_for_combat($self, $battle_uuid) {
|
|
my $battle = LasTres::Battle->get_redis($battle_uuid);
|
|
if (!defined $battle) {
|
|
$self->_expire_battle($battle_uuid);
|
|
return;
|
|
}
|
|
if (!$battle->sanity_check) {
|
|
$battle->end;
|
|
}
|
|
my @combat_members = (@{$battle->team1->combat_members}, @{$battle->team2->combat_members});
|
|
@combat_members = sort { $b->speed <=> $a->speed } @combat_members;
|
|
for my $entity (@combat_members) {
|
|
$battle->try_turn($entity);
|
|
if (my $winner = $battle->winner) {
|
|
next;
|
|
}
|
|
$battle->save_redis;
|
|
}
|
|
if (my $winner = $battle->winner) {
|
|
my $loser = $battle->loser;
|
|
$winner->on_win_combat;
|
|
$loser->on_lose_combat;
|
|
$battle->end;
|
|
}
|
|
$battle->save_redis;
|
|
}
|
|
|
|
sub _increment_frame_for_movers ($self) {
|
|
my $schema = $self->_schema;
|
|
my $result_set_teams = $schema->resultset('Team');
|
|
my @teams = $result_set_teams->search(
|
|
{ -bool => 'is_moving', current_battle => undef } );
|
|
for my $team (@teams) {
|
|
$self->_increment_frame_for_mover($team);
|
|
}
|
|
}
|
|
|
|
sub _increment_frame_for_mover ( $self, $team ) {
|
|
$team = $team->get_from_storage;
|
|
my $frame = $team->action_frame;
|
|
$team->action_frame( ++$frame );
|
|
$team->update;
|
|
my $location = $team->location;
|
|
my $target_location =
|
|
LasTres::Location::get( from_json( $team->moving_to )->@* );
|
|
if ( $frame >= $location->parent->frames_to_move ) {
|
|
$team->action_frame(0);
|
|
$team->is_moving(0);
|
|
$team->moving_to('null');
|
|
$team->update;
|
|
$target_location->place_team($team);
|
|
return;
|
|
}
|
|
$team->send_frame_to_members;
|
|
$team->location->parent->on_move_explore_frame($team);
|
|
}
|
|
|
|
sub _real_loop ($self) {
|
|
eval {
|
|
my $redis = $self->_redis;
|
|
while (1) {
|
|
if ( !defined $redis->db->get( $redis->executing_frame_key ) ) {
|
|
$redis->db->setex( $redis->executing_frame_key, 10, 1 );
|
|
$self->_work_frame;
|
|
}
|
|
my $ttl = $redis->db->ttl( $redis->executing_frame_key );
|
|
}
|
|
};
|
|
if ($@) {
|
|
warn $@;
|
|
}
|
|
}
|
|
1;
|