Skip to content

Commit aa31024

Browse files
committed
feat: Add basic Ruffle support
1 parent 348b8ed commit aa31024

File tree

10 files changed

+153
-35
lines changed

10 files changed

+153
-35
lines changed

docs/extensions/overview.md

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -266,14 +266,16 @@ However, Applications can also provide `url` or `command` instead. The full deta
266266
{
267267
"title": "Test Extension",
268268
"properties": {
269-
"title": "Test Select",
270-
"type": "string",
271-
"enum": [
272-
"string1",
273-
"string2"
274-
],
275-
"default": "string1",
276-
"description": "Example of an extension config prop",
269+
"key": {
270+
"title": "Test Select",
271+
"type": "string",
272+
"enum": [
273+
"string1",
274+
"string2"
275+
],
276+
"default": "string1",
277+
"description": "Example of an extension config prop"
278+
}
277279
}
278280
}
279281
]

extensions/core-ruffle/package.json

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,27 @@
44
"description": "Required for Ruffle playback of Flash games",
55
"version": "1.0.0",
66
"main": "./dist/extension.js",
7-
"contributes": {},
7+
"contributes": {
8+
"configuration": [
9+
{
10+
"title": "Ruffle",
11+
"properties": {
12+
"com.ruffle.enabled": {
13+
"title": "Enabled (Supported Games)",
14+
"type": "boolean",
15+
"default": false,
16+
"description": "Enables Ruffle for games that have been marked as properly supported."
17+
},
18+
"com.ruffle.enabled-all": {
19+
"title": "Enabled (Unsupported Games)",
20+
"type": "boolean",
21+
"default": false,
22+
"description": "Enables Ruffle Standalone for all games regardless of whether they have been checked as supported. Results my vary."
23+
}
24+
}
25+
}
26+
]
27+
},
828
"scripts": {
929
"build": "gulp build --color",
1030
"watch": "gulp watch --color",

extensions/core-ruffle/src/extension.ts

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,75 @@ export async function activate(context: flashpoint.ExtensionContext): Promise<vo
1919
const webEmbedMiddleware = new RuffleWebEmbedMiddleware(path.join(baseDataPath, 'webhosted'));
2020
flashpoint.middleware.registerMiddleware(webEmbedMiddleware);
2121

22+
const firstLaunch = !flashpoint.getExtConfigValue('com.ruffle.first-launch-complete');
23+
if (firstLaunch) {
24+
flashpoint.onDidConnect(async () => {
25+
const handle = await flashpoint.dialogs.showMessageBoxWithHandle({
26+
message: 'Do you want to enable Ruffle for supported Flash games?\nRuffle is a modern Flash emulator.\nThis may cause performance issues on weaker machines.',
27+
largeMessage: true,
28+
buttons: ['Yes', 'No'],
29+
cancelId: 1
30+
});
31+
const res = await flashpoint.dialogs.awaitDialog(handle);
32+
if (res.buttonIdx === 0) {
33+
flashpoint.setExtConfigValue('com.ruffle.enabled', true);
34+
}
35+
flashpoint.setExtConfigValue('com.ruffle.first-launch-complete', true);
36+
});
37+
}
38+
39+
flashpoint.games.onWillLaunchGame((launchInfo) => {
40+
const supportedEnabled = flashpoint.getExtConfigValue('com.ruffle.enabled');
41+
const unsupportedEnabled = flashpoint.getExtConfigValue('com.ruffle.enabled-all');
42+
43+
if (supportedEnabled) {
44+
if (launchInfo.game.ruffleSupport === 'Standalone') {
45+
flashpoint.log.info('Using Standalone Ruffle for supported game...');
46+
const defaultConfig = standaloneMiddleware.getDefaultConfig(launchInfo.game);
47+
standaloneMiddleware.execute(launchInfo, {
48+
middlewareId: '',
49+
name: '',
50+
enabled: true,
51+
version: defaultConfig.version,
52+
config: defaultConfig.config,
53+
});
54+
} else if (launchInfo.game.ruffleSupport === 'Webhosted') {
55+
flashpoint.log.info('Using Web Embed Ruffle for supported game...');
56+
const defaultConfig = webEmbedMiddleware.getDefaultConfig(launchInfo.game);
57+
webEmbedMiddleware.execute(launchInfo, {
58+
middlewareId: '',
59+
name: '',
60+
enabled: true,
61+
version: defaultConfig.version,
62+
config: defaultConfig.config,
63+
});
64+
}
65+
} else if (unsupportedEnabled) {
66+
// Get last launch arg to check if swf
67+
let isFlash = false;
68+
if (typeof launchInfo.launchInfo.gameArgs === 'string') {
69+
isFlash = launchInfo.launchInfo.gameArgs.toLowerCase().endsWith('.swf');
70+
} else if (launchInfo.launchInfo.gameArgs.length > 0) {
71+
const gameArg = launchInfo.launchInfo.gameArgs.at(-1);
72+
if (gameArg) {
73+
isFlash = gameArg.toLowerCase().endsWith('.swf');
74+
}
75+
}
76+
77+
if (isFlash) {
78+
flashpoint.log.info('Using Standalone Ruffle for unsupported game...');
79+
const defaultConfig = standaloneMiddleware.getDefaultConfig(launchInfo.game);
80+
standaloneMiddleware.execute(launchInfo, {
81+
middlewareId: '',
82+
name: '',
83+
enabled: true,
84+
version: defaultConfig.version,
85+
config: defaultConfig.config,
86+
});
87+
}
88+
}
89+
});
90+
2291
// Check for Standalone updates
2392
const logVoid = () => {};
2493
const standaloneAssetFile = await getGithubAsset(getPlatformRegex(), logVoid);

package-lock.json

Lines changed: 21 additions & 21 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
"@fortawesome/fontawesome-svg-core": "1.2.36",
3434
"@fortawesome/free-solid-svg-icons": "5.15.4",
3535
"@fortawesome/react-fontawesome": "0.1.18",
36-
"@fparchive/flashpoint-archive": "^0.9.1",
36+
"@fparchive/flashpoint-archive": "0.10.0",
3737
"@reduxjs/toolkit": "^2.2.6",
3838
"@types/node-7z": "2.1.8",
3939
"@types/react-virtualized": "^9.21.21",

src/renderer/components/RightBrowseSidebar.tsx

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ export class RightBrowseSidebar extends React.Component<RightBrowseSidebarProps,
117117
onStatusClick = this.wrapOnTextClick('status');
118118
onVersionClick = this.wrapOnTextClick('version');
119119
onLanguageClick = this.wrapOnTextClick('language');
120+
onRuffleSupportClick = this.wrapOnTextClick('ruffleSupport');
120121

121122
launchCommandRef: React.RefObject<HTMLInputElement> = React.createRef();
122123

@@ -733,6 +734,27 @@ export class RightBrowseSidebar extends React.Component<RightBrowseSidebarProps,
733734
editable={editable}
734735
onClick={this.onLanguageClick} />
735736
</div>
737+
<div className='browse-right-sidebar__row browse-right-sidebar__row--one-line'>
738+
<p>Ruffle Support: </p>
739+
<DropdownInputField
740+
text={game.ruffleSupport}
741+
placeholder={'None'}
742+
className='browse-right-sidebar__searchable'
743+
editable={editable}
744+
items={['None', 'Standalone']}
745+
onItemSelect={text => {
746+
console.log('selecting ' + text);
747+
if (['None', 'Standalone'].includes(text)) {
748+
this.props.onEditGame({ ruffleSupport: text as any })
749+
}
750+
}}
751+
onClick={this.onRuffleSupportClick} />
752+
{ !editable && game.ruffleSupport !== 'None' ? (
753+
<div className='browse-right-sidebar-floating-icon'>
754+
<OpenIcon icon='check'/>
755+
</div>
756+
) : undefined }
757+
</div>
736758
</div>
737759
</>
738760
{/* -- Date Display -- */}

src/renderer/components/app.tsx

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1022,9 +1022,7 @@ export class App extends React.Component<AppProps> {
10221022
if (this.props.currentView.selectedGame) {
10231023
const ng = newGame();
10241024
Object.assign(ng, { ...this.props.currentView.selectedGame, ...game });
1025-
this.props.setMainState({
1026-
currentGame: ng
1027-
});
1025+
this.props.searchActions.updateGame(ng);
10281026
}
10291027
};
10301028

@@ -1720,7 +1718,6 @@ export class App extends React.Component<AppProps> {
17201718
};
17211719

17221720
private checkGameRunningMemo = memoizeOne((gameId: string | undefined, services: IService[]) => {
1723-
console.log('checking if running:' + gameId);
17241721
return gameId ? !!services.find(s => s.id === `game.${gameId}`) : false;
17251722
});
17261723

static/window/styles/core.css

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1607,6 +1607,9 @@ body {
16071607
.browse-right-sidebar__bottom > .browse-right-sidebar__section > .browse-right-sidebar__row__screenshot-container > .browse-right-sidebar__row__screenshot> img {
16081608
height: 100%;
16091609
}
1610+
.browse-right-sidebar-floating-icon {
1611+
margin-left: 0.4rem;
1612+
}
16101613

16111614
/* Browse game stats */
16121615
.browse-right-sidebar__stats {

static/window/styles/fancy.css

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -858,6 +858,9 @@ body {
858858
.browse-right-sidebar__game-config-dropdown-none {
859859
font-style: italic;
860860
}
861+
.browse-right-sidebar-floating-icon .icon__use {
862+
fill: var(--layout__confirm-color);
863+
}
861864

862865
/* GameImageSplit */
863866
.game-image-split {

typings/flashpoint-launcher.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -674,6 +674,8 @@ declare module 'flashpoint-launcher' {
674674
* 2 = Available
675675
*/
676676
archiveState: number;
677+
/** Ruffle support for flash entries */
678+
ruffleSupport: 'None' | 'Standalone' | 'Webhosted';
677679
};
678680

679681
type GameData = {

0 commit comments

Comments
 (0)