Saving flash game state to server after window.onbeforeunload when swf is cross-domain - actionscript-3

My Facebook app is a flash game. I want the game swf to save its latest state to the server when the window unloads. Since I embed the swf with swfobject, I use its embed handler to add a onbeforeunload listener to window:
function embedHandler(event)
{
shell=event.ref;
window.onbeforeunload=function(event)
{
shell.message("save", null);
//delay the unloading a bit so flash has time to contact server
var now = new Date().getTime();
var later=now+50;
while (now < later)
{
now = new Date().getTime();
}
}
}
Here's the problem. This works every time when the swf is loaded directly from the app (a rails app). It never works when the swf is loaded from Amazon.
All the cross-domain issues are worked out between the swf and the app--the rails app accepts calls from Amazon swf, and the Amazon swf loads data from the rails app.
ExternalInterface also works for both outgoing and ingoing calls. But I suspect this is nonetheless a browser security issue, since the inward-going ExternalInterface call only fails when:
it is called from inside the window.onbeforeunload handler
the swf originates from Amazon.
What is the problem? How does one unobtrusively save game state when the game is from a CDN and the save is triggered by onbeforeunload in Javascript? Or is there a better way to accomplish this same thing?
Testing in Firefox.

ExternalInterface also works for both outgoing and ingoing calls. But
I suspect this is nonetheless a browser security issue, since the
inward-going ExternalInterface call only fails when:
it is called from inside the window.onbeforeunload handler
the swf originates from Amazon.
From the sounds of it you worked out all the security issues.
It is more likely a lack of understanding on your part on what is going on behind the scene when onbeforeunload is triggered.
This is a function that will not wait for your "game.swf" to finish the call back via ExternalInterface.This is why you added a stalling mechanism to delay that process. However, I will assume here that this works from the rails app because that is a local server and you are not subject to the lag monster.
Now you might be thinking well I put in a delay it should work. Well that delay is on 50 milliseconds. Try increasing to to 5000(5 seconds) and you should see it start to work on the cdn.
The saving of data should be controlled via the flash app and not triggered by an outside source.
In the game itself you should have milestones that should trigger a save event.
In closing I do want to add that is by far the worst method you could use to save information up to a server. onbeforeunload is unreliable and is subject to cross browser issues let alone putting a lag loop in the JavaScript is just a bad idea and in the end just annoy your users to the point that they won't return.

Related

Chrome (open) Shadow DOM Events Not Reaching Host

I'm running Chrome 56.0.x (corporate mandate), along with Polymer 2. My sample component isn't doing anything fancy; just raising a CustomEvent after making a simple AJAX call. I'm setting "bubbles":true and "composed":true, and I can validate that the event is dispatched and that my host is listening for the event properly.
sample-component.html
raiseDataRetrievedEvent() {
this.dispatchEvent(
new CustomEvent('sample-component-data-retrieved', {
bubbles: true,
composed: true,
detail: { data: "loading complete" }
}));
}
However, the events never make it out of the Shadow DOM to my host page listeners.
index.html
// Listen to Custom event from Sample Component
document.querySelector('sample-component').addEventListener('sample-component-data-retrieved', function (e) {
alert(e.detail);
console.log(e.detail);
});
Interestingly enough, when I have a user initiated event (e.g. click) trigger this CustomEvent, it happily makes its way through the Shadow DOM to my listener. It's just the events that are programmatically created that are getting stuck.
UPDATE 1
This issue only seems to manifest itself when I'm serving my site locally (e.g. http://localhost, http://127.0.0.1, http://COMPUTERNAME). When I publish the site to another host, all the events seem to propagate as expected. Feels to me more like a Chrome issue at this point...
UPDATE 2
I put my code out on github here: https://github.com/davidfilkins/polymer-test.
I did some more testing and the results keep getting weirder... when I'm developing / testing in Chrome, I almost always have Dev Tools open. I noticed strangely enough that when my tools are open, that the event isn't captured by the host page (index.html)... but this seems to only happen locally. When I close tools and load the page locally, the events bubble properly... But this is only for the dispatched events that aren’t tied to an explicit user action; those all seem to work regardless of the tools being open or not.
When I access the simple Azure app that I created - http://samplepolymertwo.azurewebsites.net/index.html - all events are bubbled / captured regardless of whether the tools are open.
No clue if this is fixed in more current versions of Chrome or not.
The culprit was all timing...
In Chrome, with Dev Tools open, running on localhost, the event was dispatched from the component before the event listener was wired up on the host page.
Event Timing
I suppose the ideal scenario would be for the web component to wait until the event listener on the host had been wired up before broadcasting the event.

Why does URLStream sometimes not fire Event.COMPLETE?

I've got an application that is downloading several large binary files and saving them to disk. On some machines it works fine and on some other machines every once in a while a download will proceed to 99.9% complete and the URLStream object will not fire Event.COMPLETE
This is almost identical to the issue that appears here:
Why does URLStream complete event get dispatched when the file is not finished loading?
I've tried using the 'Cache Bust' method described in one of the answers but still no dice.
Any help would be appreciated.
Here is some sample code to help illustrate what I am trying to do:
var contentURL:String = "http://some-large-binary-file-in-amazon-s3.tar";
var stream:URLStream = new URLStream();
stream.addEventListener(Event.COMPLETE, function(e:Event):void{
//This should fire when the file is done downloading
//On some systems this fails to fire once in a while
//On other systems it never fails to fire
});
stream.addEventListener(ProgressEvent.PROGRESS, function(pe:ProgressEvent):void{
//Write the bytes available in the stream and save them to disk
//Note that a download will reach 100% complete in terms of total progress but the 'complete' event might still not fire.
});
var urlRequest:URLRequest = new URLRequest(contentURL);
//Here we might add some headers to the URL Request for resuming a file
//but they don't matter, the 'Event.COMPLETE' will fail to fire with our without
//these headers
addCustomHeaders( urlRequest );
stream.load( urlRequest );
Imo this is a code meant to fail where you purposely give up any control on whatever is going on and just assume that everything would work by itself and go well. I never had any problems whatsoever with the URLStream class but here's basically what I never do:
I never not register all the different error event available (you don't register any).
I never use anonymous listeners. Even though they are supposed to not be GC until the download is complete this is imo an unnecessary unsafe bet especially since it's not rare for the URLStream to idle a little while loading the last bits. I would not be surprised if removing those anonymous listeners would actually fix the problem.

Windows 8 phone save state

I am quite new to windows 8 phone and I don't know all the life cycle methods and when what is called.
My problem is the following: I have a page that loads some data from the disk and when the user exits the program ( or suspends ) the data should be saved. As far as I can tell Page doesn't have an OnSuspending method only someOnNavigatingFrom, but those are not called when you just exit the program. So I read that I should use the OnSuspending in my App.xaml.cs, but this class doesn't have this data and also shouldn't have it, maybe only for OnSuspending. But I don't know how to get the data from my page in the OnSuspending method.
The OnSuspending event is quite fragile and you cannot expect it to run and save the state for a long time. But it depends on how long it would take for you to save. It doesn't even get triggered when you hit the home key while closing the app. If you really want an easy way. Just register a background task. While your app is in the background, the state can be saved and when you open the app again things are in place.
There are certain constraints With Background task as well, you cant do heavy lifting etc...here's a link you could use.
https://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh977056.aspx
Implement an observer pattern (i.e. pub/sub) for your view-models to subscribe to in the event that your app is being suspended.
Your app handles the suspended event. As a result, publish a message for your view-models to respond to within your app's method handler for the suspended event.
You can use an EventAggregator or MessageBus (that I wrote).

Synchronizing with Window Object deletion

I have a plugin which has a content stream pushed to it from an external service which I then draw into a PluginWindowlessWin.
I maintain a reference to the PluginWindowlessWin object so that I can call Invalidate() when new content arrives. However, in certain circumstances (e.g., plugin object removed from the page), the PluginWindowlessWin object is deleted without notifying my plugin. Thus, I end up calling Invalidate() on a bad pointer and crashing.
How can I continue to notify the browser of updates so it will continue to send refresh events - through Invalidate() calls or otherwise - without relying on objects that may be silently deleted?
When using a windowless plugin, you can't draw except when the browser requests it. Sounds like you have that part. You can ask the browser to request a draw by calling InvalidateWindow on the PluginWindowlessWin.
Once AttachedEvent is called on your plugin, PluginWindowlessWin will be available; you can even save the reference if you want. However, you need to release it when DetachedEvent is called.

How to detect the presense of an SWF in the browser cache?

I have an AS3 application that loads various SWFs at runtime. The loading animation that is being used has a fairly long in and out animation that I don't want to show if the target SWF is in the browser cache.
So at the moment each SWF is loaded in as required using Greensock's SWFLoader in a basic manner:
var context:LoaderContext = new LoaderContext();
context.applicationDomain = ApplicationDomain.currentDomain;
loader = new SWFLoader("mySWF.swf", {name:"sectionLoader",context:context,auditSize:true,onOpen:onLoadInit,onProgress:onLoadProgress, onComplete:onCompleteLoadHandler, onError:onLoadErrorHandler});
loader.load();
My goal is to do something before calling loader.load(); to determine if the load operation will require the request to go beyond the browser cache, but before I get into R&Ding something I thought I'd ask if anyone has already done something similar.
A few more thoughts I've had so far:
Just keeping track of what has been loaded in AS3 isn't good enough because if the user clears their cache they might be left loading a large SWF on a slow connection with no indicator.
Might a combination of LoaderItem.httpStatus and LoaderItem.auditSize() be worth investigating?
Is there a better loading framework for AS3 that I should be looking into instead of the Greensock classes?
Ideally I would prefer to also have some kind of version detection to span sessions that could be months apart, but one step at a time.
when you are doing any HTTP request, the responce comes up with HTTPStatus property. In AS3 you just need to chek if
HttpStatusEvent.status == 304
And for httpStatus in greensock library.
Basically 304 code means that no chages has been made on server side to the resource which user has requested. Which eventually leads to conclution that the resource is in the cache.
UPDATE
If this will not fit your needs try storing some variable for should you play the animation or not in Cookies or in Session variables.