Adding non destructive pokemon edition.
This commit is contained in:
parent
7ebbc18eaa
commit
65fde508f1
|
@ -23,6 +23,13 @@ sub MIGRATIONS {
|
||||||
backup_input_file TEXT,
|
backup_input_file TEXT,
|
||||||
backup_output_file TEXT
|
backup_output_file TEXT
|
||||||
);',
|
);',
|
||||||
|
'CREATE TABLE backups_pk3 (
|
||||||
|
uuid TEXT PRIMARY KEY,
|
||||||
|
date datetime NOT NULL,
|
||||||
|
nickname TEXT,
|
||||||
|
pokemon_name TEXT,
|
||||||
|
file TEXT
|
||||||
|
);',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
1;
|
1;
|
||||||
|
|
|
@ -74,6 +74,8 @@ sub backup_files {
|
||||||
next;
|
next;
|
||||||
}
|
}
|
||||||
my $basename = $file->basename;
|
my $basename = $file->basename;
|
||||||
|
$basename =~ s/\.\.//g;
|
||||||
|
$basename =~ s/\///g;
|
||||||
my $output_file = $backup_dir->child("$digest-$basename");
|
my $output_file = $backup_dir->child("$digest-$basename");
|
||||||
$output_file->spew_raw($contents);
|
$output_file->spew_raw($contents);
|
||||||
push @result_files, $output_file;
|
push @result_files, $output_file;
|
||||||
|
|
|
@ -10,6 +10,10 @@ use Rsaves;
|
||||||
use Rsaves::Constants::Emerald::Species;
|
use Rsaves::Constants::Emerald::Species;
|
||||||
use Rsaves::Constants::Emerald::SpeciesData;
|
use Rsaves::Constants::Emerald::SpeciesData;
|
||||||
use Path::Tiny;
|
use Path::Tiny;
|
||||||
|
use GEmeTool::DB;
|
||||||
|
use GEmeTool::Config;
|
||||||
|
use Digest::SHA qw/sha256_hex/;
|
||||||
|
use UUID::URandom qw/create_uuid_string/;
|
||||||
|
|
||||||
has _pokemon => ( is => 'rw', required => 1 );
|
has _pokemon => ( is => 'rw', required => 1 );
|
||||||
|
|
||||||
|
@ -38,6 +42,11 @@ sub export_file {
|
||||||
Rsaves::write_pk3_file( $self->_pokemon, $file );
|
Rsaves::write_pk3_file( $self->_pokemon, $file );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub export_raw {
|
||||||
|
my $self = shift;
|
||||||
|
return Rsaves::get_pk3_raw( $self->_pokemon );
|
||||||
|
}
|
||||||
|
|
||||||
sub empty {
|
sub empty {
|
||||||
my $class = shift;
|
my $class = shift;
|
||||||
return $class->new( _pokemon => Rsaves::read_pk3_raw( "\0" x 0x80 ) );
|
return $class->new( _pokemon => Rsaves::read_pk3_raw( "\0" x 0x80 ) );
|
||||||
|
@ -384,4 +393,40 @@ sub get_front {
|
||||||
}
|
}
|
||||||
return "pokeemerald/graphics/pokemon/@{[lc($pokemon_name)]}/front.png";
|
return "pokeemerald/graphics/pokemon/@{[lc($pokemon_name)]}/front.png";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub backup {
|
||||||
|
my $self = shift;
|
||||||
|
my $db = GEmeTool::DB->connect;
|
||||||
|
my $data_dir = GEmeTool::Config->new->data_dir;
|
||||||
|
my $backup_dir = $data_dir->child('backups/pk3');
|
||||||
|
$backup_dir->mkpath;
|
||||||
|
my $nickname = Rsaves::translate_3rd_encoding( $self->nickname );
|
||||||
|
$nickname =~ s/\.\.//g;
|
||||||
|
$nickname =~ s/\///g;
|
||||||
|
my $contents = $self->export_raw;
|
||||||
|
my $digest = sha256_hex($contents);
|
||||||
|
my $file = $backup_dir->child(
|
||||||
|
$nickname . '-' . $self->pokemon_name . '-' . $digest . '.pk3' )
|
||||||
|
->absolute;
|
||||||
|
$file->spew_raw($contents);
|
||||||
|
my $uuid = create_uuid_string();
|
||||||
|
my $query_check_exists = <<'EOF';
|
||||||
|
SELECT file FROM backups_pk3
|
||||||
|
WHERE file = ?
|
||||||
|
EOF
|
||||||
|
|
||||||
|
if ( $db->selectrow_hashref( $query_check_exists, undef, $file ) ) {
|
||||||
|
$db->do( <<'EOF', undef, $file );
|
||||||
|
UPDATE backups_pk3
|
||||||
|
SET date=datetime('now')
|
||||||
|
WHERE file = ?;
|
||||||
|
EOF
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
my $query = <<'EOF';
|
||||||
|
INSERT INTO backups_pk3 (uuid, date, nickname, pokemon_name, file)
|
||||||
|
VALUES (?, datetime('now'), ?, ?, ?);
|
||||||
|
EOF
|
||||||
|
$db->do( $query, {}, $uuid, $self->nickname, $self->pokemon_name, $file );
|
||||||
|
}
|
||||||
1;
|
1;
|
||||||
|
|
|
@ -17,6 +17,7 @@ use Rsaves::Constants::Emerald::Species;
|
||||||
use Rsaves::Constants::Emerald::Natures;
|
use Rsaves::Constants::Emerald::Natures;
|
||||||
use GEmeTool::Save::Pokemon;
|
use GEmeTool::Save::Pokemon;
|
||||||
use GEmeTool::Options;
|
use GEmeTool::Options;
|
||||||
|
use GEmeTool::DB;
|
||||||
|
|
||||||
Glib::Object::Introspection->setup(
|
Glib::Object::Introspection->setup(
|
||||||
basename => 'Gtk',
|
basename => 'Gtk',
|
||||||
|
@ -100,6 +101,7 @@ sub draw {
|
||||||
$grid->attach( $canvas, 0, 0, 2, 2 );
|
$grid->attach( $canvas, 0, 0, 2, 2 );
|
||||||
my @species = (@Rsaves::Constants::Emerald::Species::SPECIES);
|
my @species = (@Rsaves::Constants::Emerald::Species::SPECIES);
|
||||||
my $string_list = Gtk4::StringList->new( [@species] );
|
my $string_list = Gtk4::StringList->new( [@species] );
|
||||||
|
my $restore_button = Gtk4::Button->new_with_label('Restore from backup');
|
||||||
my $save_button = Gtk4::Button->new_with_label('Save changes');
|
my $save_button = Gtk4::Button->new_with_label('Save changes');
|
||||||
my $delete_button = Gtk4::Button->new_with_label('Delete pokemon');
|
my $delete_button = Gtk4::Button->new_with_label('Delete pokemon');
|
||||||
my $import_button = Gtk4::Button->new_with_label('Import .pk3');
|
my $import_button = Gtk4::Button->new_with_label('Import .pk3');
|
||||||
|
@ -118,25 +120,28 @@ sub draw {
|
||||||
$self->create_change_nickname_entry($box_right_image);
|
$self->create_change_nickname_entry($box_right_image);
|
||||||
$save_button->signal_connect(
|
$save_button->signal_connect(
|
||||||
clicked => sub {
|
clicked => sub {
|
||||||
$pokemon->species( $self->_selected_species );
|
|
||||||
$pokemon->personality( $self->_current_personality );
|
|
||||||
$self->recalculate_ivs;
|
|
||||||
$self->recalculate_evs;
|
|
||||||
for my $func ( @{ $self->_save_callbacks } ) {
|
|
||||||
$func->();
|
|
||||||
}
|
|
||||||
$self->draw;
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
$delete_button->signal_connect(clicked => sub {
|
$delete_button->signal_connect(
|
||||||
|
clicked => sub {
|
||||||
$self->delete;
|
$self->delete;
|
||||||
});
|
}
|
||||||
$import_button->signal_connect(clicked => sub {
|
);
|
||||||
|
$import_button->signal_connect(
|
||||||
|
clicked => sub {
|
||||||
$self->activate_import_pk3;
|
$self->activate_import_pk3;
|
||||||
});
|
}
|
||||||
$export_button->signal_connect(clicked => sub {
|
);
|
||||||
|
$export_button->signal_connect(
|
||||||
|
clicked => sub {
|
||||||
$self->activate_export_pk3;
|
$self->activate_export_pk3;
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
$restore_button->signal_connect(
|
||||||
|
clicked => sub {
|
||||||
|
$self->activate_restore;
|
||||||
|
}
|
||||||
|
);
|
||||||
$self->draw_dropdown_pokemon_list($box_right_image);
|
$self->draw_dropdown_pokemon_list($box_right_image);
|
||||||
my $box_label_iv = Gtk4::Box->new( 'horizontal', 10 );
|
my $box_label_iv = Gtk4::Box->new( 'horizontal', 10 );
|
||||||
$box_label_iv->append( Gtk4::Label->new('Select IV') );
|
$box_label_iv->append( Gtk4::Label->new('Select IV') );
|
||||||
|
@ -147,9 +152,67 @@ sub draw {
|
||||||
$grid->attach( $export_button, 3, 7, 1, 1 );
|
$grid->attach( $export_button, 3, 7, 1, 1 );
|
||||||
$grid->attach( $delete_button, 2, 7, 1, 1 );
|
$grid->attach( $delete_button, 2, 7, 1, 1 );
|
||||||
$grid->attach( $import_button, 1, 7, 1, 1 );
|
$grid->attach( $import_button, 1, 7, 1, 1 );
|
||||||
|
$grid->attach( $restore_button, 0, 7, 1, 1 );
|
||||||
$window->set_child($grid);
|
$window->set_child($grid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub activate_restore {
|
||||||
|
my $self = shift;
|
||||||
|
my $window = Gtk4::Window->new;
|
||||||
|
$window->set_title('Restore from backup');
|
||||||
|
my $scroll = Gtk4::ScrolledWindow->new;
|
||||||
|
my $grid = Gtk4::Grid->new;
|
||||||
|
my $backups = $self->get_backups;
|
||||||
|
my $i = 0;
|
||||||
|
for my $backup (@$backups) {
|
||||||
|
my $nickname = Rsaves::translate_3rd_encoding( $backup->{nickname} );
|
||||||
|
my $pokemon_name = $backup->{pokemon_name};
|
||||||
|
my $file = $backup->{file};
|
||||||
|
my $button =
|
||||||
|
Gtk4::Button->new_with_label( $nickname . '-' . $pokemon_name );
|
||||||
|
$button->signal_connect(
|
||||||
|
clicked => sub {
|
||||||
|
$self->activate_save;
|
||||||
|
$self->pokemon->backup;
|
||||||
|
$self->pokemon->copy(
|
||||||
|
GEmeTool::Save::Pokemon->load_from_file($file) );
|
||||||
|
$self->draw;
|
||||||
|
$window->close;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
$grid->attach( $button, $i % 6, int( $i / 6 ), 1, 1 );
|
||||||
|
$i++;
|
||||||
|
}
|
||||||
|
$window->set_child($grid);
|
||||||
|
$window->present;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get_backups {
|
||||||
|
my $self = shift;
|
||||||
|
my $db = GEmeTool::DB->connect;
|
||||||
|
my $query = <<'EOF';
|
||||||
|
SELECT nickname, pokemon_name, file
|
||||||
|
FROM backups_pk3
|
||||||
|
ORDER BY date DESC;
|
||||||
|
EOF
|
||||||
|
my $result = $db->selectall_arrayref( $query, { Slice => {} } );
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub activate_save {
|
||||||
|
my $self = shift;
|
||||||
|
my $pokemon = $self->pokemon;
|
||||||
|
$pokemon->backup;
|
||||||
|
$pokemon->species( $self->_selected_species );
|
||||||
|
$pokemon->personality( $self->_current_personality );
|
||||||
|
$self->recalculate_ivs;
|
||||||
|
$self->recalculate_evs;
|
||||||
|
for my $func ( @{ $self->_save_callbacks } ) {
|
||||||
|
$func->();
|
||||||
|
}
|
||||||
|
$self->draw;
|
||||||
|
}
|
||||||
|
|
||||||
sub activate_export_pk3 {
|
sub activate_export_pk3 {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my $win = $self->_win;
|
my $win = $self->_win;
|
||||||
|
@ -159,7 +222,10 @@ sub activate_export_pk3 {
|
||||||
if ( defined $last_dir && -d $last_dir ) {
|
if ( defined $last_dir && -d $last_dir ) {
|
||||||
my $curdir = Glib::IO::File::new_for_path($last_dir);
|
my $curdir = Glib::IO::File::new_for_path($last_dir);
|
||||||
$dialog->set_initial_folder($curdir);
|
$dialog->set_initial_folder($curdir);
|
||||||
$dialog->set_initial_name( Rsaves::translate_3rd_encoding($self->pokemon->nickname) . '-' . $self->pokemon->pokemon_name . '.pk3');
|
$dialog->set_initial_name(
|
||||||
|
Rsaves::translate_3rd_encoding( $self->pokemon->nickname ) . '-'
|
||||||
|
. $self->pokemon->pokemon_name
|
||||||
|
. '.pk3' );
|
||||||
}
|
}
|
||||||
$dialog->save(
|
$dialog->save(
|
||||||
$win, undef,
|
$win, undef,
|
||||||
|
@ -178,6 +244,7 @@ sub activate_export_pk3 {
|
||||||
|
|
||||||
sub delete {
|
sub delete {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
|
$self->pokemon->backup;
|
||||||
$self->pokemon->copy( GEmeTool::Save::Pokemon->empty );
|
$self->pokemon->copy( GEmeTool::Save::Pokemon->empty );
|
||||||
$self->draw;
|
$self->draw;
|
||||||
}
|
}
|
||||||
|
@ -205,11 +272,15 @@ sub activate_import_pk3 {
|
||||||
return if !defined $file;
|
return if !defined $file;
|
||||||
$file = path( $file->get_path );
|
$file = path( $file->get_path );
|
||||||
$options->set_last_dir_open( $file->parent . '' );
|
$options->set_last_dir_open( $file->parent . '' );
|
||||||
$self->pokemon->copy(GEmeTool::Save::Pokemon->load_from_file($file));
|
$self->activate_save;
|
||||||
|
$self->pokemon->backup;
|
||||||
|
$self->pokemon->copy(
|
||||||
|
GEmeTool::Save::Pokemon->load_from_file($file) );
|
||||||
$self->draw;
|
$self->draw;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
sub create_select_level {
|
sub create_select_level {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my $box = shift;
|
my $box = shift;
|
||||||
|
@ -220,7 +291,8 @@ sub create_select_level {
|
||||||
$entry->set_input_purpose('digits');
|
$entry->set_input_purpose('digits');
|
||||||
$entry->get_buffer->set_text( $pokemon->level, length $pokemon->level );
|
$entry->get_buffer->set_text( $pokemon->level, length $pokemon->level );
|
||||||
$box_level->append($entry);
|
$box_level->append($entry);
|
||||||
$self->onSave( sub {
|
$self->onSave(
|
||||||
|
sub {
|
||||||
my $text = $entry->get_buffer->get_text;
|
my $text = $entry->get_buffer->get_text;
|
||||||
if ( $text !~ /^[0-9]+$/ ) {
|
if ( $text !~ /^[0-9]+$/ ) {
|
||||||
return;
|
return;
|
||||||
|
@ -232,7 +304,8 @@ sub create_select_level {
|
||||||
$text = 2;
|
$text = 2;
|
||||||
}
|
}
|
||||||
$pokemon->level($text);
|
$pokemon->level($text);
|
||||||
});
|
}
|
||||||
|
);
|
||||||
$box->append($box_level);
|
$box->append($box_level);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue