It looks like you're new here. If you want to get involved, click one of these buttons!
/* setup.Event(time, [title[, passage[, openFn[, closeFn[, bHidden[, bPopUp[, log]]]]]]]) time: When the event will occur, the only mandatory field. title: Name of event to be displayed on UI. passage: Passage to be displayed if user clicks on the event's title in UI (title will only be a link if passage is not undefined). openFn: Function to be fired immediately after the event is fired. closeFn: Function to be fired after the user closes the pop-up dialog, only works if bPopUp is true and log is not undefined. bHidden: Whether or not the event should be displayed on the UI. bPopUp: Whether or the event's log should pop-up on screen as a SugarCube dialog, only works if log is not undefined. log: Historical log entry to be created after the event is fired. */ setup.Event = function(time, title, passage, openFn, closeFn, bHidden, bPopUp, log) { if (!(time instanceof Date)) { time = new Date(time); } if (openFn instanceof Array) { openFn = eval(openFn[1]); } if (closeFn instanceof Array) { closeFn = eval(closeFn[1]); } if (log instanceof Array) { log = eval(log[1][0]); } this.time = time; this.title = title; this.passage = passage; this.openFn = openFn; this.closeFn = closeFn; this.bHidden = bHidden; this.bPopUp = bPopUp; this.log = log; }; setup.Event.prototype = { toJSON: function () { var logStr, returnFn; if (this.log) { /* log is an instance of setup.EventLog, see below */ logStr = this.log.toJSON(); } returnFn = 'new setup.Event('; returnFn += JSON.stringify(this.time.getTime()) +','; returnFn += JSON.stringify(this.title) +','; returnFn += JSON.stringify(this.passage) +','; returnFn += JSON.stringify(this.openFn) +','; returnFn += JSON.stringify(this.closeFn) +','; returnFn += JSON.stringify(this.bHidden) +','; returnFn += JSON.stringify(this.bPopUp) +','; returnFn += JSON.stringify(logStr) +')'; return JSON.reviveWrapper(returnFn); } };
/* setup.EventLog(time, logSev, logType, logMessage[, learnid[, learnmsg[, read]]]) time: When the event occured. logSev: Log's severity, for filtering purposes. logType: Log's type, for filtering purposes. logMessage: Main body text of the log message. learnid: What $player_knowledge is unlocked the first time the user reads this log. learnmsg: Additional text to display the first time this $player_knowledge is found. read: A boolean to track if the user has read this log. */ setup.EventLog = function(time, logSev, logType, logMessage, learnid, learnmsg, read) { if (!(time instanceof Date)) { time = new Date(time); } this.time = time; this.severity = logSev; this.type = logType; this.message = logMessage; this.learnid = learnid; this.learnmsg = learnmsg; this.read = (read || false); }; setup.EventLog.prototype = { /* Prints the number of days since epoch */ getDays: function () { /* snip */ }, /* Prints the current time (24H). */ getTime: function () { /* snip */ }, /* creates a summary of this log for use in a <jQuery>.wiki() call */ format: function() { /* snip */ }, /* display a SugarCube dialog containing this log's information */ showDialog: function(closeFn) { /* snip */ }, toJSON: function () { var returnFn = 'new setup.EventLog('; returnFn += JSON.stringify(this.time.getTime()) +','; returnFn += JSON.stringify(this.severity) +','; returnFn += JSON.stringify(this.type) +','; returnFn += JSON.stringify(this.message) +','; returnFn += JSON.stringify(this.learnid) +','; returnFn += JSON.stringify(this.learnmsg) +','; returnFn += JSON.stringify(this.read) +')'; return JSON.reviveWrapper(returnFn); } };
setup.cannedEvents = { /* snip */ introCollisionWarning: function() { var time = new Date('1901-04-07T07:20:00Z'); var event = new setup.Event( time, //time 'introCollisionWarning', //title null, //passage setup.timeSystem.clearTimeGoal, //openFn function() { Engine.play("Event Intro Alarm"); }, //closeFn true, //bHidden true //bPopUp ); var log = new setup.EventLog( time, //time 'High', //logSev 'Collision Warning', //logType "Sensor event SE-4562 has now been upgraded to a high severity, anomaly appears to be mass-bearing. Due to possibility of kinetic impact, ship status has been upgraded to high alert status.<br/><br/>''Warning:'' Current trajectory suggests ESSD Cetacea will now encounter anomaly in ''T-1 hour.'' Brace for severe warp turbulence." //logMessage ); setup.eventSystem.addEvent(event, log); }, /* snip */ }
Comments
1. The linked thread is almost three years old, so it's not state of the art anymore.
2. I really do not recommend using individual parameters for this. If you're really married to that, then that's okay. Using a single object parameter, however, would be nearly as easy to use and make the (de)serialization code a tad simpler. What would you rather see in an example, a big list of parameters or an object parameter?
3. You're doing some peculiar—i.e. probably wrong—things in the setup.Event constructor. For example, within the following I'm suspicious of what you're doing for time and log and I have no idea why you're doing what you're doing for openFn and closeFn: Does any of that serve an actual purpose or were you throwing stuff at the wall? I ask because SugarCube serializes and restores Date objects and plain functions, so I'm unsure why you seem to attempting to force the issue with the first three. For log, as long as setup.EventLog is properly setup to be (de)serialized, then what you're doing there is unnecessary as well.
4. You're doing some peculiar—i.e. probably wrong—things in the <setup.Event>.toJSON method. For example, within the following you should not need, or want, to call <setup.EventLog>.toJSON method: The toJSON method is a magic method, which is automatically called by the JSON serializer if it exists. Forcing it is unnecessary.
5. You're passing methods as if they're regular functions in places, which may or may not be okay depending on the method—i.e. static methods may be okay, prototype and instance methods are very likely not. It mostly depends on scoping and use of this. For example, the following is probably okay if the setup.timeSystem.clearTimeGoal method does not use local scope and, if it's an instance or prototype method, does not use this. If does use local scope or this, then you'll need to wrap it within a callback to ensure that it will be invoked properly when restored from serialization. For example: You could very well be on top of this. I simply thought that I should mention it, just in case.
I should probably point out I'm not very experienced with serialisation in general.
Definitely not married to it. I did not encounter the serialisation issue until I accidentally refreshed the page... And then I tried to shoehorn the solution into my existing code.
It was just a matter of laziness, I will switch over to a single object parameter soon.
I'm just as suspicious of what I've done here, and this is exactly what prompted me to raise this thread. The problem I'm having is that when I use JSON.stringify() on Dates and functions, what gets revived is an Array, not an actual Date or function.
For example, with openFn and closeFn, in Event.toJSON, I call:
What comes back after hitting F5 is stuff like:
This is why I use eval(closeFn[1]): The function I'm attempting to revive is being passed to Event's constructor as the second element in an Array during deserialisation.
I can see where I went wrong here. While trying to get to the bottom of why functions were coming back as arrays, I was looking at JSON.stringify() output along these lines:
I incorrectly assumed all of the escaped characters were part of the problem, and tried to work around it with the above. I have removed the forcing portion of the code, and can confirm that deserialisation works without it.
That being said, I still need to call log = eval(log[1][0]); to properly revive the log object, as it still coming back as a nested array: Is this because I'm passing individual parameters? Would all of this work fine if I had been using an object parameter instead?
Thanks, that's helpful. I had noticed that this wasn't working but didn't know why (I was only wrapping functions inside callbacks where I wanted to use pass parameters to the functions being called).
Last but not least, last time I linked you my work in progress, the server hosting my site seemed unreachable from outside Australia. You're welcome to give it another go, on the off-chance they've resolved whatever issue there was last time:
http://www.rokiyo.net/games/cetacea/StoryEngine.html
If you're seeing either the revival array itself—i.e. an array whose first member is something like "(revive:…)"—or its serialized form, then you're doing it wrong. This is likely a consequence of attempting to force things, rather than letting the system handle it. By letting the system function as intended, you should get the proper type back.
I'll try to post a example later today, tomorrow at the outside.
Still unresponsive, unfortunately. I know it's not a general problem with me being able to reach Australia or something like that, as I visit various sites at Monash University from time to time.
Here, try this link: http://philome.la/rokiyo/ceteceawip/play
I'd suggest something like the following: (untested)
Example Usage:
Aaaaaand done!
I've applied each of your suggested changes and can confirm that it's working perfectly, thanks for your help on this.
While I was at it, I also went through and removed the unnecessary step of relying on addEvent to create the association between Event and EventLog (that was an artifact from when I was trying to create circular references between the two, which is what prompted that Bitbucket issue I raised a week ago).