iddqd или Violence As A Service
Иногда разработчикам хочется сделать что-то просто так. Вот о таком небольшом "просто так" данная статья, а если точнее, то о запуске DOSBox в браузере.
Немного предыстории
Если немного поискать то можно найти несколько статей о том как запустить DOSBox в браузере. Но всё это будут не наши статьи, а наша - лучше!
Наша команда делала небольшое приложение для внутреннего использования - для помощи нашим сейлзам и поддержке. И, поскольку, проект внутренний решили сделать "пасхалку", но так, чтоб еще немного потренироваться :) Короче, теперь по супер-секретной горячей кнопке мы можем запустить Doom и пройти его - батарейки и сохранения включены!
Теперь немного истории
Я, будучи лютым олдфагом старых игр, часто использую DOSBox для того, чтоб поностальгировать или даже поиграть со своими детьми (например, в Master of Orion 2), и когда на глаза попалась статья о запуске этого чудо-агрегата прямо в браузере, предложил товарищу затащить его к себе. В качестве игры выбрали культовый Doom (и не какой-то этот ваш, а настоящий! олдфаговский!). Сказано - сделано.
Реализация
Сначала надо выбрать реализацию Dosbox под JS и в нашем случае это будет caiiiycuk/js-dos:
DOSBox is an open source DOS emulator designed for running old games. Emscripten compiles C/C++ code to JavaScript. This is a version of DOSBox which can be compiled with Emscripten to run in a web browser. It allows running old DOS games and other DOS programs in a web browser.
Это JS-библиотека, которая содержит в себе всё что надо для запуска DOSBox и сильно упрощает этот процесс.
- работающее Rails-приложение (только Rails, только Ruby!);
- подключить JS-библиотеку;
- сделать Stimulus-контроллер для оживления процесса;
- сделать вёрстку (в нашем случае модалку);
- запустить, пройти и
померитьсяподелиться рейтингом!
Подключаем JS-библиотеки:
diff --git a/package.json b/package.json --- a/package.json +++ b/package.json @@ ... @@ "bootstrap-icons": "^1.10.5", "esbuild": "^0.19.2", + "hotkeys-js": "^3.12.0", + "js-dos": "^7.5.0", + "url": "^0.11.2" @@ ... @@
Тут есть небольшой нюанс: js-dos при установке подтягивает WASM досбокса, но "делает это без уважения" - поэтому мы просто руками скопировали в /public
файлы wdosbox.js
, wdosbox.js.symbols
и wdosbox.wasm
.
Stimulus и оживление вёрстки
Теперь самое большое - сделать Stimulus-контроллер для вызова модалки и обработки горячей кнопки.
#app/javascript/controllers/dos_games_controller.js import { Controller } from "@hotwired/stimulus" // кривой импорт import "js-dos" import hotkeys from 'hotkeys-js'; import * as bootstrap from "bootstrap" export default class extends Controller { static targets = ['dosContainer', 'closeButton']; connect() { this.modal = new bootstrap.Modal(this.element) this.element.addEventListener('shown.bs.modal', () => this.startPlayer()) this.element.addEventListener('hide.bs.modal', () => this.stopPlayer()) this.closeButtonTarget.addEventListener('click', () => this.modal.hide()) hotkeys('ctrl+i+q', ()=>{ this.modal.show(); }); hotkeys('ctrl+q', () => { this.modal.hide(); }) } startPlayer() { this.player ||= Dos(this.dosContainerTarget, { withNetworkingApi: false, noSocialLinks: true, clickToStart: true }) this.player.run(this.gameLink); } stopPlayer() { if (!this.player) { return; } this.player.layers.save(); this.player.stop(); } get gameLink() { // return "/Wonderfield.jsdos"; return "https://cdn.dos.zone/custom/dos/doom.jsdos"; // return "https://cdn.dos.zone/custom/dos/homm_2.jsdos"; } }
Тут можно запускать не только Doom, но и не менее православные HoMM2 и другие любимые игры детства или даже сделать селектор с выпадашкой!
Собрать свои бандлы с играми можно тут.
HTML и модалочка
Делаем вёрстку модалочки (мы используем bootstrap и очень его любим) и подключаем к ней dos-games
контроллер:
diff --git a/app/views/layouts/application.html.slim b/app/views/layouts/application.html.slim index 21dac7e..750a63e 100644 --- a/app/views/layouts/application.html.slim +++ b/app/views/layouts/application.html.slim @@ ... @@ = javascript_include_tag 'application', 'data-turbo-track': 'reload' body.p-0.bg-light + .modal.fade data-controller="dos-games" + .modal-dialog style="min-width: 50%;" + .modal-content + .modal-header + h5 = 'GAAAME' + button.btn-close.modal-close data-dos-games-target="closeButton" + .modal-body style="min-height: 600px;" + div data-dos-games-target='dosContainer' style="width: 100%; height: 600px;" #mainapp.d-flex div.d-none data-controller="toastr" = flash_to_toastr(flash).to_json =render 'layouts/sidebar'
Всё!
Теперь можно посмотреть, что получилось: