// ################################################################################################################ // ToL CloudScript for PlayFab by Dylan @ https://api.playfab.com/documentation/Server/method/ExecuteCloudScript // CHECK @ https://www.piliapp.com/syntax-check/es6/ // _____________________________________ // currentPlayerId = current user calling script // Log has 3 levels: debug, info, and error. Eg: log.debug('asdf'); // _____________________________________ // handlers.nameOfFunction = function(args, context) // args is an object - // "context" contains additional information when the Cloud Script function is called from a PlayStream action. // ################################################################################################################ var BASE_URL = 'https://api.throneoflies.com'; var GP_EARNED_WIN = 50; var GP_EARNED_LOSS = 35; // ........................................................................................... handlers.testGetInfo = function() { var req = { PlayFabId: currentPlayerId, InfoRequestParameters: getAllInfoReqParams() // InfoRequestParameters: // { // GetUserAccountInfo: true, // GetUserInventory: false, // GetUserVirtualCurrency: true, // GetUserData: true, // GetUserReadOnlyData: false, // GetCharacterInventories: false, // GetCharacterList: false, // GetTitleData: false, // GetPlayerStatistics: false // } }; var testResult = server.GetPlayerCombinedInfo(req); log.debug('testResult==' + testResult); return testResult; }; // ........................................................................................... function GET(url, body, isJsonp) { log.debug('GET >> ' + url + ' >> ' + json); var headers = { }; // var body = { // }; var content = JSON.stringify(body); var httpMethod = 'json'; if (isJsonp) httpMethod += p; // jsonp var contentType = 'application/json'; var response = http.request(url, httpMethod, content, contentType, headers); return response; }; // ........................................................................................... handlers.CheckIsAPIOnline = function() { log.debug('Checking if ToL API is online..'); var url = BASE_URL+ '/playfab?callback'; var body = { }; var isJsonp = true; var response = GET(url, body, isJsonp); return { responseContent: response } }; // ........................................................................................... handlers.ping = function() { log.debug('Pong'); var response = 'Pong'; return { responseContent: response } }; // ........................................................................................... // Lazy JSON.Stringify() for pretty logs and debugging function J(obj, pretty) { if (!pretty) return JSON.stringify(obj); // js obj >> json else return JSON.stringify(obj, null, 2); // Better for logs+humans }; // ........................................................................................... // Simple date for logs function GetDateTime() { return new Date().toISOString() .replace(/T/, ' ') // replace T with a space .replace(/\..+/, ''); // delete the dot and everything after }; // ........................................................................................... // https://api.playfab.com/documentation/Server/datatype/PlayFab.Server.Models/PlayFab.Server.Models.GetPlayerCombinedInfoRequestParams // NOT included: UserDataKeys: [], UserReadOnlyDataKeys: [], GetCharacterInventories: false, // GetCharacterList: false, TitleDataKeys: false, PlayerStatisticNames: [] function getAllInfoReqParams() { var infoRequestParameters = { GetUserAccountInfo: true, GetUserInventory: true, GetUserVirtualCurrency: true, GetUserData: true, GetUserReadOnlyData: true, GetTitleData: true, GetPlayerStatistics: true }; log.debug('[getAllInfoReqParams] infoRequestParameters == ' + J(infoRequestParameters)); return infoRequestParameters; } // ........................................................................................... // **EXPERIMENTAL** // Send message to other player >> for example, invite to party // https://community.playfab.com/questions/661/208349687-Invite-friend-to-a-game-approach-.html handlers.messageToPlayer = function (args) { // Collect args var toPlayerId = args.toPlayerId var messageTxt = args.messageText; var messageGroupId = toPlayerId + '_messages'; var dataPayload = {}; var keyString = currentPlayerId; dataPayload[keyString] = messageTxt; // http://api.playfab.com/Documentation/Server/method/UpdateSharedGroupData server.UpdateSharedGroupData( { "SharedGroupId": messageGroupId, "Data": dataPayload }); return true; }; // ........................................................................................... // https://api.playfab.com/documentation/Server/method/AddUserVirtualCurrency handlers.addGold = function(args) { log.debug('@ handlers.addGold'); var gpAmt = args.gpAmt; var player = (args.player ? args.player : currentPlayerId); // null = currentPlayerId // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> // Validate if (gpAmt == 0) { debug.error('gpAmt is 0/undefined! Aborting.'); return null; } // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> // log.debug('[handlers.addGold] gpAmt == ' + gpAmt); var addGpRequest = { PlayFabId: player, VirtualCurrency: "gp", Amount: gpAmt }; log.debug('[handlers.addGold] addGpRequest == ' + J(addGpRequest)); var addUserVirtualCurrencyResult = server.AddUserVirtualCurrency(addGpRequest); log.debug('[handlers.addGold] addUserVirtualCurrencyResult == ' + J(addUserVirtualCurrencyResult)); return addUserVirtualCurrencyResult; }; // ........................................................................................... function validateGameOverEvents(name, username, startClass, startFaction, finalClass, finalFaction, won, isDead, killedOthersCount) { log.debug('@ validateGameOverEvents'); if (!name) { log.error('name is NULL! Aborting.'); return false; } if (!username) { log.error('username is NULL! Aborting.'); return false; } if (!startClass) { log.error('startClass is NULL! Aborting.'); return nfalseull; } if (!startFaction) { log.error('startFaction is NULL! Aborting.'); return false; } if (!finalClass) { log.error('finalClass is NULL! Aborting.'); return false; } if (!finalFaction) { log.error('finalFaction is NULL! Aborting.'); return false; } // if (!won) // CANT CHECK AGAINST BOOL // { // log.error('won is NULL! Aborting.'); // return false; // } // if (!args.isDead) // CANT CHECK AGAINST BOOL // { // log.error('isDead is NULL! Aborting.'); // return false; // } // if (!args.killedOthersCount) // { // log.error('killedOthersCount is NULL! Aborting.'); // return false; // } // Success log.debug('[validateGameOverEvents] Validated'); return true; } // ........................................................................................... // gameOverEvents + global stats handlers.gameOverEventsMaster = function (args) { log.debug('@ gameOverEventsMaster'); // 1. Normal gameOverEvents var getPlayerCombinedInfoResult = handlers.gameOverEvents(args); // 2. Global stats log.debug('TODO: Global stats'); // Done return getPlayerCombinedInfoResult; }; // ........................................................................................... // 1. Assign gp // 2. Assign player stats // 3. Assign global stats // ____________________________________________________ // args == playerInfo // { // public string name; // public string username; // public string startClass; // public Classes.Faction startFaction; // public string finalClass; // public Classes.Faction finalFaction; // public bool won; // TODO: isKilled, killedOthersCount // } handlers.gameOverEvents = function(args) { log.debug('@ gameOverEvents'); // Assign vals var name = args.name; var username = args.username; var startClass = args.startClass; var startFaction = args.startFaction; var finalClass = args.finalClass; var finalFaction = args.finalFaction; var won = args.won; var isDead = args.isDead; // TODO var killedOthersCount = args.killedOthersCount; // TODO // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> // Validate var validated = validateGameOverEvents(name, username, startClass, startFaction, finalClass, finalFaction, won, isDead, killedOthersCount); // Fail logs included within if (!validated) return null; // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> // 1. Assign gp (DISABLED FOR PRE ALPHA) var gpAmt = (won ? GP_EARNED_WIN : GP_EARNED_LOSS); // 50 or 35 log.debug('[handlers.gameOverEvents] gpAmt == ' + gpAmt); var addGoldArgs = { gpAmt, currentPlayerId }; var addUserVirtualCurrencyResult = handlers.addGold(addGoldArgs); log.debug('[handlers.gameOverEvents] addUserVirtualCurrencyResult == ' + addUserVirtualCurrencyResult); // 2. TODO: Assign player stats var updateEndGameStatsResult = updateEndGameStats(startClass, startFaction, finalClass, finalFaction, won, isDead, killedOthersCount); log.debug('[handlers.gameOverEvents] updateEndGameStatsResult==' + J(updateEndGameStatsResult)); // 3. TODO: Assign global stats // 4. Return playerCombinedInfo var getPlayerCombinedInfoResult = getPlayerInfo(currentPlayerId, getAllInfoReqParams()); return getPlayerCombinedInfoResult; // return updateEndGameStatsResult; }; // ........................................................................................... // https://api.playfab.com/documentation/server/method/GetPlayerCombinedInfo function getPlayerInfo(player, infoReqParams) { log.debug('@ getPlayerInfo'); // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> // Validate if (!player) { log.error('[getPlayerInfo] player == NULL! Aborting.'); return null; } if (!infoReqParams) { log.error('[getPlayerInfo] infoReqParams == NULL! Aborting.'); return null; } log.debug('[getPlayerInfo] Validated'); // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> var getCombinedInfoRequest = { PlayFabId: player, InfoRequestParameters: infoReqParams }; log.debug('[getPlayerInfo] getCombinedInfoRequest == ' + J(getCombinedInfoRequest)); var getPlayerCombinedInfoResult = server.GetPlayerCombinedInfo(getCombinedInfoRequest); log.debug('[getPlayerInfo] getPlayerCombinedInfoResult == ' + J(getPlayerCombinedInfoResult)); return getPlayerCombinedInfoResult; } // ........................................................................................... // 4-21-2017: Losses stats REMOVED // 4-21-2017: Wins of specific class stats REMOVED (temporarily) // // startClassCounterName, startClassWinCountName, startClassLossCountName, incrementWin, // incrementLoss, incrementConvertedCount, diedCount, survivedCount, killedOthersCount, // incrementTotalGpEarned, maxNumDays function generateEndStats(combinedStats) { log.debug('@ generateEndStats'); // NOTE: Most values will fall within an automatic SUM() function upon updating. var jsonStats = [ // { // StatisticName: combinedStats.startClassCounterName, // Value: 1 // Always +1 // }, // { // StatisticName: combinedStats.startClassWinCountName, // Value: combinedStats.incrementWin // }, // { // StatisticName: combinedStats.startClassLossCountName, // Value: combinedStats.incrementLoss // }, { StatisticName: "overallWinCount", Value: combinedStats.incrementWin }, // { // StatisticName: "overallLossCount", // Value: combinedStats.incrementLoss // }, { StatisticName: "convertedCount", Value: combinedStats.incrementConvertedCount }, { StatisticName: "killedOthersCount", Value: combinedStats.killedOthersCount }, { StatisticName: "diedCount", Value: combinedStats.diedCount }, { StatisticName: "survivedCount", Value: combinedStats.survivedCount }, { StatisticName: "totalGpEarned", Value: combinedStats.incrementTotalGpEarned }, // { // StatisticName: "maxNumDays", // Value: combinedStats.maxNumDays // } ]; // Total = 11 // log.debug('[generateEndStats] incrementTotalGpEarned==' + combinedStats.incrementTotalGpEarned); log.debug('[generateEndStats] jsonStats == ' + J(jsonStats)); return jsonStats; } // ........................................................................................... // 0 >> ver, // 1 >> globalBDWonCount, globalBDWonCount, globalCultWonCount, globalNumDaysCount // 2 >> globalNumExecuted, globalNumPardoned, globalNumPlayersInMatch, globalMatchCount, // 3 >> (globalClassNameSpawnedCountKey), globalClassNameSpawnedCount, (globalClassNameWinCountKey), globalClassNameWinCount, globalBRSpawnRate, globalCultSpawnRate, function generateEndStatsMaster(combinedMasterStats) { log.debug('@ generateEndStatsMaster'); var jsonMasterStats = [ // 1 >> { StatisticName: "globalBDWonCount", Value: combinedMasterStats.globalBDWonCount }, { StatisticName: "globalBDWonCount", Value: combinedMasterStats.globalBDWonCount }, { StatisticName: "globalCultWonCount", Value: combinedMasterStats.globalCultWonCount }, { StatisticName: "globalNumDaysCount", Value: combinedMasterStats.diedCount }, // 2 >> { StatisticName: "globalNumExecuted", Value: combinedMasterStats.globalNumExecuted }, { StatisticName: "globalNumPardoned", Value: combinedMasterStats.globalNumPardoned }, { StatisticName: "globalNumPlayersInMatch", Value: combinedMasterStats.globalNumPlayersInMatch }, { StatisticName: "globalMatchCount", Value: combinedMasterStats.globalMatchCount }, // 3 >> { StatisticName: "globalClassNameSpawnedCountKey", Value: combinedMasterStats.globalClassNameSpawnedCount }, { StatisticName: "globalClassNameWinCountKey", Value: combinedMasterStats.globalClassNameWinCount }, { StatisticName: "globalBRSpawnRate", Value: combinedMasterStats.globalBRSpawnRate }, { StatisticName: "globalCultSpawnRate", Value: combinedMasterStats.globalCultSpawnRate } ]; // Total = 12 log.debug('[generateEndStatsMaster] jsonMasterStats == ' + J(jsonMasterStats)); return jsonMasterStats; } // ........................................................................................... // 1 >> globalBDWonCount, globalBDWonCount, globalCultWonCount, globalNumDaysCount // 2 >> globalNumExecuted, globalNumPardoned, globalNumPlayersInMatch, globalMatchCount, // 3 >> (globalClassNameSpawnedCountKey), globalClassNameSpawnedCount, (globalClassNameWinCountKey), globalClassNameWinCount, globalBRSpawnRate, globalCultSpawnRate, function validateMasterStats(combinedMasterStats) { log.debug('@ validateMasterStats'); // 1 >> if (combinedMasterStats.globalBDWonCount === null) { log.error('[validateStats] globalBDWonCount is NULL! Aborting.'); return false; } if (combinedMasterStats.globalBDWonCount === null) { log.error('[validateStats] globalBDWonCount is NULL! Aborting.'); return false; } if (combinedMasterStats.globalCultWonCount === null) { log.error('[validateStats] globalCultWonCount is NULL! Aborting.'); return false; } if (combinedMasterStats.globalNumDaysCount === null) { log.error('[validateStats] globalNumDaysCount is NULL! Aborting.'); return false; } // 2 >> if (combinedMasterStats.globalNumExecuted === null) { log.error('[validateStats] globalNumExecuted is NULL! Aborting.'); return false; } if (combinedMasterStats.globalNumPardoned === null) { log.error('[validateStats] globalNumPardoned is NULL! Aborting.'); return false; } if (combinedMasterStats.globalNumPlayersInMatch === null) { log.error('[validateStats] globalNumPlayersInMatch is NULL! Aborting.'); return false; } if (combinedMasterStats.globalMatchCount === null) { log.error('[validateStats] globalMatchCount is NULL! Aborting.'); return false; } // 3 >> if (combinedMasterStats.globalClassNameSpawnedCount === null) { log.error('[validateStats] globalClassNameSpawnedCount is NULL! Aborting.'); return false; } if (combinedMasterStats.globalClassNameWinCountKey === null) { log.error('[validateStats] globalClassNameWinCountKey is NULL! Aborting.'); return false; } if (combinedMasterStats.globalClassNameWinCountKey === null) { log.error('[validateStats] globalClassNameWinCountKey is NULL! Aborting.'); return false; } if (combinedMasterStats.globalClassNameWinCount === null) { log.error('[validateStats] globalClassNameWinCount is NULL! Aborting.'); return false; } if (combinedMasterStats.globalBRSpawnRate === null) { log.error('[validateStats] globalBRSpawnRate is NULL! Aborting.'); return false; } if (combinedMasterStats.globalCultSpawnRate === null) { log.error('[validateStats] globalCultSpawnRate is NULL! Aborting.'); return false; } // Success log.debug('[validateMasterStats] Validated == true'); return true; } // ........................................................................................... // 4-21-2017: Losses stats REMOVED // 4-21-2017: Wins of specific class stats REMOVED (temporarily) // // startClassCounterName, startClassWinCountName, startClassLossCountName, incrementWin, // incrementLoss, incrementConvertedCount, diedCount, survivedCount, killedOthersCount, // incrementTotalGpEarned, maxNumDays function validateStats(combinedStats) { log.debug('@ validateStats'); // if (!combinedStats.startClassCounterName) // { // log.error('[validateStats] startClassCounterName is NULL! Aborting.'); // return false; // } // if (!combinedStats.startClassWinCountName) // { // log.error('[validateStats] startClassWinCountName is NULL! Aborting.'); // return false; // } // if (!combinedStats.startClassLossCountName) // { // log.error('[validateStats] startClassLossCountName is NULL! Aborting.'); // return false; // } if (combinedStats.incrementWin === null) { log.error('[validateStats] incrementWin is NULL! Aborting.'); return false; } // if (combinedStats.incrementLoss === null) // { // log.error('[validateStats] incrementLoss is NULL! Aborting.'); // return false; // } if (combinedStats.incrementConvertedCount === null) { log.error('[validateStats] incrementConvertedCount is NULL! Aborting.'); return false; } if (combinedStats.diedCount === null) { log.error('[validateStats] diedCount is NULL! Aborting.'); return false; } if (combinedStats.survivedCount === null) { log.error('[validateStats] survivedCount is NULL0! Aborting.'); return false; } if (combinedStats.killedOthersCount === null) { log.error('[validateStats] killedOthersCount is NULL! Aborting.'); return false; } if (combinedStats.incrementTotalGpEarned === null) { log.error('[validateStats] incrementTotalGpEarned is NULL! Aborting.'); return false; } // if (combinedStats.maxNumDays === null) // { // log.error('[validateStats] maxNumDays is NULL! Aborting.'); // return false; // } // Success log.debug('[validateStats] Validated == true'); return true; } // ........................................................................................... // https://api.playfab.com/documentation/server/method/UpdatePlayerStatistics // // 4-21-2017: Losses stats REMOVED // 4-21-2017: Wins of specific class stats REMOVED // // startCounter, WinCount, LossCount, overallWinCount, // overallLossCount, convertedCount, killedCount (TODO), diedCount (TODO), totalGpEarned function updateEndGameStats(startClass, startFaction, finalClass, finalFaction, won, isDead, killedOthersCount, maxNumDays) { log.debug('@ updateEndGameStats'); // TODO fillers var diedCount = 0; var survivedCount = 0; // Dynamic stat names // var startClassCounterName = 'startClass' + startClass + 'PlayCount'; // startClassMastermindPlayCount // var startClassWinCountName = 'startClass' + startClass + 'WinCount'; // startClassMastermindWinCount // var startClassLossCountName = 'startClass' + startClass + 'LossCount'; // startClassMastermindLossCount // Calcs var incrementWin = (won ? 1 : 0); // var incrementLoss = (won ? 0 : 1); var incrementConvertedCount = (startFaction === finalFaction ? 0 : 1); //var diedCount = (isDead ? 0 : 1); // TODO: Consider rezzes //var survivedCount = (isDead ? 0 : 1); var incrementTotalGpEarned = (won ? GP_EARNED_WIN : GP_EARNED_LOSS); // Convert to object to pass around var combinedStats = { // startClassCounterName, // startClassWinCountName, // startClassLossCountName, incrementWin, // incrementLoss, incrementConvertedCount, diedCount, survivedCount, killedOthersCount, incrementTotalGpEarned, // maxNumDays }; // Validate var validStats = validateStats(combinedStats); if (!validStats) return null; var stats = generateEndStats(combinedStats); // Update stats now var updateEndGameStatsResult = updatePlayerStats(currentPlayerId, stats); log.debug('[updateEndGameStats] updateEndGameStatsResult == ' + J(updateEndGameStatsResult)); return updateEndGameStatsResult; } // ........................................................................................... // handlers.testStats = function(args) // { // log.debug('@ handlers.testStats'); // var testResult = updatePlayerStats(currentPlayerId, stat); // return testResult; // }; // ........................................................................................... // function validateStats(startClassCounterName, startClassWinCountName, startClassLossCountName, // incrementWin, incrementLoss, incrementConvertedCount, diedCount, // survivedCount, killedOthersCount, incrementTotalGpEarned) function updatePlayerStats(player, stats) { log.debug('@ updatePlayerStats'); // Validate if (!player) { log.error('[updatePlayerStats]*ERR: player == NULL! Aborting.'); return null; } if (!stats) { log.error('[updatePlayerStats]*ERR: stats == NULL! Aborting.'); } log.debug('[updatePlayerStats] Final Validation == Validated'); var updatePlayerStatsReq = { PlayFabId: player, Statistics: stats }; log.debug('[updatePlayerStats] updatePlayerStatsReq == ' + J(updatePlayerStatsReq)); var updatePlayerStatisticsResult = server.UpdatePlayerStatistics(updatePlayerStatsReq); log.debug('[updatePlayerStats] updatePlayerStatisticsResult == ' + J(updatePlayerStatisticsResult)); return updatePlayerStatisticsResult; } // ........................................................................................... function prepGetUserInventory(pfid) { log.debug('@ prepGetUserInventory'); var req = { PlayFabId: pfid }; var userInvRes = server.GetUserInventory(req); log.debug(userInvRes); return userInvRes; } // ........................................................................................... // https://api.playfab.com/documentation/server/method/GetUserInventory handlers.startSync = function(args) { log.debug('@ startSync: Getting my inventory...'); var myInv = prepGetUserInventory(currentPlayerId); //PlayFabId | Inventory | VirtualCurrency | VirtualCurrencyRechargeTimes // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> // Validate if (!myInv) { log.error('[startSync]**ERR: myInv is NULL! Aborting'); return null; } var startingSword = myInv.Inventory.find(item => item.ItemId == "WEAPON_STARTER_SWORD"); var startingArmor = myInv.Inventory.find(item => item.ItemId == "ARMOR_STARTER_M"); // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> var myNewInv; if (!startingSword && !startingArmor) myNewInv = grantStarterPack(); else if (!startingSword && startingArmor) { log.error('[startSync]**ERR: NO startingSword, but HAS startingArmor. Strange...'); var wepOnly = true; myNewInv = grantStarterPack(wepOnly); } else if (startingSword && !startingArmor) { var wepOnly = false; var armorOnly = true; myNewInv = grantStarterPack(wepOnly); } else { log.error('[startSync]**ERR: Already has starting item(s)! Aborting.'); } log.debug('[startSync] Done! myNewInv==' + myNewInv); return myNewInv; } // ........................................................................................... // https://api.playfab.com/documentation/server/method/GrantItemsToUser function grantStarterPack(wepOnly, armorOnly) { log.debug('[startSync] @ grantStarterPack'); var itemIds; if (wepOnly) itemIds = [ "WEAPON_STARTER_SWORD" ]; else if (armorOnly) { itemIds = [ "WEAPON_STARTER_ARMOR" ]; } else { // Apply both itemIds = [ "WEAPON_STARTER_SWORD", "ARMOR_STARTER_M" ]; } var annotation = "Starter Pack"; var myNewInv = prepGrantItemsToUser(itemIds, annotation); return myNewInv; } // ........................................................................................... // https://api.playfab.com/documentation/server/method/GrantItemsToUser // https://api.playfab.com/documentation/server/method/GetUserInventory function prepGrantItemsToUser(itemIds, annotation) { log.debug('@ grantItemsToUser'); var req = { PlayFabId: currentPlayerId, ItemIds: itemIds, Annotation: annotation }; log.debug('[grantItemsToUser] req == ' + req); var grantItemsToUserRes = server.GrantItemsToUser(req); log.debug('[grantItemsToUser] grantItemsToUserRes == ' + grantItemsToUserRes); // Since the above returns GrantedItemInstance[] SERVER result, it's awkward to convert. log.debug('[grantItemsToUser] Getting new inventory...'); var myNewInv = prepGetUserInventory(currentPlayerId); log.debug('[grantItemsToUser] myNewInv == ' + myNewInv); return myNewInv; }