rc light client
please don't use this until it's done.
(it's never going to be done...)
memo: now uses native JSON
// please don't use this until it's done.
package {
import flash.desktop.*;
import flash.display.*;
import flash.events.*;
import flash.external.*;
import flash.net.*;
import flash.system.*;
import flash.utils.*;
[SWF(width=1, height=1)]
public class FlashTest extends Sprite {
private function log(message:*):void {
ExternalInterface.call('console.log', message);
}
private function error(e:*):void {
ExternalInterface.call('console.error', String(e));
}
private function handleError(e:UncaughtErrorEvent):void {
error(e.error);
}
private function makeLoad(loader:IEventDispatcher, name:String):void {
ExternalInterface.call('updateLoad', name, 0, 0);
loader.addEventListener(ProgressEvent.PROGRESS, function (e:ProgressEvent):void {
ExternalInterface.call('updateLoad', name, e.bytesLoaded, e.bytesTotal);
});
}
private function completeLoad(name:String, size:Number):void {
ExternalInterface.call('updateLoad', name, size, size);
}
public function FlashTest() {
loaderInfo.uncaughtErrorEvents.addEventListener(UncaughtErrorEvent.UNCAUGHT_ERROR, handleError);
Security.allowDomain('*');
try { ExternalInterface.addCallback('appComplete', appComplete); }
catch (e:Error) { return; }
ExternalInterface.call('movieComplete');
}
private function appComplete(data:String):void {
data = decodeURIComponent(data);
completeLoad('app', data.length);
var uid:String = /"user":"(\d+)"/.exec(data)[1];
ExternalInterface.call('setUid', uid);
var match:Object = /<form action="(https:\/\/cooking\.game\.playfish\.com\/.*?)"/.exec(data);
var resource:String = match[1].replace(/&/g, '&').replace('https', 'http');
var end:int = data.indexOf('</form', match.index);
var hidden:RegExp = /<input type="hidden" autocomplete="off" name="(.+?)" value="(.+?)" \/>/g;
hidden.lastIndex = match.index;
var body:URLVariables = new URLVariables();
while (match = hidden.exec(data)) {
if (match.index > end) break;
body[match[1]] = match[2];
}
var request:URLRequest = new URLRequest(resource);
request.data = body;
request.method = URLRequestMethod.POST;
var iframeLoader:URLLoader = new URLLoader(request);
makeLoad(iframeLoader, 'iframe');
iframeLoader.addEventListener(Event.COMPLETE, iframeComplete);
}
private var databases:Object = {
'ingredient': null,
'recipe': null,
'avatar': null,
'front': null,
'restaurant': null,
'perk': null
};
private var tokenMap:Object = {};
private var remaining:int = 3;
private var base:String;
private var si_url:String;
private var si_session_id:String;
private var si_profile_base:String;
private var si_purchase_base:String;
private function iframeComplete(e:Event):void {
completeLoad('iframe', e.target.bytesTotal);
var data:String = e.target.data;
var config:Object = JSON.parse(/PF\.Config\.createParameters\('config', ({.*})\);/.exec(data)[1]);
var extra:Object = JSON.parse(/PF\.Config\.createParameters\('extra', ({.*})\);/.exec(data)[1]);
var key:String;
base = extra.resource_subdir;
si_url = extra.rpc_url;
si_session_id = extra.rpc_session_id;
si_profile_base = config.game_profile_base;
si_purchase_base = extra.purchase_base;
for (key in databases) {
remaining++;
loadResource(key, readDatabase);
}
var gameLoader:Loader = new Loader();
makeLoad(gameLoader.contentLoaderInfo, 'game');
gameLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, gameComplete);
gameLoader.load(new URLRequest(extra.swf_game_url),
new LoaderContext(false, ApplicationDomain.currentDomain, SecurityDomain.currentDomain));
}
private function allFinished():void {
if (--remaining) return;
ExternalInterface.addCallback('addOfflineMoney', addOfflineMoney);
ExternalInterface.addCallback('hire', hire);
ExternalInterface.addCallback('sendMail', sendMail);
ExternalInterface.addCallback('acceptFeedGiftMail', acceptFeedGiftMail);
ExternalInterface.addCallback('fromInventoryToGame', fromInventoryToGame);
ExternalInterface.addCallback('fromGameToInventory', fromGameToInventory);
ExternalInterface.addCallback('sellPurchaseOwnedItem', sellPurchaseOwnedItem);
ExternalInterface.addCallback('getUserInfo', getUserInfo);
ExternalInterface.addCallback('consumeItem', consumeItem);
ExternalInterface.addCallback('consumeIngredients', consumeIngredients);
ExternalInterface.addCallback('autoGift', autoGift);
ExternalInterface.call('allFinished');
}
private function loadResource(resource:String, reader:Function):void {
var resourceLoader:URLLoader = new URLLoader(new URLRequest(base + resource + '.bin'));
resourceLoader.dataFormat = URLLoaderDataFormat.BINARY;
makeLoad(resourceLoader, resource);
resourceLoader.addEventListener(Event.COMPLETE, function (e:Event):void {
var data:ByteArray = e.target.data;
completeLoad(resource, data.length);
data.uncompress();
reader(resource, new XML(data.toString()));
allFinished();
});
}
private function readDatabase(key:String, database:XML):void {
databases[key] = database;
var names:Array = [];
var ids:Array = [];
for each (var item:XML in database..item) {
names.push(item.@name.toString());
ids.push(item.@id.toString());
tokenMap[item.@id] = item.@hash.toString();
}
ExternalInterface.call('setDatabase', key, names, ids);
}
private var CPGC:Object = null;
private var CPGCR:Object = null;
private var CPRC:Object = null;
private var CPRS:Object = null;
private var GameWorld:Object;
private var RpcClient:Object;
private var RpcRequestManager:Object;
private var RpcEvent:Object;
private var AuditChange:Object;
private var AuditChangeAction:Object;
private var NetworkUid:Object;
private function gameComplete(e:Event):void {
CPGC = new DLL('com.playfish.games.cooking::');
CPGCR = new DLL('com.playfish.games.cooking.rpc::');
CPRC = new DLL('com.playfish.rpc.cooking::');
CPRS = new DLL('com.playfish.rpc.share::');
GameWorld = CPGC.GameWorld;
RpcClient = CPRC.RpcClient;
RpcRequestManager = CPGCR.RpcRequestManager;
RpcEvent = CPGCR.RpcEvent;
NetworkUid = CPRS.NetworkUid;
AuditChange = CPRC.AuditChange;
AuditChangeAction = CPRC.AuditChangeAction;
GameWorld.rpcClient = new RpcClient(new CPRS.ServerInfo(si_url, si_session_id, si_profile_base, si_purchase_base));
var rm:Object = new RpcRequestManager(RpcClient.BATCHMODE_INORDER);
rm.addEventListener(RpcEvent.SUCCESS, rpcInitSuccess);
rm.addEventListener(RpcEvent.FAIL, rpcInitFail);
rm.init();
rm.commit();
allFinished();
}
private function makeRpcLoad(name:String):void {
completeLoad(name, 1024);
}
private var getUserProfileRpc:Object;
private function rpcInitSuccess(e:Event):void {
makeRpcLoad('init');
var rm:Object = new RpcRequestManager(RpcClient.BATCHMODE_CONDITIONAL);
rm.addEventListener(RpcEvent.SUCCESS, onRpcsSuccess);
rm.addEventListener(RpcEvent.FAIL, onRpcsFail);
getUserProfileRpc = rm.getUserProfile();
rm.commit();
allFinished();
}
private function rpcInitFail(e:Event):void {
throw 'could not initialize rpc';
}
private function onRpcsSuccess(e:Event):void {
makeRpcLoad('rpcs');
var userInfo:Object = getUserProfileRpc.userInfo;
var shift:Object = userInfo.shift;
var timestamp:Number = 0;
if (shift.shiftId) {
var group:XMLList = databases['perk'].group.(@name == 'Shift');
var item:XMLList = group.item.(@id == shift.shiftId);
timestamp = shift.startTime + 60000 * parseInt(item.@workTime.toString(), 10);
}
ExternalInterface.call('setStatus', userInfo.restaurantName, timestamp);
allFinished();
}
private function onRpcsFail(e:Event):void {
throw 'onRpcsFail, lol';
}
private var saveVersion:int = 1;
private function savePlayerProfile(auditChanges:Array):void {
log('saving profile version ' + saveVersion);
var auditChangeBatch:Object = new CPRC.AuditChangeBatch();
auditChangeBatch.auditChanges = auditChanges;
auditChangeBatch.saveVersion = saveVersion++;
GameWorld.rpcClient.savePlayerProfile(getUserProfileRpc.userInfo, auditChangeBatch,
onSavePlayerProfileOk, onSavePlayerProfileFail);
}
private function onSavePlayerProfileOk(success:Number, version:Number, serverTime:Date, newMails:Array,
ingredientChanges:Array, timeToMaintenance:uint, gardenUpdates:Array, shift:Object, newChallenges:Array):void {
log('save player profile ok: ' + success);
}
private function onSavePlayerProfileFail():void {
throw 'save player profile fail';
}
private function addOfflineMoney(creditsDelta:int, times:int):void {
if (saveVersion > 1) return error('cannot add offline money after first save');
var auditChange:Object = new AuditChange();
auditChange.action = AuditChangeAction.creditChangeOffLine;
auditChange.creditsDelta = creditsDelta;
var auditChanges:Array = [];
for (var i:int = 0; i < times; i++) {
auditChanges.push(auditChange);
}
savePlayerProfile(auditChanges);
}
private function hire(uid:String):void {
log('now hiring');
var employee:Object = new CPRC.Employee();
employee.id = new NetworkUid(NetworkUid.FACEBOOK, uid, 0);
employee.task = CPGC.GameUserEmployee.JOB_WAITOR;
var auditChange:Object = new AuditChange();
auditChange.action = AuditChangeAction.hireEmployee;
auditChange.employees = [employee];
savePlayerProfile([auditChange]);
}
private function sendMail(recipientId:String, globalItemId:int, number:int):void {
log('sending mail');
var mail:Object = new CPRC.Mail();
mail.type = CPRC.RpcClient.MAIL_FAN_PAGE_ITEM;
mail.message = '';
mail.recipientId = new NetworkUid(NetworkUid.FACEBOOK, recipientId, 0);
mail.globalItemIds = [globalItemId];
GameWorld.rpcClient.beginBatch(RpcClient.BATCHMODE_CONDITIONAL);
var success:int = 0;
var fail:int = 0;
var notify:Function = function ():void {
log('mailing results: ' + success + ' succeeded, ' + fail + ' failed');
}
for (var i:int = 0; i < number; i++) {
GameWorld.rpcClient.sendMail(mail,
function (e:Number):void {
if (e) log('mail sent ' + e);
if (++success + fail == number) notify();
},
function ():void {
if (success + ++fail == number) notify();
}
);
}
GameWorld.rpcClient.endBatch();
}
private var getReceivedMailsRpc:Object;
private function acceptFeedGiftMail():void {
log('getting received mails');
var rm:Object = new RpcRequestManager(RpcClient.BATCHMODE_CONDITIONAL);
rm.addEventListener(RpcEvent.SUCCESS, onGetReceivedMailsSuccess);
rm.addEventListener(RpcEvent.FAIL, onGetReceivedMailsFail);
getReceivedMailsRpc = rm.getReceivedMails();
rm.commit();
}
private function onGetReceivedMailsSuccess(e:Event):void {
var mails:Array = getReceivedMailsRpc.mails;
var auditChange:Object = new AuditChange();
auditChange.action = AuditChangeAction.acceptFeedGiftMail;
auditChange.mailId = [];
var MAIL_FAN_PAGE_ITEM:uint = CPRC.RpcClient.MAIL_FAN_PAGE_ITEM;
for each (var mail:Object in mails)
if (mail.type == MAIL_FAN_PAGE_ITEM)
auditChange.mailId.push(mail.id);
log('accepting ' + JSON.stringify(auditChange.mailId));
savePlayerProfile([auditChange]);
}
private function onGetReceivedMailsFail(e:Event):void {
throw 'get received mails fail';
}
private function fromInventoryToGame(globalItemId:Number, positionX:Number, positionY:Number, roomIndex:uint, data:Number, number:int):void {
var auditChanges:Array = [];
for (var i:int = 0; i < number; i++) {
var ownedItem:Object = new CPRC.OwnedItem();
ownedItem.id = -i;
ownedItem.globalItemId = globalItemId;
ownedItem.positionX = positionX;
ownedItem.positionY = positionY;
ownedItem.roomIndex = roomIndex;
ownedItem.data = data;
var auditChange:Object = new AuditChange();
auditChange.action = AuditChangeAction.fromInventoryToGame;
auditChange.ownedItem = ownedItem;
auditChanges.push(auditChange);
}
savePlayerProfile(auditChanges);
}
private function fromGameToInventory(globalItemId:Number, roomIndex:uint):void {
var auditChanges:Array = [];
for each (var ownedItem:Object in getUserProfileRpc.userInfo.ownedItem) {
if (ownedItem.globalItemId != globalItemId || ownedItem.roomIndex != roomIndex)
continue;
var auditChange:Object = new AuditChange();
auditChange.action = AuditChangeAction.fromGameToInventory;
auditChange.ownedItem = ownedItem;
auditChanges.push(auditChange);
}
savePlayerProfile(auditChanges);
}
private function sellPurchaseOwnedItem(employeeId:String, globalItemId:Number):void {
var category:int = globalItemId > 999999 ? globalItemId / 10000 : globalItemId;
var auditChanges:Array = [];
var ownedItem:Object, auditChange:Object;
var employee:Object = new NetworkUid(NetworkUid.FACEBOOK, employeeId, 0);
for each (var equipped:Object in getUserProfileRpc.userInfo.ownedItem) {
if (
equipped.employeeId &&
equipped.employeeId.networkUid == employeeId &&
int(equipped.globalItemId / 10000) == category
) {
ownedItem = new CPRC.OwnedItem();
ownedItem.globalItemId = equipped.globalItemId;
ownedItem.id = equipped.id;
ownedItem.employeeId = employee;
auditChange = new AuditChange();
auditChange.action = AuditChangeAction.sellOwnedItem;
auditChange.itemToken = tokenMap[equipped.globalItemId];
auditChange.ownedItem = ownedItem;
auditChanges.push(auditChange);
log('sellOwnedItem ' + auditChange.itemToken + ' ' + ownedItem.globalItemId + ' ' + ownedItem.id + ' ' + ownedItem.employeeId.networkUid); // %%%
}
}
if (globalItemId > 999999) {
ownedItem = new CPRC.OwnedItem();
ownedItem.globalItemId = globalItemId;
ownedItem.id = -1;
ownedItem.employeeId = employee;
auditChange = new AuditChange();
auditChange.action = AuditChangeAction.purchaseOwnedItem;
auditChange.itemToken = tokenMap[globalItemId];
auditChange.ownedItem = ownedItem;
auditChanges.push(auditChange);
log('purchaseOwnedItem ' + auditChange.itemToken + ' ' + ownedItem.globalItemId + ' ' + ownedItem.id + ' ' + ownedItem.employeeId.networkUid); // %%%
}
savePlayerProfile(auditChanges);
}
// headless
private function getUserInfo():Object {
return getUserProfileRpc.userInfo;
}
// headless
private function consumeItem(itemId:int):void {
var auditChange:Object = new AuditChange();
auditChange.action = AuditChangeAction.consumeItem;
auditChange.itemId = itemId;
savePlayerProfile([auditChange]);
}
// headless
private function consumeIngredients():void {
var auditChanges:Array = [];
var auditChange:Object;
var ingredients:Array = getUserProfileRpc.userInfo.ingredients;
for each (var inventoryItem:Object in ingredients) {
for (var i:int = 0; i < inventoryItem.number; i++) {
auditChange = new AuditChange();
auditChange.action = AuditChangeAction.consumeItem;
auditChange.itemId = inventoryItem.globalItemId;
auditChanges.push(auditChange);
}
}
savePlayerProfile(auditChanges);
}
private function today():String {
var timestamp:Date = new Date();
var date:Number = timestamp.dateUTC;
var month:Number = timestamp.monthUTC + 1;
var year:Number = timestamp.fullYearUTC;
return (
(date < 10 ? '0' + date : date) + '/' +
(month < 10 ? '0' + month : month) + '/' +
year
);
}
private function reverseDate(d:String):String {
return d.split('/', 3).reverse().join('/');
}
// headless
private function autoGift():void {
log('computing deficiency');
var date:String = reverseDate(today());
var list:Object = {};
var recipeIdMap:Object = {};
var ingredientIdMap:Object = {};
var ingredientNameMap:Object = {};
var combinedMap:Object = {};
var userInfo:Object = getUserProfileRpc.userInfo;
var item:Object;
for each (item in databases['recipe']..item) {
recipeIdMap[item.@id] = item;
combinedMap[item.@id] = item.@name.toString();
list[item.@id] = 10;
}
for each (item in databases['ingredient']..item) {
ingredientIdMap[item.@id] = item;
ingredientNameMap[item.@name] = item.@id.toString();
combinedMap[item.@id] = item.@name.toString();
list[item.@id] = 1;
}
for each (item in userInfo.ingredients) list[item.globalItemId] -= item.number;
for each (item in userInfo.recipes) list[item.globalItemId] -= item.number;
for each (item in recipeIdMap) {
var id:String = item.@id;
if (list[id] <= 0) {
delete list[id];
} else {
var need:int;
if (list[id] == 10 && (item.@invisible.length() || (item.@expireDate.length() && reverseDate(item.@expireDate) < date))) {
need = 9;
list[id] = 1;
} else {
need = list[id];
delete list[id];
}
for each (var ingredientName:String in item.@ingredients.split(/\s*,\s*/)) {
if (!(ingredientName in ingredientNameMap)) log(item.toXMLString());
list[ingredientNameMap[ingredientName]] += need;
}
}
}
for each (item in ingredientIdMap) if (list[item.@id] <= 0) delete list[item.@id.toString()];
// %%%%%%%%% turns out this is far from ready
var debug:Array = [];
for (item in list) debug.push([item, combinedMap[item], list[item]]);
debug.sortOn([2, 0]);
for (var i:int = 0; i < debug.length; i++) debug[i] = debug[i].join('\t');
log('you need:\n' + debug.join('\n'));
return; // %%%
log('sending mail');
var mail:Object = new CPRC.Mail();
mail.type = CPRC.RpcClient.MAIL_FAN_PAGE_ITEM;
mail.message = '';
mail.recipientId = getUserProfileRpc.userInfo.id;
GameWorld.rpcClient.beginBatch(RpcClient.BATCHMODE_CONDITIONAL);
var notified:Boolean = false;
var count:int = 64;
queueMessages: for (var key:String in list) {
mail.globalItemIds = [parseInt(key, 10)];
for (var i:int = 0; i < list[key]; i++) {
GameWorld.rpcClient.sendMail(mail,
function (e:Number):void {
if (!notified) setTimeout(acceptFeedGiftMail, 0);
notified = true;
if (e) log('mail sent ' + e);
},
function ():void { log('failmail'); }
);
if (!--count) break queueMessages;
}
}
GameWorld.rpcClient.endBatch();
}
}
}
import flash.system.ApplicationDomain;
import flash.utils.Proxy;
import flash.utils.flash_proxy;
internal class DLL extends Proxy {
private var prefix:String;
public function DLL(prefix:String = '') {
this.prefix = prefix;
}
override flash_proxy function getProperty(name:*):* {
return ApplicationDomain.currentDomain.getDefinition(prefix + name);
}
}