mildmojo / twine-gang

Server and client for cross-browser, cross-device Twine game control and synchronization.
MIT License
10 stars 3 forks source link

Update to Twine v2 ? #3

Open bcopy opened 3 years ago

bcopy commented 3 years ago

Hi, I tried to test Twine Gang with a Twine v2 story and it doesn't seem to work. Any hints as to what might be needed to adapt it ?

mildmojo commented 3 years ago

Hi, bcopy.

Thanks for the report! Unfortunately you might've noticed this project hasn't been updated since 2014, which was before Twine v2 was released. Updating this to work with v2 sounds like a fun project! However, I'm not sure I have time (or an immediate need) to do it myself. I've never dived under the hood of Twine v2 to see how it works or what's changed.

What kind of behavior were you looking for, or what kind of game are you making (if you can talk about it)?

bcopy commented 3 years ago

Nothing special, a plain old twine v2 game without any requirements on format. I understand, any clues appreciated on how to adapt it but don't worry if that's too much time.

mildmojo commented 3 years ago

So, googling some Twine 2 examples, there are a few story formats that probably need different code to make this work.

For Sugarcube, based on the docs, it seems like you'd need code that looks roughly like this in your Story Javascript window:

// TwineGang example for Sugarcube in Twine 2
// Air code, untested

// Automatically join a room on the server based on the `room` URL parameter
if (location.search.match(/\?room=/)) {
  var joinRoom = location.search.substr(1).split('room=').pop();
  TwineGang.bind('connect', function() {
    TwineGang.join(joinRoom, function(success) {
      console.log('Joining ' + joinRoom + ': ' + (success ? 'success' : 'failed'));
    });
  });
}

// Event from the server, someone visited a passage, move this story to that passage
TwineGang.bind('arrive', function(passageName) {
  if (passage() !== passageName) {
    Engine.play(passageName)
  }
});

// Local player visited a passage, broadcast the passage name to the server so other clients can sync up
$(document).on(':passagedisplay', function () {
  if (typeof TwineGang !== 'undefined' && TwineGang) {
    TwineGang.arrive(passage());
  }
});

Harlowe seems designed to keep you from accessing it via Javascript. Snowman might look like this:

// TwineGang example for Snowman in Twine 2
// Air code, untested

// Automatically join a room on the server based on the `room` URL parameter
if (location.search.match(/\?room=/)) {
  var joinRoom = location.search.substr(1).split('room=').pop();
  TwineGang.bind('connect', function() {
    TwineGang.join(joinRoom, function(success) {
      console.log('Joining ' + joinRoom + ': ' + (success ? 'success' : 'failed'));
    });
  });
}

// Event from the server, someone visited a passage, move this story to that passage
TwineGang.bind('arrive', function(passageName) {
  if (passage() !== passageName) {
    story.show(passageName)
  }
});

// Local player visited a passage, broadcast the passage name to the server so other clients can sync up
$(document).on('sm.passage.showing', function (e) {
  if (typeof TwineGang !== 'undefined' && TwineGang) {
    TwineGang.arrive(e.passage.name);
  }
});

The gist of it is that you need to run some code when the passage changes to tell the server what passage all the other instances should visit by name. Then you also need to listen for arrive events from the server, which mean that another instance has changed the passage it's looking at, and you need to move your story to that passage.

Each of those examples shows what you'd need to run. This all assumes you've followed the other instructions in the README and you've imported this other Javascript files in your HTML story file.

mildmojo commented 3 years ago

Oh, and you would not want to include the twine_bindings.js file if you were adding one of the examples above to your Story Javascript window. You'd use the examples above instead of the contents of that file.

At least in the case of Sugarcube, a file loaded externally in the HTML wouldn't have access to the engine internals, I think. I'm pretty sure code like this has to go in the Story Javascript window.

bcopy commented 3 years ago

Many thanks :v: made it work for Sugarcube v2 !

Public example running on Glitch https://twine-gang-example.glitch.me and the code : https://glitch.com/edit/#!/twine-gang-example

There's still a small TODO though, marked in the code below, as I can't seem to find how to compare the current passage in the arrive event handler.

Two small adjustments to the example code above :

// Automatically join a room on the server based on the `room` URL parameter
    if (location.search.match(/\?room=/)) {
      var joinRoom = location.search.substr(1).split('room=').pop();
      TwineGang.bind('connect', function() {
        TwineGang.join(joinRoom, function(success) {
          console.log('Joining ' + joinRoom + ': ' + (success ? 'success' : 'failed'));
        });
      });
    }

    // Event from the server, someone visited a passage, move this story to that passage
    TwineGang.bind('arrive', function(passageName) {
        // TODO : Not quite sure how to compare the current passage to the passage name
        //if (passage() !== passageName) {
        SugarCube.Engine.play(passageName)
       // }
    });

    // Local player visited a passage, broadcast the passage name to the server so other clients can sync up
    $(document).on(':passagedisplay', function (e) {
      if (typeof TwineGang !== 'undefined' && TwineGang) {
        TwineGang.arrive(e.passage.title);
      }
    });

Would you be interested in a PR or do you prefer I fork it ?

mildmojo commented 3 years ago

I'm glad you got it working! Thanks for taking this the rest of the way! :rocket:

I'm interested in a PR, but I also think it makes sense to restructure this repo a little now that there would be a version for Twine v1, Twine v2 Sugarcube, and potentially other story formats. I'll move things around a bit this evening and try to make it super clear how to integrate the client with different versions of Twine, and make it clear where your PR would live.