From ca90048a9fb2d8c3c65d81096ecd36bbf7c51ff5 Mon Sep 17 00:00:00 2001 From: Daniel Karbach Date: Tue, 10 May 2022 19:10:37 +0200 Subject: [PATCH] aos seed generation --- .env.example | 1 + app/DiscordAppCommands/AosrPresetCommand.php | 73 +++---- app/Jobs/GenerateAosSeed.php | 80 ++++++++ app/Models/AosSeed.php | 21 ++ composer.json | 1 + composer.lock | 189 +++++++++++++++++- config/aos.php | 2 + .../2022_05_10_144912_aos_seed_generation.php | 34 ++++ resources/js/components/aos/Seed.js | 35 +++- resources/js/components/pages/AosSeed.js | 31 ++- resources/js/i18n/de.js | 9 + resources/js/i18n/en.js | 9 + 12 files changed, 442 insertions(+), 43 deletions(-) create mode 100644 app/Jobs/GenerateAosSeed.php create mode 100644 database/migrations/2022_05_10_144912_aos_seed_generation.php diff --git a/.env.example b/.env.example index 9fa47a0..c1b602f 100644 --- a/.env.example +++ b/.env.example @@ -61,5 +61,6 @@ DISCORD_BOT_TOKEN= DISCORD_BOT_CREATE_COMMANDS= DISCORD_BOT_ENABLE_COMMANDS= +AOS_BASE_ROM= AOS_HOSTNAME=aos.localhorst.tv AOS_URL=https://aos.localhorst.tv diff --git a/app/DiscordAppCommands/AosrPresetCommand.php b/app/DiscordAppCommands/AosrPresetCommand.php index 8ec3eb4..a023fcb 100644 --- a/app/DiscordAppCommands/AosrPresetCommand.php +++ b/app/DiscordAppCommands/AosrPresetCommand.php @@ -2,6 +2,7 @@ namespace App\DiscordAppCommands; +use App\Models\AosSeed; use Discord\Builders\MessageBuilder; use Discord\Discord; use Discord\Parts\Embed\Embed; @@ -22,15 +23,15 @@ class AosrPresetCommand { $cmd = $discord->application->commands->create([ 'name' => 'aosr', 'type' => 1, - 'description' => '(testing) Generate an AoSRando seed.', + 'description' => 'Generate an AoSRando seed.', 'description_localizations' => [ - 'de' => '(test) Generiert einen AoSRando Seed.', + 'de' => 'Generiert einen AoSRando Seed.', ], 'options' => [[ 'name' => 'preset', - 'description' => '(testing) Generate an AoSRando seed from preset.', + 'description' => 'Generate an AoSRando seed from preset.', 'description_localizations' => [ - 'de' => '(test) Generiert einen AoSRando Seed anhand eines Presets.', + 'de' => 'Generiert einen AoSRando Seed anhand eines Presets.', ], 'type' => 1, 'options' => [[ @@ -50,36 +51,40 @@ class AosrPresetCommand { public static function listen(Discord $discord) { $discord->listenCommand(['aosr', 'preset'], function(Interaction $interaction) use ($discord) { - $presetName = $interaction->data->options['preset']->options['preset']->value; - $message = MessageBuilder::new(); - if (isset(static::$presets[$presetName])) { - $preset = static::$presets[$presetName]; - $seed = strval(random_int(-2147483648, 2147483647)); - $params = array_merge(['seed' => $seed], $preset['settings']); - $url = 'https://aosrando.surge.sh/?'.http_build_query($params, '', '&'); - $embed = new Embed($discord, [ - 'fields' => [ - new Field($discord, [ 'name' => 'Preset', 'value' => $preset['name'], 'inline' => true ]), - new Field($discord, [ 'name' => 'Seed', 'value' => $seed, 'inline' => true ]), - new Field($discord, [ 'name' => 'Logic', 'value' => $preset['settings']['logic'], 'inline' => true ]), - new Field($discord, [ 'name' => 'Area', 'value' => $preset['settings']['area'], 'inline' => true ]), - new Field($discord, [ 'name' => 'Boss', 'value' => $preset['settings']['boss'], 'inline' => true ]), - new Field($discord, [ 'name' => 'Enemy', 'value' => $preset['settings']['enemy'], 'inline' => true ]), - new Field($discord, [ 'name' => 'Link', 'value' => $url ]), - ], - 'footer' => new Footer($discord, [ - 'text' => 'Grün', - ]), - 'timestamp' => now(), - 'title' => 'AoSRando Seed', - 'type' => 'rich', - 'url' => $url, - ]); - $message->addEmbed($embed); - } else { - $message->setContent('unknown preset '.$presetName); - } - $interaction->respondWithMessage($message); + $interaction + ->acknowledgeWithResponse() + ->done(function() use($discord, $interaction) { + $presetName = $interaction->data->options['preset']->options['preset']->value; + $message = MessageBuilder::new(); + if (isset(static::$presets[$presetName])) { + $preset = static::$presets[$presetName]; + $seed = AosSeed::generateSurge($presetName, $preset['settings']); + + $embed = new Embed($discord, [ + 'fields' => [ + new Field($discord, [ 'name' => 'Generator', 'value' => 'This seed has been generated with fusecv\'s randomizer on aosrando.surge.sh.' ]), + new Field($discord, [ 'name' => 'Preset', 'value' => $preset['name'], 'inline' => true ]), + new Field($discord, [ 'name' => 'Seed', 'value' => $seed->seed, 'inline' => true ]), + new Field($discord, [ 'name' => 'Logic', 'value' => $preset['settings']['logic'], 'inline' => true ]), + new Field($discord, [ 'name' => 'Area', 'value' => $preset['settings']['area'], 'inline' => true ]), + new Field($discord, [ 'name' => 'Boss', 'value' => $preset['settings']['boss'], 'inline' => true ]), + new Field($discord, [ 'name' => 'Enemy', 'value' => $preset['settings']['enemy'], 'inline' => true ]), + new Field($discord, [ 'name' => 'Permalink', 'value' => $seed->permalink ]), + ], + 'footer' => new Footer($discord, [ + 'text' => 'Grün', + ]), + 'timestamp' => now(), + 'title' => 'AoSRando Seed', + 'type' => 'rich', + 'url' => $seed->permalink, + ]); + $message->addEmbed($embed); + } else { + $message->setContent('unknown preset '.$presetName); + } + $interaction->updateOriginalResponse($message); + }); return true; }); } diff --git a/app/Jobs/GenerateAosSeed.php b/app/Jobs/GenerateAosSeed.php new file mode 100644 index 0000000..b8c7e9e --- /dev/null +++ b/app/Jobs/GenerateAosSeed.php @@ -0,0 +1,80 @@ +seed = $seed; + } + + /** + * Execute the job. + * + * @return void + */ + public function handle() + { + try { + $temp_dir = sys_get_temp_dir(); + + $seed = $this->seed; + $params = array_merge(['seed' => $seed->seed], $seed->settings); + $url = 'https://aosrando.surge.sh/?'.http_build_query($params, '', '&'); + + $fac = new BrowserFactory('chromium'); + $browser = $fac->createBrowser(); + + $page = $browser->createPage(); + $page->setDownloadPath($temp_dir); + $page->navigate($url)->waitForNavigation(); + + $fileInput = $page->dom()->querySelector('input[type=file]'); + $fileInput->sendFile(config('aos.base_rom')); + $page->waitUntilContainsElement('select'); + + $page->mouse()->find('button', 2)->click(); + $page->waitUntilContainsElement('a[download]'); + + $page->dom()->querySelector('a[download]')->setAttributeValue('download', $seed->hash.'.gba'); + $page->mouse()->find('a[download]')->click(); + + sleep(2); + + $encoder = new Encoder(file_get_contents(config('aos.base_rom'))); + $patch = $encoder->createPatch(file_get_contents($temp_dir.'/'.$seed->hash.'.gba')); + Storage::disk('aos-seeds')->put($seed->hash.'.bps', $patch); + unlink($temp_dir.'/'.$seed->hash.'.gba'); + + $seed->status = 'generated'; + $seed->save(); + + $browser->close(); + } catch (\Throwable) { + $seed->status = 'error'; + $seed->save(); + } + } + + protected $seed; + +} diff --git a/app/Models/AosSeed.php b/app/Models/AosSeed.php index d44cfcc..18633b7 100644 --- a/app/Models/AosSeed.php +++ b/app/Models/AosSeed.php @@ -2,13 +2,34 @@ namespace App\Models; +use App\Jobs\GenerateAosSeed; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; +use Illuminate\Support\Str; class AosSeed extends Model { use HasFactory; + public static function generateSurge($preset, $settings, $race = false, $mystery = false) { + $seed = new static(); + $seed->hash = Str::random(16); + $seed->generator = 'surge'; + $seed->preset = $preset; + $seed->race = $race; + $seed->mystery = $mystery; + $seed->seed = strval(random_int(-2147483648, 2147483647)); + $seed->settings = $settings; + $seed->status = 'pending'; + $seed->save(); + GenerateAosSeed::dispatch($seed)->onConnection('database'); + return $seed; + } + + public function getPermalinkAttribute() { + return config('aos.url').'/h/'.rawurlencode($this->hash); + } + protected $casts = [ 'mystery' => 'boolean', 'race' => 'boolean', diff --git a/composer.json b/composer.json index 490fb47..06e6186 100644 --- a/composer.json +++ b/composer.json @@ -7,6 +7,7 @@ "require": { "php": "^8.0.2", "beyondcode/laravel-websockets": "^1.13", + "chrome-php/chrome": "^1.6", "doctrine/dbal": "^3.3", "guzzlehttp/guzzle": "^7.2", "jakyeru/larascord": "^3.0", diff --git a/composer.lock b/composer.lock index 560b190..3c72e90 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "7ae17dd5730b055eb0b260e5b8ee41d5", + "content-hash": "ac83dea6ac9ea66e7899d97abf35b4fb", "packages": [ { "name": "beyondcode/laravel-websockets", @@ -211,6 +211,130 @@ }, "time": "2021-12-14T00:20:41+00:00" }, + { + "name": "chrome-php/chrome", + "version": "v1.6.0", + "source": { + "type": "git", + "url": "https://github.com/chrome-php/chrome.git", + "reference": "e8264cb33a02053caf8877c1566e54f09c60d10c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/chrome-php/chrome/zipball/e8264cb33a02053caf8877c1566e54f09c60d10c", + "reference": "e8264cb33a02053caf8877c1566e54f09c60d10c", + "shasum": "" + }, + "require": { + "chrome-php/wrench": "^1.2", + "evenement/evenement": "^3.0.1", + "monolog/monolog": "^1.26 || ^2.2", + "php": "^7.3 || ^8.0", + "psr/log": "^1.1 || ^2.0 || ^3.0", + "symfony/filesystem": "^4.4 || ^5.0 || ^6.0", + "symfony/polyfill-mbstring": "^1.23", + "symfony/process": "^4.4 || ^5.0 || ^6.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.4.1", + "phpunit/phpunit": "^9.5.10", + "symfony/var-dumper": "^4.4 || ^5.0 || ^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "HeadlessChromium\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Enrico Dias", + "email": "enricodias@gmail.com", + "homepage": "https://github.com/enricodias" + } + ], + "description": "Instrument headless chrome/chromium instances from PHP", + "keywords": [ + "browser", + "chrome", + "chromium", + "crawl", + "headless", + "pdf", + "puppeteer", + "screenshot" + ], + "support": { + "issues": "https://github.com/chrome-php/chrome/issues", + "source": "https://github.com/chrome-php/chrome/tree/v1.6.0" + }, + "time": "2022-03-30T09:50:16+00:00" + }, + { + "name": "chrome-php/wrench", + "version": "v1.2.0", + "source": { + "type": "git", + "url": "https://github.com/chrome-php/wrench.git", + "reference": "e8a34b54df8c9cd4f6d166bdb9df475988e17ce4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/chrome-php/wrench/zipball/e8a34b54df8c9cd4f6d166bdb9df475988e17ce4", + "reference": "e8a34b54df8c9cd4f6d166bdb9df475988e17ce4", + "shasum": "" + }, + "require": { + "ext-sockets": "*", + "php": "^7.3 || ^8.0", + "psr/log": "^1.1 || ^2.0 || ^3.0", + "symfony/polyfill-php80": "^1.22" + }, + "conflict": { + "wrench/wrench": "*" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.4.1", + "phpunit/phpunit": "^9.5.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Wrench\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + } + ], + "description": "A simple PHP WebSocket implementation", + "keywords": [ + "WebSockets", + "hybi", + "websocket" + ], + "support": { + "issues": "https://github.com/chrome-php/wrench/issues", + "source": "https://github.com/chrome-php/wrench/tree/v1.2.0" + }, + "time": "2022-03-30T09:35:45+00:00" + }, { "name": "dflydev/dot-access-data", "version": "v3.0.1", @@ -5486,6 +5610,69 @@ ], "time": "2022-01-02T09:55:41+00:00" }, + { + "name": "symfony/filesystem", + "version": "v6.0.7", + "source": { + "type": "git", + "url": "https://github.com/symfony/filesystem.git", + "reference": "6c9e4c41f2c51dfde3db298594ed9cba55dbf5ff" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/6c9e4c41f2c51dfde3db298594ed9cba55dbf5ff", + "reference": "6c9e4c41f2c51dfde3db298594ed9cba55dbf5ff", + "shasum": "" + }, + "require": { + "php": ">=8.0.2", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.8" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Filesystem\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides basic utilities for the filesystem", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/filesystem/tree/v6.0.7" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-04-01T12:54:51+00:00" + }, { "name": "symfony/finder", "version": "v6.0.8", diff --git a/config/aos.php b/config/aos.php index d093775..7f98a90 100644 --- a/config/aos.php +++ b/config/aos.php @@ -1,5 +1,7 @@ env('AOS_BASE_ROM', ''), 'hostname' => env('AOS_HOSTNAME', 'aos.localhorst.tv'), + 'url' => env('AOS_URL', 'https://aos.localhorst.tv'), ]; diff --git a/database/migrations/2022_05_10_144912_aos_seed_generation.php b/database/migrations/2022_05_10_144912_aos_seed_generation.php new file mode 100644 index 0000000..31debf7 --- /dev/null +++ b/database/migrations/2022_05_10_144912_aos_seed_generation.php @@ -0,0 +1,34 @@ +string('status')->default('pending'); + $table->unique('hash'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('aos_seeds', function(Blueprint $table) { + $table->dropColumn('status'); + $table->dropIndex('aos_seeds_hash_unique'); + }); + } +}; diff --git a/resources/js/components/aos/Seed.js b/resources/js/components/aos/Seed.js index 289e00e..efc1130 100644 --- a/resources/js/components/aos/Seed.js +++ b/resources/js/components/aos/Seed.js @@ -31,7 +31,7 @@ const Seed = ({ patch, seed }) => { {rom ?