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'
Всё!
Теперь можно посмотреть, что получилось: