') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); })(); Emscripten: Add Api and remove Asynchify by Ghabry · Pull Request #2862 · EasyRPG/Player · GitHub
Skip to content

Emscripten: Add Api and remove Asynchify - #2862

Merged
5 commits merged into
EasyRPG:masterfrom
Ghabry:emscripten2
Dec 20, 2023
Merged

Emscripten: Add Api and remove Asynchify#2862
5 commits merged into
EasyRPG:masterfrom
Ghabry:emscripten2

Conversation

@Ghabry

@GhabryGhabry commented Nov 21, 2022

Copy link
Copy Markdown
Member

Already wrote this in February but never gave it the final touch... Better for post 0.7.1, removing asynchify can cause problems.

Had to remove Asynchify because it breaks the Api (you cannot call back into the Player while the endless async loop is running). Previously we had bad experiences when the browser does the mainloop timing. I hope this works better by now...

New feature: Save upload and download (fix: #1025).

Screenshot_20221121_231818

New feature: Api under "easyrpgPlayer.api". Currently can do: Reset, Refresh (called after upload to refresh the scene), Upload, Download. Can be used as an extension point if you have a website that wants to access certain functionality of the Player.

Renamed constants from EASYRPG_GAME to game and EASYRPG_FS to saveFs as this is now cleaner to do with a module.
Fix passing of custom game name.
Adding an Interface class for this.
For ensuring that savegames are immediately available scene refresh is now possible.
The refresh will be also useful for other use cases later.
Is required for the Api extensions, otherwise they will crash because a async call is active the entire time.
@GhabryGhabry added this to the 0.7.2 milestone Nov 21, 2022
@ghostghost added Emscripten WebAssembly/JavaScript port for web browsers Awaiting Rebase Pull requests with conflicting files due to former merge Async Web Player Async Loading Enhancement labels Dec 3, 2022
@ghost

ghost commented Dec 3, 2022

Copy link
Copy Markdown

Looking great 👍. There's a good chance for an emscripten PR to include a couple of changes:

Pause/resume option via SDL_WINDOWEVENT_FOCUS_GAINED or whichever supports Emscripten as suggested by catinbag and Carsten:
https://community.easyrpg.org/t/pause-and-resume-on-web-version-of-player/1151/2

OSD button html shell updates by Joke:
https://community.easyrpg.org/t/web-player-on-mobile-more-touch-screen-buttons/1032/17

Module = {
EASYRPG_GAME: "",

// Do not replace Object.assign with "...Module". Breaks the Acorn optimizer

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Acorn optimizer was just fixed :) emscripten-core/emscripten#18461

@johannschopplich

Copy link
Copy Markdown
Contributor

Wow, this PR looks promising. Unfortunately, I'm not able to help technically.
Just am here to cheer and applaud for the work. 🙂

@GhabryGhabry modified the milestones: 0.8.2, 0.8.1Oct 28, 2023
@GhabryGhabry modified the milestones: 0.8.1, 0.8.2Dec 4, 2023
@GhabryGhabry removed the Awaiting Rebase Pull requests with conflicting files due to former merge label Dec 5, 2023
@Ghabry
Ghabry marked this pull request as ready for review December 19, 2023 22:09
@Ghabry

Copy link
Copy Markdown
MemberAuthor

Also added a screenshot API now that offers the screen for download. Will bind it to the screenshot key.

Is suitable for ynonline which currently downloads the canvas for screenshots and this can be black for a brief moment due to how rendering works.

- emscripten_sleep requires asynchify.
- Final fixes for save and load scene.
- New function for taking a screenshot and downloading it.
- Fix unit tests
@Ghabry

Copy link
Copy Markdown
MemberAuthor

okay rebound the Screenshot button to do a download :)

This PR is ready now. Will use the work in this PR to enhance the Fluidsynth and Font settings scene: I want to allow file "upload" so you can have custom (sound)fonts in the browser.

@ghost
ghost merged commit 77d97bb into EasyRPG:masterDec 20, 2023
@johannschopplich

Copy link
Copy Markdown
Contributor

Waited a year for this. Thank you all for your work. Is it Christmas already? 🎄

@Ghabry

Ghabry commented Jan 7, 2024

Copy link
Copy Markdown
MemberAuthor

I have to amend this.

  1. hulje from https://archive.yumeboo.ru/play/ found a regression:

The ?game argument is now always lowercased. When the game is in games/Yume_Nikki the game is not found anymore because the request goes to games/yume_nikki.

  1. papancakes from https://ynoproject.net/ noticed that the canvas steals now all input events on the entire page.

The problem is here that emscripten_set_main_loop grabs all the input (related issue is emscripten-core/emscripten#10542). Before we used Asynchify which didn`t use this funciton.

Solution seems to be:

In sdl2_ui.cpp:

#ifdef EMSCRIPTEN
// Only handle keyboard events when the canvas has focusSDL_SetHint(SDL_HINT_EMSCRIPTEN_KEYBOARD_ELEMENT, "#canvas");
#endif

Changes on the website:

// Launch the Player and configure itwindow.addEventListener('load',(event)=>{createEasyRpgPlayer({game: undefined,saveFs: undefined}).then(function(Module){// Module is readyeasyrpgPlayer=Module;easyrpgPlayer.initApi();canvas.focus();// <-- NEW// Custom code here});});// Make EasyRPG player embeddablecanvas.addEventListener('mouseenter',()=>canvas.focus());// <- CHANGEDcanvas.addEventListener('click',()=>canvas.focus());// <- CHANGED
  1. @Mimigris noticed that it is hard to upload a savegame when the game has 0 because "Load" on the title scene cannot be accessed. Will likely alter this so it can be still opened with SHIFT even if disabled.

@thenick775

thenick775 commented Apr 15, 2024

Copy link
Copy Markdown

Bump, I too am experiencing this regression related to inputs.

All of my text input fields are locked up, and this no longer works to disable:

EMSCRIPTEN_KEEPALIVE void setEventEnable(bool toggle) {
int state = toggle ? SDL_ENABLE : SDL_DISABLE;
SDL_EventState(SDL_TEXTINPUT, state);
SDL_EventState(SDL_KEYDOWN, state);
SDL_EventState(SDL_KEYUP, state);
SDL_EventState(SDL_MOUSEMOTION, state);
SDL_EventState(SDL_MOUSEBUTTONDOWN, state);
SDL_EventState(SDL_MOUSEBUTTONUP, state);
}

@Ghabry
Ghabry deleted the emscripten2 branch April 15, 2024 07:14
@Ghabry

Copy link
Copy Markdown
MemberAuthor

The fix for this is already merged.

When you use a custom shell file do not forget to update it

sevenc-nanashi pushed a commit to sevenc-nanashi/easyrpg-player that referenced this pull request May 31, 2026
Emscripten: Add Api and remove Asynchify
This pull request was closed.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AsyncWeb Player Async LoadingEmscriptenWebAssembly/JavaScript port for web browsersEnhancement

Development

Successfully merging this pull request may close these issues.

Emscripten: provide a way to handle savegame files

3 participants

@Ghabry@johannschopplich@thenick775