Skip to content

Commit

Permalink
Merge branch 'feature/ruffle' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
colin969 committed Oct 14, 2023
2 parents 72a4947 + 6d72a06 commit 894defa
Show file tree
Hide file tree
Showing 13 changed files with 330 additions and 50 deletions.
18 changes: 17 additions & 1 deletion extensions/core-ruffle/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 4 additions & 26 deletions extensions/core-ruffle/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,41 +4,19 @@
"description": "Required for Ruffle playback of Flash games",
"version": "1.0.0",
"main": "./dist/extension.js",
"contributes": {
"contextButtons": [
{
"context": "curation",
"runWithNoCuration": true,
"name": "Clear WinINet Cache",
"command": "core-curation.clear-wininet-cache"
},
{
"context": "curation",
"name": "Migrate to FP Navigator",
"command": "core-curation.fix-requirements"
},
{
"context": "curation",
"name": "Load Data Pack Into Curation",
"command": "core-curation.load-data-pack"
}, {
"context": "curation",
"runWithNoCuration": true,
"name": "Migrate Data Packs",
"command": "core-curation.migrate-data-packs"
}
]
},
"contributes": {},
"scripts": {
"build": "webpack --mode development",
"watch": "webpack --watch --mode development",
"package": "gulp",
"lint": "eslint src --ext ts"
},
"dependencies": {
"arch": "^2.2.0"
"arch": "^2.2.0",
"mustache": "^4.2.0"
},
"devDependencies": {
"@types/mustache": "^4.2.3",
"@types/node": "18.x",
"@typescript-eslint/eslint-plugin": "^5.21.0",
"@typescript-eslint/parser": "^5.21.0",
Expand Down
6 changes: 5 additions & 1 deletion extensions/core-ruffle/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import * as path from 'path';
import * as fs from 'fs';
import { downloadFile, getGithubAsset, getPlatformRegex } from './util';
import { AssetFile } from './types';
import { RuffleStandaloneMiddleware } from './middleware';
import { RuffleStandaloneMiddleware } from './middleware/standalone';
import { RuffleWebEmbedMiddleware } from './middleware/embed';

export async function activate(context: flashpoint.ExtensionContext): Promise<void> {
// const registerSub = (d: flashpoint.Disposable) => { flashpoint.registerDisposable(context.subscriptions, d); };
Expand All @@ -15,6 +16,9 @@ export async function activate(context: flashpoint.ExtensionContext): Promise<vo
const standaloneMiddleware = new RuffleStandaloneMiddleware(path.join(baseDataPath, 'standalone'));
flashpoint.middleware.registerMiddleware(standaloneMiddleware);

const webEmbedMiddleware = new RuffleWebEmbedMiddleware(path.join(baseDataPath, 'webhosted'));
flashpoint.middleware.registerMiddleware(webEmbedMiddleware);

// Check for Standalone updates
const logVoid = () => {};
const standaloneAssetFile = await getGithubAsset(getPlatformRegex(), logVoid);
Expand Down
139 changes: 139 additions & 0 deletions extensions/core-ruffle/src/middleware/embed.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import * as flashpoint from 'flashpoint-launcher';
import { ConfigSchema, Game, GameLaunchInfo, GameMiddlewareConfig, GameMiddlewareDefaultConfig, IGameMiddleware } from 'flashpoint-launcher';
import { Readable } from 'stream';
import { buildBasicTemplate } from '../template/basic';
import * as path from 'path';

// Config Schema used to configure the middleware per game
const schema: ConfigSchema = [
{
type: 'string',
key: 'template',
title: 'Template',
description: 'Template to use when creating embed webpage',
options: ['Automatic', 'Basic'],
default: 'Automatic',
},
{
type: 'string',
key: 'url',
title: 'Webpage URL',
description: 'URL to serve the webpage from',
optional: true,
}
];

// Stored config value map
type RuffleEmbedConfig = {
/** Player Options */
template: 'Automatic' | 'Basic';
url: string;
};

const DEFAULT_CONFIG: Partial<RuffleEmbedConfig> = {
template: 'Automatic'
};

export class RuffleWebEmbedMiddleware implements IGameMiddleware {
id = 'com.ruffle.middleware-embed';
name = 'Ruffle Web Embed';

constructor(
private ruffleWebRoot: string
) {}

isValidVersion(version: string): boolean {
return true;
}

async isValid(game: Game): Promise<boolean> {
if (game.activeDataId && game.activeDataId >= 0) {
const gameData = await flashpoint.gameData.findOne(game.activeDataId);
if (gameData?.launchCommand.endsWith('.swf')) {
return true;
}
}
return false;
}

async execute(gameLaunchInfo: GameLaunchInfo, middlewareConfig: GameMiddlewareConfig): Promise<GameLaunchInfo> {
// Cast our config values to the correct type
const config = {
...DEFAULT_CONFIG,
...middlewareConfig.config
} as Partial<RuffleEmbedConfig>;

const launchArgs = coerceToStringArray(gameLaunchInfo.launchInfo.gameArgs);
const sourceUrl = launchArgs[0];

// Generate a webpage for the given configuration
let data: string | null = null;
const pageUrl = config.url ? config.url : genEmbedUrl(launchArgs[0]);
switch (config.template) {
default: {
// Save generated embed to file
data = buildBasicTemplate(gameLaunchInfo.game, sourceUrl);
break;
}
}

if (!data ) {
throw 'Webpage generated data was empty?';
}

// Save generated webpage
const rs = new Readable();
rs.push(data);
rs.push(null);
await flashpoint.middleware.writeGameFileByUrl(pageUrl, rs);

// Replace launch arg
launchArgs[0] = pageUrl;

// Copy required ruffle script
await flashpoint.middleware.copyGameFilesByUrl('http://ruffle.rs/', path.join(this.ruffleWebRoot, 'latest'));

// Overwrite launch values
gameLaunchInfo.launchInfo.gamePath = path.join(flashpoint.config.flashpointPath, 'FPSoftware\\StartChrome.bat');
gameLaunchInfo.launchInfo.gameArgs = launchArgs;

return gameLaunchInfo;
}

getDefaultConfig(game: Game): GameMiddlewareDefaultConfig {
return {
version: 'latest',
config: this.getConfigSchema('latest'),
};
}

getConfigSchema(version: string): ConfigSchema {
// Only 1 kind of schema for now
return schema;
}

upgradeConfig(version: string, config: any) {
// UNIMPLEMENTED
return config;
}
}

function coerceToStringArray(arr: string[] | string): string[] {
if (Array.isArray(arr)) {
return arr;
} else {
return [arr];
}
}

// Creates an embed at the root of the current domain
function genEmbedUrl(launchUrl: string): string {
const url = new URL(launchUrl);
if (url.pathname === '/embed.html') {
url.pathname = '/embed_backup.html';
} else {
url.pathname = '/embed.html';
}
return url.href;
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { ConfigSchema, Game, GameLaunchInfo, GameMiddlewareConfig, GameMiddlewar
import * as os from 'os';
import * as fs from 'fs';
import * as path from 'path';
import { downloadFile, getGithubReleaseAsset, getPlatformRegex } from './util';
import { downloadFile, getGithubReleaseAsset, getPlatformRegex } from '../util';

// Config Schema used to configure the middleware per game
const schema: ConfigSchema = [
Expand Down Expand Up @@ -154,6 +154,7 @@ type FlashVar = {
key: string;
value: string;
}

export class RuffleStandaloneMiddleware implements IGameMiddleware {
id = 'com.ruffle.middleware-standalone';
name = 'Ruffle Standalone';
Expand Down
11 changes: 11 additions & 0 deletions extensions/core-ruffle/src/template/basic.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import * as flashpoint from 'flashpoint-launcher';
import * as path from 'path';
import * as fs from 'fs';
import * as mustache from 'mustache';

export function buildBasicTemplate(game: flashpoint.Game, sourceUrl: string) {
const templatesRoot = path.join(flashpoint.extensionPath, 'static', 'templates');
const data = fs.readFileSync(path.join(templatesRoot, 'basic.mustache'), 'utf8');
const styleData = fs.readFileSync(path.join(templatesRoot, 'basic.css'), 'utf8');
return mustache.render(data, { title: game.title, sourceUrl, styleData });
}
32 changes: 32 additions & 0 deletions extensions/core-ruffle/static/templates/basic.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
:root {
font-family: Helvetica, Arial, sans-serif;
}

body {
background-color: lightblue;
}
.page-content {
display: flex;
flex-direction: column;
align-items: center;
}
#embed-container {
display: flex;
max-width: 80%;
max-height: 80%;
border: 3px solid black;
border-radius: 2px;
}
.game-title {
font-size: 2rem;
font-weight: bold;
text-align: center;
margin-top: 1rem;
margin-bottom: 1rem;
}
.button-row {
margin-top: 1rem;
display: flex;
flex-direction: row;
justify-content: left;
}
37 changes: 37 additions & 0 deletions extensions/core-ruffle/static/templates/basic.mustache
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<!DOCTYPE html>
<html>
<head>
<title>{{title}}</title>
<style type="text/css">
{{{styleData}}}
</style>
</head>
<body>
<div class="page-content">
<div class="game-title">{{title}}</div>
<div id="embed-container"></div>
<div class="button-row">
<button class="button-basic" onclick="(() => {
window.player.enterFullscreen();
})()">Fullscreen</button>
</div>

<script>
window.RufflePlayer = window.RufflePlayer || {};
window.RufflePlayer.config = {
"allowScriptAccess": true,
"autoplay": "on",
}
window.addEventListener("load", (event) => {
const ruffle = window.RufflePlayer.newest();
const player = ruffle.createPlayer();
const container = document.getElementById("embed-container");
container.appendChild(player);
player.load("{{{sourceUrl}}}");
window.player = player;
});
</script>
<script src="http://ruffle.rs/ruffle.js"></script>
</div>
</body>
</html>
Loading

0 comments on commit 894defa

Please sign in to comment.