packager icon indicating copy to clipboard operation
packager copied to clipboard

Steamworks.js (Steam support)

Open Alestore opened this issue 2 years ago • 15 comments

I know it won't be requested by almost anyone, except a few people in the TurboWarp community who want to bring their game to Steam like me.

I searched the web for how to implement the Steamworks API to access numerous Steam features such as the Steam overlay, in-app purchases, achievements and more.

I initially found Greenworks, but it was no good as it is too outdated and has not been updated anymore. In addition, a combination of versions was needed between the .node file prepared by them, the Electron version and much more.

After some more careful research, I found Steamworks.js, a modern implementation of the Steamworks SDK for HTML / JS based applications.

I thought about using this one, as finally everything seemed to be working.

Unfortunately I did some tests trying to follow the instructions given by them on the GitHub repository and from an article site I discovered Steamworks.js from. I'll leave the sources here.

https://www.liana.one/integrate-electron-steam-api-steamworks https://github.com/ceifa/steamworks.js

I am not very used to written coding, I have tried to do what it says but I have not been able to understand much. I managed to install Steamworks.js on the PC with npm install, but I can't continue from there. On the other hand, it is also the first time that I use npm lol.

If someone could give me a hand even just to read and help me understand better what to do, I would be grateful. :)

Alestore avatar Aug 14 '22 17:08 Alestore

this looks a lot more doable than greenworks

let me see

GarboMuffin avatar Aug 15 '22 02:08 GarboMuffin

You need to use Windows 64-bit which you are probably already using. 32-bit will not work.

Extract the app. You're going to be doing a bit of surgery.

Open resources/app/electron-main.js in your text editor. You need to disable the security sandbox (this also might let you do some other cool things). Find this:

    webPreferences: {
      sandbox: true,
      contextIsolation: true,
      nodeIntegration: false,
    },

and replace it with

    webPreferences: {
      sandbox: false,
      contextIsolation: false,
      nodeIntegration: true,
    },

and add this to the end of that file:

try {
  require('steamworks.js').electronEnableSteamOverlay()
} catch (e) {
  console.error(e);
}

This will enable the Steam Overlay.

Later on you're probably going to want to have access to the developer tools, so find this:

  const window = new BrowserWindow(options);

and add this after:

  window.webContents.toggleDevTools();

but remember to remove that before you ship the final game.

Now open a terminal and navigate to resources/app/ and run:

npm install steamworks.js

You might get some warnings about package.json missing things like license or description or website. Those can be ignored.

Now open resources/app/index.html in your text editor. Add this HTML somewhere after <body>:

<script>
  var steamworks = require('steamworks.js');
  var client = steamworks.init(1); // REPLACE WITH YOUR APP ID
</script>

Run your app, look for errors in the developer tools. Make sure Steam is running.

You can use the developer tools to see what cool things you can now access on client. and use those in your project. Consult steamworks.js documentation for further steps. If the most advanced you want to go is rewarding achievements then I would guess using the eval cloud variable on some pre-defined strings may be the best way.

Please be careful using eval though, especially since you've disabled the security sandbox, if a malicious actor is able to somehow specify some arbitrary JavaScript in there, they have full control over the system and can install any malware they want. As long as you only use pre-defined strings, you should be okay

If steam isn't running then client will just be undefined. You may want to handle that, or just let the eval block log an error.

that's about as much help as you're getting from me, good luck

if your game happens to make any amount of money, consider sending a few bucks to us, to Scratch, to Steamworks.js...

GarboMuffin avatar Aug 15 '22 06:08 GarboMuffin

On Linux, resources/app is the same as on Windows

On macOS, resources/app is probably ctrl+click on the app > show package contents (the app is just a folder; you need to open it) > Contents > Resources > app

GarboMuffin avatar Aug 15 '22 06:08 GarboMuffin

Thanks a lot, really. I'm about to get out of bed and I'll do everything right away and let you know. The only thing I wonder is: will I have to do this every single time I make a new version of the game or will I be able to somehow save some files to reuse? I remember always saving electron-main.js as it had extra settings and writing them every time would have been impossible (open link in current Electron window, for example).

Alestore avatar Aug 15 '22 06:08 Alestore

Ok I did everything: it works!

The only problem is this script:

<script>
  // trick the steam overlay into fully redrawing every frame
  (function() {
    const canvas = document.createElement('canvas');
    canvas.width = 1;
    canvas.height = 1;
    const ctx = canvas.getContext('2d');
    const loop = () => {
      requestAnimationFrame(loop);
      ctx.fillStyle = 'rgba(0, 0, 0, 0)';
      ctx.fillRect(0, 0, canvas.width, canvas.height);
    };
    loop();
    canvas.style.position = 'absolute';
    canvas.style.top = '0';
    canvas.style.left = '0';
    canvas.style.width = '100%';
    canvas.style.height = '100%';
    canvas.style.zIndex = '100';
    canvas.style.pointerEvents = 'none';
    document.body.appendChild(canvas);
  })();
</script>

I inserted it after <body> in index.html and doing numerous tests, it seemed to me that this script "blocked" what came next. I put it at the beginning, and the background image was not loading. Then I tried to move it after loading background image to base64 and now it was loading, but some scripts like hidden mouse pointer were not loading. I moved it before the loading bar (color, etc.) and instead of being white, the bar stayed black. Then I moved it again towards the end of the document and (from what I saw) the project didn't load and stayed like this:

image

I don't know if this is a graphic bug of the loading bar or if the project was not actually loading, but completely removing that script from the file everything was fine. The only flaw was the graphic bugs of the Steam Overlay. How can I add this script without losing these functions?

Alestore avatar Aug 15 '22 08:08 Alestore

share some more of the surrounding code because you're probably putting it in the wrong spot

you also have two copies of it in the code snippet you pasted, which is not what you're supposed to have

GarboMuffin avatar Aug 15 '22 18:08 GarboMuffin

I eliminated the duplicate, sorry. Now it seems to work just fine. Thanks!

Alestore avatar Aug 15 '22 19:08 Alestore

@GarboMuffin Now that the Steam Overlay is working, I would like to try adding Achievements. I believe this is possible thanks to the eval cloud variable in TurboWarp and adding a few lines of code somewhere, but I don't know how I can do it in practice, and maybe it can be even more complex than I think but ... could someone just help me try to figure out how to do it?

Alestore avatar Nov 03 '22 20:11 Alestore

I've updated my previous comment https://github.com/TurboWarp/packager/issues/503#issuecomment-1214667166 to reflect some steamworks.js updates -- some things are a bit simpler now. You can look at GitHub's comment edit history to see what changed. You'll probably have to redo the npm install steamworks.js step.

I assume that you've already figured out how to add achievements in Steam's developer interface. I wouldn't know anything about that. Going by the steamworks.js documentation, it looks like client.achievement.activate('ACHIEVEMENT') is all the JS you need if you have steamworks setup as client. I assume ACHIEVEMENT is some ID that you configure in Steam's developer interface.

GarboMuffin avatar Nov 07 '22 07:11 GarboMuffin

It would be very interesting to see if a steamworks unsandboxed extension would be possible. It requires quite a bit of surgery all over app to work properly however, so probably not soon

GarboMuffin avatar Nov 07 '22 07:11 GarboMuffin

I've updated my previous comment https://github.com/TurboWarp/packager/issues/503#issuecomment-1214667166 to reflect some steamworks.js updates -- some things are a bit simpler now. You can look at GitHub's comment edit history to see what changed. You'll probably have to redo the npm install steamworks.js step.

I assume that you've already figured out how to add achievements in Steam's developer interface. I wouldn't know anything about that. Going by the steamworks.js documentation, it looks like client.achievement.activate('ACHIEVEMENT') is all the JS you need if you have steamworks setup as client. I assume ACHIEVEMENT is some ID that you configure in Steam's developer interface.

Yes, ACHIEVEMENT is an ID to replace that, and I know how to create it from the developer interface.

When I consulted the Steamworks documentation for the achievements issue, I didn't understand much about it and even thought it was necessary to identify the Steam account that is trying to activate the achievement and so on, but if it is really that simple, I'll test and let you know today!

As for the comment you edited, I noticed that you removed the HTML script needed to constantly update the screen and thus avoid any graphic bugs coming from the Steam overlay?

Alestore avatar Nov 07 '22 08:11 Alestore

@GarboMuffin I'm sorry but the new code you provided for the Steamworks.js implementation does not work. I used the old model from the comment and it worked, I also tried the achievements and they work perfectly!

Alestore avatar Nov 07 '22 16:11 Alestore

@GarboMuffin I'm afraid the edited comment with the new method doesn't work. I'll use the old one instead.

Alestore avatar Dec 21 '22 18:12 Alestore

It's still hard for me

DDDD100 avatar Sep 27 '23 19:09 DDDD100

It's still hard for me

Please add me on Discord, at "alebello18" and I will help you in call if you need to.

Alestore avatar Sep 27 '23 19:09 Alestore