PageRenderTime 116ms CodeModel.GetById 24ms RepoModel.GetById 5ms app.codeStats 0ms

/AS3/Zombeez/src/mochi/as3/MochiServices.as

https://github.com/rexstjohn/Scanplay
ActionScript | 676 lines | 520 code | 109 blank | 47 comment | 128 complexity | de898eb6874acac594e9c9468feffe8b MD5 | raw file
  1. /**
  2. * MochiServices
  3. * Connection class for all MochiAds Remote Services
  4. * @author Mochi Media
  5. */
  6. package mochi.as3 {
  7. import flash.geom.Rectangle;
  8. import flash.display.DisplayObject;
  9. import flash.display.DisplayObjectContainer;
  10. import flash.display.Sprite;
  11. import flash.display.MovieClip;
  12. import flash.events.StatusEvent;
  13. import flash.events.TimerEvent;
  14. import flash.system.Security;
  15. import flash.system.Capabilities;
  16. import flash.display.Loader;
  17. import flash.events.Event;
  18. import flash.events.IOErrorEvent;
  19. import flash.net.URLRequest;
  20. import flash.net.URLRequestMethod;
  21. import flash.net.URLVariables;
  22. import flash.net.LocalConnection;
  23. import flash.net.navigateToURL;
  24. import flash.utils.Timer;
  25. import flash.utils.getTimer;
  26. import flash.utils.ByteArray;
  27. import flash.utils.Endian;
  28. import flash.utils.setTimeout;
  29. public class MochiServices {
  30. private static var _id:String;
  31. private static var _container:Object;
  32. private static var _clip:MovieClip;
  33. private static var _loader:Loader;
  34. private static var _timer:Timer;
  35. private static var _preserved:Object;
  36. private static var _servURL:String = "http://www.mochiads.com/static/lib/services/"
  37. private static var _services:String = "services.swf";
  38. private static var _mochiLC:String = "MochiLC.swf";
  39. private static var _swfVersion:String;
  40. private static var _listenChannelName:String = "__ms_";
  41. private static var _sendChannel:LocalConnection;
  42. private static var _sendChannelName:String;
  43. private static var _connecting:Boolean = false;
  44. private static var _connected:Boolean = false;
  45. public static var netup:Boolean = true;
  46. public static var netupAttempted:Boolean = false;
  47. public static var onError:Object;
  48. public static var widget:Boolean = false;
  49. public static var servicesSync:MochiSync = new MochiSync();
  50. private static var _mochiLocalConnection:MovieClip;
  51. private static var _queue:Array;
  52. private static var _nextCallbackID:Number;
  53. private static var _callbacks:Object;
  54. //
  55. public static function get id ():String {
  56. return _id;
  57. }
  58. //
  59. public static function get clip ():Object {
  60. return _container;
  61. }
  62. //
  63. public static function get childClip ():Object {
  64. return _clip;
  65. }
  66. //
  67. //
  68. public static function getVersion():String {
  69. return "3.8 as3";
  70. }
  71. //
  72. //
  73. public static function allowDomains(server:String):String {
  74. if( flash.system.Security.sandboxType != "application" )
  75. {
  76. flash.system.Security.allowDomain("*");
  77. flash.system.Security.allowInsecureDomain("*");
  78. }
  79. if (server.indexOf("http://") != -1) {
  80. var hostname:String = server.split("/")[2].split(":")[0];
  81. if( flash.system.Security.sandboxType != "application" )
  82. {
  83. flash.system.Security.allowDomain(hostname);
  84. flash.system.Security.allowInsecureDomain(hostname);
  85. }
  86. }
  87. return hostname;
  88. }
  89. //
  90. //
  91. public static function isNetworkAvailable():Boolean {
  92. return Security.sandboxType != "localWithFile";
  93. }
  94. //
  95. public static function set comChannelName(val:String):void {
  96. if (val != null) {
  97. if (val.length > 3) {
  98. _sendChannelName = val + "_fromgame";
  99. initComChannels();
  100. }
  101. }
  102. }
  103. //
  104. public static function get connected ():Boolean {
  105. return _connected;
  106. }
  107. public static function warnID(bid:String, leaderboard:Boolean):void {
  108. bid = bid.toLowerCase();
  109. if( bid.length != 16 )
  110. {
  111. trace( "WARNING: " + (leaderboard?"board":"game") + " ID is not the appropriate length" );
  112. return ;
  113. }
  114. else if( bid == "1e113c7239048b3f" )
  115. {
  116. if( leaderboard )
  117. trace( "WARNING: Using testing board ID");
  118. else
  119. trace( "WARNING: Using testing board ID as game ID");
  120. return ;
  121. }
  122. else if( bid == "84993a1de4031cd8" )
  123. {
  124. if( leaderboard )
  125. trace( "WARNING: Using testing game ID as board ID");
  126. else
  127. trace( "WARNING: Using testing game ID");
  128. return ;
  129. }
  130. for( var i:Number = 0; i < bid.length; i++ )
  131. {
  132. switch( bid.charAt(i) )
  133. {
  134. case "0": case "1": case "2": case "3":
  135. case "4": case "5": case "6": case "7":
  136. case "8": case "9": case "a": case "b":
  137. case "c": case "d": case "e": case "f":
  138. continue ;
  139. default:
  140. trace( "WARNING: Board ID contains illegal characters: " + bid );
  141. return ;
  142. }
  143. }
  144. }
  145. /**
  146. * Method: connect
  147. * Connects your game to the MochiServices API
  148. * @param id the MochiAds ID of your game
  149. * @param clip the MovieClip in which to load the API (optional for all but AS3, defaults to _root)
  150. * @param onError a function to call upon connection or IO error
  151. */
  152. public static function connect (id:String, clip:Object, onError:Object = null):void {
  153. warnID( id, false );
  154. if (clip is DisplayObject) {
  155. if( clip.stage == null )
  156. {
  157. trace("MochiServices connect requires the containing clip be attached to the stage");
  158. }
  159. if (!_connected && _clip == null) {
  160. trace("MochiServices Connecting...");
  161. _connecting = true;
  162. init(id, clip);
  163. }
  164. } else {
  165. trace("Error, MochiServices requires a Sprite, Movieclip or instance of the stage.");
  166. }
  167. if (onError != null) {
  168. MochiServices.onError = onError;
  169. } else if (MochiServices.onError == null) {
  170. MochiServices.onError = function (errorCode:String):void { trace(errorCode); }
  171. }
  172. }
  173. public static function disconnect ():void {
  174. if (_connected || _connecting) {
  175. if (_clip != null) {
  176. if (_clip.parent != null) {
  177. if (_clip.parent is Sprite) {
  178. Sprite(_clip.parent).removeChild(_clip);
  179. _clip = null;
  180. }
  181. }
  182. }
  183. _connecting = _connected = false;
  184. flush(true);
  185. try {
  186. _mochiLocalConnection.close();
  187. } catch (error:Error) { }
  188. }
  189. if (_timer != null) {
  190. try {
  191. _timer.stop();
  192. } catch (error:Error) { }
  193. }
  194. }
  195. public static function stayOnTop ():void {
  196. _container.addEventListener(Event.ENTER_FRAME, MochiServices.bringToTop, false, 0, true);
  197. if (_clip != null) { _clip.visible = true; }
  198. }
  199. public static function doClose ():void {
  200. _container.removeEventListener(Event.ENTER_FRAME, MochiServices.bringToTop);
  201. }
  202. public static function bringToTop (e:Event = null):void {
  203. if (MochiServices.clip != null && MochiServices.childClip != null) {
  204. try {
  205. if (MochiServices.clip.numChildren > 1) {
  206. MochiServices.clip.setChildIndex(MochiServices.childClip, MochiServices.clip.numChildren - 1);
  207. }
  208. } catch (errorObject:Error) {
  209. trace("Warning: Depth sort error.");
  210. _container.removeEventListener(Event.ENTER_FRAME, MochiServices.bringToTop);
  211. }
  212. }
  213. }
  214. //
  215. //
  216. private static function init (id:String, clip:Object):void {
  217. _id = id;
  218. if (clip != null) {
  219. _container = clip;
  220. loadCommunicator(id, _container);
  221. }
  222. }
  223. //
  224. //
  225. public static function setContainer (container:Object = null, doAdd:Boolean = true):void {
  226. if( _clip.parent )
  227. _clip.parent.removeChild(_clip);
  228. if (container != null) {
  229. if (container is DisplayObjectContainer) _container = container;
  230. }
  231. if (doAdd) {
  232. if (_container is DisplayObjectContainer) {
  233. DisplayObjectContainer(_container).addChild(_clip);
  234. }
  235. }
  236. }
  237. //
  238. //
  239. private static function loadCommunicator (id:String, clip:Object):MovieClip {
  240. if (_clip != null) {
  241. return _clip;
  242. }
  243. if (!MochiServices.isNetworkAvailable()) {
  244. return null;
  245. }
  246. if (urlOptions(clip).servURL) {
  247. _servURL = urlOptions(clip).servURL;
  248. }
  249. var servicesURL:String = _servURL + _services;
  250. if (urlOptions(clip).servicesURL) {
  251. servicesURL = urlOptions(clip).servicesURL;
  252. }
  253. _listenChannelName += Math.floor((new Date()).time) + "_" + Math.floor(Math.random() * 99999);
  254. MochiServices.allowDomains(servicesURL);
  255. _clip = new MovieClip();
  256. loadLCBridge(_clip);
  257. // load services swf into container
  258. _loader = new Loader();
  259. _loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, loadError);
  260. var req:URLRequest = new URLRequest(servicesURL);
  261. var vars:URLVariables = new URLVariables();
  262. // variables for services.swf
  263. vars.listenLC = _listenChannelName;
  264. vars.mochiad_options = clip.loaderInfo.parameters.mochiad_options;
  265. vars.api_version = getVersion();
  266. if( widget )
  267. vars.widget = true;
  268. req.data = vars;
  269. _loader.load(req);
  270. _clip.addChild(_loader);
  271. // init send channel
  272. _sendChannel = new LocalConnection();
  273. _queue = [];
  274. _nextCallbackID = 0;
  275. _callbacks = {};
  276. _timer = new Timer(10000, 1);
  277. _timer.addEventListener(TimerEvent.TIMER, connectWait);
  278. _timer.start();
  279. return _clip;
  280. }
  281. private static function loadLCBridge(clip:Object):void {
  282. var loader:Loader = new Loader();
  283. var mochiLCURL:String = _servURL + _mochiLC;
  284. var req:URLRequest = new URLRequest(mochiLCURL);
  285. var complete:Function = function(ev:Object):void {
  286. _mochiLocalConnection = MovieClip(loader.content);
  287. listen();
  288. }
  289. loader.contentLoaderInfo.addEventListener(Event.COMPLETE, complete);
  290. loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, loadError);
  291. loader.load(req);
  292. clip.addChild(loader);
  293. }
  294. private static function loadError(ev:Object):void {
  295. _clip._mochiad_ctr_failed = true;
  296. trace("MochiServices could not load.");
  297. MochiServices.disconnect();
  298. MochiServices.onError("IOError");
  299. }
  300. //
  301. //
  302. public static function connectWait (e:TimerEvent):void {
  303. if (!_connected) {
  304. _clip._mochiad_ctr_failed = true;
  305. trace("MochiServices could not load. (timeout)");
  306. MochiServices.disconnect();
  307. MochiServices.onError("IOError");
  308. }
  309. }
  310. //
  311. //
  312. private static function listen ():void {
  313. _mochiLocalConnection.connect(_listenChannelName);
  314. _clip.handshake = function (args:Object):void { MochiServices.comChannelName = args.newChannel; }
  315. trace("Waiting for MochiAds services to connect...");
  316. }
  317. //
  318. //
  319. private static function initComChannels ():void {
  320. if (!_connected) {
  321. trace("[SERVICES_API] connected!");
  322. _connecting = false;
  323. _connected = true;
  324. _mochiLocalConnection.send(_sendChannelName, "onReceive", {methodName: "handshakeDone"});
  325. _mochiLocalConnection.send(_sendChannelName, "onReceive", {methodName: "registerGame", preserved:_preserved, id: _id, version: getVersion(), parentURL: _container.loaderInfo.loaderURL } );
  326. _clip.onReceive = onReceive;
  327. _clip.onEvent = onEvent;
  328. _clip.onError = function ():void { MochiServices.onError("IOError"); };
  329. while(_queue.length > 0) {
  330. _mochiLocalConnection.send(_sendChannelName, "onReceive", _queue.shift());
  331. }
  332. }
  333. }
  334. private static function onReceive(pkg:Object):void {
  335. var cb:String = pkg.callbackID;
  336. var cblst:Object = _callbacks[cb];
  337. if (!cblst) return;
  338. var method:* = cblst.callbackMethod;
  339. var methodName:String = "";
  340. var obj:Object = cblst.callbackObject;
  341. if (obj && typeof(method) == 'string') {
  342. methodName = method;
  343. if (obj[method] != null) {
  344. method = obj[method];
  345. } else {
  346. trace("Error: Method " + method + " does not exist.");
  347. }
  348. }
  349. if (method != undefined) {
  350. try {
  351. method.apply(obj, pkg.args);
  352. } catch (error:Error) {
  353. trace("Error invoking callback method '" + methodName + "': " + error.toString());
  354. }
  355. } else if (obj != null) {
  356. try {
  357. obj(pkg.args);
  358. } catch (error:Error) {
  359. trace("Error invoking method on object: " + error.toString());
  360. }
  361. }
  362. delete _callbacks[cb];
  363. }
  364. private static function onEvent(pkg:Object):void {
  365. var target:String = pkg.target;
  366. var event:String = pkg.event;
  367. switch( target )
  368. {
  369. // MochiEvents tunnel
  370. case "events":
  371. MochiEvents.triggerEvent( pkg.event, pkg.args );
  372. break ;
  373. // MochiSocial tunnel
  374. case "coins":
  375. MochiCoins.triggerEvent( pkg.event, pkg.args );
  376. break ;
  377. // MochiSync tunnel
  378. case "sync":
  379. servicesSync.triggerEvent( pkg.event, pkg.args );
  380. break ;
  381. }
  382. }
  383. public static function updateCopy( args:Object ):void {
  384. MochiServices.send("coins_updateCopy", args, null, null );
  385. }
  386. //
  387. //
  388. private static function flush (error:Boolean):void {
  389. var request:Object;
  390. var callback:Object;
  391. if (_clip && _queue) {
  392. while (_queue.length > 0) {
  393. request = _queue.shift();
  394. callback = null;
  395. if (request != null) {
  396. if (request.callbackID != null) callback = _callbacks[request.callbackID];
  397. delete _callbacks[request.callbackID];
  398. if (error && callback != null) {
  399. handleError(request.args, callback.callbackObject, callback.callbackMethod);
  400. }
  401. }
  402. }
  403. }
  404. }
  405. //
  406. //
  407. private static function handleError (args:Object, callbackObject:Object, callbackMethod:Object):void {
  408. if (args != null) {
  409. if (args.onError != null) {
  410. args.onError.apply(null, ["NotConnected"]);
  411. }
  412. if (args.options != null && args.options.onError != null) {
  413. args.options.onError.apply(null, ["NotConnected"]);
  414. }
  415. }
  416. if (callbackMethod != null) {
  417. args = { };
  418. args.error = true;
  419. args.errorCode = "NotConnected";
  420. if (callbackObject != null && callbackMethod is String) {
  421. try {
  422. callbackObject[callbackMethod](args);
  423. } catch (error:Error) { }
  424. } else if (callbackMethod != null) {
  425. try {
  426. callbackMethod.apply(args);
  427. } catch (error:Error) { }
  428. }
  429. }
  430. }
  431. //
  432. //
  433. public static function send (methodName:String, args:Object = null, callbackObject:Object = null, callbackMethod:Object = null):void {
  434. if (_connected) {
  435. _mochiLocalConnection.send(_sendChannelName, "onReceive", {methodName: methodName, args: args, callbackID: _nextCallbackID});
  436. } else if (_clip == null || !_connecting) {
  437. trace( "Error: MochiServices not connected. Please call MochiServices.connect(). Function: " + methodName);
  438. handleError(args, callbackObject, callbackMethod);
  439. flush(true);
  440. return;
  441. } else {
  442. _queue.push({methodName: methodName, args: args, callbackID: _nextCallbackID});
  443. }
  444. if (_clip != null) {
  445. if (_callbacks != null ) {
  446. _callbacks[_nextCallbackID] = {callbackObject: callbackObject, callbackMethod: callbackMethod};
  447. _nextCallbackID++;
  448. }
  449. }
  450. }
  451. private static function urlOptions(clip:Object):Object {
  452. var opts:Object = {};
  453. var options:String;
  454. if (clip.stage) {
  455. options = clip.stage.loaderInfo.parameters.mochiad_options;
  456. } else {
  457. options = clip.loaderInfo.parameters.mochiad_options;
  458. }
  459. if (options) {
  460. var pairs:Array = options.split("&");
  461. for (var i:Number = 0; i < pairs.length; i++) {
  462. var kv:Array = pairs[i].split("=");
  463. opts[unescape(kv[0])] = unescape(kv[1]);
  464. }
  465. }
  466. return opts;
  467. }
  468. public static function addLinkEvent(url:String, burl:String, btn:DisplayObjectContainer, onClick:Function = null):void {
  469. var vars:Object = new Object();
  470. var avm1Click:DisplayObject;
  471. vars["mav"] = getVersion();
  472. vars["swfv"] = "9";
  473. vars["swfurl"] = btn.loaderInfo.loaderURL;
  474. vars["fv"] = Capabilities.version;
  475. vars["os"] = Capabilities.os;
  476. vars["lang"] = Capabilities.language;
  477. vars["scres"] = (Capabilities.screenResolutionX + "x" + Capabilities.screenResolutionY);
  478. var s:String = "?";
  479. var i:Number = 0;
  480. for (var x:String in vars) {
  481. if (i != 0) s = s + "&";
  482. i++;
  483. s = s + x + "=" + escape(vars[x]);
  484. }
  485. var req:URLRequest = new URLRequest("http://x.mochiads.com/linkping.swf");
  486. var loader:Loader = new Loader();
  487. var setURL:Function = function(url:String):void {
  488. if (avm1Click) {
  489. btn.removeChild(avm1Click);
  490. }
  491. avm1Click = clickMovie(url, onClick );
  492. var rect:Rectangle = btn.getBounds(btn);
  493. btn.addChild(avm1Click);
  494. avm1Click.x = rect.x;
  495. avm1Click.y = rect.y;
  496. avm1Click.scaleX = 0.01 * rect.width;
  497. avm1Click.scaleY = 0.01 * rect.height;
  498. }
  499. var err:Function = function (ev:Object):void {
  500. netup = false;
  501. ev.target.removeEventListener(ev.type, arguments.callee);
  502. setURL(burl);
  503. }
  504. var complete:Function = function(ev:Object):void {
  505. ev.target.removeEventListener(ev.type, arguments.callee);
  506. }
  507. if (netup) {
  508. setURL(url + s);
  509. } else {
  510. setURL(burl);
  511. }
  512. if (! ( netupAttempted || _connected )) {
  513. netupAttempted = true;
  514. loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, err);
  515. loader.contentLoaderInfo.addEventListener(Event.COMPLETE, complete);
  516. loader.load(req);
  517. }
  518. }
  519. private static function clickMovie(url:String, cb:Function):MovieClip {
  520. var avm1_bytecode:Array = [150, 21, 0, 7, 1, 0, 0, 0, 0, 98, 116, 110, 0, 7, 2, 0, 0, 0, 0, 116, 104, 105, 115, 0, 28, 150, 22, 0, 0, 99, 114, 101, 97, 116, 101, 69, 109, 112, 116, 121, 77, 111, 118, 105, 101, 67, 108, 105, 112, 0, 82, 135, 1, 0, 0, 23, 150, 13, 0, 4, 0, 0, 111, 110, 82, 101, 108, 101, 97, 115, 101, 0, 142, 8, 0, 0, 0, 0, 2, 42, 0, 114, 0, 150, 17, 0, 0, 32, 0, 7, 1, 0, 0, 0, 8, 0, 0, 115, 112, 108, 105, 116, 0, 82, 135, 1, 0, 1, 23, 150, 7, 0, 4, 1, 7, 0, 0, 0, 0, 78, 150, 8, 0, 0, 95, 98, 108, 97, 110, 107, 0, 154, 1, 0, 0, 150, 7, 0, 0, 99, 108, 105, 99, 107, 0, 150, 7, 0, 4, 1, 7, 1, 0, 0, 0, 78, 150, 27, 0, 7, 2, 0, 0, 0, 7, 0, 0, 0, 0, 0, 76, 111, 99, 97, 108, 67, 111, 110, 110, 101, 99, 116, 105, 111, 110, 0, 64, 150, 6, 0, 0, 115, 101, 110, 100, 0, 82, 79, 150, 15, 0, 4, 0, 0, 95, 97, 108, 112, 104, 97, 0, 7, 0, 0, 0, 0, 79, 150, 23, 0, 7, 255, 0, 255, 0, 7, 1, 0, 0, 0, 4, 0, 0, 98, 101, 103, 105, 110, 70, 105, 108, 108, 0, 82, 23, 150, 25, 0, 7, 0, 0, 0, 0, 7, 0, 0, 0, 0, 7, 2, 0, 0, 0, 4, 0, 0, 109, 111, 118, 101, 84, 111, 0, 82, 23, 150, 25, 0, 7, 100, 0, 0, 0, 7, 0, 0, 0, 0, 7, 2, 0, 0, 0, 4, 0, 0, 108, 105, 110, 101, 84, 111, 0, 82, 23, 150, 25, 0, 7, 100, 0, 0, 0, 7, 100, 0, 0, 0, 7, 2, 0, 0, 0, 4, 0, 0, 108, 105, 110, 101, 84, 111, 0, 82, 23, 150, 25, 0, 7, 0, 0, 0, 0, 7, 100, 0, 0, 0, 7, 2, 0, 0, 0, 4, 0, 0, 108, 105, 110, 101, 84, 111, 0, 82, 23, 150, 25, 0, 7, 0, 0, 0, 0, 7, 0, 0, 0, 0, 7, 2, 0, 0, 0, 4, 0, 0, 108, 105, 110, 101, 84, 111, 0, 82, 23, 150, 16, 0, 7, 0, 0, 0, 0, 4, 0, 0, 101, 110, 100, 70, 105, 108, 108, 0, 82, 23];
  521. var b:int;
  522. var header:Array = [
  523. 0x68, 0x00, 0x1f, 0x40, 0x00, 0x07, 0xd0, 0x00,
  524. 0x00, 0x0c, 0x01, 0x00, 0x43, 0x02, 0xff, 0xff,
  525. 0xff, 0x3f, 0x03
  526. ];
  527. var footer:Array = [0x00, 0x40, 0x00, 0x00, 0x00];
  528. var mc:MovieClip = new MovieClip();
  529. var lc:LocalConnection = new LocalConnection();
  530. var lc_name:String = "_click_" + Math.floor(Math.random() * 999999) + "_" + Math.floor((new Date()).time);
  531. lc = new LocalConnection();
  532. mc.lc = lc;
  533. mc.click = cb;
  534. lc.client = mc;
  535. lc.connect(lc_name)
  536. var ba:ByteArray = new ByteArray();
  537. var cpool:ByteArray = new ByteArray();
  538. cpool.endian = Endian.LITTLE_ENDIAN;
  539. cpool.writeShort(1);
  540. cpool.writeUTFBytes(url + " " + lc_name);
  541. cpool.writeByte(0);
  542. var actionLength:uint = avm1_bytecode.length + cpool.length + 4;
  543. var fileLength:uint = actionLength + 35;
  544. ba.endian = Endian.LITTLE_ENDIAN;
  545. ba.writeUTFBytes("FWS");
  546. ba.writeByte(8);
  547. ba.writeUnsignedInt(fileLength);
  548. for each (b in header) {
  549. ba.writeByte(b);
  550. }
  551. ba.writeUnsignedInt(actionLength);
  552. ba.writeByte(0x88);
  553. ba.writeShort(cpool.length);
  554. ba.writeBytes(cpool);
  555. for each (b in avm1_bytecode) {
  556. ba.writeByte(b);
  557. }
  558. for each (b in footer) {
  559. ba.writeByte(b);
  560. }
  561. var loader:Loader = new Loader();
  562. loader.loadBytes(ba);
  563. mc.addChild(loader);
  564. return mc;
  565. }
  566. }
  567. }