Skip to content

Conversation

evilpie
Copy link
Collaborator

@evilpie evilpie commented Jul 25, 2025

This is a new optional feature, which allows SWFs running inside Ruffle to use (a currently very limited) subset of the Steamworks API. To make this API easily usable from both AS3 and AS2, I decided to implement this as a "fake" ExternalInterface. The current API is heavily inspired by steamworks.js.

The biggest missing piece is of course callback support. I have no idea which APIs to prioritize.

After compiling ruffle with cargo build --features steamworks you can use the API like this:

package {
    import flash.display.Sprite;
    public class Test extends Sprite {
        function Test() {
            var client: Client = new Client(480)

            trace("appId: " + client.utils.getAppId());

            trace("name: " + client.localPlayer.getName());
            trace("level: " + client.localPlayer.getLevel());
            trace("getIpCountry: " + client.localPlayer.getIpCountry());

            // client.achievement.activate("ACH_WIN_ONE_GAME");
            trace("isActived('ACH_WIN_ONE_GAME'): " + client.achievement.isActivated('ACH_WIN_ONE_GAME'));
        }
    }
}


import flash.external.ExternalInterface;

class Client {
    function Client(appid: *) {
        var error: * = appid ? call("client.init", appid)
                             : call("client.init");
        if (error) {
            throw new Error(error);
        }
    }

    private var _utils: Utils;
    public function get utils(): Utils {
        if (!_utils) {
            _utils = new Utils(this);
        }
        return _utils;
    }


    private var _localPlayer: LocalPlayer;
    public function get localPlayer(): LocalPlayer {
        if (!_localPlayer) {
            _localPlayer = new LocalPlayer(this);
        }
        return _localPlayer;
    }

    private var _achievement: Achievement;
    public function get achievement(): Achievement {
        if (!_achievement) {
            _achievement = new Achievement(this);
        }
        return _achievement;
    }

    public function call(name: String, ...args: *): * {
        return ExternalInterface.call.apply(null, ["steamworks." + name].concat(args));
    }
}

class Utils {
    private var _client: Client;
    public function Utils(client: Client) {
        _client = client;
    }

    public function getAppId(): uint {
        return _client.call("utils.getAppId");
    }
    public function isSteamRunningOnSteamDeck(): Boolean {
        return _client.call("utils.isSteamRunningOnSteamDeck");
    }
}

class LocalPlayer {
    private var _client: Client;
    public function LocalPlayer(client: Client) {
        _client = client;
    }

    public function getSteamId(): String {
        return _client.call("localplayer.getSteamId");
    }
    public function getName(): String {
        return _client.call("localplayer.getName");
    }
    public function getLevel(): uint {
        return _client.call("localplayer.getLevel");
    }
    public function getIpCountry(): String {
        return _client.call("localplayer.getIpCountry");
    }
}

class Achievement {
    private var _client: Client;
    public function Achievement(client: Client) {
        _client = client;
    }

    public function activate(name: String): Boolean {
        return _client.call("achievement.activate", name);
    }
    public function isActivated(name: String): Boolean {
        return _client.call("achievement.isActivated", name);
    }
}

@evilpie evilpie added T-feature Type: New Feature (that Flash doesn't have) A-desktop Area: Desktop Application labels Jul 25, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-desktop Area: Desktop Application newsworthy T-feature Type: New Feature (that Flash doesn't have)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants